diff --git a/build_scripts/Debian+Ubuntu/control.stretch b/build_scripts/Debian+Ubuntu/control.stretch index 9b557e3b8..6968c9964 100644 --- a/build_scripts/Debian+Ubuntu/control.stretch +++ b/build_scripts/Debian+Ubuntu/control.stretch @@ -2,7 +2,7 @@ Source: retroshare06 Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev (>= 3.4.0), libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default Standards-Version: 3.9.6 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index 45c4ffc33..5cbb59f24 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -4,6 +4,7 @@ version="0.6.2" gitpath="https://github.com/RetroShare/RetroShare.git" workdir=retroshare06-${version} +branch="v0.6.2-official_release" #bubba3="Y" # comment out to compile for bubba3 ###################################################### @@ -66,6 +67,7 @@ echo " "Commit count : ${ccount} echo " "Date : ${date} echo " "Time : ${time} echo " "Hash : ${hhsh} +echo " "Using branch : ${branch} echo " "Using revision : ${rev} echo Done. @@ -80,7 +82,7 @@ echo Extracting base archive... mkdir -p ${workdir}/src echo Checking out latest snapshot... cd ${workdir}/src -git clone --depth 1 https://github.com/RetroShare/RetroShare.git . +git clone --depth 1 https://github.com/RetroShare/RetroShare.git --single-branch --branch $branch . cd - if ! test -d ${workdir}/src/libretroshare/; then diff --git a/libbitdht/src/udp/udpbitdht.cc b/libbitdht/src/udp/udpbitdht.cc index 5410d50e0..39c13e182 100644 --- a/libbitdht/src/udp/udpbitdht.cc +++ b/libbitdht/src/udp/udpbitdht.cc @@ -58,7 +58,7 @@ /*************************************/ UdpBitDht::UdpBitDht(UdpPublisher *pub, bdNodeId *id, std::string appVersion, std::string bootstrapfile, const std::string& filteredipfile, bdDhtFunctions *fns) - :UdpSubReceiver(pub), dhtMtx(true), mFns(fns) + :UdpSubReceiver(pub), dhtMtx(true)//, mFns(fns) { std::string usedVersion; diff --git a/libbitdht/src/udp/udpbitdht.h b/libbitdht/src/udp/udpbitdht.h index 36946877e..f1e167abf 100644 --- a/libbitdht/src/udp/udpbitdht.h +++ b/libbitdht/src/udp/udpbitdht.h @@ -119,7 +119,7 @@ void clearDataTransferred(); bdMutex dhtMtx; /* for all class data (below) */ bdNodeManager *mBitDhtManager; - bdDhtFunctions *mFns; + //bdDhtFunctions *mFns; uint32_t mReadBytes; diff --git a/libbitdht/src/util/bdnet.h b/libbitdht/src/util/bdnet.h index 9b9d36f48..7e3e24644 100644 --- a/libbitdht/src/util/bdnet.h +++ b/libbitdht/src/util/bdnet.h @@ -103,8 +103,6 @@ int bdnet_inet_aton(const char *name, struct in_addr *addr); int bdnet_checkTTL(int fd); void bdsockaddr_clear(struct sockaddr_in *addr); -/* thread-safe version of inet_ntoa */ -std::string bdnet_inet_ntoa(struct in_addr in); /* Extra stuff to declare for windows error handling (mimics unix errno) */ @@ -175,4 +173,7 @@ int usleep(unsigned int usec); } /* C Interface */ #endif +/* thread-safe version of inet_ntoa */ +std::string bdnet_inet_ntoa(struct in_addr in); + #endif /* BITDHT_UNIVERSAL_NETWORK_HEADER */ diff --git a/libresapi/src/api/ApiServer.cpp b/libresapi/src/api/ApiServer.cpp index b9606a003..327dd6260 100644 --- a/libresapi/src/api/ApiServer.cpp +++ b/libresapi/src/api/ApiServer.cpp @@ -17,6 +17,10 @@ #include "ChannelsHandler.h" #include "StatsHandler.h" +#ifdef LIBRESAPI_QT + #include "SettingsHandler.h" +#endif + /* data types in json http://json.org/ string (utf-8 unicode) @@ -237,6 +241,9 @@ public: mApiPluginHandler(sts, ifaces), mChannelsHandler(ifaces.mGxsChannels), mStatsHandler() +#ifdef LIBRESAPI_QT + ,mSettingsHandler(sts) +#endif { // the dynamic cast is to not confuse the addResourceHandler template like this: // addResourceHandler(derived class, parent class) @@ -262,7 +269,11 @@ public: &ChannelsHandler::handleRequest); router.addResourceHandler("stats", dynamic_cast(&mStatsHandler), &StatsHandler::handleRequest); - } +#ifdef LIBRESAPI_QT + router.addResourceHandler("settings", dynamic_cast(&mSettingsHandler), + &SettingsHandler::handleRequest); +#endif + } PeersHandler mPeersHandler; IdentityHandler mIdentityHandler; @@ -274,6 +285,10 @@ public: ApiPluginHandler mApiPluginHandler; ChannelsHandler mChannelsHandler; StatsHandler mStatsHandler; + +#ifdef LIBRESAPI_QT + SettingsHandler mSettingsHandler; +#endif }; ApiServer::ApiServer(): @@ -362,6 +377,9 @@ std::string ApiServer::handleRequest(Request &request) if(data.isRawData()) return data.getRawData(); + if(!resp.mCallbackName.empty()) + outstream << resource_api::makeKeyValueReference("callback_name", resp.mCallbackName); + outstream << resource_api::makeKeyValue("debug_msg", debugString.str()); outstream << resource_api::makeKeyValueReference("returncode", returncode); if(!resp.mStateToken.isNull()) diff --git a/libresapi/src/api/ApiTypes.h b/libresapi/src/api/ApiTypes.h index c443eb170..6d6d5c746 100644 --- a/libresapi/src/api/ApiTypes.h +++ b/libresapi/src/api/ApiTypes.h @@ -252,6 +252,9 @@ public: StateToken mStateToken; + //Just for GUI benefit + std::string mCallbackName; + // the result StreamBase& mDataStream; diff --git a/libresapi/src/api/ChatHandler.cpp b/libresapi/src/api/ChatHandler.cpp index 5338ba4f9..a1c2f8feb 100644 --- a/libresapi/src/api/ChatHandler.cpp +++ b/libresapi/src/api/ChatHandler.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -165,6 +166,7 @@ ChatHandler::ChatHandler(StateTokenServer *sts, RsNotify *notify, RsMsgs *msgs, addResourceHandler("lobbies", this, &ChatHandler::handleLobbies); addResourceHandler("subscribe_lobby", this, &ChatHandler::handleSubscribeLobby); addResourceHandler("unsubscribe_lobby", this, &ChatHandler::handleUnsubscribeLobby); + addResourceHandler("autosubscribe_lobby", this, &ChatHandler::handleAutoSubsribeLobby); addResourceHandler("clear_lobby", this, &ChatHandler::handleClearLobby); addResourceHandler("lobby_participants", this, &ChatHandler::handleLobbyParticipants); addResourceHandler("messages", this, &ChatHandler::handleMessages); @@ -908,6 +910,15 @@ void ChatHandler::handleUnsubscribeLobby(Request &req, Response &resp) resp.setOk(); } +void ChatHandler::handleAutoSubsribeLobby(Request& req, Response& resp) +{ + ChatLobbyId chatId = 0; + bool autosubsribe; + req.mStream << makeKeyValueReference("chatid", chatId) << makeKeyValueReference("autosubsribe", autosubsribe); + mRsMsgs->setLobbyAutoSubscribe(chatId, autosubsribe); + resp.setOk(); +} + void ChatHandler::handleClearLobby(Request &req, Response &resp) { ChatLobbyId id = 0; @@ -949,13 +960,14 @@ void ChatHandler::handleMessages(Request &req, Response &resp) { RS_STACK_MUTEX(mMtx); /********** LOCKED **********/ - ChatId id(req.mPath.top()); + ChatId id(req.mPath.top()); + // make response a list resp.mDataStream.getStreamToMember(); if(id.isNotSet()) { - resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id"); - return; + resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id"); + return; } std::map >::iterator mit = mMsgs.find(id); if(mit == mMsgs.end()) @@ -992,10 +1004,11 @@ void ChatHandler::handleSendMessage(Request &req, Response &resp) void ChatHandler::handleMarkChatAsRead(Request &req, Response &resp) { RS_STACK_MUTEX(mMtx); /********** LOCKED **********/ - ChatId id(req.mPath.top()); + ChatId id(req.mPath.top()); + if(id.isNotSet()) { - resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id"); + resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id"); return; } std::map >::iterator mit = mMsgs.find(id); diff --git a/libresapi/src/api/ChatHandler.h b/libresapi/src/api/ChatHandler.h index dc075c77f..3463cee57 100644 --- a/libresapi/src/api/ChatHandler.h +++ b/libresapi/src/api/ChatHandler.h @@ -120,6 +120,7 @@ private: void handleLobbies(Request& req, Response& resp); void handleSubscribeLobby(Request& req, Response& resp); void handleUnsubscribeLobby(Request& req, Response& resp); + void handleAutoSubsribeLobby(Request& req, Response& resp); void handleClearLobby(Request& req, Response& resp); ResponseTask* handleLobbyParticipants(Request& req, Response& resp); void handleMessages(Request& req, Response& resp); diff --git a/libresapi/src/api/FileSearchHandler.cpp b/libresapi/src/api/FileSearchHandler.cpp index 2b56317ad..c159ad913 100644 --- a/libresapi/src/api/FileSearchHandler.cpp +++ b/libresapi/src/api/FileSearchHandler.cpp @@ -10,8 +10,8 @@ namespace resource_api { -FileSearchHandler::FileSearchHandler(StateTokenServer *sts, RsNotify *notify, RsTurtle *turtle, RsFiles *files): - mStateTokenServer(sts), mNotify(notify), mTurtle(turtle), mFiles(files), +FileSearchHandler::FileSearchHandler(StateTokenServer *sts, RsNotify *notify, RsTurtle *turtle, RsFiles */*files*/): + mStateTokenServer(sts), mNotify(notify), mTurtle(turtle),// mFiles(files), mMtx("FileSearchHandler") { mNotify->registerNotifyClient(this); diff --git a/libresapi/src/api/FileSearchHandler.h b/libresapi/src/api/FileSearchHandler.h index 1cab730a4..a049c2207 100644 --- a/libresapi/src/api/FileSearchHandler.h +++ b/libresapi/src/api/FileSearchHandler.h @@ -24,7 +24,7 @@ private: StateTokenServer* mStateTokenServer; RsNotify* mNotify; RsTurtle* mTurtle; - RsFiles* mFiles; + //RsFiles* mFiles; class Search{ public: diff --git a/libresapi/src/api/IdentityHandler.cpp b/libresapi/src/api/IdentityHandler.cpp index 6ff50fa02..5b7fd8f5f 100644 --- a/libresapi/src/api/IdentityHandler.cpp +++ b/libresapi/src/api/IdentityHandler.cpp @@ -103,9 +103,13 @@ IdentityHandler::IdentityHandler(StateTokenServer *sts, RsNotify *notify, RsIden { mNotify->registerNotifyClient(this); - addResourceHandler("*", this, &IdentityHandler::handleWildcard); - addResourceHandler("own", this, &IdentityHandler::handleOwn); - addResourceHandler("create_identity", this, &IdentityHandler::handleCreateIdentity); + addResourceHandler("*", this, &IdentityHandler::handleWildcard); + addResourceHandler("own", this, &IdentityHandler::handleOwn); + + addResourceHandler("own_ids", this, &IdentityHandler::handleOwnIdsRequest); + addResourceHandler("notown_ids", this, &IdentityHandler::handleNotOwnIdsRequest); + + addResourceHandler("create_identity", this, &IdentityHandler::handleCreateIdentity); } IdentityHandler::~IdentityHandler() @@ -178,6 +182,112 @@ void IdentityHandler::handleWildcard(Request & /*req*/, Response &resp) else resp.setFail(); } + +void IdentityHandler::handleNotOwnIdsRequest(Request & /*req*/, Response &resp) +{ + bool ok = true; + + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + uint32_t token; + mRsIdentity->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); + + time_t start = time(NULL); + while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + &&((time(NULL) < (start+10))) + ) + { +#ifdef WINDOWS_SYS + Sleep(500); +#else + usleep(500*1000); +#endif + } + + if(mRsIdentity->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + { + std::vector grps; + ok &= mRsIdentity->getGroupData(token, grps); + for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + { + RsGxsIdGroup& grp = *vit; + //electron: not very happy about this, i think the flags should stay hidden in rsidentities + if(!(grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) && grp.mIsAContact) + { + bool pgp_linked = (grp.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility ) ; + resp.mDataStream.getStreamToMember() + << makeKeyValueReference("id", grp.mMeta.mGroupId) /// @deprecated using "id" as key can cause problems in some JS based languages like Qml @see gxs_id instead + << makeKeyValueReference("gxs_id", grp.mMeta.mGroupId) + << makeKeyValueReference("pgp_id",grp.mPgpId ) + << makeKeyValueReference("name", grp.mMeta.mGroupName) + << makeKeyValueReference("pgp_linked", pgp_linked); + } + } + } + else ok = false; + + if(ok) resp.setOk(); + else resp.setFail(); +} + +void IdentityHandler::handleOwnIdsRequest(Request & /*req*/, Response &resp) +{ + bool ok = true; + + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + uint32_t token; + mRsIdentity->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); + + time_t start = time(NULL); + while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + &&((time(NULL) < (start+10))) + ) + { +#ifdef WINDOWS_SYS + Sleep(500); +#else + usleep(500*1000); +#endif + } + + if(mRsIdentity->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + { + std::vector grps; + ok &= mRsIdentity->getGroupData(token, grps); + for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + { + RsGxsIdGroup& grp = *vit; + //electron: not very happy about this, i think the flags should stay hidden in rsidentities + if(vit->mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) + { + bool pgp_linked = (grp.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility ) ; + resp.mDataStream.getStreamToMember() + << makeKeyValueReference("own_gxs_id", grp.mMeta.mGroupId) + << makeKeyValueReference("pgp_id",grp.mPgpId ) + << makeKeyValueReference("name", grp.mMeta.mGroupName) + << makeKeyValueReference("pgp_linked", pgp_linked); + } + } + + } + else + ok = false; + + if(ok) resp.setOk(); + else resp.setFail(); +} + ResponseTask* IdentityHandler::handleOwn(Request & /* req */, Response &resp) { StateToken state; diff --git a/libresapi/src/api/IdentityHandler.h b/libresapi/src/api/IdentityHandler.h index 5e5d67f13..1b54f5438 100644 --- a/libresapi/src/api/IdentityHandler.h +++ b/libresapi/src/api/IdentityHandler.h @@ -23,6 +23,9 @@ public: private: void handleWildcard(Request& req, Response& resp); + void handleNotOwnIdsRequest(Request& req, Response& resp); + void handleOwnIdsRequest(Request& req, Response& resp); + ResponseTask *handleOwn(Request& req, Response& resp); ResponseTask *handleCreateIdentity(Request& req, Response& resp); diff --git a/libresapi/src/api/PeersHandler.cpp b/libresapi/src/api/PeersHandler.cpp index 0f35e59e9..88e9bc445 100644 --- a/libresapi/src/api/PeersHandler.cpp +++ b/libresapi/src/api/PeersHandler.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -12,6 +13,12 @@ namespace resource_api { +#define PEER_STATE_ONLINE 1 +#define PEER_STATE_BUSY 2 +#define PEER_STATE_AWAY 3 +#define PEER_STATE_AVAILABLE 4 +#define PEER_STATE_INACTIVE 5 +#define PEER_STATE_OFFLINE 6 // todo: groups, add friend, remove friend, permissions void peerDetailsToStream(StreamBase& stream, RsPeerDetails& details) @@ -21,7 +28,50 @@ void peerDetailsToStream(StreamBase& stream, RsPeerDetails& details) << makeKeyValueReference("name", details.name) << makeKeyValueReference("location", details.location) << makeKeyValueReference("pgp_id", details.gpg_id) - ; + << makeKeyValueReference("pgp_id", details.gpg_id); + + if(details.state & RS_PEER_STATE_CONNECTED) + { + std::list statusInfo; + rsStatus->getStatusList(statusInfo); + + std::string state_string; + std::list::iterator it; + for (it = statusInfo.begin(); it != statusInfo.end(); ++it) + { + if (it->id == details.id) + { + switch (it->status) + { + case RS_STATUS_INACTIVE: + state_string = "inactive"; + break; + + case RS_STATUS_ONLINE: + state_string = "online"; + break; + + case RS_STATUS_AWAY: + state_string = "away"; + break; + + case RS_STATUS_BUSY: + state_string = "busy"; + break; + default: + state_string = "undefined"; + break; + } + break; + } + } + stream << makeKeyValueReference("state_string", state_string); + } + else + { + std::string state_string = "undefined"; + stream << makeKeyValueReference("state_string", state_string); + } } bool peerInfoToStream(StreamBase& stream, RsPeerDetails& details, RsPeers* peers, std::list& grpInfo, bool have_avatar) @@ -29,7 +79,9 @@ bool peerInfoToStream(StreamBase& stream, RsPeerDetails& details, RsPeers* peers bool ok = true; peerDetailsToStream(stream, details); stream << makeKeyValue("is_online", peers->isOnline(details.id)) - << makeKeyValue("chat_id", ChatId(details.id).toStdString()); + << makeKeyValue("chat_id", ChatId(details.id).toStdString()) + << makeKeyValue("custom_state_string", rsMsgs->getCustomStateString(details.id)); + std::string avatar_address = "/"+details.id.toStdString()+"/avatar_image"; @@ -63,7 +115,13 @@ PeersHandler::PeersHandler(StateTokenServer* sts, RsNotify* notify, RsPeers *pee mNotify->registerNotifyClient(this); mStateTokenServer->registerTickClient(this); addResourceHandler("*", this, &PeersHandler::handleWildcard); - addResourceHandler("examine_cert", this, &PeersHandler::handleExamineCert); + addResourceHandler("get_state_string", this, &PeersHandler::handleGetStateString); + addResourceHandler("set_state_string", this, &PeersHandler::handleSetStateString); + addResourceHandler("get_custom_state_string", this, &PeersHandler::handleGetCustomStateString); + addResourceHandler("set_custom_state_string", this, &PeersHandler::handleSetCustomStateString); + addResourceHandler("get_pgp_options", this, &PeersHandler::handleGetPGPOptions); + addResourceHandler("set_pgp_options", this, &PeersHandler::handleSetPGPOptions); + addResourceHandler("examine_cert", this, &PeersHandler::handleExamineCert); } PeersHandler::~PeersHandler() @@ -100,6 +158,27 @@ void PeersHandler::tick() mStateTokenServer->discardToken(mStateToken); mStateToken = mStateTokenServer->getNewToken(); } + + StatusInfo statusInfo; + rsStatus->getOwnStatus(statusInfo); + if(statusInfo.status != status) + { + status = statusInfo.status; + + RsStackMutex stack(mMtx); /********** STACK LOCKED MTX ******/ + mStateTokenServer->discardToken(mStringStateToken); + mStringStateToken = mStateTokenServer->getNewToken(); + } + + std::string custom_state = rsMsgs->getCustomStateString(); + if(custom_state != custom_state_string) + { + custom_state_string = custom_state; + + RsStackMutex stack(mMtx); /********** STACK LOCKED MTX ******/ + mStateTokenServer->discardToken(mCustomStateToken); + mCustomStateToken = mStateTokenServer->getNewToken(); + } } void PeersHandler::notifyUnreadMsgCountChanged(const RsPeerId &peer, uint32_t count) @@ -121,6 +200,73 @@ static bool have_avatar(RsMsgs* msgs, const RsPeerId& id) return size != 0; } +void PeersHandler::handleGetStateString(Request& /*req*/, Response& resp) +{ + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStringStateToken; + } + + std::string state_string; + StatusInfo statusInfo; + if (rsStatus->getOwnStatus(statusInfo)) + { + if(statusInfo.status == RS_STATUS_ONLINE) + state_string = "online"; + else if(statusInfo.status == RS_STATUS_BUSY) + state_string = "busy"; + else if(statusInfo.status == RS_STATUS_AWAY) + state_string = "away"; + else if(statusInfo.status == RS_STATUS_INACTIVE) + state_string = "inactive"; + else + state_string = "undefined"; + } + else + state_string = "undefined"; + + resp.mDataStream << makeKeyValueReference("state_string", state_string); + resp.setOk(); +} + +void PeersHandler::handleSetStateString(Request& req, Response& resp) +{ + std::string state_string; + req.mStream << makeKeyValueReference("state_string", state_string); + + uint32_t status = RS_STATUS_OFFLINE; + if(state_string == "online") + status = RS_STATUS_ONLINE; + else if(state_string == "busy") + status = RS_STATUS_BUSY; + else if(state_string == "away") + status = RS_STATUS_AWAY; + + rsStatus->sendStatus(RsPeerId(), status); + resp.setOk(); +} + +void PeersHandler::handleGetCustomStateString(Request& /*req*/, Response& resp) +{ + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mCustomStateToken; + } + + std::string custom_state_string = rsMsgs->getCustomStateString(); + resp.mDataStream << makeKeyValueReference("custom_state_string", custom_state_string); + resp.setOk(); +} + +void PeersHandler::handleSetCustomStateString(Request& req, Response& resp) +{ + std::string custom_state_string; + req.mStream << makeKeyValueReference("custom_state_string", custom_state_string); + + rsMsgs->setCustomStateString(custom_state_string); + resp.setOk(); +} + void PeersHandler::handleWildcard(Request &req, Response &resp) { bool ok = false; @@ -176,6 +322,9 @@ void PeersHandler::handleWildcard(Request &req, Response &resp) RsStackMutex stack(mMtx); /********** STACK LOCKED MTX ******/ unread_msgs = mUnreadMsgsCounts; } + std::list statusInfo; + rsStatus->getStatusList(statusInfo); + // list all peers ok = true; std::list identities; @@ -216,6 +365,11 @@ void PeersHandler::handleWildcard(Request &req, Response &resp) StreamBase& locationStream = itemStream.getStreamToMember("locations"); // mark as list (in case list is empty) locationStream.getStreamToMember(); + + int bestPeerState = 0; + unsigned int bestRSState = 0; + std::string bestCustomStateString; + for(std::vector::iterator vit = detailsVec.begin(); vit != detailsVec.end(); ++vit) { if(vit->gpg_id == *lit) @@ -226,8 +380,85 @@ void PeersHandler::handleWildcard(Request &req, Response &resp) unread = unread_msgs.find(vit->id)->second; stream << makeKeyValueReference("unread_msgs", unread); peerInfoToStream(stream,*vit, mRsPeers, grpInfo, have_avatar(mRsMsgs, vit->id)); - } + + + /* Custom state string */ + std::string customStateString; + if (vit->state & RS_PEER_STATE_CONNECTED) + { + customStateString = rsMsgs->getCustomStateString(vit->id); + } + + int peerState = 0; + + if (vit->state & RS_PEER_STATE_CONNECTED) + { + // get the status info for this ssl id + int rsState = 0; + std::list::iterator it; + for (it = statusInfo.begin(); it != statusInfo.end(); ++it) + { + if (it->id == vit->id) + { + rsState = it->status; + switch (rsState) + { + case RS_STATUS_INACTIVE: + peerState = PEER_STATE_INACTIVE; + break; + + case RS_STATUS_ONLINE: + peerState = PEER_STATE_ONLINE; + break; + + case RS_STATUS_AWAY: + peerState = PEER_STATE_AWAY; + break; + + case RS_STATUS_BUSY: + peerState = PEER_STATE_BUSY; + break; + } + + /* find the best ssl contact for the gpg item */ + if (bestPeerState == 0 || peerState < bestPeerState) + { + bestPeerState = peerState; + bestRSState = rsState; + bestCustomStateString = customStateString; + } + else if (peerState == bestPeerState) + { + /* equal state */ + if (bestCustomStateString.empty() && !customStateString.empty()) + { + bestPeerState = peerState; + bestRSState = rsState; + bestCustomStateString = customStateString; + } + } + break; + } + } + } + } } + itemStream << makeKeyValue("custom_state_string", bestCustomStateString); + + std::string state_string; + + if(bestRSState == RS_STATUS_ONLINE) + state_string = "online"; + else if(bestRSState == RS_STATUS_BUSY) + state_string = "busy"; + else if(bestRSState == RS_STATUS_AWAY) + state_string = "away"; + else if(bestRSState == RS_STATUS_INACTIVE) + state_string = "inactive"; + else + state_string = "undefined"; + + itemStream << makeKeyValue("state_string", state_string); } resp.mStateToken = getCurrentStateToken(); } @@ -300,6 +531,120 @@ void PeersHandler::handleExamineCert(Request &req, Response &resp) } } +void PeersHandler::handleGetPGPOptions(Request& req, Response& resp) +{ + std::string pgp_id; + req.mStream << makeKeyValueReference("pgp_id", pgp_id); + + RsPgpId pgp(pgp_id); + RsPeerDetails detail; + + if(!mRsPeers->getGPGDetails(pgp, detail)) + { + resp.setFail(); + return; + } + + std::string pgp_key = mRsPeers->getPGPKey(detail.gpg_id, false); + + resp.mDataStream << makeKeyValue("pgp_fingerprint", detail.fpr.toStdString()); + resp.mDataStream << makeKeyValueReference("pgp_key", pgp_key); + + resp.mDataStream << makeKeyValue("direct_transfer", detail.service_perm_flags & RS_NODE_PERM_DIRECT_DL); + resp.mDataStream << makeKeyValue("allow_push", detail.service_perm_flags & RS_NODE_PERM_ALLOW_PUSH); + resp.mDataStream << makeKeyValue("require_WL", detail.service_perm_flags & RS_NODE_PERM_REQUIRE_WL); + + resp.mDataStream << makeKeyValue("own_sign", detail.ownsign); + resp.mDataStream << makeKeyValue("trustLvl", detail.trustLvl); + + uint32_t max_upload_speed = 0; + uint32_t max_download_speed = 0; + + mRsPeers->getPeerMaximumRates(pgp, max_upload_speed, max_download_speed); + + resp.mDataStream << makeKeyValueReference("maxUploadSpeed", max_upload_speed); + resp.mDataStream << makeKeyValueReference("maxDownloadSpeed", max_download_speed); + + StreamBase& signersStream = resp.mDataStream.getStreamToMember("gpg_signers"); + + // mark as list (in case list is empty) + signersStream.getStreamToMember(); + + for(std::list::const_iterator it(detail.gpgSigners.begin()); it != detail.gpgSigners.end(); ++it) + { + RsPeerDetails detail; + if(!mRsPeers->getGPGDetails(*it, detail)) + continue; + + std::string pgp_id = (*it).toStdString(); + std::string name = detail.name; + + signersStream.getStreamToMember() + << makeKeyValueReference("pgp_id", pgp_id) + << makeKeyValueReference("name", name); + } + + resp.setOk(); +} + +void PeersHandler::handleSetPGPOptions(Request& req, Response& resp) +{ + std::string pgp_id; + req.mStream << makeKeyValueReference("pgp_id", pgp_id); + + RsPgpId pgp(pgp_id); + RsPeerDetails detail; + + if(!mRsPeers->getGPGDetails(pgp, detail)) + { + resp.setFail(); + return; + } + + int trustLvl; + req.mStream << makeKeyValueReference("trustLvl", trustLvl); + + if(trustLvl != (int)detail.trustLvl) + mRsPeers->trustGPGCertificate(pgp, trustLvl); + + int max_upload_speed; + int max_download_speed; + + req.mStream << makeKeyValueReference("max_upload_speed", max_upload_speed); + req.mStream << makeKeyValueReference("max_download_speed", max_download_speed); + + mRsPeers->setPeerMaximumRates(pgp, (uint32_t)max_upload_speed, (uint32_t)max_download_speed); + + bool direct_transfer; + bool allow_push; + bool require_WL; + + req.mStream << makeKeyValueReference("direct_transfer", direct_transfer); + req.mStream << makeKeyValueReference("allow_push", allow_push); + req.mStream << makeKeyValueReference("require_WL", require_WL); + + ServicePermissionFlags flags(0); + + if(direct_transfer) + flags = flags | RS_NODE_PERM_DIRECT_DL; + if(allow_push) + flags = flags | RS_NODE_PERM_ALLOW_PUSH; + if(require_WL) + flags = flags | RS_NODE_PERM_REQUIRE_WL; + + mRsPeers->setServicePermissionFlags(pgp, flags); + + bool own_sign; + req.mStream << makeKeyValueReference("own_sign", own_sign); + + if(own_sign) + mRsPeers->signGPGCertificate(pgp); + + resp.mStateToken = getCurrentStateToken(); + + resp.setOk(); +} + StateToken PeersHandler::getCurrentStateToken() { RsStackMutex stack(mMtx); /********** STACK LOCKED MTX ******/ diff --git a/libresapi/src/api/PeersHandler.h b/libresapi/src/api/PeersHandler.h index dfcc9e10c..5ae393b2f 100644 --- a/libresapi/src/api/PeersHandler.h +++ b/libresapi/src/api/PeersHandler.h @@ -35,6 +35,15 @@ private: void handleWildcard(Request& req, Response& resp); void handleExamineCert(Request& req, Response& resp); + void handleGetStateString(Request& req, Response& resp); + void handleSetStateString(Request& req, Response& resp); + + void handleGetCustomStateString(Request& req, Response& resp); + void handleSetCustomStateString(Request& req, Response& resp); + + void handleGetPGPOptions(Request& req, Response& resp); + void handleSetPGPOptions(Request& req, Response& resp); + // a helper which ensures proper mutex locking StateToken getCurrentStateToken(); @@ -44,9 +53,14 @@ private: RsMsgs* mRsMsgs; // required for avatar data std::list mOnlinePeers; + uint32_t status; + std::string custom_state_string; RsMutex mMtx; StateToken mStateToken; // mutex protected + StateToken mStringStateToken; // mutex protected + StateToken mCustomStateToken; // mutex protected + std::map mUnreadMsgsCounts; }; } // namespace resource_api diff --git a/libresapi/src/api/ResourceRouter.cpp b/libresapi/src/api/ResourceRouter.cpp index a13201a27..48050cdb6 100644 --- a/libresapi/src/api/ResourceRouter.cpp +++ b/libresapi/src/api/ResourceRouter.cpp @@ -37,6 +37,13 @@ ResponseTask* ResourceRouter::handleRequest(Request& req, Response& resp) if(vit->first == req.mPath.top()) { req.mPath.pop(); + + //Just for GUI benefit + std::string callbackName; + req.mStream << makeKeyValueReference("callback_name", callbackName); + resp.mCallbackName = callbackName; + // + return vit->second->handleRequest(req, resp); } } diff --git a/libresapi/src/api/RsControlModule.cpp b/libresapi/src/api/RsControlModule.cpp index 9430df170..2910bc443 100644 --- a/libresapi/src/api/RsControlModule.cpp +++ b/libresapi/src/api/RsControlModule.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "api/ApiServer.h" #include "api/Operators.h" @@ -23,7 +24,9 @@ RsControlModule::RsControlModule(int argc, char **argv, StateTokenServer* sts, A mDataMtx("RsControlModule::mDataMtx"), mRunState(WAITING_INIT), mAutoLoginNextTime(false), - mWantPassword(false) + mWantPassword(false), + mPassword(""), + mPrevIsBad(false) { mStateToken = sts->getNewToken(); this->argc = argc; @@ -55,13 +58,16 @@ bool RsControlModule::processShouldExit() return mProcessShouldExit; } -bool RsControlModule::askForPassword(const std::string &title, const std::string &key_details, bool /* prev_is_bad */, std::string &password, bool& cancelled) +bool RsControlModule::askForPassword(const std::string &title, const std::string &key_details, bool prev_is_bad, std::string &password, bool& cancelled) { cancelled = false ; { RS_STACK_MUTEX(mDataMtx); // ********** LOCKED ********** + + mPrevIsBad = prev_is_bad; + if(mFixedPassword != "") - { + { password = mFixedPassword; return true; } @@ -69,25 +75,31 @@ bool RsControlModule::askForPassword(const std::string &title, const std::string mWantPassword = true; mTitle = title; mKeyName = key_details; - mPassword = ""; + + if(mPassword != "") + { + password = mPassword; + mWantPassword = false; + return true; + } + mStateTokenServer->replaceToken(mStateToken); } - bool wait = true; - while(wait) + int i = 0; + while(i<100) { usleep(5*1000); - RS_STACK_MUTEX(mDataMtx); // ********** LOCKED ********** - wait = mWantPassword; - if(!wait && mPassword != "") + + if(mPassword != "") { - password = mPassword; - mPassword = ""; + password = mPassword; mWantPassword = false; mStateTokenServer->replaceToken(mStateToken); return true; } + i++; } return false; } @@ -124,6 +136,11 @@ void RsControlModule::run() bool login_ok = false; while(!login_ok) { + { + RsStackMutex stack(mDataMtx); // ********** LOCKED ********** + mPassword = ""; + } + // skip account selection if autologin is available if(initResult != RS_INIT_HAVE_ACCOUNT) setRunState(WAITING_ACCOUNT_SELECT); @@ -174,8 +191,19 @@ void RsControlModule::run() std::cerr << "RsControlModule::run() LockAndLoadCertificates failed. Unexpected switch value: " << retVal << std::endl; break; } + + { + RsStackMutex stack(mDataMtx); // ********** LOCKED ********** + mLoadPeerId.clear(); + } } + { + RsStackMutex stack(mDataMtx); // ********** LOCKED ********** + mFixedPassword = mPassword; + mPassword = ""; + } + setRunState(WAITING_STARTUP); std::cerr << "RsControlModule: login ok, starting Retroshare worker threads..." << std::endl; @@ -305,7 +333,8 @@ void RsControlModule::handlePassword(Request &req, Response &resp) resp.mDataStream << makeKeyValueReference("want_password", mWantPassword) - << makeKeyValueReference("key_name", mKeyName); + << makeKeyValueReference("key_name", mKeyName) + << makeKeyValueReference("prev_is_bad", mPrevIsBad); resp.mStateToken = mStateToken; resp.setOk(); } @@ -425,17 +454,17 @@ void RsControlModule::handleCreateLocation(Request &req, Response &resp) RsPeerId ssl_id; std::string err_string; // give the password to the password callback - { - RsStackMutex stack(mDataMtx); // ********** LOCKED ********** - mFixedPassword = pgp_password; - } + { + RsStackMutex stack(mDataMtx); // ********** LOCKED ********** + mFixedPassword = pgp_password; + } bool ssl_ok = RsAccounts::GenerateSSLCertificate(pgp_id, "", ssl_name, "", hidden_port!=0, ssl_password, ssl_id, err_string); // clear fixed password to restore normal password operation - { - RsStackMutex stack(mDataMtx); // ********** LOCKED ********** - mFixedPassword = ""; - } +// { +// RsStackMutex stack(mDataMtx); // ********** LOCKED ********** +// mFixedPassword = ""; +// } if (ssl_ok) { @@ -456,6 +485,20 @@ void RsControlModule::handleCreateLocation(Request &req, Response &resp) resp.setFail("could not create a new location. Error: "+err_string); } +bool RsControlModule::askForDeferredSelfSignature(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,int& signature_result, std::string reason /*=""*/) +{ + if(rsPeers->gpgSignData(data,len,sign,signlen,reason)) + { + signature_result = SELF_SIGNATURE_RESULT_SUCCESS; + return true; + } + else + { + signature_result = SELF_SIGNATURE_RESULT_FAILED; + return false; + } +} + void RsControlModule::setRunState(RunState s, std::string errstr) { RsStackMutex stack(mDataMtx); // ********** LOCKED ********** diff --git a/libresapi/src/api/RsControlModule.h b/libresapi/src/api/RsControlModule.h index d3c8ad18b..7e306405c 100644 --- a/libresapi/src/api/RsControlModule.h +++ b/libresapi/src/api/RsControlModule.h @@ -31,8 +31,9 @@ public: // returns true if the process should terminate bool processShouldExit(); - // from NotifyClient - virtual bool askForPassword(const std::string &title, const std::string& key_details, bool prev_is_bad , std::string& password,bool& canceled); + // from NotifyClient + virtual bool askForPassword(const std::string &title, const std::string& key_details, bool prev_is_bad , std::string& password,bool& canceled) override; + virtual bool askForDeferredSelfSignature(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,int& signature_result, std::string reason = "") override; protected: // from RsThread @@ -76,6 +77,7 @@ private: // to notify that a password callback is waiting // to answer the request, clear the flag and set the password bool mWantPassword; + bool mPrevIsBad; std::string mTitle; std::string mKeyName; std::string mPassword; diff --git a/libresapi/src/api/SettingsHandler.cpp b/libresapi/src/api/SettingsHandler.cpp new file mode 100644 index 000000000..6e1aa75da --- /dev/null +++ b/libresapi/src/api/SettingsHandler.cpp @@ -0,0 +1,182 @@ +#include "SettingsHandler.h" + +#include + +#include + +namespace resource_api +{ + #define SETTINGS_FILE (QString::fromUtf8(RsAccounts::AccountDirectory().c_str()) + "/Sonet.conf") + + SettingsHandler::SettingsHandler(StateTokenServer *sts, const QString settingsGroup) : + QSettings(SETTINGS_FILE, QSettings::IniFormat), + mStateTokenServer(sts), + mMtx("SettingsHandler Mutex"), + mStateToken(sts->getNewToken()) + { + RsPeerId sPreferedId; + m_bValid = RsAccounts::GetPreferredAccountId(sPreferedId); + + if (!settingsGroup.isEmpty()) + beginGroup(settingsGroup); + + addResourceHandler("*", this, &SettingsHandler::handleSettingsRequest); + addResourceHandler("get_advanced_mode", this, &SettingsHandler::handleGetAdvancedMode); + addResourceHandler("set_advanced_mode", this, &SettingsHandler::handleSetAdvancedMode); + addResourceHandler("get_flickable_grid_mode", this, &SettingsHandler::handleGetFlickableGridMode); + addResourceHandler("set_flickable_grid_mode", this, &SettingsHandler::handleSetFlickableGridMode); + addResourceHandler("get_auto_login", this, &SettingsHandler::handleGetAutoLogin); + addResourceHandler("set_auto_login", this, &SettingsHandler::handleSetAutoLogin); + } + + SettingsHandler::~SettingsHandler() + { + sync(); + } + + void SettingsHandler::handleSettingsRequest(Request &/*req*/, Response &resp) + { + + } + + void SettingsHandler::handleGetAdvancedMode(Request &/*req*/, Response &resp) + { + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + + bool advanced_mode = valueFromGroup("General", "Advanced", false).toBool(); + resp.mDataStream << makeKeyValueReference("advanced_mode", advanced_mode); + resp.setOk(); + sync(); + } + + void SettingsHandler::handleSetAdvancedMode(Request &req, Response &resp) + { + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + + bool advanced_mode; + req.mStream << makeKeyValueReference("advanced_mode", advanced_mode); + setValueToGroup("General", "Advanced", advanced_mode); + resp.setOk(); + sync(); + } + + void SettingsHandler::handleGetFlickableGridMode(Request &/*req*/, Response &resp) + { + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + + bool flickable_grid_mode = valueFromGroup("General", "FlickableGrid", false).toBool(); + resp.mDataStream << makeKeyValueReference("flickable_grid_mode", flickable_grid_mode); + resp.setOk(); + sync(); + } + + void SettingsHandler::handleSetFlickableGridMode(Request &req, Response &resp) + { + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + + bool flickable_grid_mode; + req.mStream << makeKeyValueReference("flickable_grid_mode", flickable_grid_mode); + setValueToGroup("General", "FlickableGrid", flickable_grid_mode); + + resp.setOk(); + sync(); + } + + void SettingsHandler::handleGetAutoLogin(Request &/*req*/, Response &resp) + { + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + + bool autoLogin = RsInit::getAutoLogin();; + resp.mDataStream << makeKeyValueReference("auto_login", autoLogin); + resp.setOk(); + sync(); + } + + void SettingsHandler::handleSetAutoLogin(Request &req, Response &resp) + { + { + RS_STACK_MUTEX(mMtx); + resp.mStateToken = mStateToken; + } + + bool autoLogin; + req.mStream << makeKeyValueReference("auto_login", autoLogin); + RsInit::setAutoLogin(autoLogin); + + resp.setOk(); + sync(); + } + + QVariant SettingsHandler::value(const QString &key, const QVariant &defaultVal) const + { + if (m_bValid == false) + { + return defaultVal.isNull() ? defaultValue(key) : defaultVal; + } + return QSettings::value(key, defaultVal.isNull() ? defaultValue(key) : defaultVal); + } + + void SettingsHandler::setValue(const QString &key, const QVariant &val) + { + if (m_bValid == false) + { + std::cerr << "RSettings::setValue() Calling on invalid object, key = " << key.toStdString() << std::endl; + return; + } + if (val == defaultValue(key)) + QSettings::remove(key); + else if (val != value(key)) + QSettings::setValue(key, val); + } + + QVariant SettingsHandler::valueFromGroup(const QString &group, const QString &key, const QVariant &defaultVal) + { + beginGroup(group); + QVariant val = value(key, defaultVal); + endGroup(); + + return val; + } + + void SettingsHandler::setValueToGroup(const QString &group, const QString &key, const QVariant &val) + { + beginGroup(group); + setValue(key, val); + endGroup(); + } + + void SettingsHandler::setDefault(const QString &key, const QVariant &val) + { + _defaults.insert(key, val); + } + + QVariant SettingsHandler::defaultValue(const QString &key) const + { + if (_defaults.contains(key)) + return _defaults.value(key); + return QVariant(); + } + + void SettingsHandler::reset() + { + /* Static method, so we have to create a QSettings object. */ + QSettings settings(SETTINGS_FILE, QSettings::IniFormat); + settings.clear(); + } +} // namespace resource_api + diff --git a/libresapi/src/api/SettingsHandler.h b/libresapi/src/api/SettingsHandler.h new file mode 100644 index 000000000..b4c21fae2 --- /dev/null +++ b/libresapi/src/api/SettingsHandler.h @@ -0,0 +1,59 @@ +#ifndef SETTINGSHANDLER_H +#define SETTINGSHANDLER_H + +#include + +#include + +#include "ResourceRouter.h" +#include "StateTokenServer.h" + +/* Reimplemented class RSettings*/ +namespace resource_api +{ + class SettingsHandler : public ResourceRouter, public QSettings + { + public: + SettingsHandler(StateTokenServer* sts, const QString group = QString()); + ~SettingsHandler(); + + static void reset(); + + QVariant value(const QString &key, + const QVariant &defaultVal = QVariant()) const; + + void setValue(const QString &key, const QVariant &val); + + QVariant valueFromGroup(const QString &group, const QString &key, + const QVariant &defaultVal = QVariant()); + void setValueToGroup(const QString &group, const QString &key, + const QVariant &val); + + protected: + void setDefault(const QString &key, const QVariant &val); + QVariant defaultValue(const QString &key) const; + + bool m_bValid; + + private: + void handleSettingsRequest(Request& req, Response& resp); + + void handleGetAdvancedMode(Request& req, Response& resp); + void handleSetAdvancedMode(Request& req, Response& resp); + + void handleGetFlickableGridMode(Request& req, Response& resp); + void handleSetFlickableGridMode(Request& req, Response& resp); + + void handleGetAutoLogin(Request& req, Response& resp); + void handleSetAutoLogin(Request& req, Response& resp); + + QHash _defaults; + + StateTokenServer* mStateTokenServer; + + RsMutex mMtx; + StateToken mStateToken; // mutex protected + }; +} // namespace resource_api + +#endif // SETTINGSHANDLER_H diff --git a/libresapi/src/libresapi.pro b/libresapi/src/libresapi.pro index f310198fb..e548ea9d0 100644 --- a/libresapi/src/libresapi.pro +++ b/libresapi/src/libresapi.pro @@ -10,6 +10,40 @@ DESTDIR = lib INCLUDEPATH += ../../libretroshare/src +retroshare_android_service { + win32 { + OBJECTS_DIR = temp/obj + + LIBS_DIR = $$PWD/../../libs/lib + LIBS += $$OUT_PWD/../../libretroshare/src/lib/libretroshare.a + LIBS += $$OUT_PWD/../../openpgpsdk/src/lib/libops.a + + for(lib, LIB_DIR):LIBS += -L"$$lib" + for(bin, BIN_DIR):LIBS += -L"$$bin" + + + LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -lws2_32 + LIBS += -luuid -lole32 -liphlpapi -lcrypt32 -lgdi32 + LIBS += -lwinmm + + DEFINES *= WINDOWS_SYS WIN32_LEAN_AND_MEAN _USE_32BIT_TIME_T + + DEPENDPATH += . $$INC_DIR + INCLUDEPATH += . $$INC_DIR + + greaterThan(QT_MAJOR_VERSION, 4) { + # Qt 5 + RC_INCLUDEPATH += $$_PRO_FILE_PWD_/../../libretroshare/src + } else { + # Qt 4 + QMAKE_RC += --include-dir=$$_PRO_FILE_PWD_/../../libretroshare/src + } + } + + DEPENDPATH += . ../../libretroshare/src/ + INCLUDEPATH += ../../libretroshare/src/ +} + libresapihttpserver { CONFIG += libmicrohttpd @@ -183,3 +217,11 @@ libresapilocalserver { SOURCES *= api/ApiServerLocal.cpp HEADERS *= api/ApiServerLocal.h } + +qt_dependencies { + CONFIG *= qt + QT *= core + + SOURCES += api/SettingsHandler.cpp + HEADERS += api/SettingsHandler.h +} diff --git a/libretroshare/src/gxs/gxssecurity.cc b/libretroshare/src/gxs/gxssecurity.cc index ff430796c..6868d6934 100644 --- a/libretroshare/src/gxs/gxssecurity.cc +++ b/libretroshare/src/gxs/gxssecurity.cc @@ -459,8 +459,12 @@ bool GxsSecurity::validateNxsMsg(const RsNxsMsg& msg, const RsTlvKeySignature& s msgMeta.signSet.TlvClear(); RsGxsMessageId msgId = msgMeta.mMsgId, origMsgId = msgMeta.mOrigMsgId; - msgMeta.mOrigMsgId.clear(); + + if(msgMeta.mOrigMsgId == msgMeta.mMsgId) // message is not versionned, then the signature was made with mOrigMsgId==NULL + msgMeta.mOrigMsgId.clear(); + msgMeta.mMsgId.clear(); + int signOk = 0 ; { diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 63c0d2e86..dcad97017 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1270,6 +1270,58 @@ bool RsGenExchange::getMsgRelatedMeta(const uint32_t &token, GxsMsgRelatedMetaMa return ok; } +bool RsGenExchange::getSerializedGroupData(const uint32_t &token, RsGxsGroupId& id,unsigned char *& data,uint32_t& size) +{ + RS_STACK_MUTEX(mGenMtx) ; + + std::list nxsGrps; + + if(!mDataAccess->getGroupData(token, nxsGrps)) + return false ; + + if(nxsGrps.size() != 1) + { + std::cerr << "(EE) getSerializedGroupData() got multiple groups in single request. This is unexpected." << std::endl; + + for(std::list::const_iterator it(nxsGrps.begin());it!=nxsGrps.end();++it) + delete *it ; + + return false ; + } + RsNxsGrp *nxs_grp = *(nxsGrps.begin()); + + size = nxs_grp->serial_size() ; + id = nxs_grp->metaData->mGroupId ; + + if(size > 1024*1024 || NULL==(data = (unsigned char *)rs_malloc(size))) + { + std::cerr << "(EE) getSerializedGroupData() cannot allocate mem chunk of size " << size << ". Too big, or no room." << std::endl; + delete nxs_grp ; + return false ; + } + + return nxs_grp->serialise(data,size) ; +} + +bool RsGenExchange::deserializeGroupData(unsigned char *data,uint32_t size) +{ + RS_STACK_MUTEX(mGenMtx) ; + + RsItem *item = RsNxsSerialiser(mServType).deserialise(data, &size); + + RsNxsGrp *nxs_grp = dynamic_cast(item) ; + + if(item == NULL) + { + std::cerr << "(EE) RsGenExchange::deserializeGroupData(): cannot deserialise this data. Something's wrong." << std::endl; + delete item ; + return false ; + } + + mReceivedGrps.push_back( GxsPendingItem(nxs_grp, nxs_grp->grpId,time(NULL)) ); + + return true ; +} bool RsGenExchange::getGroupData(const uint32_t &token, std::vector& grpItem) { @@ -2135,7 +2187,9 @@ void RsGenExchange::publishMsgs() if(createOk && validSize) { // empty orig msg id means this is the original - // msg + // msg. + // (csoler) Why are we doing this??? + if(msg->metaData->mOrigMsgId.isNull()) { msg->metaData->mOrigMsgId = msg->metaData->mMsgId; diff --git a/libretroshare/src/gxs/rsgenexchange.h b/libretroshare/src/gxs/rsgenexchange.h index 15c991847..689db377f 100644 --- a/libretroshare/src/gxs/rsgenexchange.h +++ b/libretroshare/src/gxs/rsgenexchange.h @@ -288,6 +288,20 @@ protected: */ bool getGroupData(const uint32_t &token, std::vector& grpItem); + /*! + * \brief getSerializedGroupData + * Retrieves the complete group data serialized into a chunk of memory. This can be useful to + * transfer a full group from one machine to another. + * + * \param token token previously obtained from cache request + * \param data memory chunk allocated (using malloc) + * \param size size of the memory chunk. + * \return + */ + + bool getSerializedGroupData(const uint32_t &token, RsGxsGroupId &id, unsigned char *& data, uint32_t& size); + bool deserializeGroupData(unsigned char *data, uint32_t size); + template bool getGroupDataT(const uint32_t &token, std::vector& grpItem) { diff --git a/libretroshare/src/gxs/rsgxsdata.h b/libretroshare/src/gxs/rsgxsdata.h index 21fbe1445..2b2e9f14d 100644 --- a/libretroshare/src/gxs/rsgxsdata.h +++ b/libretroshare/src/gxs/rsgxsdata.h @@ -34,8 +34,8 @@ #include "serialiser/rstlvkeys.h" #include "serialiser/rsgxsitems.h" -class RsGroupMetaData; -class RsMsgMetaData; +struct RsGroupMetaData; +struct RsMsgMetaData; static const uint32_t RS_GXS_GRP_META_DATA_VERSION_ID_0001 = 0x0000 ; // change this, and keep old values if the content changes static const uint32_t RS_GXS_GRP_META_DATA_VERSION_ID_0002 = 0xaf01 ; // current API @@ -56,22 +56,22 @@ public: void clear(); void operator =(const RsGroupMetaData& rMeta); - //Sort data in same order than serialiser and deserializer + //Sort data in same order than serialiser and deserializer RsGxsGroupId mGroupId; RsGxsGroupId mOrigGrpId; - RsGxsGroupId mParentGrpId; + RsGxsGroupId mParentGrpId; std::string mGroupName; uint32_t mGroupFlags; // GXS_SERV::FLAG_PRIVACY_RESTRICTED | GXS_SERV::FLAG_PRIVACY_PRIVATE | GXS_SERV::FLAG_PRIVACY_PUBLIC uint32_t mPublishTs; - uint32_t mCircleType; - uint32_t mAuthenFlags; + uint32_t mCircleType; + uint32_t mAuthenFlags; RsGxsId mAuthorId; - std::string mServiceString; + std::string mServiceString; RsGxsCircleId mCircleId; RsTlvKeySignatureSet signSet; RsTlvSecurityKeySet keys; - uint32_t mSignFlags; + uint32_t mSignFlags; // BELOW HERE IS LOCAL DATA, THAT IS NOT FROM MSG. @@ -103,9 +103,9 @@ public: void clear(); void operator =(const RsMsgMetaData& rMeta); - static int refcount; - - //Sort data in same order than serialiser and deserializer + static int refcount; + + //Sort data in same order than serialiser and deserializer RsGxsGroupId mGroupId; RsGxsMessageId mMsgId; RsGxsMessageId mThreadId; @@ -121,7 +121,7 @@ public: // BELOW HERE IS LOCAL DATA, THAT IS NOT FROM MSG. // normally READ / UNREAD flags. LOCAL Data. - std::string mServiceString; + std::string mServiceString; uint32_t mMsgStatus; uint32_t mMsgSize; time_t mChildTs; diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index 8fcbbde5d..56899d4ce 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -75,6 +75,12 @@ bool RsGxsDataAccess::requestGroupInfo(uint32_t &token, uint32_t ansType, const gir->mGroupIds = groupIds; req = gir; } + else if(reqType & GXS_REQUEST_TYPE_GROUP_SERIALIZED_DATA) + { + GroupSerializedDataReq* gir = new GroupSerializedDataReq(); + gir->mGroupIds = groupIds; + req = gir; + } if(req == NULL) { @@ -103,34 +109,25 @@ bool RsGxsDataAccess::requestGroupInfo(uint32_t &token, uint32_t ansType, const uint32_t reqType = opts.mReqType; if(reqType & GXS_REQUEST_TYPE_GROUP_META) - { - GroupMetaReq* gmr = new GroupMetaReq(); - req = gmr; - } + req = new GroupMetaReq(); else if(reqType & GXS_REQUEST_TYPE_GROUP_DATA) - { - GroupDataReq* gdr = new GroupDataReq(); - req = gdr; - } + req = new GroupDataReq(); else if(reqType & GXS_REQUEST_TYPE_GROUP_IDS) - { - GroupIdReq* gir = new GroupIdReq(); - req = gir; - } - - if(req == NULL) + req = new GroupIdReq(); + else if(reqType & GXS_REQUEST_TYPE_GROUP_SERIALIZED_DATA) + req = new GroupSerializedDataReq(); + else { std::cerr << "RsGxsDataAccess::requestGroupInfo() request type not recognised, type " << reqType << std::endl; return false; - }else - { - generateToken(token); -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::requestGroupInfo() gets Token: " << token << std::endl; -#endif } + generateToken(token); +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::requestGroupInfo() gets Token: " << token << std::endl; +#endif + setReq(req, token, ansType, opts); storeRequest(req); @@ -430,7 +427,16 @@ bool RsGxsDataAccess::getGroupData(const uint32_t& token, std::list& else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE) { GroupDataReq* gmreq = dynamic_cast(req); - if(gmreq) + GroupSerializedDataReq* gsreq = dynamic_cast(req); + + if(gsreq) + { + grpData.swap(gsreq->mGroupData); + gsreq->mGroupData.clear(); + + locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + } + else if(gmreq) { grpData.swap(gmreq->mGroupData); gmreq->mGroupData.clear(); @@ -804,6 +810,7 @@ void RsGxsDataAccess::processRequests() MsgIdReq* mir; MsgRelatedInfoReq* mri; GroupStatisticRequest* gsr; + GroupSerializedDataReq* grr; ServiceStatisticRequest* ssr; #ifdef DATA_DEBUG @@ -851,6 +858,11 @@ void RsGxsDataAccess::processRequests() { ok = getServiceStatistic(ssr); } + else if((grr = dynamic_cast(req)) != NULL) + { + ok = getGroupSerializedData(grr); + } + else { std::cerr << "RsGxsDataAccess::processRequests() Failed to process request, token: " @@ -929,7 +941,30 @@ bool RsGxsDataAccess::getServiceStatistic(const uint32_t &token, GxsServiceStati return true; } +bool RsGxsDataAccess::getGroupSerializedData(GroupSerializedDataReq* req) +{ + std::map grpData; + std::list grpIdsOut; + getGroupList(req->mGroupIds, req->Options, grpIdsOut); + + if(grpIdsOut.empty()) + return true; + + + for(std::list::iterator lit = grpIdsOut.begin();lit != grpIdsOut.end();++lit) + grpData[*lit] = NULL; + + bool ok = mDataStore->retrieveNxsGrps(grpData, true, true); + req->mGroupData.clear(); + + std::map::iterator mit = grpData.begin(); + + for(; mit != grpData.end(); ++mit) + req->mGroupData.push_back(mit->second) ; + + return ok; +} bool RsGxsDataAccess::getGroupData(GroupDataReq* req) { std::map grpData; diff --git a/libretroshare/src/gxs/rsgxsdataaccess.h b/libretroshare/src/gxs/rsgxsdataaccess.h index ac21f4c41..d39823f81 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.h +++ b/libretroshare/src/gxs/rsgxsdataaccess.h @@ -418,6 +418,13 @@ private: */ bool getGroupStatistic(GroupStatisticRequest* req); + /*! + * + * Attempts to retrieve group data in serialized format + * @param req Request object to satisfy + */ + bool getGroupSerializedData(GroupSerializedDataReq* req); + /*! * * Attempts to service statistic diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 259d01135..3811ddd0c 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -1972,7 +1972,7 @@ void RsGxsNetService::updateServerSyncTS() #endif // I keep the creation, but the data is not used yet. -#warning disabled this, but do we need it? +#warning csoler 2016-12-12: Disabled this, but do we need it? // RsGxsServerMsgUpdate& msui(mServerMsgUpdateMap[grpId]) ; // (cyril) I'm removing this, because the msgUpdateTS is updated when new messages are received by calling locked_stampMsgServerUpdateTS(). @@ -3000,7 +3000,7 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) } // FIXTESTS global variable rsReputations not available in unittests! -#warning Update the code below to correctly send/recv dependign on reputation +#warning csoler 2016-12-23: Update the code below to correctly send/recv dependign on reputation if(!grpSyncItem->authorId.isNull() && mReputations->overallReputationLevel(grpSyncItem->authorId) == RsReputations::REPUTATION_LOCALLY_NEGATIVE) { #ifdef NXS_NET_DEBUG_0 diff --git a/libretroshare/src/gxs/rsgxsnetutils.cc b/libretroshare/src/gxs/rsgxsnetutils.cc index 4d54ce117..7454ba58a 100644 --- a/libretroshare/src/gxs/rsgxsnetutils.cc +++ b/libretroshare/src/gxs/rsgxsnetutils.cc @@ -45,7 +45,7 @@ bool AuthorPending::getAuthorRep(GixsReputation& rep, const RsGxsId& authorId, c rep.id = authorId ; rep.reputation_level = mRep->overallReputationLevel(authorId); -#warning can it happen that reputations do not have the info yet? +#warning csoler 2017-01-10: Can it happen that reputations do not have the info yet? return true ; #ifdef TO_BE_REMOVED { diff --git a/libretroshare/src/gxs/rsgxsrequesttypes.h b/libretroshare/src/gxs/rsgxsrequesttypes.h index a344a55e7..8009f294b 100644 --- a/libretroshare/src/gxs/rsgxsrequesttypes.h +++ b/libretroshare/src/gxs/rsgxsrequesttypes.h @@ -61,6 +61,12 @@ public: std::list mGroupIds; std::list mGroupIdResult; }; +class GroupSerializedDataReq : public GxsRequest +{ +public: + std::list mGroupIds; + std::list mGroupData; +}; class GroupDataReq : public GxsRequest { diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 2d2da50dc..c5781c87d 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -1194,7 +1194,7 @@ bool p3GxsTunnelService::locked_sendClearTunnelData(RsGxsTunnelDHPublicKeyItem * if(gitem->data_bytes == NULL) { delete gitem ; - return NULL ; + return false ; } // by convention, we use a IV of 0 for unencrypted data. memset(gitem->data_bytes,0,8) ; diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index fb135f196..3bc7f23ea 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -279,7 +279,12 @@ win32 { CONFIG += upnp_miniupnpc - LIBS += -lsqlcipher + no_sqlcipher { + PKGCONFIG *= sqlite3 + LIBS += -lsqlite3 + } else { + LIBS += -lsqlcipher + } DEPENDPATH += . $$INC_DIR INCLUDEPATH += . $$INC_DIR diff --git a/libretroshare/src/plugins/pluginmanager.cc b/libretroshare/src/plugins/pluginmanager.cc index 431b6c2f8..259004300 100644 --- a/libretroshare/src/plugins/pluginmanager.cc +++ b/libretroshare/src/plugins/pluginmanager.cc @@ -51,9 +51,14 @@ RsPluginManager::RsPluginManager(const RsFileHash &hash) _allow_all_plugins = false ; } +bool RsPluginManager::loadConfiguration(RsFileHash &loadHash) +{ + return p3Config::loadConfiguration(loadHash); +} + void RsPluginManager::loadConfiguration() { - RsFileHash dummyHash ; + RsFileHash dummyHash; p3Config::loadConfiguration(dummyHash); } diff --git a/libretroshare/src/plugins/pluginmanager.h b/libretroshare/src/plugins/pluginmanager.h index 5f2a8c3b7..27a74f870 100644 --- a/libretroshare/src/plugins/pluginmanager.h +++ b/libretroshare/src/plugins/pluginmanager.h @@ -74,6 +74,7 @@ class RsPluginManager: public RsPluginHandler, public p3Config // -------------------- Own members -------------------------// // virtual void addConfigurations(p3ConfigMgr *cfgMgr) ; + virtual bool loadConfiguration(RsFileHash &loadHash) ; virtual void loadConfiguration() ; /*! diff --git a/libretroshare/src/pqi/p3dhtmgr.cc b/libretroshare/src/pqi/p3dhtmgr.cc index a93577581..c1d929c94 100644 --- a/libretroshare/src/pqi/p3dhtmgr.cc +++ b/libretroshare/src/pqi/p3dhtmgr.cc @@ -92,7 +92,7 @@ dhtPeerEntry::dhtPeerEntry() return; } -p3DhtMgr::p3DhtMgr(std::string id, pqiConnectCb *cb) +p3DhtMgr::p3DhtMgr(RsPeerId id, pqiConnectCb *cb) :pqiNetAssistConnect(id, cb), dhtMtx("p3DhtMgr"), mStunRequired(true) { /* setup own entry */ @@ -237,13 +237,13 @@ bool p3DhtMgr::setExternalInterface( /* add / remove peers */ -bool p3DhtMgr::findPeer(std::string id) +bool p3DhtMgr::findPeer(const RsPeerId& id) { RsStackMutex stack(dhtMtx); /***** LOCK MUTEX *****/ mDhtModifications = true; - std::map::iterator it; + std::map::iterator it; it = peers.find(id); if (it != peers.end()) { @@ -281,14 +281,14 @@ bool p3DhtMgr::findPeer(std::string id) return true; } -bool p3DhtMgr::dropPeer(std::string id) +bool p3DhtMgr::dropPeer(const RsPeerId& id) { RsStackMutex stack(dhtMtx); /***** LOCK MUTEX *****/ mDhtModifications = true; /* once we are connected ... don't worry about them anymore */ - std::map::iterator it; + std::map::iterator it; it = peers.find(id); if (it == peers.end()) { @@ -302,14 +302,14 @@ bool p3DhtMgr::dropPeer(std::string id) } /* post DHT key saying we should connect */ -bool p3DhtMgr::notifyPeer(std::string id) +bool p3DhtMgr::notifyPeer(const RsPeerId& id) { RsStackMutex stack(dhtMtx); /***** LOCK MUTEX *****/ #ifdef DHT_DEBUG - std::cerr << "p3DhtMgr::notifyPeer() " << id << std::endl; + std::cerr << "p3DhtMgr::notifyPeer() " << id.toStdString() << std::endl; #endif - std::map::iterator it; + std::map::iterator it; it = peers.find(id); if (it == peers.end()) { @@ -333,7 +333,7 @@ bool p3DhtMgr::notifyPeer(std::string id) #ifdef DHT_LOGS { /* Log */ - rslog(RSL_WARNING, p3dhtzone, "p3DhtMgr::notifyPeer() Id: " + id + " TO SOON - DROPPING"); + rslog(RSL_WARNING, p3dhtzone, "p3DhtMgr::notifyPeer() Id: " + id.toStdString() + " TO SOON - DROPPING"); } #endif @@ -352,7 +352,7 @@ bool p3DhtMgr::notifyPeer(std::string id) #ifdef DHT_LOGS { /* Log */ - rslog(RSL_WARNING, p3dhtzone, "p3DhtMgr::notifyPeer() Id: " + id + " PEER NOT FOUND - Trigger Search"); + rslog(RSL_WARNING, p3dhtzone, "p3DhtMgr::notifyPeer() Id: " + id.toStdString() + " PEER NOT FOUND - Trigger Search"); } #endif it->second.lastTS = 0; @@ -364,14 +364,14 @@ bool p3DhtMgr::notifyPeer(std::string id) } /* extract current peer status */ -bool p3DhtMgr::getPeerStatus(std::string id, - struct sockaddr_in &laddr, - struct sockaddr_in &raddr, +bool p3DhtMgr::getPeerStatus(const RsPeerId &id, + struct sockaddr_in &laddr, + struct sockaddr_in &raddr, uint32_t &type, uint32_t &state) { RsStackMutex stack(dhtMtx); /* LOCK MUTEX */ - std::map::iterator it; + std::map::iterator it; it = peers.find(id); /* ignore OFF peers */ @@ -776,7 +776,7 @@ int p3DhtMgr::checkPeerDHTKeys() dhtMtx.lock(); /* LOCK MUTEX */ /* iterate through and find min time and suitable candidate */ - std::map::iterator it,pit; + std::map::iterator it,pit; time_t now = time(NULL); uint32_t period = 0; uint32_t repeatPeriod = 6000; @@ -802,7 +802,7 @@ int p3DhtMgr::checkPeerDHTKeys() period = DHT_CHECK_PERIOD; } #ifdef DHT_DEBUG - std::cerr << "p3DhtMgr::checkPeerDHTKeys() Peer: " << it->second.id; + std::cerr << "p3DhtMgr::checkPeerDHTKeys() Peer: " << it->second.id.toStdString(); std::cerr << " Period: " << period; std::cerr << " Delta: " << delta; std::cerr << std::endl; @@ -865,7 +865,7 @@ int p3DhtMgr::checkNotifyDHT() RsStackMutex stack(dhtMtx); /***** LOCK MUTEX *****/ /* iterate through and find min time and suitable candidate */ - std::map::iterator it; + std::map::iterator it; time_t now = time(NULL); int repeatPeriod = DHT_DEFAULT_PERIOD; @@ -1015,7 +1015,7 @@ int p3DhtMgr::checkStunState() if (mDhtState == DHT_STATE_CHECK_PEERS) { /* check that they have all be searched for */ - std::map::iterator it; + std::map::iterator it; for(it = peers.begin(); it != peers.end(); it++) { if (it->second.state == DHT_PEER_INIT) @@ -1287,7 +1287,7 @@ int p3DhtMgr::status(std::ostream &out) out << "OWN DETAILS END----------------------------------------" << std::endl; /* now peers states */ - std::map::iterator it; + std::map::iterator it; out << "PEER DETAILS ------------------------------------------" << std::endl; for(it = peers.begin(); it != peers.end(); it++) { @@ -1622,15 +1622,13 @@ bool p3DhtMgr::dhtResultNotify(std::string idhash) std::cerr << "p3DhtMgr::dhtResultNotify() from idhash: "; std::cerr << RsUtil::BinToHex(idhash) << std::endl; #endif - std::map::iterator it; + std::map::iterator it; time_t now = time(NULL); /* if notify - we must match on the second hash */ for(it = peers.begin(); (it != peers.end()) && ((it->second).hash2 != idhash); it++) ; /* update data */ - std::string peerid; - /* ignore OFF peers */ if ((it != peers.end()) && (it->second.state != DHT_PEER_OFF)) { @@ -1677,7 +1675,7 @@ bool p3DhtMgr::dhtResultSearch(std::string idhash, std::cerr << "p3DhtMgr::dhtResultSearch() for idhash: "; std::cerr << RsUtil::BinToHex(idhash) << std::endl; #endif - std::map::iterator it; + std::map::iterator it; bool doCb = false; bool doStun = false; uint32_t stunFlags = 0; @@ -1780,7 +1778,7 @@ bool p3DhtMgr::dhtResultSearch(std::string idhash, void printDhtPeerEntry(dhtPeerEntry *ent, std::ostream &out) { - out << "DhtEntry: ID: " << ent->id; + out << "DhtEntry: ID: " << ent->id.toStdString(); out << " State: " << ent->state; out << " lastTS: " << ent->lastTS; out << " notifyPending: " << ent->notifyPending; diff --git a/libretroshare/src/pqi/p3dhtmgr.h b/libretroshare/src/pqi/p3dhtmgr.h index f08c2bc96..86d6b5424 100644 --- a/libretroshare/src/pqi/p3dhtmgr.h +++ b/libretroshare/src/pqi/p3dhtmgr.h @@ -78,7 +78,7 @@ class dhtPeerEntry public: dhtPeerEntry(); - std::string id; + RsPeerId id; uint32_t state; time_t lastTS; @@ -97,7 +97,7 @@ class p3DhtMgr: public pqiNetAssistConnect, public RsThread /* */ public: - p3DhtMgr(std::string id, pqiConnectCb *cb); + p3DhtMgr(RsPeerId id, pqiConnectCb *cb); /********** External DHT Interface ************************ * These Functions are the external interface @@ -121,15 +121,15 @@ virtual bool setExternalInterface(struct sockaddr_in laddr, struct sockaddr_in raddr, uint32_t type); /* add / remove peers */ -virtual bool findPeer(std::string id); -virtual bool dropPeer(std::string id); +virtual bool findPeer(const RsPeerId& id); +virtual bool dropPeer(const RsPeerId& id); /* post DHT key saying we should connect (callback when done) */ -virtual bool notifyPeer(std::string id); +virtual bool notifyPeer(const RsPeerId& id); /* extract current peer status */ -virtual bool getPeerStatus(std::string id, - struct sockaddr_in &laddr, struct sockaddr_in &raddr, +virtual bool getPeerStatus(const RsPeerId& id, + struct sockaddr_in &laddr, struct sockaddr_in &raddr, uint32_t &type, uint32_t &mode); /* stun */ @@ -154,17 +154,17 @@ virtual bool dhtResultBootstrap(std::string idhash); protected: /* can block briefly (called only from thread) */ -virtual bool dhtPublish(std::string id, +virtual bool dhtPublish(std::string idhash, struct sockaddr_in &laddr, struct sockaddr_in &raddr, uint32_t type, std::string sign); -virtual bool dhtNotify(std::string peerid, std::string ownId, +virtual bool dhtNotify(std::string idhash, std::string ownIdHash, std::string sign); -virtual bool dhtSearch(std::string id, uint32_t mode); +virtual bool dhtSearch(std::string idhash, uint32_t mode); -virtual bool dhtBootstrap(std::string storehash, std::string ownIdHash, +virtual bool dhtBootstrap(std::string idhash, std::string ownIdHash, std::string sign); /* to publish bootstrap */ @@ -232,7 +232,7 @@ std::string randomBootstrapId(); dhtPeerEntry ownEntry; time_t ownNotifyTS; - std::map peers; + std::map peers; std::list stunIds; bool mStunRequired; diff --git a/libretroshare/src/pqi/p3peermgr.h b/libretroshare/src/pqi/p3peermgr.h index ee581b275..f0a9a44cb 100644 --- a/libretroshare/src/pqi/p3peermgr.h +++ b/libretroshare/src/pqi/p3peermgr.h @@ -397,7 +397,7 @@ private: std::map mReportedOwnAddresses ; std::map groupList; - uint32_t lastGroupId; + //uint32_t lastGroupId; std::list saveCleanupList; /* TEMPORARY LIST WHEN SAVING */ diff --git a/libretroshare/src/pqi/pqimonitor.cc b/libretroshare/src/pqi/pqimonitor.cc index 03894a66d..fac7a50f9 100644 --- a/libretroshare/src/pqi/pqimonitor.cc +++ b/libretroshare/src/pqi/pqimonitor.cc @@ -61,14 +61,20 @@ void pqiConnectCbDummy::peerStatus(const RsPeerId& id, const pqiIpAddrSet &ad std::cerr << out << std::endl; } -void pqiConnectCbDummy::peerConnectRequest(const RsPeerId& id, - const struct sockaddr_storage &raddr, uint32_t source) +void pqiConnectCbDummy::peerConnectRequest(const RsPeerId &id, const sockaddr_storage &raddr + , const sockaddr_storage &proxyaddr, const sockaddr_storage &srcaddr + , uint32_t source, uint32_t flags, uint32_t delay, uint32_t bandwidth) { std::cerr << "pqiConnectCbDummy::peerConnectRequest()"; std::cerr << " id: " << id; std::cerr << " raddr: " << sockaddr_storage_tostring(raddr); + std::cerr << " proxyaddr: " << sockaddr_storage_tostring(proxyaddr); + std::cerr << " srcaddr: " << sockaddr_storage_tostring(srcaddr); std::cerr << " source: " << source; - std::cerr << std::endl; + std::cerr << " flags: " << flags; + std::cerr << " delay: " << delay; + std::cerr << " bandwidth: " << bandwidth; + std::cerr << std::endl; } void pqiMonitor::disconnectPeer(const RsPeerId &/*peer*/) diff --git a/libretroshare/src/pqi/pqimonitor.h b/libretroshare/src/pqi/pqimonitor.h index 34d998e75..94e9bdf05 100644 --- a/libretroshare/src/pqi/pqimonitor.h +++ b/libretroshare/src/pqi/pqimonitor.h @@ -179,8 +179,9 @@ virtual ~pqiConnectCbDummy(); virtual void peerStatus(const RsPeerId& id, const pqiIpAddrSet &addrs, uint32_t type, uint32_t mode, uint32_t source); -virtual void peerConnectRequest(const RsPeerId& id, - const struct sockaddr_storage &raddr, uint32_t source); + virtual void peerConnectRequest(const RsPeerId& id, const struct sockaddr_storage &raddr, + const struct sockaddr_storage &proxyaddr, const struct sockaddr_storage &srcaddr, + uint32_t source, uint32_t flags, uint32_t delay, uint32_t bandwidth); //virtual void stunStatus(std::string id, const struct sockaddr_storage &raddr, uint32_t type, uint32_t flags); }; diff --git a/libretroshare/src/pqi/pqiperson.cc b/libretroshare/src/pqi/pqiperson.cc index cade0c39e..e7d1cf18b 100644 --- a/libretroshare/src/pqi/pqiperson.cc +++ b/libretroshare/src/pqi/pqiperson.cc @@ -40,7 +40,7 @@ static struct RsLog::logInfo pqipersonzoneInfo = {RsLog::Default, "pqiperson"}; pqiperson::pqiperson(const RsPeerId& id, pqipersongrp *pg) : PQInterface(id), mNotifyMtx("pqiperson-notify"), mPersonMtx("pqiperson"), - active(false), activepqi(NULL), inConnectAttempt(false), waittimes(0), + active(false), activepqi(NULL), inConnectAttempt(false),// waittimes(0), pqipg(pg) {} // TODO: must check id! pqiperson::~pqiperson() diff --git a/libretroshare/src/pqi/pqiperson.h b/libretroshare/src/pqi/pqiperson.h index f3ff940e1..69faec48c 100644 --- a/libretroshare/src/pqi/pqiperson.h +++ b/libretroshare/src/pqi/pqiperson.h @@ -29,6 +29,7 @@ #define MRK_PQI_PERSON_HEADER +#include #include "pqi/pqi.h" #include "util/rsnet.h" @@ -66,7 +67,7 @@ public: virtual int reset() { pqistreamer::reset(); return ni->reset(); } virtual int disconnect() { return reset() ; } virtual bool connect_parameter(uint32_t type, uint32_t value) { return ni->connect_parameter(type, value);} - virtual bool connect_parameter(uint32_t type, std::string value) { return ni->connect_parameter(type, value);} + virtual bool connect_parameter(uint32_t type, const std::string &value) { return ni->connect_parameter(type, value);} virtual bool connect_additional_address(uint32_t type, const struct sockaddr_storage &addr) { return ni->connect_additional_address(type, addr); } virtual int getConnectAddress(struct sockaddr_storage &raddr){ return ni->getConnectAddress(raddr); } @@ -171,7 +172,7 @@ private: bool active; pqiconnect *activepqi; bool inConnectAttempt; - int waittimes; + //int waittimes; time_t lastHeartbeatReceived; // use to track connection failure pqipersongrp *pqipg; /* parent for callback */ }; diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index b7709bb82..bcc49cbbc 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -1009,7 +1009,7 @@ int pqissl::Basic_Connection_Complete() return -1; } - else if ((err == ECONNREFUSED)) + else if (err == ECONNREFUSED) { rslog(RSL_WARNING, pqisslzone, "pqissl::Basic_Connection_Complete() ECONNREFUSED: cert: " + PeerId().toStdString()); diff --git a/libretroshare/src/pqi/pqissludp.cc b/libretroshare/src/pqi/pqissludp.cc index 9519e2af3..29bd228c9 100644 --- a/libretroshare/src/pqi/pqissludp.cc +++ b/libretroshare/src/pqi/pqissludp.cc @@ -53,7 +53,7 @@ static const uint32_t PQI_SSLUDP_DEF_CONN_PERIOD = 300; /* 5 minutes? */ /********** PQI SSL UDP STUFF **************************************/ pqissludp::pqissludp(PQInterface *parent, p3LinkMgr *lm) : - pqissl(NULL, parent, lm), tou_bio(NULL), listen_checktime(0), + pqissl(NULL, parent, lm), tou_bio(NULL),// listen_checktime(0), mConnectPeriod(PQI_SSLUDP_DEF_CONN_PERIOD), mConnectFlags(0), mConnectBandwidth(0) { diff --git a/libretroshare/src/pqi/pqissludp.h b/libretroshare/src/pqi/pqissludp.h index 848717bbd..195e9e604 100644 --- a/libretroshare/src/pqi/pqissludp.h +++ b/libretroshare/src/pqi/pqissludp.h @@ -95,7 +95,7 @@ private: BIO *tou_bio; // specific to ssludp. - long listen_checktime; + //long listen_checktime; uint32_t mConnectPeriod; uint32_t mConnectFlags; diff --git a/libretroshare/src/pqi/sslfns.cc b/libretroshare/src/pqi/sslfns.cc index 7cf742956..ba5a9e6a3 100644 --- a/libretroshare/src/pqi/sslfns.cc +++ b/libretroshare/src/pqi/sslfns.cc @@ -627,7 +627,7 @@ bool getX509id(X509 *x509, RsPeerId& xid) * more randomness */ -#warning this is cryptographically horrible. We should do a hash of the public key here!!! +#warning csoler 2017-02-19: This is cryptographically horrible. We should do a hash of the public key here!!! xid = RsPeerId(&signdata[signlen - CERTSIGNLEN]) ; diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index 6fd907898..1bc17b5e0 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -25,7 +25,7 @@ typedef std::pair RsGxsGrpMsgIdPair; typedef std::map > MsgRelatedIdResult; typedef std::map > GxsMsgReq; -class RsMsgMetaData; +struct RsMsgMetaData; typedef std::map > MsgMetaResult; diff --git a/libretroshare/src/retroshare/rsgxsservice.h b/libretroshare/src/retroshare/rsgxsservice.h index 8f26e5262..6afed31c6 100644 --- a/libretroshare/src/retroshare/rsgxsservice.h +++ b/libretroshare/src/retroshare/rsgxsservice.h @@ -5,7 +5,7 @@ #include "retroshare/rsgxsifacetypes.h" #include "retroshare/rstokenservice.h" -class RsMsgMetaData ; +struct RsMsgMetaData ; typedef std::map > GxsMsgMetaMap; typedef std::map > GxsMsgRelatedMetaMap; diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index 7ecc785d0..3cf15e912 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -305,6 +305,9 @@ public: virtual bool setAsRegularContact(const RsGxsId& id,bool is_a_contact) = 0 ; virtual bool isARegularContact(const RsGxsId& id) = 0 ; + virtual bool serialiseIdentityToMemory(const RsGxsId& id,std::string& radix_string)=0; + virtual bool deserialiseIdentityFromMemory(const std::string& radix_string)=0; + /*! * \brief overallReputationLevel * Returns the overall reputation level of the supplied identity. See rsreputations.h @@ -319,6 +322,7 @@ public: */ virtual bool getGroupData(const uint32_t &token, std::vector &groups) = 0; + virtual bool getGroupSerializedData(const uint32_t &token, std::map& serialized_groups)=0; //virtual bool getMsgData(const uint32_t &token, std::vector &opinions) = 0; }; diff --git a/libretroshare/src/retroshare/rstokenservice.h b/libretroshare/src/retroshare/rstokenservice.h index 79097cc5c..bcb273dd5 100644 --- a/libretroshare/src/retroshare/rstokenservice.h +++ b/libretroshare/src/retroshare/rstokenservice.h @@ -47,6 +47,7 @@ #define GXS_REQUEST_TYPE_GROUP_STATS 0x01600000 #define GXS_REQUEST_TYPE_SERVICE_STATS 0x03200000 +#define GXS_REQUEST_TYPE_GROUP_SERIALIZED_DATA 0x04000000 // TODO CLEANUP: RS_TOKREQOPT_MSG_* should be an inner enum of RsTokReqOptions diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index 73a5801fd..f43dfb485 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -1037,6 +1037,9 @@ bool p3Peers::setProxyServer(const uint32_t type, const std::string &addr_str, c std::cerr << "(EE) attempt to set proxy server address to something not allowed: " << addr_str << ":" << port << std::endl; return false ; } + + std::cerr << "Settign proxy server address to " << addr_str << ":" << port << std::endl; + struct sockaddr_storage addr; struct sockaddr_in *addrv4p = (struct sockaddr_in *) &addr; addrv4p->sin_family = AF_INET; diff --git a/libretroshare/src/services/p3banlist.cc b/libretroshare/src/services/p3banlist.cc index 157cc23f8..65d56987b 100644 --- a/libretroshare/src/services/p3banlist.cc +++ b/libretroshare/src/services/p3banlist.cc @@ -66,8 +66,8 @@ */ RsBanList *rsBanList = NULL ; -p3BanList::p3BanList(p3ServiceControl *sc, p3NetMgr *nm) - :p3Service(), mBanMtx("p3BanList"), mServiceCtrl(sc), mNetMgr(nm) +p3BanList::p3BanList(p3ServiceControl *sc, p3NetMgr */*nm*/) + :p3Service(), mBanMtx("p3BanList"), mServiceCtrl(sc)//, mNetMgr(nm) { addSerialType(new RsBanListSerialiser()); diff --git a/libretroshare/src/services/p3banlist.h b/libretroshare/src/services/p3banlist.h index 87bb7104a..86456d6ae 100644 --- a/libretroshare/src/services/p3banlist.h +++ b/libretroshare/src/services/p3banlist.h @@ -148,7 +148,7 @@ private: std::map mWhiteListedRanges; p3ServiceControl *mServiceCtrl; - p3NetMgr *mNetMgr; + //p3NetMgr *mNetMgr; time_t mLastDhtInfoRequest ; bool mIPFilteringEnabled ; diff --git a/libretroshare/src/services/p3gxsreputation.cc b/libretroshare/src/services/p3gxsreputation.cc index 45fd95898..c60f54f0c 100644 --- a/libretroshare/src/services/p3gxsreputation.cc +++ b/libretroshare/src/services/p3gxsreputation.cc @@ -1035,7 +1035,7 @@ bool p3GxsReputation::setOwnOpinion(const RsGxsId& gxsid, const RsReputations::O if (rit == mReputations.end()) { -#warning we should set the owner node id here. +#warning csoler 2017-01-05: We should set the owner node id here. mReputations[gxsid] = Reputation(gxsid); rit = mReputations.find(gxsid); } diff --git a/libretroshare/src/services/p3gxsreputation.h b/libretroshare/src/services/p3gxsreputation.h index baabdaa43..890092237 100644 --- a/libretroshare/src/services/p3gxsreputation.h +++ b/libretroshare/src/services/p3gxsreputation.h @@ -174,7 +174,7 @@ private: time_t mLastIdentityFlagsUpdate ; bool mReputationsUpdated; - float mAutoBanIdentitiesLimit ; + //float mAutoBanIdentitiesLimit ; bool mAutoSetPositiveOptionToContacts; p3LinkMgr *mLinkMgr; diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 0211b6cf1..bd9dfc772 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -70,6 +70,8 @@ static const time_t MAX_KEEP_KEYS_SIGNED_KNOWN = 30 * 86400 ; // signed ident static const uint32_t MAX_DELAY_BEFORE_CLEANING= 1800 ; // clean old keys every 30 mins +static const uint32_t MAX_SERIALISED_IDENTITY_AGE = 600 ; // after 10 mins, a serialised identity record must be renewed. + RsIdentity *rsIdentity = NULL; /****** @@ -97,13 +99,12 @@ RsIdentity *rsIdentity = NULL; #define BG_REPUTATION 3 -#define GXSIDREQ_CACHELOAD 0x0001 -#define GXSIDREQ_CACHEOWNIDS 0x0002 - -#define GXSIDREQ_PGPHASH 0x0010 -#define GXSIDREQ_RECOGN 0x0020 - -#define GXSIDREQ_OPINION 0x0030 +#define GXSIDREQ_CACHELOAD 0x0001 +#define GXSIDREQ_CACHEOWNIDS 0x0002 +#define GXSIDREQ_PGPHASH 0x0010 +#define GXSIDREQ_RECOGN 0x0020 +#define GXSIDREQ_OPINION 0x0030 +#define GXSIDREQ_SERIALIZE_TO_MEMORY 0x0040 #define GXSIDREQ_CACHETEST 0x1000 @@ -697,6 +698,84 @@ bool p3IdService::getOwnIds(std::list &ownIds) return true ; } +bool p3IdService::serialiseIdentityToMemory(const RsGxsId& id,std::string& radix_string) +{ + RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/ + + // look into cache. If available, return the data. If not, request it. + + std::map::const_iterator it = mSerialisedIdentities.find(id); + + if(it != mSerialisedIdentities.end()) + { + Radix64::encode(it->second.mMem,it->second.mSize,radix_string) ; + + if(it->second.mLastUsageTS + MAX_SERIALISED_IDENTITY_AGE > time(NULL)) + return true ; + + std::cerr << "Identity " << id << " will be re-serialised, because the last record is too old." << std::endl; + } + + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + uint32_t token = 0; + std::list groupIds; + + groupIds.push_back(RsGxsGroupId(id)) ; + + RsGenExchange::getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds); + GxsTokenQueue::queueRequest(token, GXSIDREQ_SERIALIZE_TO_MEMORY); + + return false; +} + +void p3IdService::handle_get_serialized_grp(uint32_t token) +{ + // store the serialized data in cache. + + unsigned char *mem = NULL; + uint32_t size; + RsGxsGroupId id ; + + if(!RsGenExchange::getSerializedGroupData(token,id, mem,size)) + { + std::cerr << "(EE) call to RsGenExchage::getSerializedGroupData() failed." << std::endl; + return ; + } + + std::cerr << "Received serialised group from RsGenExchange." << std::endl; + + std::map::const_iterator it = mSerialisedIdentities.find(RsGxsId(id)); + + if(it != mSerialisedIdentities.end()) + free(it->second.mMem) ; + + SerialisedIdentityStruct s ; + s.mMem = mem ; + s.mSize = size ; + s.mLastUsageTS = time(NULL) ; + + mSerialisedIdentities[RsGxsId(id)] = s ; +} + +bool p3IdService::deserialiseIdentityFromMemory(const std::string& radix_string) +{ + std::vector mem = Radix64::decode(radix_string) ; + + if(mem.empty()) + { + std::cerr << "Cannot decode radix string \"" << radix_string << "\"" << std::endl; + return false ; + } + + if(!RsGenExchange::deserializeGroupData(mem.data(),mem.size())) + { + std::cerr << "Cannot load identity from radix string \"" << radix_string << "\"" << std::endl; + return false ; + } + + return true ; +} bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters ¶ms) { @@ -709,7 +788,7 @@ bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters ¶ms) if (params.isPgpLinked) { -#warning Backward compatibility issue to fix here in v0.7.0 +#warning csoler 2017-02-07: Backward compatibility issue to fix here in v0.7.0 // This is a hack, because a bad decision led to having RSGXSID_GROUPFLAG_REALID be equal to GXS_SERV::FLAG_PRIVACY_PRIVATE. // In order to keep backward compatibility, we'll also add the new value @@ -1587,6 +1666,28 @@ bool p3IdService::getGroupData(const uint32_t &token, std::vector return ok; } +bool p3IdService::getGroupSerializedData(const uint32_t &token, std::map& serialized_groups) +{ + unsigned char *mem = NULL; + uint32_t size; + RsGxsGroupId id ; + + serialized_groups.clear() ; + + if(!RsGenExchange::getSerializedGroupData(token,id, mem,size)) + { + std::cerr << "(EE) call to RsGenExchage::getSerializedGroupData() failed." << std::endl; + return false; + } + + std::string radix ; + + Radix64::encode(mem,size,radix) ; + + serialized_groups[RsGxsId(id)] = radix ; + + return true; +} /********************************************************************************/ /********************************************************************************/ @@ -4309,6 +4410,9 @@ void p3IdService::handleResponse(uint32_t token, uint32_t req_type) case GXSIDREQ_OPINION: opinion_handlerequest(token); break; + case GXSIDREQ_SERIALIZE_TO_MEMORY: + handle_get_serialized_grp(token) ; + default: /* error */ std::cerr << "p3IdService::handleResponse() Unknown Request Type: " << req_type; diff --git a/libretroshare/src/services/p3idservice.h b/libretroshare/src/services/p3idservice.h index c93581597..4c6b352db 100644 --- a/libretroshare/src/services/p3idservice.h +++ b/libretroshare/src/services/p3idservice.h @@ -212,6 +212,13 @@ private: void init(const RsGxsIdGroupItem *item, const RsTlvPublicRSAKey& in_pub_key, const RsTlvPrivateRSAKey& in_priv_key,const std::list &tagList); }; +struct SerialisedIdentityStruct +{ + unsigned char *mMem ; + uint32_t mSize ; + time_t mLastUsageTS; +}; + // Not sure exactly what should be inherited here? // Chris - please correct as necessary. @@ -238,6 +245,8 @@ public: // These are exposed via RsIdentity. virtual bool getGroupData(const uint32_t &token, std::vector &groups); + virtual bool getGroupSerializedData(const uint32_t &token, std::map& serialized_groups); + //virtual bool getMsgData(const uint32_t &token, std::vector &opinions); // These are local - and not exposed via RsIdentity. @@ -341,6 +350,8 @@ public: const RsIdentityUsage &use_info ); virtual bool requestPrivateKey(const RsGxsId &id); + virtual bool serialiseIdentityToMemory(const RsGxsId& id,std::string& radix_string); + virtual bool deserialiseIdentityFromMemory(const std::string& radix_string); /**************** RsGixsReputation Implementation ****************/ @@ -433,6 +444,12 @@ private: bool mBgSchedule_Active; uint32_t mBgSchedule_Mode; + /***********************************8 + * Fonction to receive and handle group serialisation to memory + */ + + virtual void handle_get_serialized_grp(uint32_t token); + /************************************************************************ * pgphash processing. * @@ -563,6 +580,8 @@ private: std::map > mIdsNotPresent; std::map mKeysTS ; + std::map mSerialisedIdentities ; + // keep a list of regular contacts. This is useful to sort IDs, and allow some services to priviledged ids only. std::set mContacts; RsNetworkExchangeService* mNes; diff --git a/libretroshare/src/util/radix64.h b/libretroshare/src/util/radix64.h index dc7f8528c..7776995f9 100644 --- a/libretroshare/src/util/radix64.h +++ b/libretroshare/src/util/radix64.h @@ -93,9 +93,9 @@ again: idx = (idx + 1) % 4; } - idx = idx; + //idx = idx; - return buf; + return buf ; } /**************** @@ -147,7 +147,7 @@ again: private: static inline char *bintoasc() { static char bta[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; return bta ; } - static inline char *asctobin() { static char s[256]; return s ; } /* runtime radix64_initd */ + static inline uint8_t *asctobin() { static uint8_t s[256]; return s ; } /* runtime radix64_initd */ static int& is_radix64_initd() { static int is_inited = false ; return is_inited ; } /* hey, guess what: this is a read-only table. diff --git a/openpgpsdk/src/openpgpsdk/packet-parse.c b/openpgpsdk/src/openpgpsdk/packet-parse.c index b80cf4ef8..a4596a55c 100644 --- a/openpgpsdk/src/openpgpsdk/packet-parse.c +++ b/openpgpsdk/src/openpgpsdk/packet-parse.c @@ -2394,7 +2394,7 @@ static int parse_secret_key(ops_region_t *region,ops_parse_info_t *pinfo) else if(C.secret_key.s2k_usage != OPS_S2KU_NONE) { // this is V3 style, looks just like a V4 simple hash - C.secret_key.algorithm=C.secret_key.s2k_usage; + C.secret_key.algorithm=(ops_symmetric_algorithm_t)C.secret_key.s2k_usage; C.secret_key.s2k_usage=OPS_S2KU_ENCRYPTED; C.secret_key.s2k_specifier=OPS_S2KS_SIMPLE; C.secret_key.hash_algorithm=OPS_HASH_MD5; diff --git a/plugins/FeedReader/services/p3FeedReaderThread.cc b/plugins/FeedReader/services/p3FeedReaderThread.cc index c638304f4..9ec1106ef 100644 --- a/plugins/FeedReader/services/p3FeedReaderThread.cc +++ b/plugins/FeedReader/services/p3FeedReaderThread.cc @@ -651,7 +651,7 @@ static time_t parseRFC822Date(const std::string &pubDate) offset = abs(offset); offset = ((offset / 100)*60 + (offset % 100))*sgn; } else { - for (int i=0; known_zones[i].tzName != 0; i++) { + for (int i=0; known_zones[i].tzName[0] != 0; i++) { if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { offset = known_zones[i].tzOffset; break; diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index 4e47b2c29..4946c4342 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -66,7 +66,9 @@ private: AVPacket decoding_buffer; uint64_t encoding_frame_count ; +#ifdef DEBUG_MPEG_VIDEO FILE *encoding_debug_file ; +#endif }; // This class decodes video from a stream. It keeps a queue of diff --git a/retroshare-android-service/src/retroshare-android-service.pro b/retroshare-android-service/src/retroshare-android-service.pro index c2caa12a0..54843d34f 100644 --- a/retroshare-android-service/src/retroshare-android-service.pro +++ b/retroshare-android-service/src/retroshare-android-service.pro @@ -6,13 +6,11 @@ QT += core network QT -= gui CONFIG += c++11 -CONFIG += dll +android-g++:CONFIG += dll android-g++:TEMPLATE = lib !android-g++:TEMPLATE = app -SOURCES += service.cpp - DEPENDPATH *= ../../libresapi/src INCLUDEPATH *= ../../libresapi/src PRE_TARGETDEPS *= ../../libresapi/src/lib/libresapi.a @@ -22,3 +20,34 @@ DEPENDPATH *= ../../libretroshare/src INCLUDEPATH *= ../../libretroshare/src PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a LIBS *= ../../libretroshare/src/lib/libretroshare.a + +win32 { + OBJECTS_DIR = temp/obj + + LIBS_DIR = $$PWD/../../libs/lib + LIBS += $$OUT_PWD/../../libretroshare/src/lib/libretroshare.a + LIBS += $$OUT_PWD/../../openpgpsdk/src/lib/libops.a + + for(lib, LIB_DIR):LIBS += -L"$$lib" + for(bin, BIN_DIR):LIBS += -L"$$bin" + + + LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -lws2_32 + LIBS += -luuid -lole32 -liphlpapi -lcrypt32 -lgdi32 + LIBS += -lwinmm + + DEFINES *= WINDOWS_SYS WIN32_LEAN_AND_MEAN _USE_32BIT_TIME_T + + DEPENDPATH += . $$INC_DIR + INCLUDEPATH += . $$INC_DIR + + greaterThan(QT_MAJOR_VERSION, 4) { + # Qt 5 + RC_INCLUDEPATH += $$_PRO_FILE_PWD_/../../libretroshare/src + } else { + # Qt 4 + QMAKE_RC += --include-dir=$$_PRO_FILE_PWD_/../../libretroshare/src + } +} + +SOURCES += service.cpp diff --git a/retroshare-android-service/src/service.cpp b/retroshare-android-service/src/service.cpp index a7f72bcfa..d641dd9e9 100644 --- a/retroshare-android-service/src/service.cpp +++ b/retroshare-android-service/src/service.cpp @@ -24,12 +24,10 @@ # include "util/androiddebug.h" #endif -#include "retroshare/rsinit.h" #include "api/ApiServer.h" #include "api/ApiServerLocal.h" #include "api/RsControlModule.h" - using namespace resource_api; int main(int argc, char *argv[]) @@ -46,7 +44,12 @@ int main(int argc, char *argv[]) dynamic_cast(&ctrl_mod), &resource_api::RsControlModule::handleRequest); - QString sockPath = QString::fromStdString(RsAccounts::ConfigDirectory()); +#ifdef QT_DEBUG + QString sockPath = "RS/"; +#else + QString sockPath = QCoreApplication::applicationDirPath(); +#endif + sockPath.append("/libresapi.sock"); qDebug() << "Listening on:" << sockPath; ApiServerLocal apiServerLocal(&api, sockPath); (void) apiServerLocal; diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.cpp b/retroshare-gui/src/gui/ChatLobbyWidget.cpp index 07d5112be..dadf04939 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.cpp +++ b/retroshare-gui/src/gui/ChatLobbyWidget.cpp @@ -378,8 +378,12 @@ static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobby +QObject::tr("Id:")+" "+QString::number(id,16) ; if(lobby_flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) + { tooltipstr += QObject::tr("\nSecurity: no anonymous IDs") ; - + QColor foreground = QColor(0, 128, 0); // green + for (int column = 0; column < COLUMN_COUNT; ++column) + item->setTextColor(column, foreground); + } item->setToolTip(0,tooltipstr) ; } @@ -653,7 +657,9 @@ void ChatLobbyWidget::updateDisplay() updateItem(ui.lobbyTreeWidget, item, lobby.lobby_id, lobby.lobby_name,lobby.lobby_topic, lobby.gxs_ids.size(), true, autoSubscribe,lobby_flags); } publicSubLobbyItem->setHidden(publicSubLobbyItem->childCount()==0); + publicSubLobbyItem->setText(COLUMN_NAME, tr("Public Subscribed chat rooms")+ QString(" (") + QString::number(publicSubLobbyItem->childCount())+QString(")")); privateSubLobbyItem->setHidden(privateSubLobbyItem->childCount()==0); + publicLobbyItem->setText(COLUMN_NAME, tr("Public chat rooms")+ " (" + QString::number(publicLobbyItem->childCount())+QString(")")); } void ChatLobbyWidget::createChatLobby() diff --git a/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp b/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp index 851679931..4728dde14 100644 --- a/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp +++ b/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp @@ -407,6 +407,13 @@ void SearchDialog::download() for(std::list::const_iterator it(srcIds.begin()); it!=srcIds.end(); ++it) { std::cout << *it << "-" << std::endl; }//for(std::list::const_iterator + //QColor foreground = QColor(0, 128, 0); // green + QColor foreground = textColorDownloading(); + QBrush brush(foreground); + for (int i = 0; i < item->columnCount(); ++i) + { + item->setForeground(i, brush); + } }//if(!rsFiles -> FileRequest( }//if (item->text(SR_HASH_COL).isEmpty()) }//for (int i = 0 @@ -1189,6 +1196,11 @@ void SearchDialog::insertFile(qulonglong searchId, const FileDetail& file, int s found = true ; if (!item->data(SR_DATA_COL, SR_ROLE_LOCAL).toBool()) { + + FileInfo fi; + if (rsFiles->FileDetails(file.hash, RS_FILE_HINTS_DOWNLOAD, fi)) + break; + QColor foreground; int sources = friendSource + anonymousSource ; @@ -1281,6 +1293,12 @@ void SearchDialog::insertFile(qulonglong searchId, const FileDetail& file, int s setForeground = true; } } + if (rsFiles->FileDetails(file.hash, RS_FILE_HINTS_DOWNLOAD, fi)) + { + //foreground = QColor(0, 128, 0); // green + foreground = textColorDownloading(); + setForeground = true; + } if (setForeground) { QBrush brush(foreground); diff --git a/retroshare-gui/src/gui/FileTransfer/SearchDialog.h b/retroshare-gui/src/gui/FileTransfer/SearchDialog.h index bfc5892cc..57846692c 100644 --- a/retroshare-gui/src/gui/FileTransfer/SearchDialog.h +++ b/retroshare-gui/src/gui/FileTransfer/SearchDialog.h @@ -38,6 +38,7 @@ class SearchDialog : public MainPage Q_OBJECT Q_PROPERTY(QColor textColorLocal READ textColorLocal WRITE setTextColorLocal) + Q_PROPERTY(QColor textColorDownloading READ textColorDownloading WRITE setTextColorDownloading) Q_PROPERTY(QColor textColorNoSources READ textColorNoSources WRITE setTextColorNoSources) Q_PROPERTY(QColor textColorLowSources READ textColorLowSources WRITE setTextColorLowSources) Q_PROPERTY(QColor textColorHighSources READ textColorHighSources WRITE setTextColorHighSources) @@ -51,11 +52,13 @@ public: void searchKeywords(const QString& keywords); QColor textColorLocal() const { return mTextColorLocal; } + QColor textColorDownloading() const { return mTextColorDownloading; } QColor textColorNoSources() const { return mTextColorNoSources; } QColor textColorLowSources() const { return mTextColorLowSources; } QColor textColorHighSources() const { return mTextColorHighSources; } void setTextColorLocal(QColor color) { mTextColorLocal = color; } + void setTextColorDownloading(QColor color) { mTextColorDownloading = color; } void setTextColorNoSources(QColor color) { mTextColorNoSources = color; } void setTextColorLowSources(QColor color) { mTextColorLowSources = color; } void setTextColorHighSources(QColor color) { mTextColorHighSources = color; } @@ -154,6 +157,7 @@ private: /* Color definitions (for standard see qss.default) */ QColor mTextColorLocal; + QColor mTextColorDownloading; QColor mTextColorNoSources; QColor mTextColorLowSources; QColor mTextColorHighSources; diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 25db8896d..aac7e3ba5 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -55,10 +55,11 @@ *****/ // Data Requests. -#define IDDIALOG_IDLIST 1 -#define IDDIALOG_IDDETAILS 2 -#define IDDIALOG_REPLIST 3 -#define IDDIALOG_REFRESH 4 +#define IDDIALOG_IDLIST 1 +#define IDDIALOG_IDDETAILS 2 +#define IDDIALOG_REPLIST 3 +#define IDDIALOG_REFRESH 4 +#define IDDIALOG_SERIALIZED_GROUP 5 #define CIRCLEGROUP_CIRCLE_COL_GROUPNAME 0 #define CIRCLEGROUP_CIRCLE_COL_GROUPID 1 @@ -814,7 +815,7 @@ void IdDialog::loadCircleGroupData(const uint32_t& token) #ifdef ID_DEBUG std::cerr << "Loading circle info" << std::endl; #endif - + std::vector circle_grp_v ; rsGxsCircles->getGroupData(token, circle_grp_v); @@ -1207,6 +1208,7 @@ void IdDialog::CircleListCustomPopupMenu( QPoint ) contextMnu.exec(QCursor::pos()); } +#ifdef SUSPENDED static void set_item_background(QTreeWidgetItem *item, uint32_t type) { QBrush brush; @@ -1247,7 +1249,6 @@ static void update_children_background(QTreeWidgetItem *item, uint32_t type) } } -#ifdef SUSPENDED static void set_tree_background(QTreeWidget *tree, uint32_t type) { std::cerr << "CirclesDialog set_tree_background()"; @@ -1385,6 +1386,8 @@ void IdDialog::updateSelection() } } + + void IdDialog::requestIdList() { //Disable by default, will be enable by insertIdDetails() @@ -1990,7 +1993,7 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const return tr("Membership verification in circle %1.").arg(QString::fromStdString(u.mGrpId.toStdString())); } -#warning TODO! Add the different strings and translations here. +#warning TODO! csoler 2017-01-03: Add the different strings and translations here. default: return QString("Undone yet"); } @@ -2174,6 +2177,45 @@ void IdDialog::insertRepList(uint32_t token) mStateHelper->setActive(IDDIALOG_REPLIST, true); } +void IdDialog::handleSerializedGroupData(uint32_t token) +{ + std::map serialized_group_map ; + + rsIdentity->getGroupSerializedData(token, serialized_group_map); + + if(serialized_group_map.size() < 1) + { + std::cerr << "(EE) Cannot get radix data " << std::endl; + return; + } + if(serialized_group_map.size() > 1) + { + std::cerr << "(EE) Too many results for serialized data" << std::endl; + return; + } + + RsGxsId gxs_id = serialized_group_map.begin()->first ; + std::string radix = serialized_group_map.begin()->second ; + + RsIdentityDetails details ; + + if(!rsIdentity->getIdDetails(gxs_id,details)) + { + std::cerr << "(EE) Cannot get id details for key " << gxs_id << std::endl; + return; + } + + QList urls ; + + RetroShareLink link ; + link.createIdentity(gxs_id,QString::fromUtf8(details.mNickname.c_str()),QString::fromStdString(radix)) ; + urls.push_back(link); + + RSLinkClipboard::copyLinks(urls) ; + + QMessageBox::information(NULL,tr("information"),tr("This identity link was copied to your clipboard. Paste it in a mail, or a message to transmit the identity to someone.")) ; +} + void IdDialog::loadRequest(const TokenQueue * queue, const TokenRequest &req) { #ifdef ID_DEBUG @@ -2197,6 +2239,10 @@ void IdDialog::loadRequest(const TokenQueue * queue, const TokenRequest &req) insertRepList(req.mToken); break; + case IDDIALOG_SERIALIZED_GROUP: + handleSerializedGroupData(req.mToken); + break; + case IDDIALOG_REFRESH: // replaced by RsGxsUpdateBroadcastPage // updateDisplay(true); @@ -2240,165 +2286,211 @@ void IdDialog::loadRequest(const TokenQueue * queue, const TokenRequest &req) void IdDialog::IdListCustomPopupMenu( QPoint ) { - QMenu *contextMenu = new QMenu(this); + QMenu *contextMenu = new QMenu(this); - std::list own_identities ; - rsIdentity->getOwnIds(own_identities) ; + std::list own_identities ; + rsIdentity->getOwnIds(own_identities) ; - // make some stats about what's selected. If the same value is used for all selected items, it can be switched. + // make some stats about what's selected. If the same value is used for all selected items, it can be switched. - QList selected_items = ui->idTreeWidget->selectedItems(); + QList selected_items = ui->idTreeWidget->selectedItems(); - bool root_node_present = false ; - bool one_item_owned_by_you = false ; - uint32_t n_positive_reputations = 0 ; - uint32_t n_negative_reputations = 0 ; - uint32_t n_neutral_reputations = 0 ; - uint32_t n_is_a_contact = 0 ; - uint32_t n_is_not_a_contact = 0 ; - uint32_t n_selected_items =0 ; + bool root_node_present = false ; + bool one_item_owned_by_you = false ; + uint32_t n_positive_reputations = 0 ; + uint32_t n_negative_reputations = 0 ; + uint32_t n_neutral_reputations = 0 ; + uint32_t n_is_a_contact = 0 ; + uint32_t n_is_not_a_contact = 0 ; + uint32_t n_selected_items =0 ; - for(QList::const_iterator it(selected_items.begin());it!=selected_items.end();++it) - { - if(*it == allItem || *it == contactsItem || *it == ownItem) - { - root_node_present = true ; - continue ; - } - - uint32_t item_flags = (*it)->data(RSID_COL_KEYID,Qt::UserRole).toUInt() ; - - if(item_flags & RSID_FILTER_OWNED_BY_YOU) - one_item_owned_by_you = true ; - -#ifdef ID_DEBUG - std::cerr << " item flags = " << item_flags << std::endl; -#endif - RsGxsId keyId((*it)->text(RSID_COL_KEYID).toStdString()); - - RsIdentityDetails det ; - rsIdentity->getIdDetails(keyId,det) ; - - switch(det.mReputation.mOwnOpinion) - { - case RsReputations::OPINION_NEGATIVE: ++n_negative_reputations ; - break ; - - case RsReputations::OPINION_POSITIVE: ++n_positive_reputations ; - break ; - - case RsReputations::OPINION_NEUTRAL: ++n_neutral_reputations ; - break ; - } - - ++n_selected_items ; - - if(rsIdentity->isARegularContact(keyId)) - ++n_is_a_contact ; - else - ++n_is_not_a_contact ; - } - - if(!root_node_present) // don't show menu if some of the root nodes are present + for(QList::const_iterator it(selected_items.begin());it!=selected_items.end();++it) + { + if(*it == allItem || *it == contactsItem || *it == ownItem) { - - if(!one_item_owned_by_you) - { - QWidget *widget = new QWidget(contextMenu); - widget->setStyleSheet( ".QWidget{background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,stop:0 #FEFEFE, stop:1 #E8E8E8); border: 1px solid #CCCCCC;}"); - - // create menu header - QHBoxLayout *hbox = new QHBoxLayout(widget); - hbox->setMargin(0); - hbox->setSpacing(6); - - QLabel *iconLabel = new QLabel(widget); - QPixmap pix = QPixmap(":/images/user/friends24.png").scaledToHeight(QFontMetricsF(iconLabel->font()).height()*1.5); - iconLabel->setPixmap(pix); - iconLabel->setMaximumSize(iconLabel->frameSize().height() + pix.height(), pix.width()); - hbox->addWidget(iconLabel); - - QLabel *textLabel = new QLabel("" + ui->titleBarLabel->text() + "", widget); - hbox->addWidget(textLabel); - - QSpacerItem *spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - hbox->addItem(spacerItem); - - widget->setLayout(hbox); - - QWidgetAction *widgetAction = new QWidgetAction(this); - widgetAction->setDefaultWidget(widget); - contextMenu->addAction(widgetAction); - - if(n_selected_items == 1) // if only one item is selected, allow to chat with this item - { - if(own_identities.size() <= 1) - { - QAction *action = contextMenu->addAction(QIcon(":/images/chat_24.png"), tr("Chat with this person"), this, SLOT(chatIdentity())); - - if(own_identities.empty()) - action->setEnabled(false) ; - else - action->setData(QString::fromStdString((own_identities.front()).toStdString())) ; - } - else - { - QMenu *mnu = contextMenu->addMenu(QIcon(":/images/chat_24.png"),tr("Chat with this person as...")) ; - - for(std::list::const_iterator it=own_identities.begin();it!=own_identities.end();++it) - { - RsIdentityDetails idd ; - rsIdentity->getIdDetails(*it,idd) ; - - QPixmap pixmap ; - - if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ; - - QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(chatIdentity())); - action->setData(QString::fromStdString((*it).toStdString())) ; - } - } - } - - // always allow to send messages - contextMenu->addAction(QIcon(":/images/mail_new.png"), tr("Send message"), this, SLOT(sendMsg())); - - contextMenu->addSeparator(); - - if(n_is_a_contact == 0) - contextMenu->addAction(QIcon(), tr("Add to Contacts"), this, SLOT(addtoContacts())); - - if(n_is_not_a_contact == 0) - contextMenu->addAction(QIcon(":/images/cancel.png"), tr("Remove from Contacts"), this, SLOT(removefromContacts())); - - contextMenu->addSeparator(); - - if(n_positive_reputations == 0) // only unban when all items are banned - contextMenu->addAction(QIcon(":/icons/png/thumbs-up.png"), tr("Set positive opinion"), this, SLOT(positivePerson())); - - if(n_neutral_reputations == 0) // only unban when all items are banned - contextMenu->addAction(QIcon(":/icons/png/thumbs-neutral.png"), tr("Set neutral opinion"), this, SLOT(neutralPerson())); - - if(n_negative_reputations == 0) - contextMenu->addAction(QIcon(":/icons/png/thumbs-down.png"), tr("Set negative opinion"), this, SLOT(negativePerson())); - } - - if(one_item_owned_by_you && n_selected_items==1) - { - contextMenu->addSeparator(); - - contextMenu->addAction(ui->editIdentity); - contextMenu->addAction(ui->removeIdentity); - } - + root_node_present = true ; + continue ; } - contextMenu = ui->idTreeWidget->createStandardContextMenu(contextMenu); + uint32_t item_flags = (*it)->data(RSID_COL_KEYID,Qt::UserRole).toUInt() ; - contextMenu->exec(QCursor::pos()); - delete contextMenu; + if(item_flags & RSID_FILTER_OWNED_BY_YOU) + one_item_owned_by_you = true ; + +#ifdef ID_DEBUG + std::cerr << " item flags = " << item_flags << std::endl; +#endif + RsGxsId keyId((*it)->text(RSID_COL_KEYID).toStdString()); + + RsIdentityDetails det ; + rsIdentity->getIdDetails(keyId,det) ; + + switch(det.mReputation.mOwnOpinion) + { + case RsReputations::OPINION_NEGATIVE: ++n_negative_reputations ; + break ; + + case RsReputations::OPINION_POSITIVE: ++n_positive_reputations ; + break ; + + case RsReputations::OPINION_NEUTRAL: ++n_neutral_reputations ; + break ; + } + + ++n_selected_items ; + + if(rsIdentity->isARegularContact(keyId)) + ++n_is_a_contact ; + else + ++n_is_not_a_contact ; + } + + if(!root_node_present) // don't show menu if some of the root nodes are present + { + + if(!one_item_owned_by_you) + { + QWidget *widget = new QWidget(contextMenu); + widget->setStyleSheet( ".QWidget{background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,stop:0 #FEFEFE, stop:1 #E8E8E8); border: 1px solid #CCCCCC;}"); + + // create menu header + QHBoxLayout *hbox = new QHBoxLayout(widget); + hbox->setMargin(0); + hbox->setSpacing(6); + + QLabel *iconLabel = new QLabel(widget); + QPixmap pix = QPixmap(":/images/user/friends24.png").scaledToHeight(QFontMetricsF(iconLabel->font()).height()*1.5); + iconLabel->setPixmap(pix); + iconLabel->setMaximumSize(iconLabel->frameSize().height() + pix.height(), pix.width()); + hbox->addWidget(iconLabel); + + QLabel *textLabel = new QLabel("" + ui->titleBarLabel->text() + "", widget); + hbox->addWidget(textLabel); + + QSpacerItem *spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + hbox->addItem(spacerItem); + + widget->setLayout(hbox); + + QWidgetAction *widgetAction = new QWidgetAction(this); + widgetAction->setDefaultWidget(widget); + contextMenu->addAction(widgetAction); + + if(n_selected_items == 1) // if only one item is selected, allow to chat with this item + { + if(own_identities.size() <= 1) + { + QAction *action = contextMenu->addAction(QIcon(":/images/chat_24.png"), tr("Chat with this person"), this, SLOT(chatIdentity())); + + if(own_identities.empty()) + action->setEnabled(false) ; + else + action->setData(QString::fromStdString((own_identities.front()).toStdString())) ; + } + else + { + QMenu *mnu = contextMenu->addMenu(QIcon(":/images/chat_24.png"),tr("Chat with this person as...")) ; + + for(std::list::const_iterator it=own_identities.begin();it!=own_identities.end();++it) + { + RsIdentityDetails idd ; + rsIdentity->getIdDetails(*it,idd) ; + + QPixmap pixmap ; + + if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG")) + pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ; + + QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(chatIdentity())); + action->setData(QString::fromStdString((*it).toStdString())) ; + } + } + } + + if(n_selected_items==1) + QAction *action = contextMenu->addAction(QIcon(":/images/chat_24.png"),tr("Copy identity to clipboard"),this,SLOT(copyRetroshareLink())) ; + + // always allow to send messages + contextMenu->addAction(QIcon(":/images/mail_new.png"), tr("Send message"), this, SLOT(sendMsg())); + + contextMenu->addSeparator(); + + if(n_is_a_contact == 0) + contextMenu->addAction(QIcon(), tr("Add to Contacts"), this, SLOT(addtoContacts())); + + if(n_is_not_a_contact == 0) + contextMenu->addAction(QIcon(":/images/cancel.png"), tr("Remove from Contacts"), this, SLOT(removefromContacts())); + + contextMenu->addSeparator(); + + if(n_positive_reputations == 0) // only unban when all items are banned + contextMenu->addAction(QIcon(":/icons/png/thumbs-up.png"), tr("Set positive opinion"), this, SLOT(positivePerson())); + + if(n_neutral_reputations == 0) // only unban when all items are banned + contextMenu->addAction(QIcon(":/icons/png/thumbs-neutral.png"), tr("Set neutral opinion"), this, SLOT(neutralPerson())); + + if(n_negative_reputations == 0) + contextMenu->addAction(QIcon(":/icons/png/thumbs-down.png"), tr("Set negative opinion"), this, SLOT(negativePerson())); + } + + if(one_item_owned_by_you && n_selected_items==1) + { + contextMenu->addSeparator(); + + contextMenu->addAction(QIcon(":/images/chat_24.png"),tr("Copy identity to clipboard"),this,SLOT(copyRetroshareLink())) ; + contextMenu->addAction(ui->editIdentity); + contextMenu->addAction(ui->removeIdentity); + } + + } + + contextMenu = ui->idTreeWidget->createStandardContextMenu(contextMenu); + + contextMenu->exec(QCursor::pos()); + delete contextMenu; +} + +void IdDialog::copyRetroshareLink() +{ + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); + + if (!item) + { + std::cerr << "IdDialog::editIdentity() Invalid item"; + std::cerr << std::endl; + return; + } + + RsGxsId gxs_id(item->text(RSID_COL_KEYID).toStdString()); + + if(gxs_id.isNull()) + { + std::cerr << "Null GXS id. Something went wrong." << std::endl; + return ; + } + + RsIdentityDetails details ; + + if(! rsIdentity->getIdDetails(gxs_id,details)) + return ; + + if (!mIdQueue) + return; + + mStateHelper->setLoading(IDDIALOG_SERIALIZED_GROUP, true); + + mIdQueue->cancelActiveRequestTokens(IDDIALOG_SERIALIZED_GROUP); + + std::list ids ; + ids.push_back(RsGxsGroupId(gxs_id)) ; + + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_SERIALIZED_DATA; + + uint32_t token; + + mIdQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, ids, IDDIALOG_SERIALIZED_GROUP); } void IdDialog::chatIdentity() diff --git a/retroshare-gui/src/gui/Identity/IdDialog.h b/retroshare-gui/src/gui/Identity/IdDialog.h index a44d83677..1eaae935d 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.h +++ b/retroshare-gui/src/gui/Identity/IdDialog.h @@ -93,6 +93,7 @@ private slots: void editIdentity(); void chatIdentity(); void sendMsg(); + void copyRetroshareLink(); void on_closeInfoFrameButton_clicked(); void updateSelection(); @@ -132,6 +133,7 @@ private: void requestRepList(); void insertRepList(uint32_t token); + void handleSerializedGroupData(uint32_t token); void requestIdEdit(std::string &id); void showIdEdit(uint32_t token); diff --git a/retroshare-gui/src/gui/Identity/IdDialog.ui b/retroshare-gui/src/gui/Identity/IdDialog.ui index 016ff28e1..1c52802ef 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.ui +++ b/retroshare-gui/src/gui/Identity/IdDialog.ui @@ -287,7 +287,7 @@ 692 - + @@ -296,12 +296,12 @@ QFrame::Raised - + 12 - + @@ -397,7 +397,7 @@ QFrame::Box - + 6 @@ -514,7 +514,7 @@ border-image: url(:/images/closepressed.png) Identity info - + @@ -526,7 +526,7 @@ border-image: url(:/images/closepressed.png) - + Your opinion: @@ -540,7 +540,7 @@ border-image: url(:/images/closepressed.png) - + Qt::Horizontal @@ -728,7 +728,7 @@ p, li { white-space: pre-wrap; } - + @@ -774,12 +774,12 @@ p, li { white-space: pre-wrap; } - + 6 - + 34 @@ -813,14 +813,14 @@ p, li { white-space: pre-wrap; } - + Qt::Vertical - + 34 @@ -856,7 +856,7 @@ p, li { white-space: pre-wrap; } - + Qt::Vertical @@ -874,11 +874,11 @@ p, li { white-space: pre-wrap; } - + Usage statistics - + @@ -886,7 +886,7 @@ p, li { white-space: pre-wrap; } - + Qt::Vertical @@ -900,10 +900,8 @@ p, li { white-space: pre-wrap; } detailsGroupBox - detailsGroupBox - groupBox + usageStatisticsGBox headerFramePerson - verticalSpacer_2 diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 4fecfa620..8e8534345 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -1207,7 +1207,7 @@ void MainWindow::showHelpDialog(const QString &topic) void MainWindow::retranslateUi() { - retranslateUi(); + //retranslateUi(); foreach (MainPage *page, ui->stackPages->pages()) { page->retranslateUi(); } diff --git a/retroshare-gui/src/gui/People/CircleWidget.cpp b/retroshare-gui/src/gui/People/CircleWidget.cpp index 3a192f97a..b36a3fa56 100644 --- a/retroshare-gui/src/gui/People/CircleWidget.cpp +++ b/retroshare-gui/src/gui/People/CircleWidget.cpp @@ -96,7 +96,7 @@ void CircleWidget::updateData(const RsGroupMetaData& gxs_group_info } } -QSize CircleWidget::sizeHint() +QSize CircleWidget::sizeHint() const { QSize size; size.setHeight(ui->graphicsView->size().height() + ui->label->size().height()); diff --git a/retroshare-gui/src/gui/People/CircleWidget.h b/retroshare-gui/src/gui/People/CircleWidget.h index 08b6ad6dc..75d6899ba 100644 --- a/retroshare-gui/src/gui/People/CircleWidget.h +++ b/retroshare-gui/src/gui/People/CircleWidget.h @@ -24,7 +24,7 @@ public: , const RsGxsCircleDetails& details); //Start QWidget Properties - QSize sizeHint(); + QSize sizeHint() const; //Start FlowLayoutItem Properties virtual const QPixmap getImage(); virtual const QPixmap getDragImage(); diff --git a/retroshare-gui/src/gui/People/IdentityWidget.cpp b/retroshare-gui/src/gui/People/IdentityWidget.cpp index 902a4dc18..0fcfbc127 100644 --- a/retroshare-gui/src/gui/People/IdentityWidget.cpp +++ b/retroshare-gui/src/gui/People/IdentityWidget.cpp @@ -148,7 +148,7 @@ void IdentityWidget::updateData(const RsGxsIdGroup &gxs_group_info, const RsPeer updateData(pgp_details); } -QSize IdentityWidget::sizeHint() +QSize IdentityWidget::sizeHint() const { QSize size; size.setHeight(ui->graphicsView->size().height() + ui->labelName->size().height()); diff --git a/retroshare-gui/src/gui/People/IdentityWidget.h b/retroshare-gui/src/gui/People/IdentityWidget.h index c9ade98e3..7f5dcd97f 100644 --- a/retroshare-gui/src/gui/People/IdentityWidget.h +++ b/retroshare-gui/src/gui/People/IdentityWidget.h @@ -26,7 +26,7 @@ public: , const RsPeerDetails& pgp_details); //Start QWidget Properties - QSize sizeHint(); + QSize sizeHint() const; //Start FlowLayoutItem Properties virtual const QPixmap getImage(); virtual const QPixmap getDragImage(); diff --git a/retroshare-gui/src/gui/People/PeopleDialog.cpp b/retroshare-gui/src/gui/People/PeopleDialog.cpp index 5098da953..bdf247a4f 100644 --- a/retroshare-gui/src/gui/People/PeopleDialog.cpp +++ b/retroshare-gui/src/gui/People/PeopleDialog.cpp @@ -901,7 +901,7 @@ void PeopleDialog::pf_dropEventOccursExt(QDropEvent *event) QWidget *wid = qobject_cast(event->source());//QT5 return QObject - FlowLayout *layout; + FlowLayout *layout = NULL; if (wid) layout = qobject_cast(wid->layout()); if (layout) { @@ -991,7 +991,7 @@ void PeopleDialog::pf_dropEventOccursInt(QDropEvent *event) QWidget *wid = qobject_cast(event->source());//QT5 return QObject - FlowLayout *layout; + FlowLayout *layout = NULL; if (wid) layout = qobject_cast(wid->layout()); if (layout) { diff --git a/retroshare-gui/src/gui/RetroShareLink.cpp b/retroshare-gui/src/gui/RetroShareLink.cpp index 957b61f7f..28a2d09c6 100644 --- a/retroshare-gui/src/gui/RetroShareLink.cpp +++ b/retroshare-gui/src/gui/RetroShareLink.cpp @@ -67,7 +67,8 @@ #define HOST_SEARCH "search" #define HOST_CERTIFICATE "certificate" #define HOST_PUBLIC_MSG "public_msg" -#define HOST_REGEXP "file|extra|person|forum|channel|posted|search|message|certificate|private_chat|public_msg" +#define HOST_IDENTITY "identity" +#define HOST_REGEXP "file|extra|person|forum|channel|posted|search|message|certificate|private_chat|public_msg|identity" #define FILE_NAME "name" #define FILE_SIZE "size" @@ -89,6 +90,9 @@ #define POSTED_ID "id" #define POSTED_MSGID "msgid" +#define IDENTITY_NAME "name" +#define IDENTITY_ID "gxsid" +#define IDENTITY_GROUP "groupdata" #define MESSAGE_ID "id" #define MESSAGE_SUBJECT "subject" @@ -303,6 +307,21 @@ void RetroShareLink::fromUrl(const QUrl& url) return; } + if(url.host() == HOST_IDENTITY) { + _type = TYPE_IDENTITY ; + QString name = decodedQueryItemValue(urlQuery, IDENTITY_NAME) ; + QString radix= decodedQueryItemValue(urlQuery, IDENTITY_GROUP) ; + QString gxsid= urlQuery.queryItemValue(IDENTITY_ID) ; + + RsGxsId id(gxsid.toStdString()) ; + + if(!id.isNull()) + createIdentity(id,name,radix) ; + else + std::cerr << "(EE) identity link is not valid." << std::endl; + return ; + } + if (url.host() == HOST_MESSAGE) { _type = TYPE_MESSAGE; std::string id = urlQuery.queryItemValue(MESSAGE_ID).toStdString(); @@ -312,7 +331,7 @@ void RetroShareLink::fromUrl(const QUrl& url) if (url.host() == HOST_CERTIFICATE) { _type = TYPE_CERTIFICATE; - _radix = urlQuery.queryItemValue(CERTIFICATE_RADIX); + _radix = decodedQueryItemValue(urlQuery, CERTIFICATE_RADIX); #ifdef DEBUG_RSLINK std::cerr << "Got a certificate link!!" << std::endl; @@ -333,6 +352,21 @@ RetroShareLink::RetroShareLink() clear(); } +bool RetroShareLink::createIdentity(const RsGxsId& id, const QString& name, const QString& radix_data) +{ + clear(); + + _name = name; + _hash = QString::fromStdString(id.toStdString()); + _radix_group_data = radix_data ; + + _type = TYPE_IDENTITY; + + check(); + + return valid(); +} + bool RetroShareLink::createExtraFile(const QString& name, uint64_t size, const QString& hash,const QString& ssl_id) { clear(); @@ -534,6 +568,7 @@ void RetroShareLink::clear() _GPGid = "" ; _time_stamp = 0 ; _encrypted_chat_info = "" ; + _radix_group_data = "" ; } void RetroShareLink::check() @@ -565,6 +600,17 @@ void RetroShareLink::check() if(!checkPGPId(_GPGid)) _valid = false ; break ; + case TYPE_IDENTITY: + if(_name.isNull()) + _valid = false ; + + if(_radix_group_data.isNull()) + _valid = false ; + + if(_hash.isNull()) + _valid = false ; + break ; + case TYPE_PERSON: if(_size != 0) _valid = false; @@ -651,6 +697,9 @@ QString RetroShareLink::title() const return QObject::tr("%1 (%2, Extra - Source included)").arg(hash()).arg(misc::friendlyUnit(size())); case TYPE_FILE: return QString("%1 (%2)").arg(hash()).arg(misc::friendlyUnit(size())); + case TYPE_IDENTITY: + return _name ; + case TYPE_PERSON: return PeerDefs::rsidFromId(RsPgpId(hash().toStdString())); case TYPE_FORUM: @@ -711,6 +760,14 @@ QString RetroShareLink::toString() const break; + case TYPE_IDENTITY: + url.setScheme(RSLINK_SCHEME) ; + url.setHost(HOST_IDENTITY) ; + urlQuery.addQueryItem(IDENTITY_ID,_hash) ; + urlQuery.addQueryItem(IDENTITY_NAME,encodeItem(_name)) ; + urlQuery.addQueryItem(IDENTITY_GROUP,encodeItem(_radix_group_data)) ; + break ; + case TYPE_EXTRAFILE: url.setScheme(RSLINK_SCHEME); url.setHost(HOST_EXTRAFILE); @@ -782,9 +839,9 @@ QString RetroShareLink::toString() const case TYPE_CERTIFICATE: url.setScheme(RSLINK_SCHEME); url.setHost(HOST_CERTIFICATE) ; - urlQuery.addQueryItem(CERTIFICATE_RADIX, _radix); - urlQuery.addQueryItem(CERTIFICATE_NAME, _name); - urlQuery.addQueryItem(CERTIFICATE_LOCATION, _location); + urlQuery.addQueryItem(CERTIFICATE_RADIX, encodeItem(_radix)); + urlQuery.addQueryItem(CERTIFICATE_NAME, encodeItem(_name)); + urlQuery.addQueryItem(CERTIFICATE_LOCATION, encodeItem(_location)); break; } @@ -798,9 +855,11 @@ QString RetroShareLink::toString() const QString RetroShareLink::niceName() const { - if (type() == TYPE_PERSON) { + if (type() == TYPE_PERSON) return PeerDefs::rsid(name().toUtf8().constData(), RsPgpId(hash().toStdString())); - } + + if(type() == TYPE_IDENTITY) + return QObject::tr("Identity link (name=%1, ID=%2)").arg(_name).arg(_hash) ; if(type() == TYPE_PUBLIC_MSG) { RsPeerDetails detail; @@ -1011,6 +1070,7 @@ static void processList(const QStringList &list, const QString &textSingular, co case TYPE_POSTED: case TYPE_SEARCH: case TYPE_MESSAGE: + case TYPE_IDENTITY: case TYPE_CERTIFICATE: case TYPE_PUBLIC_MSG: case TYPE_PRIVATE_CHAT: @@ -1156,6 +1216,15 @@ static void processList(const QStringList &list, const QString &textSingular, co } break ; + case TYPE_IDENTITY: + { + if(rsIdentity->deserialiseIdentityFromMemory(link.radixGroupData().toStdString())) + QMessageBox::information(NULL,QObject::tr("Identity added to People"),QObject::tr("The identity was added to people. You can now chat with it, send messages to it, etc.")) ; + else + QMessageBox::warning(NULL,QObject::tr("Identity cannot be added to People"),QObject::tr("The identity was not added to people. Some error occured. The link is probably corrupted.")) ; + } + break; + case TYPE_FILE: case TYPE_EXTRAFILE: { diff --git a/retroshare-gui/src/gui/RetroShareLink.h b/retroshare-gui/src/gui/RetroShareLink.h index d1390d18d..241d56740 100644 --- a/retroshare-gui/src/gui/RetroShareLink.h +++ b/retroshare-gui/src/gui/RetroShareLink.h @@ -68,7 +68,8 @@ class RetroShareLink TYPE_EXTRAFILE = 0x08, TYPE_PRIVATE_CHAT = 0x09, TYPE_PUBLIC_MSG = 0x0a, - TYPE_POSTED = 0x0b + TYPE_POSTED = 0x0b, + TYPE_IDENTITY = 0x0c }; public: @@ -76,7 +77,7 @@ class RetroShareLink RetroShareLink(const QUrl& url); RetroShareLink(const QString& url); -#warning these methods should be static and return a created link +#warning csoler 2017-01-04: These methods should be static and return a created link bool createFile(const QString& name, uint64_t size, const QString& hash); bool createExtraFile(const QString& name, uint64_t size, const QString& hash, const QString& ssl_id); bool createPerson(const RsPgpId &id); @@ -85,6 +86,7 @@ class RetroShareLink bool createSearch(const QString& keywords); bool createMessage(const RsPeerId &peerId, const QString& subject); bool createMessage(const RsGxsId &peerId, const QString& subject); + bool createIdentity(const RsGxsId& gxs_id,const QString& name,const QString& radix_data) ; bool createCertificate(const RsPeerId &ssl_id) ; bool createPublicMsgInvite(time_t time_stamp,const QString& pgp_id,const QString& hash) ; bool createUnknwonSslCertificate(const RsPeerId &sslId, const RsPgpId &gpgId = RsPgpId()) ; @@ -101,12 +103,13 @@ class RetroShareLink const QString& SSLId() const { return _SSLid ; } const QString& GPGId() const { return _GPGid ; } const QString& localIPAndPort() const { return _loc_ip_port ; } - const QString& externalIPAndPort() const { return _ext_ip_port ; } - const QString& dyndns() const { return _dyndns_name ; } - const QString& location() const { return _location ; } - const QString& radix() const { return _radix ; } - time_t timeStamp() const { return _time_stamp ; } - QString title() const; + const QString& externalIPAndPort() const { return _ext_ip_port ; } + const QString& dyndns() const { return _dyndns_name ; } + const QString& location() const { return _location ; } + const QString& radix() const { return _radix ; } + time_t timeStamp() const { return _time_stamp ; } + QString title() const; + QString radixGroupData() const { return _radix_group_data ;} unsigned int subType() const { return _subType; } void setSubType(unsigned int subType) { _subType = subType; } @@ -158,12 +161,13 @@ class RetroShareLink QString _GPGBase64String ; // GPG Cert QString _GPGBase64CheckSum ; // GPG Cert QString _location ; // location - QString _ext_ip_port ; - QString _loc_ip_port ; - QString _dyndns_name ; + QString _ext_ip_port ; + QString _loc_ip_port ; + QString _dyndns_name ; QString _radix ; - QString _encrypted_chat_info ; // encrypted data string for the recipient of a chat invite - time_t _time_stamp ; // time stamp at which the link will expire. + QString _encrypted_chat_info ; // encrypted data string for the recipient of a chat invite + time_t _time_stamp ; // time stamp at which the link will expire. + QString _radix_group_data; unsigned int _subType; // for general use as sub type for _type (RSLINK_SUBTYPE_...) }; diff --git a/retroshare-gui/src/gui/chat/ChatDialog.cpp b/retroshare-gui/src/gui/chat/ChatDialog.cpp index 2ab8b8e90..9fe8220ab 100644 --- a/retroshare-gui/src/gui/chat/ChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatDialog.cpp @@ -63,7 +63,7 @@ void ChatDialog::closeEvent(QCloseEvent *event) emit dialogClose(this); } -void ChatDialog::init(ChatId id, const QString &title) +void ChatDialog::init(const ChatId &id, const QString &title) { mChatId = id; ChatWidget *cw = getChatWidget(); @@ -102,14 +102,14 @@ void ChatDialog::init(ChatId id, const QString &title) if (chatflags & RS_CHAT_OPEN) { if (id.isLobbyId()) { ChatLobbyDialog* cld = new ChatLobbyDialog(id.toLobbyId()); - cld->init(); + cld->init(ChatId(), ""); cd = cld; } else if(id.isDistantChatId()) { PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toDistantChatId()); - pdcd->init(id.toDistantChatId()); + pdcd->init(id, ""); cd = pdcd; } else diff --git a/retroshare-gui/src/gui/chat/ChatDialog.h b/retroshare-gui/src/gui/chat/ChatDialog.h index f6b4ae57e..a5c6a0bc3 100644 --- a/retroshare-gui/src/gui/chat/ChatDialog.h +++ b/retroshare-gui/src/gui/chat/ChatDialog.h @@ -84,7 +84,7 @@ protected: virtual QString getPeerName(const ChatId &sslid) const ; // can be overloaded for chat dialogs that have specific peers virtual QString getOwnName() const; - virtual void init(ChatId id, const QString &title); + virtual void init(const ChatId &id, const QString &title); virtual void addChatMsg(const ChatMessage& msg) = 0; ChatId mChatId; diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index 4056156bb..20352b888 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -304,7 +304,7 @@ void ChatLobbyDialog::showInPeopleTab() idDialog->navigate(nickname); } -void ChatLobbyDialog::init() +void ChatLobbyDialog::init(const ChatId &/*id*/, const QString &/*title*/) { ChatLobbyInfo linfo ; diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h index 40fb44014..420524f93 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h @@ -71,7 +71,7 @@ protected: virtual ~ChatLobbyDialog(); void processSettings(bool load); - virtual void init(); + virtual void init(const ChatId &id, const QString &title); virtual bool canClose(); virtual void addChatMsg(const ChatMessage &msg); diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 6d558c5a8..10791b530 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -76,7 +76,7 @@ ChatWidget::ChatWidget(QWidget *parent) : int iconHeight = FMM*QFontMetricsF(font()).height() ; QSize iconSize = QSize(iconHeight,iconHeight); - QSize buttonSize = QSize(iconSize + QSize(FMM,FMM)); + QSize buttonSize = QSize(iconSize + QSize((int)FMM,(int)FMM)); newMessages = false; typing = false; @@ -258,7 +258,7 @@ void ChatWidget::addChatBarWidget(QWidget *w) { int iconHeight = FMM*QFontMetricsF(font()).height() ; QSize iconSize = QSize(iconHeight,iconHeight); - QSize buttonSize = QSize(iconSize + QSize(FMM,FMM)); + QSize buttonSize = QSize(iconSize + QSize((int)FMM,(int)FMM)); w->setFixedSize(buttonSize); ui->pluginButtonFrame->layout()->addWidget(w) ; } diff --git a/retroshare-gui/src/gui/chat/PopupChatDialog.h b/retroshare-gui/src/gui/chat/PopupChatDialog.h index 0a304b14c..49e3036b3 100644 --- a/retroshare-gui/src/gui/chat/PopupChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupChatDialog.h @@ -46,7 +46,7 @@ protected: /** Default destructor */ virtual ~PopupChatDialog(); - virtual void init(const ChatId &chat_id, const QString &title); + virtual void init(const ChatId &chat_id, const QString &title); virtual void showDialog(uint chatflags); virtual ChatWidget *getChatWidget(); virtual bool hasPeerStatus() { return true; } diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp index 5e7c6d80e..5e3eca6d7 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.cpp @@ -63,9 +63,12 @@ PopupDistantChatDialog::PopupDistantChatDialog(const DistantChatPeerId& tunnel_i updateDisplay() ; } -void PopupDistantChatDialog::init(const DistantChatPeerId &peer_id) +void PopupDistantChatDialog::init(const ChatId &chat_id, const QString &/*title*/) { - _tunnel_id = peer_id; + if (!chat_id.isDistantChatId()) + return; + + _tunnel_id = chat_id.toDistantChatId(); DistantChatPeerInfo tinfo; if(!rsMsgs->getDistantChatStatus(_tunnel_id,tinfo)) @@ -74,15 +77,15 @@ void PopupDistantChatDialog::init(const DistantChatPeerId &peer_id) RsIdentityDetails iddetails ; if(rsIdentity->getIdDetails(tinfo.to_id,iddetails)) - PopupChatDialog::init(ChatId(peer_id), QString::fromUtf8(iddetails.mNickname.c_str())) ; + PopupChatDialog::init(chat_id, QString::fromUtf8(iddetails.mNickname.c_str())) ; else - PopupChatDialog::init(ChatId(peer_id), QString::fromStdString(tinfo.to_id.toStdString())) ; + PopupChatDialog::init(chat_id, QString::fromStdString(tinfo.to_id.toStdString())) ; // Do not use setOwnId, because we don't want the user to change the GXS avatar from the chat window // it will not be transmitted. ui.ownAvatarWidget->setOwnId() ; // sets the flag - ui.ownAvatarWidget->setId(ChatId(peer_id)) ; // sets the actual Id + ui.ownAvatarWidget->setId(chat_id) ; // sets the actual Id } void PopupDistantChatDialog::updateDisplay() diff --git a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h index dfe75b9de..ff05f70c0 100644 --- a/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h +++ b/retroshare-gui/src/gui/chat/PopupDistantChatDialog.h @@ -38,7 +38,7 @@ class PopupDistantChatDialog: public PopupChatDialog /** Default destructor */ virtual ~PopupDistantChatDialog(); - virtual void init(const DistantChatPeerId& peer_id); + virtual void init(const ChatId& chat_id, const QString &title); virtual void closeEvent(QCloseEvent *e) ; virtual QString getPeerName(const ChatId &id) const ; diff --git a/retroshare-gui/src/gui/common/rwindow.cpp b/retroshare-gui/src/gui/common/rwindow.cpp index 32cfba943..e86be7fa2 100644 --- a/retroshare-gui/src/gui/common/rwindow.cpp +++ b/retroshare-gui/src/gui/common/rwindow.cpp @@ -76,11 +76,20 @@ RWindow::restoreWindowState() m_bSaveStateOnClose = true; // now we save the window state on close #if QT_VERSION >= 0x040200 - QByteArray geometry = getSetting("Geometry", QByteArray()).toByteArray(); - if (geometry.isEmpty()) + QByteArray geo = getSetting("Geometry", QByteArray()).toByteArray(); + if (geo.isEmpty()) + { adjustSize(); + QRect rect = geometry(); + int h = fontMetrics().height()*40; + if (rect.height()show(); ui.label_version->show(); - ui.groupBox->show(); + //ui.groupBox->show(); ui.groupBox_4->show(); - ui.tabWidget->show(); + //ui.tabWidget->show(); //ui.rsid->hide(); //ui.label_rsid->hide(); ui.pgpfingerprint->show(); diff --git a/retroshare-gui/src/gui/connect/ConfCertDialog.ui b/retroshare-gui/src/gui/connect/ConfCertDialog.ui index 469bae218..fec736831 100644 --- a/retroshare-gui/src/gui/connect/ConfCertDialog.ui +++ b/retroshare-gui/src/gui/connect/ConfCertDialog.ui @@ -6,8 +6,8 @@ 0 0 - 722 - 651 + 1104 + 1086 @@ -69,7 +69,7 @@ - 1 + 0 @@ -85,7 +85,7 @@ - Friend info + Node info: @@ -249,6 +249,114 @@ + + + + Current address: + + + + + + + + 0 + + + 65535 + + + 7812 + + + + + + + + + + 0 + + + 65535 + + + 7812 + + + + + + + Dynamic DNS + + + + + + + + + + External Address + + + + + + + + + + Port + + + + + + + Port + + + + + + + Qt::LeftToRight + + + Local Address + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + + List of known addresses: + + + + + + Qt::DefaultContextMenu + + + QAbstractItemView::MultiSelection + + + + + + @@ -264,170 +372,6 @@ - - - - :/images/kcmsystem24.png:/images/kcmsystem24.png - - - Connectivity - - - - - - 1 - - - - Peer Addresses - - - - - - Peer Address - - - - - - Qt::Vertical - - - - 20 - 47 - - - - - - - - Qt::Vertical - - - - 20 - 47 - - - - - - - - - - Qt::LeftToRight - - - Local Address - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - External Address - - - - - - - - - - Dynamic DNS - - - - - - - - - - Port - - - - - - - Port - - - - - - - 0 - - - 65535 - - - 7812 - - - - - - - 0 - - - 65535 - - - 7812 - - - - - - - - - - - - - Addresses list - - - - - - Addresses list - - - - - - - Qt::DefaultContextMenu - - - QAbstractItemView::MultiSelection - - - - - - - - - Retroshare Certificate diff --git a/retroshare-gui/src/gui/elastic/edge.cpp b/retroshare-gui/src/gui/elastic/edge.cpp index 4fec24fe7..e9e60f06b 100644 --- a/retroshare-gui/src/gui/elastic/edge.cpp +++ b/retroshare-gui/src/gui/elastic/edge.cpp @@ -46,7 +46,7 @@ #include -static const double Pi = 3.14159265358979323846264338327950288419717; +//static const double Pi = 3.14159265358979323846264338327950288419717; Edge::Edge(Node *sourceNode, Node *destNode) : arrowSize(10) diff --git a/retroshare-gui/src/gui/elastic/graphwidget.cpp b/retroshare-gui/src/gui/elastic/graphwidget.cpp index bb1f9ffb8..a2c69c80d 100644 --- a/retroshare-gui/src/gui/elastic/graphwidget.cpp +++ b/retroshare-gui/src/gui/elastic/graphwidget.cpp @@ -362,7 +362,7 @@ void GraphWidget::timerEvent(QTimerEvent *event) bool itemsMoved = false; foreach (Node *node, _nodes) - if(node->advance()) + if(node->progress()) itemsMoved = true; if (!itemsMoved) { diff --git a/retroshare-gui/src/gui/elastic/node.cpp b/retroshare-gui/src/gui/elastic/node.cpp index bc33151df..6a3020b21 100644 --- a/retroshare-gui/src/gui/elastic/node.cpp +++ b/retroshare-gui/src/gui/elastic/node.cpp @@ -215,7 +215,7 @@ void Node::calculateForces(const double *map,int width,int height,int W,int H,fl newPos.setY(qMin(qMax(newPos.y(), sceneRect.top()) , sceneRect.bottom())); } -bool Node::advance() +bool Node::progress() { if(_type == GraphWidget::ELASTIC_NODE_TYPE_OWN) return false; diff --git a/retroshare-gui/src/gui/elastic/node.h b/retroshare-gui/src/gui/elastic/node.h index 13c717b0b..e43fa3521 100644 --- a/retroshare-gui/src/gui/elastic/node.h +++ b/retroshare-gui/src/gui/elastic/node.h @@ -77,7 +77,7 @@ public: std::string descString() const { return _desc_string ; } void calculateForces(const double *data,int width,int height,int W,int H,float x,float y,float speedf); - bool advance(); + bool progress(); QRectF boundingRect() const; QPainterPath shape() const; diff --git a/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp b/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp index 2fa1f3b1e..a99e815c7 100644 --- a/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp +++ b/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp @@ -25,6 +25,7 @@ #include #include +#include "gui/common/RSElidedItemDelegate.h" #include "gui/gxs/GxsCommentTreeWidget.h" #include "gui/gxs/GxsCreateCommentDialog.h" #include "gui/gxs/GxsIdTreeWidgetItem.h" @@ -57,6 +58,10 @@ GxsCommentTreeWidget::GxsCommentTreeWidget(QWidget *parent) // QTreeWidget* widget = this; setContextMenuPolicy(Qt::CustomContextMenu); + RSElidedItemDelegate *itemDelegate = new RSElidedItemDelegate(this); + itemDelegate->setSpacing(QSize(0, 2)); + setItemDelegate(itemDelegate); + setWordWrap(true); // QFont font = QFont("ARIAL", 10); // font.setBold(true); diff --git a/retroshare-gui/src/gui/gxs/GxsCreateCommentDialog.cpp b/retroshare-gui/src/gui/gxs/GxsCreateCommentDialog.cpp index a1e20e37c..500693df0 100644 --- a/retroshare-gui/src/gui/gxs/GxsCreateCommentDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsCreateCommentDialog.cpp @@ -25,6 +25,8 @@ #include "GxsCreateCommentDialog.h" #include "ui_GxsCreateCommentDialog.h" +#include "util/HandleRichText.h" + #include #include @@ -45,7 +47,11 @@ void GxsCreateCommentDialog::createComment() { RsGxsComment comment; - comment.mComment = std::string(ui->commentTextEdit->document()->toPlainText().toUtf8()); + QString text = ui->commentTextEdit->toHtml(); + RsHtml::optimizeHtml(text); + std::string msg = text.toUtf8().constData(); + + comment.mComment = msg; comment.mMeta.mParentId = mParentId.second; comment.mMeta.mGroupId = mParentId.first; comment.mMeta.mThreadId = mThreadId; diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 2bfdb6c0d..6ab4ca165 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -841,8 +841,11 @@ void GxsGroupFrameDialog::insertGroupsData(const std::list &gro /* now we can add them in as a tree! */ ui->groupTreeWidget->fillGroupItems(mYourGroups, adminList); ui->groupTreeWidget->fillGroupItems(mSubscribedGroups, subList); + mSubscribedGroups->setText(2, QString::number(mSubscribedGroups->childCount())); // 1 COLUMN_UNREAD 2 COLUMN_POPULARITY ui->groupTreeWidget->fillGroupItems(mPopularGroups, popList); + mPopularGroups->setText(2, QString::number(mPopularGroups->childCount())); ui->groupTreeWidget->fillGroupItems(mOtherGroups, otherList); + mOtherGroups->setText(2, QString::number(mOtherGroups->childCount())); mInFill = false; diff --git a/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.cpp b/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.cpp index 9b8cd40ea..aaab89231 100644 --- a/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.cpp +++ b/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.cpp @@ -45,12 +45,13 @@ #define CREATEGXSFORUMMSG_FORUMINFO 1 #define CREATEGXSFORUMMSG_PARENTMSG 2 #define CREATEGXSFORUMMSG_CIRCLENFO 3 +#define CREATEGXSFORUMMSG_ORIGMSG 4 //#define ENABLE_GENERATE /** Constructor */ -CreateGxsForumMsg::CreateGxsForumMsg(const RsGxsGroupId &fId, const RsGxsMessageId &pId) -: QDialog(NULL, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint), mForumId(fId), mParentId(pId) +CreateGxsForumMsg::CreateGxsForumMsg(const RsGxsGroupId &fId, const RsGxsMessageId &pId,const RsGxsMessageId& mOId,const RsGxsId& posterId) +: QDialog(NULL, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint), mForumId(fId), mParentId(pId), mOrigMsgId(mOId),mPosterId(posterId) { /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); @@ -75,7 +76,14 @@ CreateGxsForumMsg::CreateGxsForumMsg(const RsGxsGroupId &fId, const RsGxsMessage mStateHelper->addLoadPlaceholder(CREATEGXSFORUMMSG_PARENTMSG, ui.forumSubject); mStateHelper->addClear(CREATEGXSFORUMMSG_PARENTMSG, ui.forumName); - QString text = pId.isNull() ? tr("Start New Thread") : tr("Post Forum Message"); + mStateHelper->addWidget(CREATEGXSFORUMMSG_ORIGMSG, ui.buttonBox->button(QDialogButtonBox::Ok)); + mStateHelper->addWidget(CREATEGXSFORUMMSG_ORIGMSG, ui.innerFrame); + mStateHelper->addLoadPlaceholder(CREATEGXSFORUMMSG_ORIGMSG, ui.forumName); + mStateHelper->addLoadPlaceholder(CREATEGXSFORUMMSG_ORIGMSG, ui.forumSubject); + mStateHelper->addClear(CREATEGXSFORUMMSG_ORIGMSG, ui.forumName); + + + QString text = mOId.isNull()?(pId.isNull() ? tr("Start New Thread") : tr("Post Forum Message")):tr("Edit Message"); setWindowTitle(text); ui.headerFrame->setHeaderImage(QPixmap(":/images/konversation64.png")); @@ -103,7 +111,7 @@ CreateGxsForumMsg::CreateGxsForumMsg(const RsGxsGroupId &fId, const RsGxsMessage mParentMsgLoaded = false; mForumMetaLoaded = false; - mForumCircleLoaded = false; + mForumCircleLoaded = false; newMsg(); @@ -129,13 +137,24 @@ void CreateGxsForumMsg::newMsg() //std::cerr << "Initing ID chooser. Sign flags = " << std::hex << mForumMeta.mSignFlags << std::dec << std::endl; - ui.idChooser->loadIds(IDCHOOSER_ID_REQUIRED, RsGxsId()); + if(!mPosterId.isNull()) + { + std::set id_set ; + id_set.insert(mPosterId) ; + + ui.idChooser->loadIds(IDCHOOSER_ID_REQUIRED | IDCHOOSER_NO_CREATE, mPosterId); + ui.idChooser->setIdConstraintSet(id_set); + } + else + ui.idChooser->loadIds(IDCHOOSER_ID_REQUIRED, mPosterId); if (mForumId.isNull()) { mStateHelper->setActive(CREATEGXSFORUMMSG_FORUMINFO, false); mStateHelper->setActive(CREATEGXSFORUMMSG_PARENTMSG, false); + mStateHelper->setActive(CREATEGXSFORUMMSG_ORIGMSG, false); mStateHelper->clear(CREATEGXSFORUMMSG_FORUMINFO); mStateHelper->clear(CREATEGXSFORUMMSG_PARENTMSG); + mStateHelper->clear(CREATEGXSFORUMMSG_ORIGMSG); ui.forumName->setText(tr("No Forum")); return; }//if ( mForumId.isNull()) @@ -174,11 +193,53 @@ void CreateGxsForumMsg::newMsg() uint32_t token; mForumQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, CREATEGXSFORUMMSG_PARENTMSG); }//if (mParentId.isNull()) + + if (mOrigMsgId.isNull()) { + mStateHelper->setActive(CREATEGXSFORUMMSG_ORIGMSG, true); + mOrigMsgLoaded = true; + } else { + mStateHelper->setLoading(CREATEGXSFORUMMSG_ORIGMSG, true); + + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + + GxsMsgReq msgIds; + std::vector &vect = msgIds[mForumId]; + vect.push_back(mOrigMsgId); + + //std::cerr << "ForumsV2Dialog::newMsg() Requesting Parent Summary(" << mParentId << ")"; + //std::cerr << std::endl; + + uint32_t token; + mForumQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, CREATEGXSFORUMMSG_ORIGMSG); + }//if (mParentId.isNull()) } void CreateGxsForumMsg::loadFormInformation() { - if (!mParentId.isNull()) { + if (!mOrigMsgId.isNull()) + { + if (mOrigMsgLoaded) { + mStateHelper->setActive(CREATEGXSFORUMMSG_ORIGMSG, true); + mStateHelper->setLoading(CREATEGXSFORUMMSG_ORIGMSG, false); + } else { + //std::cerr << "CreateGxsForumMsg::loadMsgInformation() ParentMsg not Loaded Yet"; + //std::cerr << std::endl; + + mStateHelper->setActive(CREATEGXSFORUMMSG_ORIGMSG, false); + + return; + } + } + else + { + mStateHelper->setActive(CREATEGXSFORUMMSG_ORIGMSG, true); + mStateHelper->setLoading(CREATEGXSFORUMMSG_ORIGMSG, false); + } + + + if (!mParentId.isNull()) + { if (mParentMsgLoaded) { mStateHelper->setActive(CREATEGXSFORUMMSG_PARENTMSG, true); mStateHelper->setLoading(CREATEGXSFORUMMSG_PARENTMSG, false); @@ -190,7 +251,9 @@ void CreateGxsForumMsg::loadFormInformation() return; } - } else { + } + else + { mStateHelper->setActive(CREATEGXSFORUMMSG_PARENTMSG, true); mStateHelper->setLoading(CREATEGXSFORUMMSG_PARENTMSG, false); } @@ -212,14 +275,24 @@ void CreateGxsForumMsg::loadFormInformation() //std::cerr << "CreateGxsForumMsg::loadMsgInformation() using signFlags=" << std::hex << mForumMeta.mSignFlags << std::dec << std::endl; - if( (mForumMeta.mSignFlags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG) || (mForumMeta.mSignFlags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG_KNOWN)) - ui.idChooser->setFlags(IDCHOOSER_ID_REQUIRED | IDCHOOSER_NON_ANONYMOUS) ; - else - ui.idChooser->setFlags(IDCHOOSER_ID_REQUIRED) ; - + uint32_t fl = IDCHOOSER_ID_REQUIRED ; + + if( (mForumMeta.mSignFlags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG) || (mForumMeta.mSignFlags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_GPG_KNOWN)) + fl |= IDCHOOSER_NON_ANONYMOUS ; + + if(!mPosterId.isNull()) + fl |= IDCHOOSER_NO_CREATE; + + ui.idChooser->setFlags(fl) ; + QString name = QString::fromUtf8(mForumMeta.mGroupName.c_str()); QString subj; - if (!mParentId.isNull()) + + if(!mOrigMsgId.isNull()) + { + subj = QString::fromUtf8(mOrigMsg.mMeta.mMsgName.c_str()); + } + else if (!mParentId.isNull()) { QString title = QString::fromUtf8(mParentMsg.mMeta.mMsgName.c_str()); name += " " + tr("In Reply to") + ": "; @@ -228,17 +301,14 @@ void CreateGxsForumMsg::loadFormInformation() QString text = title; if (text.startsWith("Re:", Qt::CaseInsensitive)) - { subj = title; - } else - { subj = "Re: " + title; - } } ui.forumName->setText(misc::removeNewLine(name)); ui.forumSubject->setText(misc::removeNewLine(subj)); + //ui.forumSubject->setReadOnly(!mOrigMsgId.isNull()); if (ui.forumSubject->text().isEmpty()) { @@ -286,6 +356,7 @@ void CreateGxsForumMsg::createMsg() RsGxsForumMsg msg; msg.mMeta.mGroupId = mForumId; msg.mMeta.mParentId = mParentId; + msg.mMeta.mOrigMsgId = mOrigMsgId; msg.mMeta.mMsgId.clear() ; if (mParentMsgLoaded) { msg.mMeta.mThreadId = mParentMsg.mMeta.mThreadId; @@ -377,9 +448,9 @@ void CreateGxsForumMsg::reject() { if (ui.forumMessage->document()->isModified()) { QMessageBox::StandardButton ret; - ret = QMessageBox::warning(this, tr("Forum Message"), - tr("Forum Message has not been Sent.\n" - "Do you want to reject this message?"), + ret = QMessageBox::warning(this, tr("Cancel Forum Message"), + tr("Forum Message has not been sent yet!\n" + "Do you want to discard this message?"), QMessageBox::Yes | QMessageBox::No); switch (ret) { case QMessageBox::Yes: @@ -521,6 +592,35 @@ void CreateGxsForumMsg::loadForumCircleInfo(const uint32_t& token) } } +void CreateGxsForumMsg::loadOrigMsg(const uint32_t &token) +{ + //std::cerr << "CreateGxsForumMsg::loadParentMsg()"; + //std::cerr << std::endl; + + // Only grab one.... ignore more (shouldn't be any). + std::vector msgs; + if (rsGxsForums->getMsgData(token, msgs)) + { + if (msgs.size() != 1) + { + /* error */ + std::cerr << "CreateGxsForumMsg::loadOrigMsg() ERROR wrong number of msgs"; + std::cerr << std::endl; + + mStateHelper->setActive(CREATEGXSFORUMMSG_ORIGMSG, false); + mStateHelper->setLoading(CREATEGXSFORUMMSG_ORIGMSG, false); + + return; + } + + mOrigMsg = msgs[0]; + mOrigMsgLoaded = true; + + loadFormInformation(); + } +} + + void CreateGxsForumMsg::loadParentMsg(const uint32_t &token) { //std::cerr << "CreateGxsForumMsg::loadParentMsg()"; @@ -562,6 +662,9 @@ void CreateGxsForumMsg::loadRequest(const TokenQueue *queue, const TokenRequest case CREATEGXSFORUMMSG_FORUMINFO: loadForumInfo(req.mToken); break; + case CREATEGXSFORUMMSG_ORIGMSG: + loadOrigMsg(req.mToken); + break; case CREATEGXSFORUMMSG_PARENTMSG: loadParentMsg(req.mToken); break; diff --git a/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.h b/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.h index ae06b0b0c..7f84a434b 100644 --- a/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.h +++ b/retroshare-gui/src/gui/gxsforums/CreateGxsForumMsg.h @@ -36,7 +36,7 @@ class CreateGxsForumMsg : public QDialog, public TokenResponse Q_OBJECT public: - CreateGxsForumMsg(const RsGxsGroupId &fId, const RsGxsMessageId &pId); + CreateGxsForumMsg(const RsGxsGroupId &fId, const RsGxsMessageId &pId, const RsGxsMessageId &moId, const RsGxsId &posterId = RsGxsId()); ~CreateGxsForumMsg(); void newMsg(); /* cleanup */ @@ -61,18 +61,24 @@ private: void loadForumInfo(const uint32_t &token); void loadParentMsg(const uint32_t &token); + void loadOrigMsg(const uint32_t &token); void loadForumCircleInfo(const uint32_t &token); RsGxsGroupId mForumId; - RsGxsCircleId mCircleId ; - RsGxsMessageId mParentId; + RsGxsCircleId mCircleId ; + RsGxsMessageId mParentId; + RsGxsMessageId mOrigMsgId; + RsGxsId mPosterId; bool mParentMsgLoaded; + bool mOrigMsgLoaded; bool mForumMetaLoaded; - bool mForumCircleLoaded ; + bool mForumCircleLoaded ; + RsGxsForumMsg mParentMsg; + RsGxsForumMsg mOrigMsg; RsGroupMetaData mForumMeta; - RsGxsCircleGroup mForumCircleData ; + RsGxsCircleGroup mForumCircleData ; TokenQueue *mForumQueue; TokenQueue *mCirclesQueue; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 4abfb4569..5c479005c 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -160,6 +160,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget mTokenTypeNegativeAuthor = nextTokenType(); mTokenTypeNeutralAuthor = nextTokenType(); mTokenTypePositiveAuthor = nextTokenType(); + mTokenTypeEditForumMessage = nextTokenType(); setUpdateWhenInvisible(true); @@ -199,6 +200,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->threadTreeWidget->setItemDelegateForColumn(COLUMN_THREAD_DISTRIBUTION,new DistributionItemDelegate()) ; + connect(ui->versions_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changedVersion())); connect(ui->threadTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(threadListCustomPopupMenu(QPoint))); connect(ui->postText, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuTextBrowser(QPoint))); @@ -483,11 +485,14 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) QMenu contextMnu(this); + QAction *editAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Edit"), &contextMnu); + connect(editAct, SIGNAL(triggered()), this, SLOT(editforummessage())); + QAction *replyAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply"), &contextMnu); connect(replyAct, SIGNAL(triggered()), this, SLOT(replytoforummessage())); QAction *replyauthorAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply to author with private message"), &contextMnu); - connect(replyauthorAct, SIGNAL(triggered()), this, SLOT(replytomessage())); + connect(replyauthorAct, SIGNAL(triggered()), this, SLOT(reply_with_private_message())); QAction *flagaspositiveAct = new QAction(QIcon(IMAGE_POSITIVE_OPINION), tr("Give positive opinion"), &contextMnu); flagaspositiveAct->setToolTip(tr("This will block/hide messages from this person, and notify friend nodes.")) ; @@ -572,6 +577,18 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) replyauthorAct->setDisabled (true); } + QList selectedItems = ui->threadTreeWidget->selectedItems(); + + if(selectedItems.size() == 1) + { + QTreeWidgetItem *item = *selectedItems.begin(); + GxsIdRSTreeWidgetItem *gxsIdItem = dynamic_cast(item); + + RsGxsId author_id; + if(gxsIdItem && gxsIdItem->getId(author_id) && rsIdentity->isOwnId(author_id)) + contextMnu.addAction(editAct); + } + contextMnu.addAction(replyAct); contextMnu.addAction(newthreadAct); QAction* action = contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink())); @@ -585,8 +602,6 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) contextMnu.addAction(expandAll); contextMnu.addAction(collapseAll); - QList selectedItems = ui->threadTreeWidget->selectedItems(); - if(selectedItems.size() == 1) { QTreeWidgetItem *item = *selectedItems.begin(); @@ -680,6 +695,17 @@ void GxsForumThreadWidget::togglethreadview_internal() } } +void GxsForumThreadWidget::changedVersion() +{ + mThreadId = RsGxsMessageId(ui->versions_CB->itemData(ui->versions_CB->currentIndex()).toString().toStdString()) ; + + if (mFillThread) { + return; + } + ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()) ; + insertMessage(); +} + void GxsForumThreadWidget::changedThread() { /* just grab the ids of the current item */ @@ -687,8 +713,10 @@ void GxsForumThreadWidget::changedThread() if (!item || !item->isSelected()) { mThreadId.clear(); + mOrigThreadId.clear(); } else { - mThreadId = RsGxsMessageId(item->data(COLUMN_THREAD_MSGID, Qt::DisplayRole).toString().toStdString()); + + mThreadId = mOrigThreadId = RsGxsMessageId(item->data(COLUMN_THREAD_MSGID, Qt::DisplayRole).toString().toStdString()); } if (mFillThread) { @@ -1014,10 +1042,12 @@ void GxsForumThreadWidget::fillThreadFinished() mLastViewType = thread->mViewType; mLastForumID = groupId(); ui->threadTreeWidget->insertTopLevelItems(0, thread->mItems); + mPostVersions = thread->mPostVersions; // clear list thread->mItems.clear(); } else { + mPostVersions = thread->mPostVersions; fillThreads(thread->mItems, thread->mExpandNewMessages, thread->mItemToExpand); // cleanup list @@ -1507,6 +1537,9 @@ void GxsForumThreadWidget::insertMessage() mStateHelper->setActive(mTokenTypeMessageData, false); mStateHelper->clear(mTokenTypeMessageData); + ui->versions_CB->hide(); + ui->time_label->show(); + ui->postText->clear(); //ui->threadTitle->clear(); return; @@ -1517,6 +1550,9 @@ void GxsForumThreadWidget::insertMessage() mStateHelper->setActive(mTokenTypeMessageData, false); mStateHelper->clear(mTokenTypeMessageData); + ui->versions_CB->hide(); + ui->time_label->show(); + //ui->threadTitle->setText(tr("Forum Description")); ui->postText->setText(mForumDescription); return; @@ -1535,6 +1571,8 @@ void GxsForumThreadWidget::insertMessage() // there is something wrong mStateHelper->setWidgetEnabled(ui->previousButton, false); mStateHelper->setWidgetEnabled(ui->nextButton, false); + ui->versions_CB->hide(); + ui->time_label->show(); return; } @@ -1549,6 +1587,47 @@ void GxsForumThreadWidget::insertMessage() ui->by_text_label->hide(); ui->by_label->hide(); + // add/show combobox for versions, if applicable, and enable it. If no older versions of the post available, hide the combobox. + + std::cerr << "Looking into existing versions for post " << mThreadId << ", thread history: " << mPostVersions.size() << std::endl; + + QMap > >::const_iterator it = mPostVersions.find(mOrigThreadId) ; + + ui->versions_CB->blockSignals(true) ; + + while(ui->versions_CB->count() > 0) + ui->versions_CB->removeItem(0); + + if(it != mPostVersions.end()) + { + std::cerr << (*it).size() << " versions found " << std::endl; + + ui->versions_CB->setVisible(true) ; + ui->time_label->hide(); + + int current_index = 0 ; + + for(int i=0;i<(*it).size();++i) + { + ui->versions_CB->insertItem(i, ((i==0)?tr("(Latest) "):tr("(Old) "))+" "+DateTime::formatLongDateTime( (*it)[i].first)); + ui->versions_CB->setItemData(i,QString::fromStdString((*it)[i].second.toStdString())); + + std::cerr << " added new post version " << (*it)[i].first << " " << (*it)[i].second << std::endl; + + if(mThreadId == (*it)[i].second) + current_index = i ; + } + + ui->versions_CB->setCurrentIndex(current_index) ; + } + else + { + ui->versions_CB->hide(); + ui->time_label->show(); + } + + ui->versions_CB->blockSignals(false) ; + /* request Post */ RsGxsGrpMsgIdPair msgId = std::make_pair(groupId(), mThreadId); requestMessageData(msgId); @@ -1951,7 +2030,7 @@ void GxsForumThreadWidget::createmessage() return; } - CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), mThreadId); + CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), mThreadId,RsGxsMessageId()); cfm->show(); /* window will destroy itself! */ @@ -1964,7 +2043,7 @@ void GxsForumThreadWidget::createthread() return; } - CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), RsGxsMessageId()); + CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), RsGxsMessageId(),RsGxsMessageId()); cfm->show(); /* window will destroy itself! */ @@ -2018,7 +2097,7 @@ void GxsForumThreadWidget::flagperson() mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, token_type); } -void GxsForumThreadWidget::replytomessage() +void GxsForumThreadWidget::reply_with_private_message() { if (groupId().isNull() || mThreadId.isNull()) { QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message")); @@ -2027,9 +2106,19 @@ void GxsForumThreadWidget::replytomessage() // Get Message ... then complete replyMessageData(). RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); - requestMsgData_ReplyMessage(postId); + requestMsgData_ReplyWithPrivateMessage(postId); } +void GxsForumThreadWidget::editforummessage() +{ + if (groupId().isNull() || mThreadId.isNull()) { + QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message")); + return; + } + // Get Message ... then complete replyMessageData(). + RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId); + requestMsgData_EditForumMessage(postId); +} void GxsForumThreadWidget::replytoforummessage() { if (groupId().isNull() || mThreadId.isNull()) { @@ -2082,6 +2171,29 @@ void GxsForumThreadWidget::showAuthorInPeople(const RsGxsForumMsg& msg) requestMsgData_ShowAuthorInPeople(postId); } +void GxsForumThreadWidget::editForumMessageData(const RsGxsForumMsg& msg) +{ + if ((msg.mMeta.mGroupId != groupId()) || (msg.mMeta.mMsgId != mThreadId)) + { + std::cerr << "GxsForumThreadWidget::replyMessageData() ERROR Message Ids have changed!"; + std::cerr << std::endl; + return; + } + + if (!msg.mMeta.mAuthorId.isNull()) + { + CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), msg.mMeta.mParentId, msg.mMeta.mMsgId, msg.mMeta.mAuthorId); + + cfm->insertPastedText(QString::fromUtf8(msg.mMsg.c_str())) ; + cfm->show(); + + /* window will destroy itself! */ + } + else + { + QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to an Anonymous Author")); + } +} void GxsForumThreadWidget::replyForumMessageData(const RsGxsForumMsg &msg) { if ((msg.mMeta.mGroupId != groupId()) || (msg.mMeta.mMsgId != mThreadId)) @@ -2093,10 +2205,12 @@ void GxsForumThreadWidget::replyForumMessageData(const RsGxsForumMsg &msg) if (!msg.mMeta.mAuthorId.isNull()) { - CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), mThreadId); - QTextDocument doc ; + CreateGxsForumMsg *cfm = new CreateGxsForumMsg(groupId(), mThreadId,RsGxsMessageId()); + +// QTextDocument doc ; // doc.setHtml(QString::fromUtf8(msg.mMsg.c_str()) ); // std::string cited_text(doc.toPlainText().toStdString()) ; + RsHtml::makeQuotedText(ui->postText); cfm->insertPastedText(RsHtml::makeQuotedText(ui->postText)) ; @@ -2317,7 +2431,8 @@ void GxsForumThreadWidget::loadMessageData(const uint32_t &token) /*********************** **** **** **** ***********************/ /*********************** **** **** **** ***********************/ -void GxsForumThreadWidget::requestMsgData_ReplyMessage(const RsGxsGrpMsgIdPair &msgId) + +void GxsForumThreadWidget::requestMsgData_ReplyWithPrivateMessage(const RsGxsGrpMsgIdPair &msgId) { RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; @@ -2352,7 +2467,23 @@ void GxsForumThreadWidget::requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgId uint32_t token; mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeShowAuthorInPeople); } +void GxsForumThreadWidget::requestMsgData_EditForumMessage(const RsGxsGrpMsgIdPair &msgId) +{ + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumThreadWidget::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")"; + std::cerr << std::endl; +#endif + + GxsMsgReq msgIds; + std::vector &vect = msgIds[msgId.first]; + vect.push_back(msgId.second); + + uint32_t token; + mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeEditForumMessage); +} void GxsForumThreadWidget::requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId) { RsTokReqOptions opts; @@ -2396,6 +2527,31 @@ void GxsForumThreadWidget::loadMsgData_ReplyMessage(const uint32_t &token) } } +void GxsForumThreadWidget::loadMsgData_EditForumMessage(const uint32_t &token) +{ +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumThreadWidget::loadMsgData_EditMessage()"; + std::cerr << std::endl; +#endif + + std::vector msgs; + if (rsGxsForums->getMsgData(token, msgs)) + { + if (msgs.size() != 1) + { + std::cerr << "GxsForumThreadWidget::loadMsgData_EditMessage() ERROR Wrong number of answers"; + std::cerr << std::endl; + return; + } + + editForumMessageData(msgs[0]); + } + else + { + std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Missing Message Data..."; + std::cerr << std::endl; + } +} void GxsForumThreadWidget::loadMsgData_ReplyForumMessage(const uint32_t &token) { #ifdef DEBUG_FORUMS @@ -2523,6 +2679,10 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque return; } + if (req.mUserType == mTokenTypeEditForumMessage) { + loadMsgData_EditForumMessage(req.mToken); + return; + } if (req.mUserType == mTokenTypeShowAuthorInPeople) { loadMsgData_ShowAuthorInPeople(req.mToken); return; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h index e4ab0b5b4..71103507e 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.h @@ -1,6 +1,8 @@ #ifndef GXSFORUMTHREADWIDGET_H #define GXSFORUMTHREADWIDGET_H +#include + #include "gui/gxs/GxsMessageFrameWidget.h" #include #include "gui/gxs/GxsIdDetails.h" @@ -73,12 +75,15 @@ private slots: void contextMenuTextBrowser(QPoint point); void changedThread(); + void changedVersion(); void clickedThread (QTreeWidgetItem *item, int column); - void replytomessage(); + void reply_with_private_message(); void replytoforummessage(); + void editforummessage(); void replyMessageData(const RsGxsForumMsg &msg); + void editForumMessageData(const RsGxsForumMsg &msg); void replyForumMessageData(const RsGxsForumMsg &msg); void showAuthorInPeople(const RsGxsForumMsg& msg); @@ -147,19 +152,22 @@ private: static void loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/); void requestMessageData(const RsGxsGrpMsgIdPair &msgId); - void requestMsgData_ReplyMessage(const RsGxsGrpMsgIdPair &msgId); + void requestMsgData_ReplyWithPrivateMessage(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair &msgId); void requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId); + void requestMsgData_EditForumMessage(const RsGxsGrpMsgIdPair &msgId); void loadMessageData(const uint32_t &token); void loadMsgData_ReplyMessage(const uint32_t &token); void loadMsgData_ReplyForumMessage(const uint32_t &token); + void loadMsgData_EditForumMessage(const uint32_t &token); void loadMsgData_ShowAuthorInPeople(const uint32_t &token); void loadMsgData_SetAuthorOpinion(const uint32_t &token, RsReputations::Opinion opinion); private: RsGxsGroupId mLastForumID; RsGxsMessageId mThreadId; + RsGxsMessageId mOrigThreadId; RsGxsForumGroup mForumGroup; QString mForumDescription; int mSubscribeFlags; @@ -177,6 +185,7 @@ private: uint32_t mTokenTypeMessageData; uint32_t mTokenTypeReplyMessage; uint32_t mTokenTypeReplyForumMessage; + uint32_t mTokenTypeEditForumMessage; uint32_t mTokenTypeShowAuthorInPeople; uint32_t mTokenTypeNegativeAuthor; uint32_t mTokenTypePositiveAuthor; @@ -192,6 +201,8 @@ private: RsGxsMessageId mNavigatePendingMsgId; QList mIgnoredMsgId; + QMap > > mPostVersions ; // holds older versions of posts + Ui::GxsForumThreadWidget *ui; }; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui index 3a93e9973..789616228 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui @@ -289,14 +289,7 @@ - - - - - - - - + @@ -332,7 +325,7 @@ - + @@ -372,7 +365,7 @@ - + Qt::Horizontal @@ -464,20 +457,30 @@ - + - + By + + + + + + + + + + @@ -562,8 +565,8 @@ - + diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp index 4c381ce42..199748346 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp @@ -89,6 +89,8 @@ void GxsForumsFillThread::calculateExpand(const RsGxsForumMsg &msg, QTreeWidgetI } } +static bool decreasing_time_comp(const QPair& e1,const QPair& e2) { return e2.first < e1.first ; } + void GxsForumsFillThread::run() { RsTokenService *service = rsGxsForums->getTokenService(); @@ -171,7 +173,7 @@ void GxsForumsFillThread::run() int pos = 0; int steps = count / PROGRESSBAR_MAX; int step = 0; - + // ThreadList contains the list of parent threads. The algorithm below iterates through all messages // and tries to establish parenthood relationships between them, given that we only know the // immediate parent of a message and now its children. Some messages have a missing parent and for them @@ -185,6 +187,99 @@ void GxsForumsFillThread::run() std::map > kids_array ; std::set missing_parents; + // First of all, remove all older versions of posts. This is done by first adding all posts into a hierarchy structure + // and then removing all posts which have a new versions available. The older versions are kept appart. + +#ifdef DEBUG_FORUMS + std::cerr << "GxsForumsFillThread::run() Collecting post versions" << std::endl; +#endif + mPostVersions.clear(); + std::list msg_stack ; + + for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) + if(!msgIt->second.mMeta.mOrigMsgId.isNull() && msgIt->second.mMeta.mOrigMsgId != msgIt->second.mMeta.mMsgId) + { +#ifdef DEBUG_FORUMS + std::cerr << " Post " << msgIt->second.mMeta.mMsgId << " is a new version of " << msgIt->second.mMeta.mOrigMsgId << std::endl; +#endif + std::map::iterator msgIt2 = msgs.find(msgIt->second.mMeta.mOrigMsgId); + + // Ensuring that the post exists allows to only collect the existing data. + + if(msgIt2 == msgs.end()) + continue ; + + // Make sure that the author is the same than the original message. This should always happen, but nothing can prevent someone to + // craft a new version of a message with his own signature. + + if(msgIt2->second.mMeta.mAuthorId != msgIt->second.mMeta.mAuthorId) + continue ; + + // always add the post a self version + + if(mPostVersions[msgIt->second.mMeta.mOrigMsgId].empty()) + mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt2->second.mMeta.mPublishTs,msgIt2->second.mMeta.mMsgId)) ; + + mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair(msgIt->second.mMeta.mPublishTs,msgIt->second.mMeta.mMsgId)) ; + } + + // The following code assembles all new versions of a given post into the same array, indexed by the oldest version of the post. + + for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) + { + QVector >& v(*it) ; + + for(int32_t i=0;i > >::iterator it2 = mPostVersions.find(sub_msg_id); + + if(it2 != mPostVersions.end()) + { + for(int32_t j=0;j<(*it2).size();++j) + if((*it2)[j].second != sub_msg_id) // dont copy it, since it is already present at slot i + v.append((*it2)[j]) ; + + mPostVersions.erase(it2) ; // it2 is never equal to it + } + } + } + + // Now remove from msg ids, all posts except the most recent one. And make the mPostVersion be indexed by the most recent version of the post, + // which corresponds to the item in the tree widget. + +#ifdef DEBUG_FORUMS + std::cerr << "Final post versions: " << std::endl; +#endif + QMap > > mTmp; + + for(QMap > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it) + { +#ifdef DEBUG_FORUMS + std::cerr << "Original post: " << it.key() << std::endl; +#endif + // Finally, sort the posts from newer to older + + qSort((*it).begin(),(*it).end(),decreasing_time_comp) ; + +#ifdef DEBUG_FORUMS + std::cerr << " most recent version " << (*it)[0].first << " " << (*it)[0].second << std::endl; +#endif + for(int32_t i=1;i<(*it).size();++i) + { + msgs.erase((*it)[i].second) ; + +#ifdef DEBUG_FORUMS + std::cerr << " older version " << (*it)[i].first << " " << (*it)[i].second << std::endl; +#endif + } + + mTmp[(*it)[0].second] = *it ; // index the versions map by the ID of the most recent post. + } + mPostVersions = mTmp ; + // The first step is to find the top level thread messages. These are defined as the messages without // any parent message ID. @@ -194,6 +289,8 @@ void GxsForumsFillThread::run() std::map kept_msgs; for ( std::map::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt) + { + if(mFlatView || msgIt->second.mMeta.mParentId.isNull()) { @@ -234,9 +331,12 @@ void GxsForumsFillThread::run() kids_array[msgIt->second.mMeta.mParentId].push_back(msgIt->first) ; kept_msgs.insert(*msgIt) ; } + } msgs = kept_msgs; + // Also create a list of posts by time, when they are new versions of existing posts. Only the last one will have an item created. + // Add a fake toplevel item for the parent IDs that we dont actually have. for(std::set::const_iterator it(missing_parents.begin());it!=missing_parents.end();++it) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h index 58a461607..2b5974855 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h @@ -2,6 +2,8 @@ #define GXSFORUMSFILLTHREAD_H #include +#include +#include #include "retroshare/rsgxsifacetypes.h" class GxsForumThreadWidget; @@ -39,6 +41,7 @@ public: QList mItems; QList mItemToExpand; + QMap > > mPostVersions ; private: void calculateExpand(const RsGxsForumMsg &msg, QTreeWidgetItem *item); diff --git a/retroshare-gui/src/gui/qss/stylesheet/qss.default b/retroshare-gui/src/gui/qss/stylesheet/qss.default index b762d626a..db24fd45e 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/qss.default +++ b/retroshare-gui/src/gui/qss/stylesheet/qss.default @@ -174,6 +174,7 @@ FriendList SearchDialog { qproperty-textColorLocal: red; + qproperty-textColorDownloading: green; qproperty-textColorNoSources: rgb(0, 0, 19); qproperty-textColorLowSources: rgb(0, 0, 38); qproperty-textColorHighSources: rgb(0, 0, 228); diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index 4357f0d2c..d9dd900fb 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -109,7 +109,7 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) connect( ui.netModeComboBox, SIGNAL( activated ( int ) ), this, SLOT( toggleUPnP( ) ) ); connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) ); connect( ui.cleanKnownIPs_PB, SIGNAL( clicked( ) ), this, SLOT( clearKnownAddressList() ) ); - connect( ui.testIncoming_PB, SIGNAL( clicked( ) ), this, SLOT( updateInProxyIndicator() ) ); + connect( ui.testIncoming_PB, SIGNAL( clicked( ) ), this, SLOT( saveAndTestInProxy() ) ); connect( ui.showDiscStatusBar,SIGNAL(toggled(bool)),this,SLOT(updateShowDiscStatusBar())) ; #ifdef SERVER_DEBUG @@ -132,6 +132,12 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) connect(ui.totalUploadRate, SIGNAL(valueChanged(int)),this,SLOT(saveRates())); } +void ServerPage::saveAndTestInProxy() +{ + saveAddresses(); + updateInProxyIndicator() ; +} + void ServerPage::checkIpRange(const QString& ipstr) { QColor color; diff --git a/retroshare-gui/src/gui/settings/ServerPage.h b/retroshare-gui/src/gui/settings/ServerPage.h index 02685bfc0..5b300e084 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.h +++ b/retroshare-gui/src/gui/settings/ServerPage.h @@ -61,6 +61,7 @@ private slots: // ban list void updateSelectedBlackListIP(int row, int, int, int); void updateSelectedWhiteListIP(int row,int,int,int); + void saveAndTestInProxy(); void addIpRangeToBlackList(); void addIpRangeToWhiteList(); void moveToWhiteList0(); diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 3755b0536..a0f16a62b 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -26,7 +26,7 @@ - 0 + 2 @@ -985,7 +985,7 @@ You can connect to Hidden Nodes, even if you are running a standard Node, so why <html><head/><body><p>This button simulates a SSL connection to your hidden address using the corresponding proxy. If your hidden node is reachable, it should cause a SSL handshake error, which RS will interpret as a valid connection state. This operation might also cause several &quot;security warning&quot; about connections from your local host IP (127.0.0.1) in the News Feed if you enabled it, which you should interpret as a sign of good communication.</p></body></html> - Test + Apply diff --git a/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp b/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp index a309717b8..a8e830624 100644 --- a/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp @@ -379,7 +379,7 @@ void GlobalRouterStatisticsWidget::updateContent() painter.setPen(QColor::fromRgb(0,0,0)) ; - painter.setPen(QColor::fromRgb(0.5,0.5,0.5)); + painter.setPen(QColor::fromRgb(127,127,127)); painter.drawRect(ox+2*cellx,current_oy+0.15*celly,fm_monospace.width(ids)+cellx*matrix_info.friend_ids.size()- 2*cellx,celly) ; float total_length = (matrix_info.friend_ids.size()+2)*cellx ; diff --git a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp index 6d8a46e32..a76b5b5c3 100644 --- a/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp +++ b/retroshare-gui/src/gui/statistics/TurtleRouterDialog.cpp @@ -153,7 +153,7 @@ void TurtleRouterDialog::updateTunnelRequests( const std::vectorsetFont(0,font); } - if(strtol(tunnels_info[i][5].c_str(), NULL, 0)>1000) // fast + if(strtof(tunnels_info[i][5].c_str(), NULL)>1000) // fast { font.setBold(true); item->setFont(0,font); diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 9e2951f87..6c4fdeb67 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -5,7 +5,7 @@ QT += network xml CONFIG += qt gui uic qrc resources idle bitdht CONFIG += link_prl TARGET = RetroShare06 -DEFINES += TARGET=\\\"$TARGET\\\" +DEFINES += TARGET=\\\"$${TARGET}\\\" # Plz never commit the .pro with these flags enabled. # Use this flag when developping new features only. diff --git a/retroshare-gui/src/rshare.cpp b/retroshare-gui/src/rshare.cpp index a2de0840a..040992afe 100644 --- a/retroshare-gui/src/rshare.cpp +++ b/retroshare-gui/src/rshare.cpp @@ -68,6 +68,17 @@ #define ARG_RSFILE_L "rsfile" /**< Open RsFile with or without arg */ //Other defined for server in /libretroshare/src/rsserver/rsinit.cc:351 +// The arguments here can be send to a running instance. +// If the command line contains arguments not listed here, we have to start a new instance. +// For exmample, the user wants to start a second instance using --base-dir arg of libretroshare. +static const char* const forwardableArgs[] = { + ARG_RSLINK_S, + ARG_RSLINK_L, + ARG_RSFILE_S, + ARG_RSFILE_L, + NULL, +}; + /* Static member variables */ QMap Rshare::_args; /**< List of command-line arguments. */ QString Rshare::_style; /**< The current GUI style. */ @@ -115,6 +126,27 @@ void qt_msg_handler(QtMsgType type, const char *msg) } } +static bool notifyRunningInstance() +{ + // Connect to the Local Server of the main process to notify it + // that a new process had been started + QLocalSocket localSocket; + localSocket.connectToServer(QString(TARGET)); + + std::cerr << "Rshare::Rshare waitForConnected to other instance." << std::endl; + if( localSocket.waitForConnected(100) ) + { + std::cerr << "Rshare::Rshare Connection etablished. Waiting for disconnection." << std::endl; + localSocket.waitForDisconnected(1000); + return true; + } + else + { + std::cerr << "Rshare::Rshare failed to connect to other instance." << std::endl; + return false; + } +} + /** Constructor. Parses the command-line arguments, resets Rshare's * configuration (if requested), and sets up the GUI style and language * translation. */ @@ -128,7 +160,32 @@ Rshare::Rshare(QStringList args, int &argc, char **argv, const QString &dir) { QString serverName = QString(TARGET); - if (!args.isEmpty()) { + // check if another instance is running + bool haveRunningInstance = notifyRunningInstance(); + + bool sendArgsToRunningInstance = haveRunningInstance; + if(args.empty()) + sendArgsToRunningInstance = false; + // if we find non-forwardable args, start a new instance + for(int i = 0; i < args.size(); ++i) + { + const char* const* argit = forwardableArgs; + bool found = false; + while(*argit && i < args.size()) + { + if(args.value(i) == "-"+QString(*argit) || args.value(i) == "--"+QString(*argit)) + { + found = true; + if(argNeedsValue(*argit)) + i++; + } + argit++; + } + if(!found) + sendArgsToRunningInstance = false; + } + + if (sendArgsToRunningInstance) { // load into shared memory QBuffer buffer; buffer.open(QBuffer::ReadWrite); @@ -156,30 +213,29 @@ Rshare::Rshare(QStringList args, int &argc, char **argv, const QString &dir) memcpy(to, from, qMin(newArgs.size(), size)); newArgs.unlock(); - // Connect to the Local Server of the main process to notify it - // that a new process had been started - QLocalSocket localSocket; - localSocket.connectToServer(QString(TARGET)); - std::cerr << "Rshare::Rshare waitForConnected to other instance." << std::endl; - if( localSocket.waitForConnected(100) ) + if(notifyRunningInstance()) { - std::cerr << "Rshare::Rshare Connection etablished. Waiting for disconnection." << std::endl; - localSocket.waitForDisconnected(1000); newArgs.detach(); std::cerr << "Rshare::Rshare Arguments was sended." << std::endl << " To disable it, in Options - General - Misc," << std::endl << " uncheck \"Use Local Server to get new Arguments\"." << std::endl; ::exit(EXIT_SUCCESS); // Terminate the program using STDLib's exit function } + else + std::cerr << "Rshare::Rshare failed to connect to other instance." << std::endl; newArgs.detach(); } - // No main process exists - // Or started without arguments - // So we start a Local Server to listen for connections from new process - localServer= new QLocalServer(); - QObject::connect(localServer, SIGNAL(newConnection()), this, SLOT(slotConnectionEstablished())); - updateLocalServer(); + + if(!haveRunningInstance) + { + // No main process exists + // Or started without arguments + // So we start a Local Server to listen for connections from new process + localServer= new QLocalServer(); + QObject::connect(localServer, SIGNAL(newConnection()), this, SLOT(slotConnectionEstablished())); + updateLocalServer(); + } } #if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0) diff --git a/retroshare.pri b/retroshare.pri index d5bfa0b11..f9d160ac3 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -35,6 +35,11 @@ retroshare_qml_app:CONFIG -= no_retroshare_qml_app CONFIG *= no_libresapilocalserver libresapilocalserver:CONFIG -= no_libresapilocalserver +# To enable Qt dependencies in libresapi append the following +# assignation to qmake command line "CONFIG+=qt_dependencies" +CONFIG *= no_qt_dependencies +qt_dependencies:CONFIG -= no_qt_dependencies + # To disable libresapi via HTTP (based on libmicrohttpd) append the following # assignation to qmake command line "CONFIG+=no_libresapihttpserver" CONFIG *= libresapihttpserver @@ -174,6 +179,7 @@ unfinished { wikipoos:DEFINES *= RS_USE_WIKI rs_gxs:DEFINES *= RS_ENABLE_GXS libresapilocalserver:DEFINES *= LIBRESAPI_LOCAL_SERVER +qt_dependencies:DEFINES *= LIBRESAPI_QT libresapihttpserver:DEFINES *= ENABLE_WEBUI sqlcipher:DEFINES -= NO_SQLCIPHER no_sqlcipher:DEFINES *= NO_SQLCIPHER