From ae54e53bc1c64c27ce522c07e4f7a149d05b88bf Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 26 Apr 2020 00:18:01 +0200 Subject: [PATCH 01/79] updated RsGenExchange::performUpdateValidation to simplify the logic and save (oldGrp,newGrp) in a specific RsGxsGroupUpdate subclass of GxsNotify so as to be able to handle group data notifications in services --- libretroshare/src/gxs/rsgds.h | 2 +- libretroshare/src/gxs/rsgenexchange.cc | 77 ++++++++++----------- libretroshare/src/retroshare/rsgxsservice.h | 27 ++++++-- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/libretroshare/src/gxs/rsgds.h b/libretroshare/src/gxs/rsgds.h index 4e67f9d8c..04c2b17e7 100644 --- a/libretroshare/src/gxs/rsgds.h +++ b/libretroshare/src/gxs/rsgds.h @@ -149,7 +149,7 @@ public: bool withMeta = false ) = 0; /*! - * Retrieves all groups stored + * Retrieves all groups stored. Caller owns the memory and is supposed to delete the RsNxsGrp pointers after use. * @param grp retrieved groups * @param withMeta if true the meta handle of nxs grps is intitialised * @param cache whether to store retrieval in mem for faster later retrieval diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index af4a02fcd..6a95168d1 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -3230,39 +3230,41 @@ void RsGenExchange::performUpdateValidation() std::cerr << "RsGenExchange::performUpdateValidation() " << std::endl; #endif - RsGxsGrpMetaTemporaryMap grpMetas; + RsNxsGrpDataTemporaryMap grpDatas; - std::vector::iterator vit = mGroupUpdates.begin(); - for(; vit != mGroupUpdates.end(); ++vit) - grpMetas.insert(std::make_pair(vit->newGrp->grpId, (RsGxsGrpMetaData*)NULL)); + for(auto vit(mGroupUpdates.begin()); vit != mGroupUpdates.end(); ++vit) + grpDatas.insert(std::make_pair(vit->newGrp->grpId, (RsNxsGrp*)NULL)); + + if(grpDatas.empty() || !mDataStore->retrieveNxsGrps(grpDatas,true,false)) + { + if(grpDatas.empty()) + RsErr() << __PRETTY_FUNCTION__ << " Validation of multiple group updates failed: no group in list!" << std::endl; + else + RsErr() << __PRETTY_FUNCTION__ << " Validation of multiple group updates failed: cannot retrieve froup data for these groups!" << std::endl; - if(!grpMetas.empty()) - mDataStore->retrieveGxsGrpMetaData(grpMetas); - else return; - - vit = mGroupUpdates.begin(); - for(; vit != mGroupUpdates.end(); ++vit) - { - GroupUpdate& gu = *vit; - std::map::iterator mit = grpMetas.find(gu.newGrp->grpId); - gu.oldGrpMeta = mit->second; - gu.validUpdate = updateValid(*(gu.oldGrpMeta), *(gu.newGrp)); - } + } #ifdef GEN_EXCH_DEBUG std::cerr << "RsGenExchange::performUpdateValidation() " << std::endl; #endif - vit = mGroupUpdates.begin(); - RsNxsGrpDataTemporaryList grps ; - for(; vit != mGroupUpdates.end(); ++vit) + for(auto vit(mGroupUpdates.begin()); vit != mGroupUpdates.end(); ++vit) { GroupUpdate& gu = *vit; - if(gu.validUpdate) + auto mit = grpDatas.find(gu.newGrp->grpId); + + if(mit == grpDatas.end()) + { + RsErr() << __PRETTY_FUNCTION__ << " Validation of group update failed for group " << gu.newGrp->grpId << " because previous grp version cannot be found." << std::endl; + continue; + } + RsGxsGrpMetaData *oldGrpMeta(mit->second->metaData); + + if(updateValid(*oldGrpMeta, *gu.newGrp)) { if(gu.newGrp->metaData->mCircleType == GXS_CIRCLE_TYPE_YOUR_FRIENDS_ONLY) gu.newGrp->metaData->mOriginator = gu.newGrp->PeerId(); @@ -3270,14 +3272,28 @@ void RsGenExchange::performUpdateValidation() // Keep subscriptionflag to what it was. This avoids clearing off the flag when updates to group meta information // is received. - gu.newGrp->metaData->mSubscribeFlags = gu.oldGrpMeta->mSubscribeFlags ; + gu.newGrp->metaData->mSubscribeFlags = oldGrpMeta->mSubscribeFlags ; // Also keep private keys if present if(!gu.newGrp->metaData->keys.private_keys.empty()) std::cerr << "(EE) performUpdateValidation() group " <metaData->mGroupId << " has been received with private keys. This is very unexpected!" << std::endl; else - gu.newGrp->metaData->keys.private_keys = gu.oldGrpMeta->keys.private_keys ; + gu.newGrp->metaData->keys.private_keys = oldGrpMeta->keys.private_keys ; + + // Now prepare notification of the client + + RsGxsGroupUpdate *c = new RsGxsGroupUpdate(); + + c->mGroupId = gu.newGrp->grpId ; + c->mNewGroup = gu.newGrp->clone(); // make a copy because mDataStore will destroy it on update + c->mOldGroup = mit->second; // do not make a copy since we own the memory + + mit->second = nullptr; // prevents deletion in auto delete map + + mNotifications.push_back(c); + + // finally, add the group to grps.push_back(gu.newGrp); } @@ -3286,26 +3302,9 @@ void RsGenExchange::performUpdateValidation() delete gu.newGrp; gu.newGrp = NULL ; } - - gu.oldGrpMeta = NULL ; } - // notify the client - - RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, true); - - for(uint32_t i=0;imGrpIdList.push_back(mGroupUpdates[i].newGrp->grpId) ; -#ifdef GEN_EXCH_DEBUG - std::cerr << " " << mGroupUpdates[i].newGrp->grpId << std::endl; -#endif - } - - mNotifications.push_back(c); // Warning: updateGroup will destroy the objects in grps. Dont use it afterwards! - mDataStore->updateGroup(grps); #ifdef GEN_EXCH_DEBUG diff --git a/libretroshare/src/retroshare/rsgxsservice.h b/libretroshare/src/retroshare/rsgxsservice.h index 4739b0ec2..0549eacbd 100644 --- a/libretroshare/src/retroshare/rsgxsservice.h +++ b/libretroshare/src/retroshare/rsgxsservice.h @@ -32,6 +32,8 @@ typedef uint32_t TurtleRequestId; typedef std::map > GxsMsgMetaMap; typedef std::map > GxsMsgRelatedMetaMap; +class RsNxsGrp; + /*! * The aim of this class is to abstract how changes are represented so they can * be determined outside the client API without explcitly enumerating all @@ -47,7 +49,8 @@ struct RsGxsNotify TYPE_PROCESSED = 0x03, TYPE_RECEIVED_PUBLISHKEY = 0x04, TYPE_RECEIVED_DISTANT_SEARCH_RESULTS = 0x05, - TYPE_STATISTICS_CHANGED = 0x06 + TYPE_STATISTICS_CHANGED = 0x06, + TYPE_UPDATED = 0x07, }; virtual ~RsGxsNotify() {} @@ -60,15 +63,29 @@ struct RsGxsNotify class RsGxsGroupChange : public RsGxsNotify { public: - RsGxsGroupChange(NotifyType type, bool metaChange) : NOTIFY_TYPE(type), mMetaChange(metaChange) {} + RsGxsGroupChange(NotifyType type, bool metaChange) : mNotifyType(type), mMetaChange(metaChange) {} std::list mGrpIdList; - NotifyType getType(){ return NOTIFY_TYPE;} + NotifyType getType() override { return mNotifyType;} bool metaChange() { return mMetaChange; } -private: - const NotifyType NOTIFY_TYPE; + +protected: + NotifyType mNotifyType; bool mMetaChange; }; +class RsGxsGroupUpdate : public RsGxsNotify +{ +public: + RsGxsGroupUpdate() : mOldGroup(nullptr),mNewGroup(nullptr) {} + + RsGxsGroupId mGroupId; + RsNxsGrp *mOldGroup; + RsNxsGrp *mNewGroup; + + NotifyType getType() override { return RsGxsNotify::TYPE_UPDATED;} +}; + + class RsGxsDistantSearchResultChange: public RsGxsNotify { public: From f7199f1f1cf785bc968c912a80993fb53a870415 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 26 Apr 2020 23:35:37 +0200 Subject: [PATCH 02/79] moved GxsNotify classes to rsgxsnotify.h internal to gxs (not visible in API) since it is unused in GUI. Added event item in forum to handle moderator list changes --- libretroshare/src/gxs/rsgenexchange.cc | 15 ++-- libretroshare/src/gxs/rsgenexchange.h | 6 +- libretroshare/src/libretroshare.pro | 1 + libretroshare/src/retroshare/rsgxsforums.h | 6 ++ libretroshare/src/retroshare/rsgxsiface.h | 2 + .../src/retroshare/rsgxsifacehelper.h | 2 + libretroshare/src/retroshare/rsgxsservice.h | 80 ------------------- libretroshare/src/services/p3gxsforums.cc | 44 ++++++++++ libretroshare/src/services/p3posted.h | 2 + 9 files changed, 69 insertions(+), 89 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 6a95168d1..7ed1b498a 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1110,6 +1110,7 @@ static void addMessageChanged(std::map > } } +#ifdef TO_REMOVE void RsGenExchange::receiveChanges(std::vector& changes) { std::cerr << "*********************************** RsGenExchange::receiveChanges()" << std::endl; @@ -1155,6 +1156,7 @@ void RsGenExchange::receiveChanges(std::vector& changes) if(rsEvents) rsEvents->postEvent(std::move(evt)); } +#endif bool RsGenExchange::subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, bool subscribe) { @@ -3263,6 +3265,7 @@ void RsGenExchange::performUpdateValidation() continue; } RsGxsGrpMetaData *oldGrpMeta(mit->second->metaData); + RsNxsGrp *oldGrp(mit->second); if(updateValid(*oldGrpMeta, *gu.newGrp)) { @@ -3285,21 +3288,21 @@ void RsGenExchange::performUpdateValidation() RsGxsGroupUpdate *c = new RsGxsGroupUpdate(); - c->mGroupId = gu.newGrp->grpId ; - c->mNewGroup = gu.newGrp->clone(); // make a copy because mDataStore will destroy it on update - c->mOldGroup = mit->second; // do not make a copy since we own the memory + c->mNewGroupItem = dynamic_cast(mSerialiser->deserialise(gu.newGrp->grp.bin_data,&gu.newGrp->grp.bin_len)); + c->mNewGroupItem->meta = *gu.newGrp->metaData; // gu.newGrp will be deleted because mDataStore will destroy it on update - mit->second = nullptr; // prevents deletion in auto delete map + c->mOldGroupItem = dynamic_cast(mSerialiser->deserialise(oldGrp->grp.bin_data,&oldGrp->grp.bin_len)); + c->mOldGroupItem->meta = *oldGrpMeta; // no need to delete mit->second, as it will be deleted automatically in the temporary map mNotifications.push_back(c); - // finally, add the group to + // finally, add the group to the list to send to mDataStore grps.push_back(gu.newGrp); } else { - delete gu.newGrp; + delete gu.newGrp; // delete here because mDataStore will not take care of this one. no need to delete mit->second, as it will be deleted automatically in the temporary map gu.newGrp = NULL ; } } diff --git a/libretroshare/src/gxs/rsgenexchange.h b/libretroshare/src/gxs/rsgenexchange.h index 840dc97b3..4a05e61c4 100644 --- a/libretroshare/src/gxs/rsgenexchange.h +++ b/libretroshare/src/gxs/rsgenexchange.h @@ -33,6 +33,7 @@ #include "rsnxsobserver.h" #include "retroshare/rsgxsservice.h" #include "rsitems/rsnxsitems.h" +#include "gxs/rsgxsnotify.h" #include "rsgxsutil.h" template @@ -262,12 +263,14 @@ public: */ bool getPublishedMsgMeta(const uint32_t& token,RsMsgMetaData& meta); +#ifdef TO_REMOVE /*! * Gxs services should call this for automatic handling of * changes, send * @param changes */ virtual void receiveChanges(std::vector& changes); +#endif /*! * \brief acceptNewGroup @@ -748,9 +751,6 @@ protected: */ virtual void notifyChanges(std::vector& changes) = 0; - - - private: void processRecvdData(); diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 54a4989ec..c7b38ce0b 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -672,6 +672,7 @@ HEADERS += rsitems/rsnxsitems.h \ util/rsdbbind.h \ util/contentvalue.h \ gxs/rsgxsutil.h \ + gxs/rsgxsnotify.h \ gxs/gxssecurity.h \ gxs/rsgds.h \ gxs/rsgxs.h \ diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index f7c8153ba..c033bf3ac 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -112,6 +112,7 @@ enum class RsForumEventCode: uint8_t SUBSCRIBE_STATUS_CHANGED = 0x05, /// forum was subscribed or unsubscribed READ_STATUS_CHANGED = 0x06, /// msg was read or marked unread STATISTICS_CHANGED = 0x07, /// suppliers and how many messages they have changed + MODERATOR_LIST_CHANGED = 0x08, /// forum moderation list has changed. }; struct RsGxsForumEvent: RsEvent @@ -123,6 +124,8 @@ struct RsGxsForumEvent: RsEvent RsForumEventCode mForumEventCode; RsGxsGroupId mForumGroupId; RsGxsMessageId mForumMsgId; + std::list mModeratorsAdded; + std::list mModeratorsRemoved; ///* @see RsEvent @see RsSerializable void serial_process( @@ -133,6 +136,9 @@ struct RsGxsForumEvent: RsEvent RS_SERIAL_PROCESS(mForumEventCode); RS_SERIAL_PROCESS(mForumGroupId); RS_SERIAL_PROCESS(mForumMsgId); + RS_SERIAL_PROCESS(mForumMsgId); + RS_SERIAL_PROCESS(mModeratorsAdded); + RS_SERIAL_PROCESS(mModeratorsRemoved); } ~RsGxsForumEvent() override; diff --git a/libretroshare/src/retroshare/rsgxsiface.h b/libretroshare/src/retroshare/rsgxsiface.h index 7bb6bba28..36bee517e 100644 --- a/libretroshare/src/retroshare/rsgxsiface.h +++ b/libretroshare/src/retroshare/rsgxsiface.h @@ -116,12 +116,14 @@ struct RsGxsIface */ virtual uint16_t serviceType() const =0; +#ifdef TO_REMOVE /*! * Gxs services should call this for automatic handling of * changes, send * @param changes */ virtual void receiveChanges(std::vector& changes) = 0; +#endif /*! * @return handle to token service for this GXS service diff --git a/libretroshare/src/retroshare/rsgxsifacehelper.h b/libretroshare/src/retroshare/rsgxsifacehelper.h index 0addbf6e5..d2f588623 100644 --- a/libretroshare/src/retroshare/rsgxsifacehelper.h +++ b/libretroshare/src/retroshare/rsgxsifacehelper.h @@ -72,6 +72,7 @@ public: ~RsGxsIfaceHelper() = default; +#ifdef TO_REMOVE /*! * Gxs services should call this for automatic handling of * changes, send @@ -81,6 +82,7 @@ public: { mGxs.receiveChanges(changes); } +#endif /* Generic Lists */ diff --git a/libretroshare/src/retroshare/rsgxsservice.h b/libretroshare/src/retroshare/rsgxsservice.h index 0549eacbd..152b018c9 100644 --- a/libretroshare/src/retroshare/rsgxsservice.h +++ b/libretroshare/src/retroshare/rsgxsservice.h @@ -32,86 +32,6 @@ typedef uint32_t TurtleRequestId; typedef std::map > GxsMsgMetaMap; typedef std::map > GxsMsgRelatedMetaMap; -class RsNxsGrp; - -/*! - * The aim of this class is to abstract how changes are represented so they can - * be determined outside the client API without explcitly enumerating all - * possible changes at the interface - */ -struct RsGxsNotify -{ - enum NotifyType - { - TYPE_UNKNOWN = 0x00, - TYPE_PUBLISHED = 0x01, - TYPE_RECEIVED_NEW = 0x02, - TYPE_PROCESSED = 0x03, - TYPE_RECEIVED_PUBLISHKEY = 0x04, - TYPE_RECEIVED_DISTANT_SEARCH_RESULTS = 0x05, - TYPE_STATISTICS_CHANGED = 0x06, - TYPE_UPDATED = 0x07, - }; - - virtual ~RsGxsNotify() {} - virtual NotifyType getType() = 0; -}; - -/*! - * Relevant to group changes - */ -class RsGxsGroupChange : public RsGxsNotify -{ -public: - RsGxsGroupChange(NotifyType type, bool metaChange) : mNotifyType(type), mMetaChange(metaChange) {} - std::list mGrpIdList; - NotifyType getType() override { return mNotifyType;} - bool metaChange() { return mMetaChange; } - -protected: - NotifyType mNotifyType; - bool mMetaChange; -}; - -class RsGxsGroupUpdate : public RsGxsNotify -{ -public: - RsGxsGroupUpdate() : mOldGroup(nullptr),mNewGroup(nullptr) {} - - RsGxsGroupId mGroupId; - RsNxsGrp *mOldGroup; - RsNxsGrp *mNewGroup; - - NotifyType getType() override { return RsGxsNotify::TYPE_UPDATED;} -}; - - -class RsGxsDistantSearchResultChange: public RsGxsNotify -{ -public: - RsGxsDistantSearchResultChange(TurtleRequestId id,const RsGxsGroupId& group_id) : mRequestId(id),mGroupId(group_id){} - - NotifyType getType() { return TYPE_RECEIVED_DISTANT_SEARCH_RESULTS ; } - - TurtleRequestId mRequestId ; - RsGxsGroupId mGroupId; -}; - -/*! - * Relevant to message changes - */ -class RsGxsMsgChange : public RsGxsNotify -{ -public: - RsGxsMsgChange(NotifyType type, bool metaChange) : NOTIFY_TYPE(type), mMetaChange(metaChange) {} - std::map > msgChangeMap; - NotifyType getType(){ return NOTIFY_TYPE;} - bool metaChange() { return mMetaChange; } -private: - const NotifyType NOTIFY_TYPE; - bool mMetaChange; -}; - #endif // RSGXSSERVICE_H diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 42b60fad2..6b8f91f9f 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -189,6 +189,7 @@ void p3GxsForums::notifyChanges(std::vector &changes) for(it = changes.begin(); it != changes.end(); ++it) { RsGxsMsgChange *msgChange = dynamic_cast(*it); + if (msgChange) { if (msgChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW || msgChange->getType() == RsGxsNotify::TYPE_PUBLISHED) /* message received */ @@ -328,6 +329,49 @@ void p3GxsForums::notifyChanges(std::vector &changes) #endif } } + + RsGxsGroupUpdate *grpUpdate = dynamic_cast(*it); + + if (grpUpdate && rsEvents) + { + // Happens when the group data has changed. In this case we need to analyse the old and new group in order to detect possible notifications for clients + + RsGxsForumGroupItem *old_forum_grp_item = dynamic_cast(grpUpdate->mOldGroupItem); + RsGxsForumGroupItem *new_forum_grp_item = dynamic_cast(grpUpdate->mNewGroupItem); + + if(old_forum_grp_item == nullptr || new_forum_grp_item == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsForumGroupItem. This is inconsistent!" << std::endl; + delete grpUpdate; + continue; + } + + // First of all, we check if there is a difference between the old and new list of moderators + + std::list added_mods, removed_mods; + + for(auto& gxs_id: new_forum_grp_item->mGroup.mAdminList.ids) + if(old_forum_grp_item->mGroup.mAdminList.ids.find(gxs_id) == old_forum_grp_item->mGroup.mAdminList.ids.end()) + added_mods.push_back(gxs_id); + + for(auto& gxs_id: old_forum_grp_item->mGroup.mAdminList.ids) + if(new_forum_grp_item->mGroup.mAdminList.ids.find(gxs_id) == new_forum_grp_item->mGroup.mAdminList.ids.end()) + removed_mods.push_back(gxs_id); + + if(!added_mods.empty() || !removed_mods.empty()) + { + auto ev = std::make_shared(); + + ev->mForumGroupId = new_forum_grp_item->meta.mGroupId; + ev->mModeratorsAdded = added_mods; + ev->mModeratorsRemoved = removed_mods; + ev->mForumEventCode = RsForumEventCode::MODERATOR_LIST_CHANGED; + + rsEvents->postEvent(ev); + } + + } + } } diff --git a/libretroshare/src/services/p3posted.h b/libretroshare/src/services/p3posted.h index b6f3ccee5..a6dc4be73 100644 --- a/libretroshare/src/services/p3posted.h +++ b/libretroshare/src/services/p3posted.h @@ -53,10 +53,12 @@ virtual void notifyChanges(std::vector& changes) public: +#ifdef TO_REMOVE virtual void receiveHelperChanges(std::vector& changes) { return RsGxsIfaceHelper::receiveChanges(changes); } +#endif bool getBoardsInfo(const std::list& boardsIds, std::vector& groupsInfo ) override; From 89843a6cbe5679c67a7a69a455be226d2ce62623 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 27 Apr 2020 15:11:32 +0200 Subject: [PATCH 03/79] added NewsFeed item for advertising about new/removed moderators --- retroshare-gui/src/gui/NewsFeed.cpp | 10 ++- retroshare-gui/src/gui/NewsFeed.h | 6 +- .../src/gui/feeds/GxsForumGroupItem.cpp | 66 ++++++++++++++++++- .../src/gui/feeds/GxsForumGroupItem.h | 4 ++ .../src/gui/feeds/GxsForumGroupItem.ui | 37 +++++++++-- 5 files changed, 111 insertions(+), 12 deletions(-) diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index 9b85a32d1..391aba690 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -251,14 +251,20 @@ void NewsFeed::handleForumEvent(std::shared_ptr event) switch(pe->mForumEventCode) { + case RsForumEventCode::MODERATOR_LIST_CHANGED: + addFeedItem(new GxsForumGroupItem(this, NEWSFEED_UPDATED_FORUM, pe->mForumGroupId,pe->mModeratorsAdded,pe->mModeratorsRemoved, false, true)); + break; + case RsForumEventCode::UPDATED_FORUM: case RsForumEventCode::NEW_FORUM: - addFeedItem(new GxsForumGroupItem(this, NEWSFEED_FORUMNEWLIST, pe->mForumGroupId, false, true)); + addFeedItem(new GxsForumGroupItem(this, NEWSFEED_NEW_FORUM, pe->mForumGroupId, false, true)); break; + case RsForumEventCode::UPDATED_MESSAGE: case RsForumEventCode::NEW_MESSAGE: - addFeedItem(new GxsForumMsgItem(this, NEWSFEED_FORUMNEWLIST, pe->mForumGroupId, pe->mForumMsgId, false, true)); + addFeedItem(new GxsForumMsgItem(this, NEWSFEED_NEW_FORUM, pe->mForumGroupId, pe->mForumMsgId, false, true)); break; + default: break; } } diff --git a/retroshare-gui/src/gui/NewsFeed.h b/retroshare-gui/src/gui/NewsFeed.h index 0086009aa..713bcf96c 100644 --- a/retroshare-gui/src/gui/NewsFeed.h +++ b/retroshare-gui/src/gui/NewsFeed.h @@ -31,8 +31,10 @@ const uint32_t NEWSFEED_PEERLIST = 0x0001; -const uint32_t NEWSFEED_FORUMNEWLIST = 0x0002; -const uint32_t NEWSFEED_FORUMMSGLIST = 0x0003; +const uint32_t NEWSFEED_NEW_FORUM = 0x0002; +const uint32_t NEWSFEED_NEW_FORUM_MSG = 0x0003; +const uint32_t NEWSFEED_UPDATED_FORUM = 0x000f; + const uint32_t NEWSFEED_CHANNELNEWLIST = 0x0004; //const uint32_t NEWSFEED_CHANNELMSGLIST = 0x0005; #if 0 diff --git a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp index ee96c068e..99a7f61a0 100644 --- a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp @@ -20,6 +20,7 @@ #include "GxsForumGroupItem.h" #include "ui_GxsForumGroupItem.h" +#include "gui/NewsFeed.h" #include "FeedHolder.h" #include "gui/RetroShareLink.h" @@ -37,6 +38,16 @@ GxsForumGroupItem::GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, co requestGroup(); } +GxsForumGroupItem::GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const std::list& added_moderators,const std::list& removed_moderators,bool isHome, bool autoUpdate): + GxsGroupFeedItem(feedHolder, feedId, groupId, isHome, rsGxsForums, autoUpdate), + mAddedModerators(added_moderators), + mRemovedModerators(removed_moderators) +{ + setup(); + + requestGroup(); +} + GxsForumGroupItem::GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumGroup &group, bool isHome, bool autoUpdate) : GxsGroupFeedItem(feedHolder, feedId, group.mMeta.mGroupId, isHome, rsGxsForums, autoUpdate) { @@ -158,10 +169,59 @@ void GxsForumGroupItem::fill() ui->subscribeButton->setEnabled(true); } -// if (mIsNew) -// { + if(feedId() == NEWSFEED_UPDATED_FORUM) + { + if(!mAddedModerators.empty() || !mRemovedModerators.empty()) + { + ui->titleLabel->setText(tr("Moderator list changed")); + ui->moderatorList_GB->show(); + + QString msg; + + if(!mAddedModerators.empty()) + { + msg += "Added moderators:" ; + msg += "

"; + for(auto& gxsid: mAddedModerators) + { + RsIdentityDetails det; + if(rsIdentity->getIdDetails(gxsid,det)) + msg += QString::fromUtf8(det.mNickname.c_str())+" ("+QString::fromStdString(gxsid.toStdString())+"), "; + else + msg += QString("[Unknown name]") + " ("+QString::fromStdString(gxsid.toStdString())+"), "; + } + msg.resize(msg.size()-2); + msg += "

"; + } + if(!mRemovedModerators.empty()) + { + msg += "Removed moderators:" ; + msg += "

"; + for(auto& gxsid: mRemovedModerators) + { + RsIdentityDetails det; + + if( rsIdentity->getIdDetails(gxsid,det)) + msg += QString::fromUtf8(det.mNickname.c_str())+" ("+QString::fromStdString(gxsid.toStdString())+"), "; + else + msg += QString("[Unknown name]") + " ("+QString::fromStdString(gxsid.toStdString())+"), "; + } + msg.resize(msg.size()-2); + msg += "

"; + } + ui->moderatorList_TE->setText(msg); + } + else + { + ui->moderatorList_GB->hide(); + + ui->titleLabel->setText(tr("Forum updated")); + ui->moderatorList_GB->hide(); + } + } + else ui->titleLabel->setText(tr("New Forum")); -// } + // else // { // ui->titleLabel->setText(tr("Updated Forum")); diff --git a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.h b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.h index 442ad70e8..29b7851f2 100644 --- a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.h +++ b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.h @@ -37,6 +37,7 @@ class GxsForumGroupItem : public GxsGroupFeedItem public: /** Default Constructor */ GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, bool autoUpdate); + GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const std::list& added_moderators,const std::list& removed_moderators,bool isHome, bool autoUpdate); GxsForumGroupItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsForumGroup &group, bool isHome, bool autoUpdate); ~GxsForumGroupItem(); @@ -65,6 +66,9 @@ private: /** Qt Designer generated object */ Ui::GxsForumGroupItem *ui; + + std::list mAddedModerators; + std::list mRemovedModerators; }; #endif diff --git a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.ui b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.ui index a506efa7b..cc3994307 100644 --- a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.ui +++ b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.ui @@ -6,8 +6,8 @@ 0 0 - 618 - 161 + 784 + 464 @@ -104,8 +104,8 @@ QFrame::Sunken - - + + @@ -280,7 +280,7 @@ - + @@ -334,6 +334,33 @@ + + + + Moderator list + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + From 80b7f2a3cdc24832214a577cc85a0cd967e0b7ad Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 27 Apr 2020 17:00:13 +0200 Subject: [PATCH 04/79] fixed loading of already selected ids in FriendSelectionDialog and automatically display existing GxsGroupDialog moderators --- .../src/gui/common/FriendSelectionDialog.cpp | 2 +- .../src/gui/common/FriendSelectionWidget.cpp | 49 ++++++++++++++++--- .../src/gui/common/FriendSelectionWidget.h | 12 +++-- retroshare-gui/src/gui/gxs/GxsGroupDialog.cpp | 4 ++ retroshare-gui/src/gui/gxs/GxsGroupDialog.ui | 9 ++-- 5 files changed, 57 insertions(+), 19 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendSelectionDialog.cpp b/retroshare-gui/src/gui/common/FriendSelectionDialog.cpp index 9201a0458..9631054a0 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionDialog.cpp +++ b/retroshare-gui/src/gui/common/FriendSelectionDialog.cpp @@ -100,7 +100,7 @@ FriendSelectionDialog::FriendSelectionDialog(QWidget *parent,const QString& head friends_widget->setModus(modus) ; friends_widget->setShowType(show_type) ; friends_widget->start() ; - friends_widget->setSelectedIds(pre_selected_id_type, pre_selected_ids, false); + friends_widget->setSelectedIdsFromString(pre_selected_id_type, pre_selected_ids, false); QLayout *l = new QVBoxLayout ; setLayout(l) ; diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp index 43179518a..53ded6615 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp @@ -278,18 +278,35 @@ void FriendSelectionWidget::secured_fillList() // get selected items std::set sslIdsSelected; - if (mShowTypes & SHOW_SSL) { + if (mShowTypes & SHOW_SSL) + { + if(!ui->friendList->topLevelItemCount()) // if not loaded yet, use the existing list. + for(auto& s:mPreSelectedIds) + sslIdsSelected.insert(RsPeerId(s)); + selectedIds(sslIdsSelected,true); } std::set groupIdsSelected; - if (mShowTypes & SHOW_GROUP) { + + if (mShowTypes & SHOW_GROUP) + { selectedIds(groupIdsSelected,true); + + if(!ui->friendList->topLevelItemCount()) // if not loaded yet, use the existing list. + for(auto& s:mPreSelectedIds) + groupIdsSelected.insert(RsNodeGroupId(s)); } std::set gpgIdsSelected; - if (mShowTypes & (SHOW_GPG | SHOW_NON_FRIEND_GPG)) { + + if (mShowTypes & (SHOW_GPG | SHOW_NON_FRIEND_GPG)) + { selectedIds(gpgIdsSelected,true); + + if(!ui->friendList->topLevelItemCount()) // if not loaded yet, use the existing list. + for(auto& s:mPreSelectedIds) + gpgIdsSelected.insert(RsPgpId(s)); } std::set gxsIdsSelected; @@ -299,7 +316,8 @@ void FriendSelectionWidget::secured_fillList() selectedIds(gxsIdsSelected,true); if(!ui->friendList->topLevelItemCount()) // if not loaded yet, use the existing list. - gxsIdsSelected = mPreSelectedGxsIds; + for(auto& s:mPreSelectedIds) + gxsIdsSelected.insert(RsGxsId(s)); } std::set gxsIdsSelected2; @@ -678,7 +696,12 @@ void FriendSelectionWidget::updateDisplay(bool) // This call is inlined so that there's no linking conflict with MinGW on Windows template<> inline void FriendSelectionWidget::setSelectedIds(const std::set& ids, bool add) { - mPreSelectedGxsIds = ids ; + if(!add) + mPreSelectedIds.clear(); + + for(auto& gxsId:ids) + mPreSelectedIds.insert(gxsId.toStdString()); + loadIdentities(); } @@ -981,7 +1004,7 @@ std::string FriendSelectionWidget::selectedId(IdType &idType) return idFromItem(item); } -void FriendSelectionWidget::selectedIds(IdType idType, std::set &ids, bool onlyDirectSelected) +void FriendSelectionWidget::selectedIds_internal(IdType idType, std::set &ids, bool onlyDirectSelected) { QTreeWidgetItemIterator itemIterator(ui->friendList); QTreeWidgetItem *item; @@ -1055,11 +1078,21 @@ void FriendSelectionWidget::selectAll() setSelected(mListModus, *itemIterator, true); } -void FriendSelectionWidget::setSelectedIds(IdType idType, const std::set &ids, bool add) +void FriendSelectionWidget::setSelectedIdsFromString(IdType type, const std::set& ids, bool add) { + setSelectedIds_internal(type,ids,add); +} + +void FriendSelectionWidget::setSelectedIds_internal(IdType idType, const std::set &ids, bool add) +{ + mPreSelectedIds = ids; + + // if items are already loaded, check them + QTreeWidgetItemIterator itemIterator(ui->friendList); QTreeWidgetItem *item; - while ((item = *itemIterator) != NULL) { + while ((item = *itemIterator) != NULL) + { ++itemIterator; std::string id = idFromItem(item); diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.h b/retroshare-gui/src/gui/common/FriendSelectionWidget.h index e770d4b43..7a2fb718e 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.h +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.h @@ -85,10 +85,12 @@ public: int selectedItemCount(); std::string selectedId(IdType &idType); + void setSelectedIdsFromString(IdType type,const std::set& ids,bool add); + template void selectedIds(std::set& ids, bool onlyDirectSelected) { std::set tmpids ; - selectedIds(TYPE, tmpids, onlyDirectSelected); + selectedIds_internal(TYPE, tmpids, onlyDirectSelected); ids.clear() ; for(std::set::const_iterator it(tmpids.begin());it!=tmpids.end();++it) ids.insert(ID_CLASS(*it)) ; @@ -98,7 +100,7 @@ public: std::set tmpids ; for(typename std::set::const_iterator it(ids.begin());it!=ids.end();++it) tmpids.insert((*it).toStdString()) ; - setSelectedIds(TYPE, tmpids, add); + setSelectedIds_internal(TYPE, tmpids, add); } void itemsFromId(IdType idType, const std::string &id, QList &items); @@ -145,8 +147,8 @@ private: void fillList(); void secured_fillList(); - void selectedIds(IdType idType, std::set &ids, bool onlyDirectSelected); - void setSelectedIds(IdType idType, const std::set &ids, bool add); + void selectedIds_internal(IdType idType, std::set &ids, bool onlyDirectSelected); + void setSelectedIds_internal(IdType idType, const std::set &ids, bool add); private: bool mStarted; @@ -170,7 +172,7 @@ private: std::vector gxsIds ; QList mContextMenuActions; - std::set mPreSelectedGxsIds; // because loading of GxsIds is asynchroneous we keep selected Ids from the client in a list here and use it to initialize after loading them. + std::set mPreSelectedIds; // because loading of GxsIds is asynchroneous we keep selected Ids from the client in a list here and use it to initialize after loading them. }; Q_DECLARE_OPERATORS_FOR_FLAGS(FriendSelectionWidget::ShowTypes) diff --git a/retroshare-gui/src/gui/gxs/GxsGroupDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupDialog.cpp index 62e1101c9..240f321db 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupDialog.cpp @@ -892,6 +892,10 @@ void GxsGroupDialog::getSelectedModerators(std::set& ids) void GxsGroupDialog::setSelectedModerators(const std::set& ids) { + ui.addAdmins_cb->setChecked(true); + ui.adminsList->show(); + ui.filtercomboBox->show(); + ui.adminsList->setSelectedIds(ids, false); QString moderatorsListString ; diff --git a/retroshare-gui/src/gui/gxs/GxsGroupDialog.ui b/retroshare-gui/src/gui/gxs/GxsGroupDialog.ui index bc417db65..88777cd59 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupDialog.ui +++ b/retroshare-gui/src/gui/gxs/GxsGroupDialog.ui @@ -6,8 +6,8 @@ 0 0 - 600 - 563 + 1231 + 967 @@ -223,14 +223,14 @@ - Required + Re&quired - Encrypted Msgs + Encrypted &Msgs @@ -856,7 +856,6 @@ - From 28a6b43357d3a55956ebf8cf073cb23b8875fe8b Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 27 Apr 2020 17:11:06 +0200 Subject: [PATCH 05/79] added missing file --- libretroshare/src/gxs/rsgxsnotify.h | 101 ++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 libretroshare/src/gxs/rsgxsnotify.h diff --git a/libretroshare/src/gxs/rsgxsnotify.h b/libretroshare/src/gxs/rsgxsnotify.h new file mode 100644 index 000000000..847a78d38 --- /dev/null +++ b/libretroshare/src/gxs/rsgxsnotify.h @@ -0,0 +1,101 @@ +/******************************************************************************* + * libretroshare/src/gxs/: rsgxsnotify.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2015 Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +/*! + * The aim of this class is to implement notifications internally to GXS, which are + * mostly used by RsGenExchange to send information to specific services. These services + * then interpret these changes and turn them into human-readable/processed service-specific changes. + */ + +struct RsGxsNotify +{ + enum NotifyType + { + TYPE_UNKNOWN = 0x00, + TYPE_PUBLISHED = 0x01, + TYPE_RECEIVED_NEW = 0x02, + TYPE_PROCESSED = 0x03, + TYPE_RECEIVED_PUBLISHKEY = 0x04, + TYPE_RECEIVED_DISTANT_SEARCH_RESULTS = 0x05, + TYPE_STATISTICS_CHANGED = 0x06, + TYPE_UPDATED = 0x07, + }; + + virtual ~RsGxsNotify() {} + virtual NotifyType getType() = 0; +}; + +/*! + * Relevant to group changes + */ +class RsGxsGroupChange : public RsGxsNotify +{ +public: + RsGxsGroupChange(NotifyType type, bool metaChange) : mNotifyType(type), mMetaChange(metaChange) {} + std::list mGrpIdList; + NotifyType getType() override { return mNotifyType;} + bool metaChange() { return mMetaChange; } + +protected: + NotifyType mNotifyType; + bool mMetaChange; +}; + +class RsGxsGroupUpdate : public RsGxsNotify +{ +public: + RsGxsGroupUpdate() : mOldGroupItem(nullptr),mNewGroupItem(nullptr) {} + virtual ~RsGxsGroupUpdate() { delete mOldGroupItem; delete mNewGroupItem ; } + + RsGxsGrpItem *mOldGroupItem; + RsGxsGrpItem *mNewGroupItem; + + NotifyType getType() override { return RsGxsNotify::TYPE_UPDATED;} +}; + + +class RsGxsDistantSearchResultChange: public RsGxsNotify +{ +public: + RsGxsDistantSearchResultChange(TurtleRequestId id,const RsGxsGroupId& group_id) : mRequestId(id),mGroupId(group_id){} + + NotifyType getType() { return TYPE_RECEIVED_DISTANT_SEARCH_RESULTS ; } + + TurtleRequestId mRequestId ; + RsGxsGroupId mGroupId; +}; + +/*! + * Relevant to message changes + */ +class RsGxsMsgChange : public RsGxsNotify +{ +public: + RsGxsMsgChange(NotifyType type, bool metaChange) : NOTIFY_TYPE(type), mMetaChange(metaChange) {} + std::map > msgChangeMap; + NotifyType getType(){ return NOTIFY_TYPE;} + bool metaChange() { return mMetaChange; } +private: + const NotifyType NOTIFY_TYPE; + bool mMetaChange; +}; + From f5af7dfeb306d373f00a546462bdc690d8af08d9 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 27 Apr 2020 21:56:43 +0200 Subject: [PATCH 06/79] fixed up top bar tooltips to display what the numbers actually mean --- libretroshare/src/pqi/pqissl.cc | 14 ++++++++++---- .../src/gui/FileTransfer/TransferUserNotify.h | 1 + retroshare-gui/src/gui/MainWindow.cpp | 2 +- retroshare-gui/src/gui/Posted/PostedUserNotify.cpp | 5 +++-- retroshare-gui/src/gui/Posted/PostedUserNotify.h | 1 + retroshare-gui/src/gui/chat/ChatUserNotify.h | 1 + retroshare-gui/src/gui/common/UserNotify.cpp | 8 ++++++-- retroshare-gui/src/gui/common/UserNotify.h | 8 +++++++- retroshare-gui/src/gui/feeds/NewsFeedUserNotify.h | 1 + .../src/gui/gxschannels/GxsChannelUserNotify.cpp | 5 +++-- .../src/gui/gxschannels/GxsChannelUserNotify.h | 1 + .../src/gui/gxsforums/GxsForumUserNotify.cpp | 5 +++-- .../src/gui/gxsforums/GxsForumUserNotify.h | 1 + retroshare-gui/src/gui/msgs/MessageUserNotify.h | 1 + 14 files changed, 40 insertions(+), 14 deletions(-) diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 0ef930fc2..db8d32cf7 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -1110,10 +1110,16 @@ int pqissl::SSL_Connection_Complete() if(rsEvents) { X509 *x509 = SSL_get_peer_certificate(ssl_connection); - auto ev = std::make_shared(); - ev->mSslId = RsX509Cert::getCertSslId(*x509); - ev->mErrorCode = RsAuthSslError::PEER_REFUSED_CONNECTION; - rsEvents->postEvent(ev); + + if(x509) + { + auto ev = std::make_shared(); + ev->mSslId = RsX509Cert::getCertSslId(*x509); + ev->mErrorCode = RsAuthSslError::PEER_REFUSED_CONNECTION; + + if(!ev->mSslId.isNull()) + rsEvents->postEvent(ev); + } } std::string out; diff --git a/retroshare-gui/src/gui/FileTransfer/TransferUserNotify.h b/retroshare-gui/src/gui/FileTransfer/TransferUserNotify.h index f883ed33c..06d352487 100644 --- a/retroshare-gui/src/gui/FileTransfer/TransferUserNotify.h +++ b/retroshare-gui/src/gui/FileTransfer/TransferUserNotify.h @@ -31,6 +31,7 @@ public: TransferUserNotify(QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); + virtual QString textInfo() const override { return tr("completed transfer(s)"); } private: virtual QIcon getIcon(); diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index d66421243..53ea8bfe9 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -483,7 +483,7 @@ void MainWindow::initStackedPage() for (notifyIt = notify.begin(); notifyIt != notify.end(); ++notifyIt) { UserNotify *userNotify = notifyIt->first->getUserNotify(); if (userNotify) { - userNotify->initialize(ui->toolBarPage, notifyIt->second.first, notifyIt->second.second); + userNotify->initialize(ui->toolBarPage, notifyIt->second.first, notifyIt->second.second,userNotify->textInfo()); connect(userNotify, SIGNAL(countChanged()), this, SLOT(updateTrayCombine())); userNotifyList.push_back(userNotify); } diff --git a/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp b/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp index 39fddd451..bbc58e436 100644 --- a/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp +++ b/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp @@ -21,6 +21,7 @@ #include "retroshare/rsposted.h" #include "PostedUserNotify.h" #include "gui/MainWindow.h" +#include "gui/common/FilesDefs.h" PostedUserNotify::PostedUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent) : GxsUserNotify(ifaceImpl, g, parent) @@ -37,12 +38,12 @@ bool PostedUserNotify::hasSetting(QString *name, QString *group) QIcon PostedUserNotify::getIcon() { - return QIcon(":/icons/png/posted.png"); + return FilesDefs::getIconFromQtResourcePath(":/icons/png/posted.png"); } QIcon PostedUserNotify::getMainIcon(bool hasNew) { - return hasNew ? QIcon(":/icons/png/posted-notify.png") : QIcon(":/icons/png/posted.png"); + return hasNew ? FilesDefs::getIconFromQtResourcePath(":/icons/png/posted-notify.png") : FilesDefs::getIconFromQtResourcePath(":/icons/png/posted.png"); } void PostedUserNotify::iconClicked() diff --git a/retroshare-gui/src/gui/Posted/PostedUserNotify.h b/retroshare-gui/src/gui/Posted/PostedUserNotify.h index 2c12ac889..2541a9d39 100644 --- a/retroshare-gui/src/gui/Posted/PostedUserNotify.h +++ b/retroshare-gui/src/gui/Posted/PostedUserNotify.h @@ -31,6 +31,7 @@ public: PostedUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); + virtual QString textInfo() const override { return tr("new board post(s)"); } private: virtual QIcon getIcon(); diff --git a/retroshare-gui/src/gui/chat/ChatUserNotify.h b/retroshare-gui/src/gui/chat/ChatUserNotify.h index f70b37a54..8f6502847 100644 --- a/retroshare-gui/src/gui/chat/ChatUserNotify.h +++ b/retroshare-gui/src/gui/chat/ChatUserNotify.h @@ -41,6 +41,7 @@ public: ~ChatUserNotify(); virtual bool hasSetting(QString *name, QString *group); + virtual QString textInfo() const override { return tr("mention(s)"); } private slots: void chatMessageReceived(ChatMessage msg); diff --git a/retroshare-gui/src/gui/common/UserNotify.cpp b/retroshare-gui/src/gui/common/UserNotify.cpp index e030f9ccf..dc95127a8 100644 --- a/retroshare-gui/src/gui/common/UserNotify.cpp +++ b/retroshare-gui/src/gui/common/UserNotify.cpp @@ -88,11 +88,12 @@ void UserNotify::setNotifyEnabled(bool enabled, bool combined, bool blink) Settings->endGroup(); } -void UserNotify::initialize(QToolBar *mainToolBar, QAction *mainAction, QListWidgetItem *listItem) +void UserNotify::initialize(QToolBar *mainToolBar, QAction *mainAction, QListWidgetItem *listItem,const QString& subtext) { mMainAction = mainAction; if (mMainAction) { mButtonText = mMainAction->text(); + mButtonText2 = subtext; if (mainToolBar) { mMainToolButton = dynamic_cast(mainToolBar->widgetForAction(mMainAction)); } @@ -165,7 +166,10 @@ void UserNotify::update() if (mMainAction) { mMainAction->setIcon(getMainIcon(count > 0)); - mMainAction->setText((count > 0) ? QString("%1 (%2)").arg(mButtonText).arg(count) : mButtonText); + + + mMainAction->setText((count > 0) ? (!mButtonText2.isNull())?QString("%1 (%2)").arg(mButtonText).arg(count).arg(mButtonText2) : QString("%1 (%2 %3)").arg(mButtonText).arg(count) : mButtonText); + mMainAction->setToolTip((count > 0) ? (!mButtonText2.isNull())?QString("%1 %2").arg(count).arg(mButtonText2) : QString("%1").arg(count) : mButtonText); QFont font = mMainAction->font(); font.setBold(count > 0); diff --git a/retroshare-gui/src/gui/common/UserNotify.h b/retroshare-gui/src/gui/common/UserNotify.h index 500c26dc3..8c8f99e2d 100644 --- a/retroshare-gui/src/gui/common/UserNotify.h +++ b/retroshare-gui/src/gui/common/UserNotify.h @@ -37,12 +37,17 @@ public: UserNotify(QObject *parent = 0); virtual ~UserNotify(); - void initialize(QToolBar *mainToolBar, QAction *mainAction, QListWidgetItem *listItem); + void initialize(QToolBar *mainToolBar, QAction *mainAction, QListWidgetItem *listItem,const QString& subtext); void createIcons(QMenu *notifyMenu); QSystemTrayIcon* getTrayIcon(){ return mTrayIcon;} QAction* getNotifyIcon(){ return mNotifyIcon;} virtual bool hasSetting(QString */*name*/, QString */*group*/) { return false; } + + // UserNotify is used to display tooltips when some services have no messages and so on, in the format of "Name (43242 new messages)" + // This method is used to pass the string that comes after the number. + virtual QString textInfo() const { return QString() ; } + bool notifyEnabled(); bool notifyCombined(); bool notifyBlink(); @@ -82,6 +87,7 @@ private: QAction *mNotifyIcon; unsigned int mNewCount; QString mButtonText; + QString mButtonText2; bool mLastBlinking; }; diff --git a/retroshare-gui/src/gui/feeds/NewsFeedUserNotify.h b/retroshare-gui/src/gui/feeds/NewsFeedUserNotify.h index 081053593..c5206f24f 100644 --- a/retroshare-gui/src/gui/feeds/NewsFeedUserNotify.h +++ b/retroshare-gui/src/gui/feeds/NewsFeedUserNotify.h @@ -29,6 +29,7 @@ class NewsFeedUserNotify : public UserNotify { Q_OBJECT + virtual QString textInfo() const override { return tr("logged event(s)"); } public: NewsFeedUserNotify(NewsFeed *newsFeed, QObject *parent = 0); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp index eb54a39c3..ce88231fc 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp @@ -21,6 +21,7 @@ #include "retroshare/rsgxschannels.h" #include "GxsChannelUserNotify.h" #include "gui/MainWindow.h" +#include "gui/common/FilesDefs.h" GxsChannelUserNotify::GxsChannelUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent) : GxsUserNotify(ifaceImpl, g, parent) @@ -37,12 +38,12 @@ bool GxsChannelUserNotify::hasSetting(QString *name, QString *group) QIcon GxsChannelUserNotify::getIcon() { - return QIcon(":/icons/png/channel.png"); + return FilesDefs::getIconFromQtResourcePath(":/icons/png/channel.png"); } QIcon GxsChannelUserNotify::getMainIcon(bool hasNew) { - return hasNew ? QIcon(":/icons/png/channels-notify.png") : QIcon(":/icons/png/channel.png"); + return hasNew ? FilesDefs::getIconFromQtResourcePath(":/icons/png/channels-notify.png") : FilesDefs::getIconFromQtResourcePath(":/icons/png/channel.png"); } void GxsChannelUserNotify::iconClicked() diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h index df29a0202..8345b96d6 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h @@ -32,6 +32,7 @@ public: GxsChannelUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); + virtual QString textInfo() const override { return tr("new message(s)"); } private: virtual QIcon getIcon(); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp index 876aa3a95..b2e5bcc8e 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp @@ -19,6 +19,7 @@ *******************************************************************************/ #include "retroshare/rsgxsforums.h" +#include "gui/common/FilesDefs.h" #include "GxsForumUserNotify.h" #include "gui/MainWindow.h" @@ -38,12 +39,12 @@ bool GxsForumUserNotify::hasSetting(QString *name, QString *group) QIcon GxsForumUserNotify::getIcon() { - return QIcon(":/icons/png/forums.png"); + return FilesDefs::getIconFromQtResourcePath(":/icons/png/forums.png"); } QIcon GxsForumUserNotify::getMainIcon(bool hasNew) { - return hasNew ? QIcon(":/icons/png/forums-notify.png") : QIcon(":/icons/png/forums.png"); + return hasNew ? FilesDefs::getIconFromQtResourcePath(":/icons/png/forums-notify.png") : FilesDefs::getIconFromQtResourcePath(":/icons/png/forums.png"); } void GxsForumUserNotify::iconClicked() diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h index 172a327ae..9fbef1e5e 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h @@ -31,6 +31,7 @@ public: GxsForumUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); + virtual QString textInfo() const override { return tr("new message(s)"); } private: virtual QIcon getIcon(); diff --git a/retroshare-gui/src/gui/msgs/MessageUserNotify.h b/retroshare-gui/src/gui/msgs/MessageUserNotify.h index b032123a0..34c65dad6 100644 --- a/retroshare-gui/src/gui/msgs/MessageUserNotify.h +++ b/retroshare-gui/src/gui/msgs/MessageUserNotify.h @@ -31,6 +31,7 @@ public: MessageUserNotify(QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); + virtual QString textInfo() const override { return tr("new mail(s)"); } private: virtual QIcon getIcon(); From 767440afc547035e609d14aef9cdd45402a1f7ed Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 28 Apr 2020 21:39:38 +0200 Subject: [PATCH 07/79] added circle invite notifications --- libretroshare/src/retroshare/rsgxscircles.h | 2 +- libretroshare/src/retroshare/rsnotify.h | 2 +- libretroshare/src/services/p3gxscircles.cc | 58 +++++++++++++++++++ retroshare-gui/src/gui/Identity/IdDialog.cpp | 2 +- retroshare-gui/src/gui/NewsFeed.cpp | 4 +- .../src/gui/feeds/GxsCircleItem.cpp | 2 +- 6 files changed, 64 insertions(+), 6 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index 61e743323..a06430334 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -183,7 +183,7 @@ enum class RsGxsCircleEventCode: uint8_t CIRCLE_MEMBERSHIP_JOIN = 0x04, /** mCircleId contains the circle id and mGxsId is the id that was revoqued * by admin */ - CIRCLE_MEMBERSHIP_REVOQUED= 0x05, + CIRCLE_MEMBERSHIP_REVOKED = 0x05, /** mCircleId contains the circle id */ NEW_CIRCLE = 0x06, diff --git a/libretroshare/src/retroshare/rsnotify.h b/libretroshare/src/retroshare/rsnotify.h index bc9ef2971..a7e43a4e8 100644 --- a/libretroshare/src/retroshare/rsnotify.h +++ b/libretroshare/src/retroshare/rsnotify.h @@ -119,7 +119,7 @@ const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_REQ = RS_FEED_TYPE_CIRCLE | 0x0001 const uint32_t RS_FEED_ITEM_CIRCLE_INVIT_REC = RS_FEED_TYPE_CIRCLE | 0x0002; const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_LEAVE = RS_FEED_TYPE_CIRCLE | 0x0003; const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_JOIN = RS_FEED_TYPE_CIRCLE | 0x0004; -const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_REVOQUED = RS_FEED_TYPE_CIRCLE | 0x0005; +const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_REVOKED = RS_FEED_TYPE_CIRCLE | 0x0005; const uint32_t RS_MESSAGE_CONNECT_ATTEMPT = 0x0001; diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index c00532b82..44b095ac5 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -679,6 +679,64 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } } + RsGxsGroupUpdate *grpUpdate = dynamic_cast(*it); + + if (grpUpdate && rsEvents) + { + // Happens when the group data has changed. In this case we need to analyse the old and new group in order to detect possible notifications for clients + + RsGxsCircleGroupItem *old_circle_grp_item = dynamic_cast(grpUpdate->mOldGroupItem); + RsGxsCircleGroupItem *new_circle_grp_item = dynamic_cast(grpUpdate->mNewGroupItem); + + const RsGxsCircleId circle_id ( old_circle_grp_item->meta.mGroupId ); + + if(old_circle_grp_item == nullptr || new_circle_grp_item == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsCircleGroupItem. This is inconsistent!" << std::endl; + delete grpUpdate; + continue; + } + + // First of all, we check if there is a difference between the old and new list of invited members + + std::list added_identities, removed_identities; + std::list own_ids_lst; + rsIdentity->getOwnIds(own_ids_lst,false); // retrieve own identities + + std::set own_ids; + for(auto& id:own_ids_lst) + own_ids.insert(id); // put them in a std::set for O(log(n)) search + + for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) + if(old_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) + added_identities.push_back(gxs_id); + + for(auto& gxs_id: old_circle_grp_item->gxsIdSet.ids) + if(new_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) + removed_identities.push_back(gxs_id); + + for(auto& gxs_id:added_identities) + { + auto ev = std::make_shared(); + + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE; + ev->mCircleId = circle_id; + ev->mGxsId = gxs_id; + + rsEvents->sendEvent(ev); + } + for(auto& gxs_id:removed_identities) + { + auto ev = std::make_shared(); + + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED; + ev->mCircleId = circle_id; + ev->mGxsId = gxs_id; + + rsEvents->sendEvent(ev); + } + } + delete *it; } } diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index d646227f8..d111b7299 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -438,7 +438,7 @@ void IdDialog::handleEvent_main_thread(std::shared_ptr event) case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE: case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_JOIN: - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOQUED: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED: case RsGxsCircleEventCode::CACHE_DATA_UPDATED: updateCircles(); diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index 391aba690..ddbd545c1 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -329,8 +329,8 @@ void NewsFeed::handleCircleEvent(std::shared_ptr event) case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE: addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVIT_REC),true); break; - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOQUED: - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOQUED),true); + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED: + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); break; default: break; } diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp index 11ccf3004..4ba0f48c6 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp @@ -136,7 +136,7 @@ void GxsCircleItem::setup() ui->acceptButton->setHidden(true); ui->revokeButton->setHidden(true); } - else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REVOQUED) + else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REVOKED) { if(rsIdentity->isOwnId(mGxsId)) ui->titleLabel->setText(tr("Your identity %1 has been revoqued from this circle.").arg(idName)); From d32daaa111520712fd28a3ba2e72a3173ed37d01 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 1 May 2020 00:00:13 +0200 Subject: [PATCH 08/79] made group notifications separate so that they can be treated more easily and added group item to new_group notifications, to allow more GUI notifications --- libretroshare/src/gxs/rsgenexchange.cc | 104 +++++---- libretroshare/src/gxs/rsgxsnotify.h | 25 +-- libretroshare/src/gxstrans/p3gxstrans.cc | 7 +- libretroshare/src/services/p3gxschannels.cc | 75 +++---- libretroshare/src/services/p3gxscircles.cc | 229 +++++++++----------- libretroshare/src/services/p3gxsforums.cc | 151 +++++-------- libretroshare/src/services/p3idservice.cc | 18 +- libretroshare/src/services/p3postbase.cc | 59 ++--- 8 files changed, 293 insertions(+), 375 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 7ed1b498a..18f62a4a3 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -236,14 +236,19 @@ void RsGenExchange::tick() if (!grpIds.empty()) { - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PROCESSED, false); - gc->mGrpIdList = grpIds; + for(auto& groupId:grpIds) + { + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_MESSAGES_DELETED, false); + + gc->mGroupId = groupId; + #ifdef GEN_EXCH_DEBUG - std::cerr << " adding the following grp ids to notification: " << std::endl; - for(std::list::const_iterator it(grpIds.begin());it!=grpIds.end();++it) - std::cerr << " " << *it << std::endl; + std::cerr << " adding the following grp ids to notification: " << std::endl; + for(std::list::const_iterator it(grpIds.begin());it!=grpIds.end();++it) + std::cerr << " " << *it << std::endl; #endif - mNotifications.push_back(gc); + mNotifications.push_back(gc); + } // also notify the network exchange service that these groups no longer exist. @@ -1686,7 +1691,8 @@ void RsGenExchange::notifyReceivePublishKey(const RsGxsGroupId &grpId) RS_STACK_MUTEX(mGenMtx); RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY, true); - gc->mGrpIdList.push_back(grpId); + gc->mGroupId = grpId; + mNotifications.push_back(gc); } @@ -1695,7 +1701,8 @@ void RsGenExchange::notifyChangedGroupStats(const RsGxsGroupId &grpId) RS_STACK_MUTEX(mGenMtx); RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_STATISTICS_CHANGED, false); - gc->mGrpIdList.push_back(grpId); + gc->mGroupId = grpId; + mNotifications.push_back(gc); } @@ -2101,11 +2108,13 @@ void RsGenExchange::processGrpMetaChanges() } } - if(!grpChanged.empty()) + for(auto& groupId:grpChanged) { RS_STACK_MUTEX(mGenMtx); + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PROCESSED, true); - gc->mGrpIdList = grpChanged; + gc->mGroupId = groupId; + mNotifications.push_back(gc); #ifdef GEN_EXCH_DEBUG std::cerr << " adding the following grp ids to notification: " << std::endl; @@ -2496,15 +2505,17 @@ void RsGenExchange::processGroupDelete() grpDeleted.push_back(note.second); } - if(!grpDeleted.empty()) + for(auto& groupId:grpDeleted) { - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PUBLISHED, false); - gc->mGrpIdList = grpDeleted; + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_GROUP_DELETED, false); + gc->mGroupId = groupId; + mNotifications.push_back(gc); } mGroupDeletePublish.clear(); } + void RsGenExchange::processMessageDelete() { RS_STACK_MUTEX(mGenMtx) ; @@ -2523,31 +2534,29 @@ void RsGenExchange::processMessageDelete() mDataStore->removeMsgs( (*vit).mMsgs ); } +// std::list grpDeleted; +// std::map::iterator mit = toNotify.begin(); +// for(; mit != toNotify.end(); ++mit) +// { +// GrpNote& note = mit->second; +// uint8_t status = note.first ? RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE +// : RsTokenService::GXS_REQUEST_V2_STATUS_FAILED; +// +// mGrpNotify.insert(std::make_pair(mit->first, note.second)); +// mDataAccess->updatePublicRequestStatus(mit->first, status); +// +// if(note.first) +// grpDeleted.push_back(note.second); +// } -#warning csoler: TODO: notify for deleted messages -#ifdef SUSPENDED - std::list grpDeleted; - std::map::iterator mit = toNotify.begin(); - for(; mit != toNotify.end(); ++mit) - { - GrpNote& note = mit->second; - uint8_t status = note.first ? RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE - : RsTokenService::GXS_REQUEST_V2_STATUS_FAILED; + for(uint32_t i=0;imGroupId = it->first; - mGrpNotify.insert(std::make_pair(mit->first, note.second)); - mDataAccess->updatePublicRequestStatus(mit->first, status); - - if(note.first) - grpDeleted.push_back(note.second); - } - - if(!grpDeleted.empty()) - { - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PUBLISH, false); - gc->mGrpIdList = grpDeleted; - mNotifications.push_back(gc); - } -#endif + mNotifications.push_back(gc); + } mMsgDeletePublish.clear(); } @@ -2807,10 +2816,12 @@ void RsGenExchange::publishGrps() grpChanged.push_back(note.second); } - if(!grpChanged.empty()) + for(auto& groupId:grpChanged) { RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, true); - gc->mGrpIdList = grpChanged; + + gc->mGroupId = groupId; + mNotifications.push_back(gc); #ifdef GEN_EXCH_DEBUG std::cerr << " adding the following grp ids to notification: " << std::endl; @@ -3207,11 +3218,18 @@ void RsGenExchange::processRecvdGroups() vit = tmp ; } - if(!grpIds.empty()) + if(!grps_to_store.empty()) { - RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, false); - c->mGrpIdList = grpIds; - mNotifications.push_back(c); + for(auto Grp:grps_to_store) + { + RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, false); + + c->mGroupId = Grp->grpId; + c->mNewGroupItem = dynamic_cast(mSerialiser->deserialise(Grp->grp.bin_data,&Grp->grp.bin_len)); + + mNotifications.push_back(c); + } + mDataStore->storeGroup(grps_to_store); #ifdef GEN_EXCH_DEBUG std::cerr << " adding the following grp ids to notification: " << std::endl; @@ -3286,7 +3304,7 @@ void RsGenExchange::performUpdateValidation() // Now prepare notification of the client - RsGxsGroupUpdate *c = new RsGxsGroupUpdate(); + RsGxsGroupChange *c = new RsGxsGroupChange(RsGxsNotify::TYPE_UPDATED,false); c->mNewGroupItem = dynamic_cast(mSerialiser->deserialise(gu.newGrp->grp.bin_data,&gu.newGrp->grp.bin_len)); c->mNewGroupItem->meta = *gu.newGrp->metaData; // gu.newGrp will be deleted because mDataStore will destroy it on update diff --git a/libretroshare/src/gxs/rsgxsnotify.h b/libretroshare/src/gxs/rsgxsnotify.h index 847a78d38..0e6d39877 100644 --- a/libretroshare/src/gxs/rsgxsnotify.h +++ b/libretroshare/src/gxs/rsgxsnotify.h @@ -38,6 +38,8 @@ struct RsGxsNotify TYPE_RECEIVED_DISTANT_SEARCH_RESULTS = 0x05, TYPE_STATISTICS_CHANGED = 0x06, TYPE_UPDATED = 0x07, + TYPE_MESSAGES_DELETED = 0x08, + TYPE_GROUP_DELETED = 0x09, }; virtual ~RsGxsNotify() {} @@ -50,29 +52,22 @@ struct RsGxsNotify class RsGxsGroupChange : public RsGxsNotify { public: - RsGxsGroupChange(NotifyType type, bool metaChange) : mNotifyType(type), mMetaChange(metaChange) {} - std::list mGrpIdList; + RsGxsGroupChange(NotifyType type, bool metaChange) : mNewGroupItem(nullptr),mOldGroupItem(nullptr), mNotifyType(type), mMetaChange(metaChange) {} + virtual ~RsGxsGroupChange() { delete mOldGroupItem; delete mNewGroupItem ; } + NotifyType getType() override { return mNotifyType;} bool metaChange() { return mMetaChange; } + RsGxsGroupId mGroupId; // Group id of the group we're talking about. When the group is deleted, it's useful to know which group + // that was although there is no pointers to the actual group data anymore. + RsGxsGrpItem *mNewGroupItem; // Valid when a group has changed, or a new group is received. + RsGxsGrpItem *mOldGroupItem; // only valid when mNotifyType is TYPE_UPDATED + protected: NotifyType mNotifyType; bool mMetaChange; }; -class RsGxsGroupUpdate : public RsGxsNotify -{ -public: - RsGxsGroupUpdate() : mOldGroupItem(nullptr),mNewGroupItem(nullptr) {} - virtual ~RsGxsGroupUpdate() { delete mOldGroupItem; delete mNewGroupItem ; } - - RsGxsGrpItem *mOldGroupItem; - RsGxsGrpItem *mNewGroupItem; - - NotifyType getType() override { return RsGxsNotify::TYPE_UPDATED;} -}; - - class RsGxsDistantSearchResultChange: public RsGxsNotify { public: diff --git a/libretroshare/src/gxstrans/p3gxstrans.cc b/libretroshare/src/gxstrans/p3gxstrans.cc index 92af56f08..b85bcea9a 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.cc +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -656,6 +656,8 @@ void p3GxsTrans::notifyChanges(std::vector& changes) #ifdef DEBUG_GXSTRANS std::cout << "p3GxsTrans::notifyChanges(...)" << std::endl; #endif + std::list grps_to_request; + for( auto it = changes.begin(); it != changes.end(); ++it ) { RsGxsGroupChange* grpChange = dynamic_cast(*it); @@ -666,7 +668,7 @@ void p3GxsTrans::notifyChanges(std::vector& changes) #ifdef DEBUG_GXSTRANS std::cout << "p3GxsTrans::notifyChanges(...) grpChange" << std::endl; #endif - requestGroupsData(&(grpChange->mGrpIdList)); + grps_to_request.push_back(grpChange->mGroupId); } else if(msgChange) { @@ -698,6 +700,9 @@ void p3GxsTrans::notifyChanges(std::vector& changes) } delete *it; } + + if(!grps_to_request.empty()) + requestGroupsData(&grps_to_request); } uint32_t p3GxsTrans::AuthenPolicy() diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 9e0072d5b..40df82862 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -304,71 +304,52 @@ void p3GxsChannels::notifyChanges(std::vector &changes) { case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed { - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - for (git = grpList.begin(); git != grpList.end(); ++git) - { - auto ev = std::make_shared(); - ev->mChannelGroupId = *git; - ev->mChannelEventCode = RsChannelEventCode::SUBSCRIBE_STATUS_CHANGED; - rsEvents->postEvent(ev); - } - + auto ev = std::make_shared(); + ev->mChannelGroupId = grpChange->mGroupId; + ev->mChannelEventCode = RsChannelEventCode::SUBSCRIBE_STATUS_CHANGED; + rsEvents->postEvent(ev); } break; case RsGxsNotify::TYPE_STATISTICS_CHANGED: - { - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - for (git = grpList.begin(); git != grpList.end(); ++git) - { - auto ev = std::make_shared(); - ev->mChannelGroupId = *git; - ev->mChannelEventCode = RsChannelEventCode::STATISTICS_CHANGED; - rsEvents->postEvent(ev); - } - } + { + auto ev = std::make_shared(); + ev->mChannelGroupId = grpChange->mGroupId; + ev->mChannelEventCode = RsChannelEventCode::STATISTICS_CHANGED; + rsEvents->postEvent(ev); + } break; case RsGxsNotify::TYPE_PUBLISHED: case RsGxsNotify::TYPE_RECEIVED_NEW: { /* group received */ - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - RS_STACK_MUTEX(mKnownChannelsMutex); - for (git = grpList.begin(); git != grpList.end(); ++git) - { - if(mKnownChannels.find(*git) == mKnownChannels.end()) - { - mKnownChannels.insert(std::make_pair(*git,time(NULL))) ; - IndicateConfigChanged(); - auto ev = std::make_shared(); - ev->mChannelGroupId = *git; - ev->mChannelEventCode = RsChannelEventCode::NEW_CHANNEL; - rsEvents->postEvent(ev); - } - else - std::cerr << "(II) Not notifying already known channel " << *git << std::endl; + RS_STACK_MUTEX(mKnownChannelsMutex); + + if(mKnownChannels.find(grpChange->mGroupId) == mKnownChannels.end()) + { + mKnownChannels.insert(std::make_pair(grpChange->mGroupId,time(NULL))) ; + IndicateConfigChanged(); + + auto ev = std::make_shared(); + ev->mChannelGroupId = grpChange->mGroupId; + ev->mChannelEventCode = RsChannelEventCode::NEW_CHANNEL; + rsEvents->postEvent(ev); } - break; + else + std::cerr << "(II) Not notifying already known channel " << grpChange->mGroupId << std::endl; } + break; case RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY: { /* group received */ - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - for (git = grpList.begin(); git != grpList.end(); ++git) - { - auto ev = std::make_shared(); - ev->mChannelGroupId = *git; - ev->mChannelEventCode = RsChannelEventCode::RECEIVED_PUBLISH_KEY; + auto ev = std::make_shared(); + ev->mChannelGroupId = grpChange->mGroupId; + ev->mChannelEventCode = RsChannelEventCode::RECEIVED_PUBLISH_KEY; - rsEvents->postEvent(ev); - } + rsEvents->postEvent(ev); } break; diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 44b095ac5..e300f8a11 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -535,7 +535,6 @@ void p3GxsCircles::notifyChanges(std::vector &changes) for(auto it = changes.begin(); it != changes.end(); ++it) { - RsGxsGroupChange *groupChange = dynamic_cast(*it); RsGxsMsgChange *msgChange = dynamic_cast(*it); RsGxsNotify *c = *it; @@ -581,93 +580,127 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } } + RsGxsGroupChange *groupChange = dynamic_cast(*it); + /* add groups to ExternalIdList (Might get Personal Circles here until NetChecks in place) */ - if (groupChange && !groupChange->metaChange()) - { -#ifdef DEBUG_CIRCLES - std::cerr << " Found Group Change Notification" << std::endl; -#endif - for(std::list::iterator git = groupChange->mGrpIdList.begin(); git != groupChange->mGrpIdList.end(); ++git) - { -#ifdef DEBUG_CIRCLES - std::cerr << " Incoming Group: " << *git << ". Forcing cache load." << std::endl; -#endif - - // for new circles we need to add them to the list. - // we don't know the type of this circle here - // original behavior was to add all ids to the external ids list - - addCircleIdToList(RsGxsCircleId(*git), 0); - - // reset the cached circle data for this id - { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - mCircleCache.erase(RsGxsCircleId(*git)); - mCacheUpdated = true; - } - } - } - - if(groupChange) + if (groupChange) { - std::list own_ids; - rsIdentity->getOwnIds(own_ids); + const RsGxsGroupId *git(&groupChange->mGroupId); - for(std::list::const_iterator git(groupChange->mGrpIdList.begin());git!=groupChange->mGrpIdList.end();++git) + if(!groupChange->metaChange()) { #ifdef DEBUG_CIRCLES - std::cerr << " forcing cache loading for circle " << *git << " in order to trigger subscribe update." << std::endl; + std::cerr << " Found Group Change Notification" << std::endl; +#endif + //for(std::list::iterator git = groupChange->mGrpIdList.begin(); git != groupChange->mGrpIdList.end(); ++git) + { +#ifdef DEBUG_CIRCLES + std::cerr << " Incoming Group: " << *git << ". Forcing cache load." << std::endl; #endif -#ifdef TODO - // This code will not work: we would like to detect changes in the circle data that reflects the fact that one of the - // owned GXS ids is invited. But there's no way to compare the old circle data to the new if cache has to be updated. - // For this we need to add the old metadata and group data in the RsGxsGroupChange structure and account for it. + // for new circles we need to add them to the list. + // we don't know the type of this circle here + // original behavior was to add all ids to the external ids list - if(rsEvents && (c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW) ) - { - RsGxsCircleId circle_id(*git); - force_cache_reload(circle_id); + addCircleIdToList(RsGxsCircleId(*git), 0); - RsGxsCircleDetails details; - getCircleDetails(circle_id,details); - - // We check that the change corresponds to one of our own ids. Since we do not know what the change is, we notify - // for whatever is different from what is currently known. Other ids, that get invited only trigger a notification when the - // ID also accepts the invitation, so it becomes a member of the circle. - - for(auto own_id: own_ids) + // reset the cached circle data for this id { - auto it = details.mSubscriptionFlags.find(own_id); - - if(it == details.mSubscriptionFlags.end()) - continue; - - bool invited ( it->second & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ); - bool subscrb ( it->second & GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED ); - - if(std::find(details.mAllowedGxsIds.begin(),details.mAllowedGxsIds.end(),id) != details.mAllowedGxsIds.end() && !me_in_circle) - { - auto ev = std::make_shared(); - - ev->mType = RsGxsCircleEvent::CIRCLE_MEMBERSHIP_INVITE; - ev->mCircleId = circle_id; - ev->mGxsId = ; - - rsEvents->sendEvent(ev); - } + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + mCircleCache.erase(RsGxsCircleId(*git)); + mCacheUpdated = true; } - } -#endif + } - if(rsEvents && (c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW|| c->getType() == RsGxsNotify::TYPE_PUBLISHED) ) + if(rsEvents) + { + std::list own_ids_lst; + rsIdentity->getOwnIds(own_ids_lst,false); // retrieve own identities + + std::set own_ids; + for(auto& id:own_ids_lst) + own_ids.insert(id); // put them in a std::set for O(log(n)) search + + if(c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW|| c->getType() == RsGxsNotify::TYPE_PUBLISHED) { auto ev = std::make_shared(); ev->mCircleId = RsGxsCircleId(*git); ev->mCircleEventType = RsGxsCircleEventCode::NEW_CIRCLE; + rsEvents->postEvent(ev); + + // we also need to look into invitee list here! + + RsGxsCircleGroupItem *new_circle_grp_item = dynamic_cast(groupChange->mNewGroupItem); + + std::list added_identities; + + for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) + if(own_ids.find(gxs_id)!=own_ids.end()) + added_identities.push_back(gxs_id); + + for(auto& gxs_id:added_identities) + { + auto ev = std::make_shared(); + + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE; + ev->mCircleId = RsGxsCircleId(*git); + ev->mGxsId = gxs_id; + + rsEvents->sendEvent(ev); + } } + else if(c->getType()==RsGxsNotify::TYPE_UPDATED) + { + // Happens when the group data has changed. In this case we need to analyse the old and new group in order to detect possible notifications for clients + + RsGxsCircleGroupItem *old_circle_grp_item = dynamic_cast(groupChange->mOldGroupItem); + RsGxsCircleGroupItem *new_circle_grp_item = dynamic_cast(groupChange->mNewGroupItem); + + const RsGxsCircleId circle_id ( old_circle_grp_item->meta.mGroupId ); + + if(old_circle_grp_item == nullptr || new_circle_grp_item == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsCircleGroupItem. This is inconsistent!" << std::endl; + delete groupChange; + continue; + } + + // First of all, we check if there is a difference between the old and new list of invited members + + std::list added_identities, removed_identities; + + for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) + if(old_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) + added_identities.push_back(gxs_id); + + for(auto& gxs_id: old_circle_grp_item->gxsIdSet.ids) + if(new_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) + removed_identities.push_back(gxs_id); + + for(auto& gxs_id:added_identities) + { + auto ev = std::make_shared(); + + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE; + ev->mCircleId = circle_id; + ev->mGxsId = gxs_id; + + rsEvents->sendEvent(ev); + } + for(auto& gxs_id:removed_identities) + { + auto ev = std::make_shared(); + + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED; + ev->mCircleId = circle_id; + ev->mGxsId = gxs_id; + + rsEvents->sendEvent(ev); + } + + } // reset circle from cache since the number of invitee may have changed. { @@ -679,64 +712,6 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } } - RsGxsGroupUpdate *grpUpdate = dynamic_cast(*it); - - if (grpUpdate && rsEvents) - { - // Happens when the group data has changed. In this case we need to analyse the old and new group in order to detect possible notifications for clients - - RsGxsCircleGroupItem *old_circle_grp_item = dynamic_cast(grpUpdate->mOldGroupItem); - RsGxsCircleGroupItem *new_circle_grp_item = dynamic_cast(grpUpdate->mNewGroupItem); - - const RsGxsCircleId circle_id ( old_circle_grp_item->meta.mGroupId ); - - if(old_circle_grp_item == nullptr || new_circle_grp_item == nullptr) - { - RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsCircleGroupItem. This is inconsistent!" << std::endl; - delete grpUpdate; - continue; - } - - // First of all, we check if there is a difference between the old and new list of invited members - - std::list added_identities, removed_identities; - std::list own_ids_lst; - rsIdentity->getOwnIds(own_ids_lst,false); // retrieve own identities - - std::set own_ids; - for(auto& id:own_ids_lst) - own_ids.insert(id); // put them in a std::set for O(log(n)) search - - for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) - if(old_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) - added_identities.push_back(gxs_id); - - for(auto& gxs_id: old_circle_grp_item->gxsIdSet.ids) - if(new_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) - removed_identities.push_back(gxs_id); - - for(auto& gxs_id:added_identities) - { - auto ev = std::make_shared(); - - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE; - ev->mCircleId = circle_id; - ev->mGxsId = gxs_id; - - rsEvents->sendEvent(ev); - } - for(auto& gxs_id:removed_identities) - { - auto ev = std::make_shared(); - - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED; - ev->mCircleId = circle_id; - ev->mGxsId = gxs_id; - - rsEvents->sendEvent(ev); - } - } - delete *it; } } diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 6b8f91f9f..b81a31479 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -249,16 +249,10 @@ void p3GxsForums::notifyChanges(std::vector &changes) { case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed { - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - for (git = grpList.begin(); git != grpList.end(); ++git) - { auto ev = std::make_shared(); - ev->mForumGroupId = *git; + ev->mForumGroupId = grpChange->mGroupId; ev->mForumEventCode = RsForumEventCode::SUBSCRIBE_STATUS_CHANGED; rsEvents->postEvent(ev); - } - } break; @@ -266,112 +260,81 @@ void p3GxsForums::notifyChanges(std::vector &changes) case RsGxsNotify::TYPE_RECEIVED_NEW: { /* group received */ - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; RS_STACK_MUTEX(mKnownForumsMutex); - for (git = grpList.begin(); git != grpList.end(); ++git) - { - if(mKnownForums.find(*git) == mKnownForums.end()) - { - mKnownForums.insert( - std::make_pair(*git, time(nullptr))); - IndicateConfigChanged(); - auto ev = std::make_shared(); - ev->mForumGroupId = *git; - ev->mForumEventCode = RsForumEventCode::NEW_FORUM; - rsEvents->postEvent(ev); - } - else - RsInfo() << __PRETTY_FUNCTION__ - << " Not notifying already known forum " - << *git << std::endl; + if(mKnownForums.find(grpChange->mGroupId) == mKnownForums.end()) + { + mKnownForums.insert( std::make_pair(grpChange->mGroupId, time(nullptr))); + IndicateConfigChanged(); + + auto ev = std::make_shared(); + ev->mForumGroupId = grpChange->mGroupId; + ev->mForumEventCode = RsForumEventCode::NEW_FORUM; + rsEvents->postEvent(ev); } + else + RsInfo() << __PRETTY_FUNCTION__ + << " Not notifying already known forum " + << grpChange->mGroupId << std::endl; } break; case RsGxsNotify::TYPE_STATISTICS_CHANGED: { - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - for (git = grpList.begin(); git != grpList.end(); ++git) + auto ev = std::make_shared(); + ev->mForumGroupId = grpChange->mGroupId; + ev->mForumEventCode = RsForumEventCode::STATISTICS_CHANGED; + rsEvents->postEvent(ev); + } + break; + + case RsGxsNotify::TYPE_UPDATED: + { + // Happens when the group data has changed. In this case we need to analyse the old and new group in order to detect possible notifications for clients + + RsGxsForumGroupItem *old_forum_grp_item = dynamic_cast(grpChange->mOldGroupItem); + RsGxsForumGroupItem *new_forum_grp_item = dynamic_cast(grpChange->mNewGroupItem); + + if(old_forum_grp_item == nullptr || new_forum_grp_item == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsForumGroupItem. This is inconsistent!" << std::endl; + delete grpChange; + continue; + } + + // First of all, we check if there is a difference between the old and new list of moderators + + std::list added_mods, removed_mods; + + for(auto& gxs_id: new_forum_grp_item->mGroup.mAdminList.ids) + if(old_forum_grp_item->mGroup.mAdminList.ids.find(gxs_id) == old_forum_grp_item->mGroup.mAdminList.ids.end()) + added_mods.push_back(gxs_id); + + for(auto& gxs_id: old_forum_grp_item->mGroup.mAdminList.ids) + if(new_forum_grp_item->mGroup.mAdminList.ids.find(gxs_id) == new_forum_grp_item->mGroup.mAdminList.ids.end()) + removed_mods.push_back(gxs_id); + + if(!added_mods.empty() || !removed_mods.empty()) { auto ev = std::make_shared(); - ev->mForumGroupId = *git; - ev->mForumEventCode = RsForumEventCode::STATISTICS_CHANGED; + + ev->mForumGroupId = new_forum_grp_item->meta.mGroupId; + ev->mModeratorsAdded = added_mods; + ev->mModeratorsRemoved = removed_mods; + ev->mForumEventCode = RsForumEventCode::MODERATOR_LIST_CHANGED; + rsEvents->postEvent(ev); } } - break; + break; + + default: RsErr() << " Got a GXS event of type " << grpChange->getType() << " Currently not handled." << std::endl; break; - - -#ifdef NOT_USED_YET - case RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY: - { - /* group received */ - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - for (git = grpList.begin(); git != grpList.end(); ++git) - { - auto ev = std::make_shared(); - - ev->mChannelGroupId = *git; - ev->mChannelEventCode = RsGxsChannelEvent::RECEIVED_PUBLISH_KEY; - - rsEvents->sendEvent(ev); - } - } - break; -#endif } } - - RsGxsGroupUpdate *grpUpdate = dynamic_cast(*it); - - if (grpUpdate && rsEvents) - { - // Happens when the group data has changed. In this case we need to analyse the old and new group in order to detect possible notifications for clients - - RsGxsForumGroupItem *old_forum_grp_item = dynamic_cast(grpUpdate->mOldGroupItem); - RsGxsForumGroupItem *new_forum_grp_item = dynamic_cast(grpUpdate->mNewGroupItem); - - if(old_forum_grp_item == nullptr || new_forum_grp_item == nullptr) - { - RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsForumGroupItem. This is inconsistent!" << std::endl; - delete grpUpdate; - continue; - } - - // First of all, we check if there is a difference between the old and new list of moderators - - std::list added_mods, removed_mods; - - for(auto& gxs_id: new_forum_grp_item->mGroup.mAdminList.ids) - if(old_forum_grp_item->mGroup.mAdminList.ids.find(gxs_id) == old_forum_grp_item->mGroup.mAdminList.ids.end()) - added_mods.push_back(gxs_id); - - for(auto& gxs_id: old_forum_grp_item->mGroup.mAdminList.ids) - if(new_forum_grp_item->mGroup.mAdminList.ids.find(gxs_id) == new_forum_grp_item->mGroup.mAdminList.ids.end()) - removed_mods.push_back(gxs_id); - - if(!added_mods.empty() || !removed_mods.empty()) - { - auto ev = std::make_shared(); - - ev->mForumGroupId = new_forum_grp_item->meta.mGroupId; - ev->mModeratorsAdded = added_mods; - ev->mModeratorsRemoved = removed_mods; - ev->mForumEventCode = RsForumEventCode::MODERATOR_LIST_CHANGED; - - rsEvents->postEvent(ev); - } - - } - } } diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index b3e30d8ca..4c17a1dda 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -631,16 +631,13 @@ void p3IdService::notifyChanges(std::vector &changes) std::cerr << "p3IdService::notifyChanges() Found Group Change Notification"; std::cerr << std::endl; #endif - std::list &groupList = groupChange->mGrpIdList; - - for(auto git = groupList.begin(); git != groupList.end();++git) - { #ifdef DEBUG_IDS std::cerr << "p3IdService::notifyChanges() Auto Subscribe to Incoming Groups: " << *git; std::cerr << std::endl; #endif + const RsGxsGroupId& gid(groupChange->mGroupId); - if(!rsReputations->isIdentityBanned(RsGxsId(*git))) + if(!rsReputations->isIdentityBanned(RsGxsId(gid))) { // notify that a new identity is received, if needed @@ -654,12 +651,12 @@ void p3IdService::notifyChanges(std::vector &changes) case RsGxsNotify::TYPE_PUBLISHED: { auto ev = std::make_shared(); - ev->mIdentityId = *git; + ev->mIdentityId = gid; ev->mIdentityEventCode = RsGxsIdentityEventCode::UPDATED_IDENTITY; rsEvents->postEvent(ev); // also time_stamp the key that this group represents - timeStampKey(RsGxsId(*git),RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_DATA_UPDATE)) ; + timeStampKey(RsGxsId(gid),RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_DATA_UPDATE)) ; should_subscribe = true; } break; @@ -667,12 +664,12 @@ void p3IdService::notifyChanges(std::vector &changes) case RsGxsNotify::TYPE_RECEIVED_NEW: { auto ev = std::make_shared(); - ev->mIdentityId = *git; + ev->mIdentityId = gid; ev->mIdentityEventCode = RsGxsIdentityEventCode::NEW_IDENTITY; rsEvents->postEvent(ev); // also time_stamp the key that this group represents - timeStampKey(RsGxsId(*git),RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_DATA_UPDATE)) ; + timeStampKey(RsGxsId(gid),RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_DATA_UPDATE)) ; should_subscribe = true; } break; @@ -684,11 +681,10 @@ void p3IdService::notifyChanges(std::vector &changes) if(should_subscribe) { uint32_t token; - RsGenExchange::subscribeToGroup(token, *git, true); + RsGenExchange::subscribeToGroup(token, gid, true); } } - } } delete changes[i]; diff --git a/libretroshare/src/services/p3postbase.cc b/libretroshare/src/services/p3postbase.cc index 771103eb0..9c11dcd64 100644 --- a/libretroshare/src/services/p3postbase.cc +++ b/libretroshare/src/services/p3postbase.cc @@ -131,36 +131,25 @@ void p3PostBase::notifyChanges(std::vector &changes) std::cerr << "p3PostBase::notifyChanges() Found Group Change Notification"; std::cerr << std::endl; #endif + const RsGxsGroupId& group_id(grpChange->mGroupId); switch(grpChange->getType()) { case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed { - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - for (git = grpList.begin(); git != grpList.end(); ++git) - { - auto ev = std::make_shared(); - ev->mPostedGroupId = *git; - ev->mPostedEventCode = RsPostedEventCode::SUBSCRIBE_STATUS_CHANGED; - rsEvents->postEvent(ev); - } - + auto ev = std::make_shared(); + ev->mPostedGroupId = group_id; + ev->mPostedEventCode = RsPostedEventCode::SUBSCRIBE_STATUS_CHANGED; + rsEvents->postEvent(ev); } break; case RsGxsNotify::TYPE_STATISTICS_CHANGED: { - std::list &grpList = grpChange->mGrpIdList; - std::list::iterator git; - - for (git = grpList.begin(); git != grpList.end(); ++git) - { - auto ev = std::make_shared(); - ev->mPostedGroupId = *git; - ev->mPostedEventCode = RsPostedEventCode::STATISTICS_CHANGED; - rsEvents->postEvent(ev); - } + auto ev = std::make_shared(); + ev->mPostedGroupId = group_id; + ev->mPostedEventCode = RsPostedEventCode::STATISTICS_CHANGED; + rsEvents->postEvent(ev); } break; @@ -168,30 +157,26 @@ void p3PostBase::notifyChanges(std::vector &changes) case RsGxsNotify::TYPE_RECEIVED_NEW: { /* group received */ - const std::list& grpList = grpChange->mGrpIdList; - for (auto git = grpList.begin(); git != grpList.end(); ++git) + if(mKnownPosted.find(group_id) == mKnownPosted.end()) { - if(mKnownPosted.find(*git) == mKnownPosted.end()) - { - mKnownPosted.insert(std::make_pair(*git, time(nullptr))); - IndicateConfigChanged(); + mKnownPosted.insert(std::make_pair(group_id, time(nullptr))); + IndicateConfigChanged(); - auto ev = std::make_shared(); - ev->mPostedGroupId = *git; - ev->mPostedEventCode = RsPostedEventCode::NEW_POSTED_GROUP; - rsEvents->postEvent(ev); + auto ev = std::make_shared(); + ev->mPostedGroupId = group_id; + ev->mPostedEventCode = RsPostedEventCode::NEW_POSTED_GROUP; + rsEvents->postEvent(ev); #ifdef POSTBASE_DEBUG - std::cerr << "p3PostBase::notifyChanges() Incoming Group: " << *git; - std::cerr << std::endl; + std::cerr << "p3PostBase::notifyChanges() Incoming Group: " << group_id; + std::cerr << std::endl; #endif - } - else - RsInfo() << __PRETTY_FUNCTION__ - << " Not notifying already known forum " - << *git << std::endl; } + else + RsInfo() << __PRETTY_FUNCTION__ + << " Not notifying already known forum " + << group_id << std::endl; } break; From 39fe2f2211aa614c509c5c40170a2af6af7b71a7 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 1 May 2020 21:36:26 +0200 Subject: [PATCH 09/79] added save/restore of hierarchy in circles --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 55 ++++++++++++++++++++ retroshare-gui/src/gui/Identity/IdDialog.h | 3 ++ 2 files changed, 58 insertions(+) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index d111b7299..7709fcbfa 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -594,6 +594,10 @@ void IdDialog::loadCircles(const std::list& groupInfo) mStateHelper->setActive(CIRCLESDIALOG_GROUPMETA, true); + std::vector expanded_top_level_items; + std::set expanded_circle_items; + saveExpandedCircleItems(expanded_top_level_items,expanded_circle_items); + #ifdef QT_BUG_CRASH_IN_TAKECHILD_WORKAROUND // These 3 lines are normally not needed. But apparently a bug (in Qt ??) causes Qt to crash when takeChild() is called. If we remove everything from the // tree widget before updating it, takeChild() is never called, but the all tree is filled again from scratch. This is less efficient obviously, and @@ -852,6 +856,7 @@ void IdDialog::loadCircles(const std::list& groupInfo) else item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,QIcon(IMAGE_UNKNOWN)) ; } + restoreExpandedCircleItems(expanded_top_level_items,expanded_circle_items); } static void mark_matching_tree(QTreeWidget *w, const std::set& members, int col) @@ -2445,3 +2450,53 @@ void IdDialog::on_closeInfoFrameButton_clicked() { ui->inviteFrame->setVisible(false); } + +// We need to use indexes here because saving items is not possible since they can be re-created. + +void IdDialog::saveExpandedCircleItems(std::vector& expanded_root_items, std::set& expanded_circle_items) const +{ + expanded_root_items.clear(); + expanded_root_items.resize(3,false); + expanded_circle_items.clear(); + + auto saveTopLevel = [&](const QTreeWidgetItem* top_level_item,uint32_t index){ + if(!top_level_item) + return; + + if(top_level_item->isExpanded()) + { + expanded_root_items[index] = true; + + for(int row=0;rowchildCount();++row) + if(top_level_item->child(row)->isExpanded()) + expanded_circle_items.insert(RsGxsCircleId(top_level_item->child(row)->data(CIRCLEGROUP_CIRCLE_COL_GROUPID,Qt::UserRole).toString().toStdString())); + } + }; + + saveTopLevel(mExternalBelongingCircleItem,0); + saveTopLevel(mExternalOtherCircleItem,1); + saveTopLevel(mMyCircleItem,2); +} + +void IdDialog::restoreExpandedCircleItems(const std::vector& expanded_root_items,const std::set& expanded_circle_items) +{ + auto restoreTopLevel = [=](QTreeWidgetItem* top_level_item,uint32_t index){ + if(!top_level_item) + return; + + top_level_item->setExpanded(expanded_root_items[index]); + + for(int row=0;rowchildCount();++row) + { + RsGxsCircleId circle_id(RsGxsCircleId(top_level_item->child(row)->data(CIRCLEGROUP_CIRCLE_COL_GROUPID,Qt::UserRole).toString().toStdString())); + bool expanded = expanded_circle_items.find(circle_id) != expanded_circle_items.end(); + + top_level_item->child(row)->setExpanded(expanded_circle_items.find(circle_id) != expanded_circle_items.end()); + } + }; + + restoreTopLevel(mExternalBelongingCircleItem,0); + restoreTopLevel(mExternalOtherCircleItem,1); + restoreTopLevel(mMyCircleItem,2); +} + diff --git a/retroshare-gui/src/gui/Identity/IdDialog.h b/retroshare-gui/src/gui/Identity/IdDialog.h index 7cecd4cc5..dd3669f4c 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.h +++ b/retroshare-gui/src/gui/Identity/IdDialog.h @@ -145,6 +145,9 @@ private: QTreeWidgetItem *mMyCircleItem; RsGxsUpdateBroadcastBase *mCirclesBroadcastBase ; + void saveExpandedCircleItems(std::vector &expanded_root_items, std::set& expanded_circle_items) const; + void restoreExpandedCircleItems(const std::vector& expanded_root_items,const std::set& expanded_circle_items); + std::map mCircleUpdates ; RsGxsGroupId mId; From 26dd71696742f35edcdcd5d77afc305f9eb4137a Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 1 May 2020 22:59:39 +0200 Subject: [PATCH 10/79] added documentation on circle membership at UI and circles API level. Internals need to be implemented accordingly --- libretroshare/src/retroshare/rsgxscircles.h | 85 +++++++++++++++++---- retroshare-gui/src/gui/NewsFeed.cpp | 38 +++++++++ 2 files changed, 108 insertions(+), 15 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index a06430334..78907b1a9 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -165,32 +165,87 @@ struct RsGxsCircleDetails : RsSerializable enum class RsGxsCircleEventCode: uint8_t { +// Notications received depending on wether you got a membership request, if you +// are admin of that circle, etc. +// +// Message-based notifications: +// +// +---------------------------+----------------------------+ +// | Membership request | Membership cancellation | +// +-------------+-------------+-------------+--------------+ +// | Admin | Not admin | Admin | Not admin | +// +--------------------+-------------+-------------+----------------------------+ +// | in invitee list | 0x04 | 0x04 | 0x03 | 0x03 | +// +--------------------+-------------+-------------+-------------+--------------+ +// |not in invitee list | 0x01 | X | X | X | +// +--------------------+-------------+-------------+-------------+--------------+ +// +// Note: in this case, the GxsId never belongs to you, since you dont need to handle +// notifications for actions you took yourself (leave/join a circle) +// +// Group-based notifications, the GxsId belongs to you: +// +// +---------------------------+----------------------------+ +// | GxsId joins invitee list | GxsId leaves invitee list | +// +-------------+-------------+-------------+--------------+ +// | Id is yours| Id is not | Id is yours | Id is not | +// +--------------------+-------------+-------------+-------------+--------------+ +// | Has Member request | 0x06 | 0x04 | 0x05 | 0x03 | +// +--------------------+-------------+-------------+-------------+--------------+ +// | No Member request | 0x02 | X | 0x05 | X | +// +--------------------+-------------+-------------+-------------+--------------+ +// +// Note: In this case you're never an admin of the circle, since these notification +// would be a direct consequence of your own actions. + + // Notifications be only have 4 different possibilities: + // + // invitee list join/leave and + // membership request / leave request + // + // From there, depending on what the client displays, it is possible to interpret these + // as "some user joined the circle", or "membership pending for that Id", etc, depending + // on whether the current node owns the circle, or the admin is or is not yours. + // + // These should be decided in the UI based on what the circle cache is displaying. + // UNKNOWN = 0x00, - /** mCircleId contains the circle id and mGxsId is the id requesting - * membership */ + /** + * Sent when we receive a membership request msg for a particular circle. + * + * mCircleId contains the circle id and mGxsId is the id requesting membership */ CIRCLE_MEMBERSHIP_REQUEST = 0x01, - /** mCircleId is the circle that invites me, and mGxsId is my own Id that is - * invited */ + /** + * Sent when the ID has been added to the circle invitee list. + * + * mCircleId is the circle that invites me, and mGxsId is my own Id that is invited */ CIRCLE_MEMBERSHIP_INVITE = 0x02, - /** mCircleId contains the circle id and mGxsId is the id dropping - * membership */ + /** + * Sent when a GxsId annouces its will to not be in the circle. + * + * mCircleId contains the circle id and mGxsId is the id dropping membership */ CIRCLE_MEMBERSHIP_LEAVE = 0x03, - /// mCircleId contains the circle id and mGxsId is the id of the new member - CIRCLE_MEMBERSHIP_JOIN = 0x04, - - /** mCircleId contains the circle id and mGxsId is the id that was revoqued * by admin */ + /** + * Sent when the Id has been removed from the invitee list. + * + * mCircleId contains the circle id and mGxsId is the id that was revoqued * by admin */ CIRCLE_MEMBERSHIP_REVOKED = 0x05, - /** mCircleId contains the circle id */ - NEW_CIRCLE = 0x06, - - /** no additional information. Simply means that the info previously from the cache has changed. */ - CACHE_DATA_UPDATED = 0x07, + /** + * Means a new circle has been received. + * + * mCircleId contains the circle id */ + NEW_CIRCLE = 0x07, + /** + * Means that the circle cache has updated, and membership status that is displayed should probably be updated to. + * + * no additional information. Simply means that the info previously from the cache has changed. */ + CACHE_DATA_UPDATED = 0x08, }; struct RsGxsCircleEvent: RsEvent diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index ddbd545c1..033d4d942 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -311,6 +311,39 @@ void NewsFeed::handleCircleEvent(std::shared_ptr event) // Check if the circle is one of which we belong to. If so, then notify in the GUI about other members leaving/subscribing + // Notications received depending on wether you got a membership request, if you + // are admin of that circle, etc. + // + // Message-based notifications: + // + // +---------------------------+----------------------------+ + // | Membership request | Membership cancellation | + // +-------------+-------------+-------------+--------------+ + // | Admin | Not admin | Admin | Not admin | + // +--------------------+-------------+-------------+----------------------------+ + // | in invitee list | 0x04 | 0x04 | 0x03 | 0x03 | + // +--------------------+-------------+-------------+-------------+--------------+ + // |not in invitee list | 0x01 | X | X | X | + // +--------------------+-------------+-------------+-------------+--------------+ + // + // Note: in this case, the GxsId never belongs to you, since you dont need to handle + // notifications for actions you took yourself (leave/join a circle) + // + // Group-based notifications, the GxsId belongs to you: + // + // +---------------------------+----------------------------+ + // | GxsId joins invitee list | GxsId leaves invitee list | + // +-------------+-------------+-------------+--------------+ + // | Id is yours| Id is not | Id is yours | Id is not | + // +--------------------+-------------+-------------+-------------+--------------+ + // | Has Member request | 0x06 | 0x04 | 0x05 | 0x03 | + // +--------------------+-------------+-------------+-------------+--------------+ + // | No Member request | 0x02 | X | 0x05 | X | + // +--------------------+-------------+-------------+-------------+--------------+ + // + // Note: In this case you're never an admin of the circle, since these notification + // would be a direct consequence of your own actions. + if(details.mAmIAllowed || details.mAmIAdmin) { switch(pe->mCircleEventType) @@ -320,18 +353,23 @@ void NewsFeed::handleCircleEvent(std::shared_ptr event) if(details.mAmIAdmin) addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ),true); break; + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_JOIN: addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_JOIN),true); break; + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_LEAVE),true); break; + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE: addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVIT_REC),true); break; + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED: addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); break; + default: break; } } From 32baccae972d1f86688ec205e89d8020839df9f8 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 2 May 2020 15:09:32 +0200 Subject: [PATCH 11/79] finished cleaning GxsCircle Notifications --- libretroshare/src/retroshare/rsgxscircles.h | 83 +++++++------------ libretroshare/src/retroshare/rsnotify.h | 12 +-- libretroshare/src/services/p3gxscircles.cc | 81 +++++++----------- libretroshare/src/services/p3gxscircles.h | 2 +- retroshare-gui/src/gui/Identity/IdDialog.cpp | 7 +- retroshare-gui/src/gui/NewsFeed.cpp | 70 +++++++++------- .../src/gui/People/PeopleDialog.cpp | 26 ++++-- .../src/gui/feeds/GxsCircleItem.cpp | 51 +++++++----- 8 files changed, 160 insertions(+), 172 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index 78907b1a9..5120d5674 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -45,25 +45,23 @@ extern RsGxsCircles* rsGxsCircles; enum class RsGxsCircleType : uint32_t // 32 bit overkill, just for retrocompat { - UNKNOWN = 0, /// Used to detect uninizialized values. - PUBLIC = 1, /// Public distribution - EXTERNAL = 2, /// Restricted to an external circle + UNKNOWN = 0, /// Used to detect uninizialized values. + PUBLIC = 1, /// Public distribution, based on GxsIds + EXTERNAL = 2, /// Restricted to an external circle, based on GxsIds - /** Restricted to a group of friend nodes, the administrator of the circle - * behave as a hub for them */ - NODES_GROUP = 3, + NODES_GROUP = 3, /// Restricted to a group of friend nodes, the administrator of the circle behave as a hub for them + /// Based on PGP nodes ids. LOCAL = 4, /// not distributed at all /** Self-restricted. Used only at creation time of self-restricted circles * when the circle id isn't known yet. Once the circle id is known the type * is set to EXTERNAL, and the external circle id is set to the id of the - * circle itself. + * circle itself. Based on GxsIds. */ EXT_SELF = 5, - /// distributed to nodes signed by your own PGP key only. - YOUR_EYES_ONLY = 6 + YOUR_EYES_ONLY = 6 /// distributed to nodes signed by your own PGP key only. }; // TODO: convert to enum class @@ -121,15 +119,29 @@ struct RsGxsCircleMsg : RsSerializable struct RsGxsCircleDetails : RsSerializable { - RsGxsCircleDetails() : - mCircleType(static_cast(RsGxsCircleType::EXTERNAL)), - mAmIAllowed(false),mAmIAdmin(false) {} + RsGxsCircleDetails() : mCircleType(RsGxsCircleType::EXTERNAL), mAmIAllowed(false),mAmIAdmin(false) {} ~RsGxsCircleDetails() override; + // helper functions. + bool isIdInCircle(const RsGxsId& id) const { return mAllowedGxsIds.find(id) != mAllowedGxsIds.end(); } + bool isIdInInviteeList(const RsGxsId& id) const + { + auto it = mSubscriptionFlags.find(id); + return (it != mSubscriptionFlags.end()) && (it->second & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ); + } + bool isIdRequestingMembership(const RsGxsId& id) const + { + auto it = mSubscriptionFlags.find(id); + return it != mSubscriptionFlags.end() && (it->second & GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED ); + } + bool isGxsIdBased() const { return mCircleType==RsGxsCircleType::PUBLIC || mCircleType==RsGxsCircleType::EXTERNAL || mCircleType==RsGxsCircleType::EXT_SELF; } + + // Members + RsGxsCircleId mCircleId; std::string mCircleName; - uint32_t mCircleType; + RsGxsCircleType mCircleType; RsGxsCircleId mRestrictedCircleId; /** true when one of load GXS ids belong to the circle allowed list (admin @@ -165,39 +177,6 @@ struct RsGxsCircleDetails : RsSerializable enum class RsGxsCircleEventCode: uint8_t { -// Notications received depending on wether you got a membership request, if you -// are admin of that circle, etc. -// -// Message-based notifications: -// -// +---------------------------+----------------------------+ -// | Membership request | Membership cancellation | -// +-------------+-------------+-------------+--------------+ -// | Admin | Not admin | Admin | Not admin | -// +--------------------+-------------+-------------+----------------------------+ -// | in invitee list | 0x04 | 0x04 | 0x03 | 0x03 | -// +--------------------+-------------+-------------+-------------+--------------+ -// |not in invitee list | 0x01 | X | X | X | -// +--------------------+-------------+-------------+-------------+--------------+ -// -// Note: in this case, the GxsId never belongs to you, since you dont need to handle -// notifications for actions you took yourself (leave/join a circle) -// -// Group-based notifications, the GxsId belongs to you: -// -// +---------------------------+----------------------------+ -// | GxsId joins invitee list | GxsId leaves invitee list | -// +-------------+-------------+-------------+--------------+ -// | Id is yours| Id is not | Id is yours | Id is not | -// +--------------------+-------------+-------------+-------------+--------------+ -// | Has Member request | 0x06 | 0x04 | 0x05 | 0x03 | -// +--------------------+-------------+-------------+-------------+--------------+ -// | No Member request | 0x02 | X | 0x05 | X | -// +--------------------+-------------+-------------+-------------+--------------+ -// -// Note: In this case you're never an admin of the circle, since these notification -// would be a direct consequence of your own actions. - // Notifications be only have 4 different possibilities: // // invitee list join/leave and @@ -215,37 +194,37 @@ enum class RsGxsCircleEventCode: uint8_t * Sent when we receive a membership request msg for a particular circle. * * mCircleId contains the circle id and mGxsId is the id requesting membership */ - CIRCLE_MEMBERSHIP_REQUEST = 0x01, + CIRCLE_MEMBERSHIP_REQUEST = 0x01, /** * Sent when the ID has been added to the circle invitee list. * * mCircleId is the circle that invites me, and mGxsId is my own Id that is invited */ - CIRCLE_MEMBERSHIP_INVITE = 0x02, + CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST = 0x02, /** * Sent when a GxsId annouces its will to not be in the circle. * * mCircleId contains the circle id and mGxsId is the id dropping membership */ - CIRCLE_MEMBERSHIP_LEAVE = 0x03, + CIRCLE_MEMBERSHIP_LEAVE = 0x03, /** * Sent when the Id has been removed from the invitee list. * * mCircleId contains the circle id and mGxsId is the id that was revoqued * by admin */ - CIRCLE_MEMBERSHIP_REVOKED = 0x05, + CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST = 0x04, /** * Means a new circle has been received. * * mCircleId contains the circle id */ - NEW_CIRCLE = 0x07, + NEW_CIRCLE = 0x05, /** * Means that the circle cache has updated, and membership status that is displayed should probably be updated to. * * no additional information. Simply means that the info previously from the cache has changed. */ - CACHE_DATA_UPDATED = 0x08, + CACHE_DATA_UPDATED = 0x06, }; struct RsGxsCircleEvent: RsEvent diff --git a/libretroshare/src/retroshare/rsnotify.h b/libretroshare/src/retroshare/rsnotify.h index a7e43a4e8..e8c9de614 100644 --- a/libretroshare/src/retroshare/rsnotify.h +++ b/libretroshare/src/retroshare/rsnotify.h @@ -115,11 +115,13 @@ const uint32_t RS_FEED_ITEM_CHAT_NEW = RS_FEED_TYPE_CHAT | 0x0001; const uint32_t RS_FEED_ITEM_MESSAGE = RS_FEED_TYPE_MSG | 0x0001; const uint32_t RS_FEED_ITEM_FILES_NEW = RS_FEED_TYPE_FILES | 0x0001; -const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_REQ = RS_FEED_TYPE_CIRCLE | 0x0001; -const uint32_t RS_FEED_ITEM_CIRCLE_INVIT_REC = RS_FEED_TYPE_CIRCLE | 0x0002; -const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_LEAVE = RS_FEED_TYPE_CIRCLE | 0x0003; -const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_JOIN = RS_FEED_TYPE_CIRCLE | 0x0004; -const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_REVOKED = RS_FEED_TYPE_CIRCLE | 0x0005; +const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_REQ = RS_FEED_TYPE_CIRCLE | 0x0001; +const uint32_t RS_FEED_ITEM_CIRCLE_INVITE_REC = RS_FEED_TYPE_CIRCLE | 0x0002; +const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_LEAVE = RS_FEED_TYPE_CIRCLE | 0x0003; +const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_JOIN = RS_FEED_TYPE_CIRCLE | 0x0004; +const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED = RS_FEED_TYPE_CIRCLE | 0x0005; +const uint32_t RS_FEED_ITEM_CIRCLE_MEMB_REVOKED = RS_FEED_TYPE_CIRCLE | 0x0006; +const uint32_t RS_FEED_ITEM_CIRCLE_INVITE_CANCELLED= RS_FEED_TYPE_CIRCLE | 0x0007; const uint32_t RS_MESSAGE_CONNECT_ATTEMPT = 0x0001; diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index e300f8a11..97b19151e 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -566,13 +566,15 @@ void p3GxsCircles::notifyChanges(std::vector &changes) ev->mGxsId = msg.mMeta.mAuthorId; if (msg.stuff == "SUBSCRIPTION_REQUEST_UNSUBSCRIBE") + { ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE; - else if(details.mAllowedGxsIds.find(msg.mMeta.mAuthorId) != details.mAllowedGxsIds.end()) - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_JOIN; - else + rsEvents->postEvent(ev); + } + else if(msg.stuff == "SUBSCRIPTION_REQUEST_SUBSCRIBE") + { ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST; - - rsEvents->postEvent(ev); + rsEvents->postEvent(ev); + } } mCircleCache.erase(circle_id); @@ -615,13 +617,6 @@ void p3GxsCircles::notifyChanges(std::vector &changes) if(rsEvents) { - std::list own_ids_lst; - rsIdentity->getOwnIds(own_ids_lst,false); // retrieve own identities - - std::set own_ids; - for(auto& id:own_ids_lst) - own_ids.insert(id); // put them in a std::set for O(log(n)) search - if(c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW|| c->getType() == RsGxsNotify::TYPE_PUBLISHED) { auto ev = std::make_shared(); @@ -634,17 +629,11 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsGxsCircleGroupItem *new_circle_grp_item = dynamic_cast(groupChange->mNewGroupItem); - std::list added_identities; - for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) - if(own_ids.find(gxs_id)!=own_ids.end()) - added_identities.push_back(gxs_id); - - for(auto& gxs_id:added_identities) { auto ev = std::make_shared(); - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE; + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST; ev->mCircleId = RsGxsCircleId(*git); ev->mGxsId = gxs_id; @@ -669,36 +658,29 @@ void p3GxsCircles::notifyChanges(std::vector &changes) // First of all, we check if there is a difference between the old and new list of invited members - std::list added_identities, removed_identities; - for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) - if(old_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) - added_identities.push_back(gxs_id); + if(old_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end()) + { + auto ev = std::make_shared(); + + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST; + ev->mCircleId = circle_id; + ev->mGxsId = gxs_id; + + rsEvents->sendEvent(ev); + } for(auto& gxs_id: old_circle_grp_item->gxsIdSet.ids) - if(new_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end() && own_ids.find(gxs_id)!=own_ids.end()) - removed_identities.push_back(gxs_id); + if(new_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end()) + { + auto ev = std::make_shared(); - for(auto& gxs_id:added_identities) - { - auto ev = std::make_shared(); + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST; + ev->mCircleId = circle_id; + ev->mGxsId = gxs_id; - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE; - ev->mCircleId = circle_id; - ev->mGxsId = gxs_id; - - rsEvents->sendEvent(ev); - } - for(auto& gxs_id:removed_identities) - { - auto ev = std::make_shared(); - - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED; - ev->mCircleId = circle_id; - ev->mGxsId = gxs_id; - - rsEvents->sendEvent(ev); - } + rsEvents->sendEvent(ev); + } } @@ -720,8 +702,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) /******************* RsCircles Interface ***************************************/ /********************************************************************************/ -bool p3GxsCircles::getCircleDetails( - const RsGxsCircleId& id, RsGxsCircleDetails& details) +bool p3GxsCircles::getCircleDetails(const RsGxsCircleId& id, RsGxsCircleDetails& details) { #ifdef DEBUG_CIRCLES @@ -818,7 +799,7 @@ int p3GxsCircles::canSend(const RsGxsCircleId &circleId, const RsPgpId &id, bool if (mCircleCache.is_cached(circleId)) { RsGxsCircleCache &data = mCircleCache.ref(circleId); - should_encrypt = (data.mCircleType == GXS_CIRCLE_TYPE_EXTERNAL); + should_encrypt = (data.mCircleType == RsGxsCircleType::EXTERNAL); if (data.isAllowedPeer(id)) return 1; @@ -1051,7 +1032,7 @@ RsGenExchange::ServiceCreate_Return p3GxsCircles::service_CreateGroup(RsGxsGrpIt RsGxsCircleCache::RsGxsCircleCache() { - mCircleType = GXS_CIRCLE_TYPE_EXTERNAL; + mCircleType = RsGxsCircleType::EXTERNAL; mIsExternal = true; mUpdateTime = 0; mGroupStatus = 0; @@ -1070,8 +1051,8 @@ bool RsGxsCircleCache::loadBaseCircle(const RsGxsCircleGroup &circle) mUpdateTime = time(NULL); // mProcessedCircles.insert(mCircleId); - mCircleType = circle.mMeta.mCircleType; - mIsExternal = (mCircleType != GXS_CIRCLE_TYPE_LOCAL); + mCircleType = static_cast(circle.mMeta.mCircleType); + mIsExternal = (mCircleType != RsGxsCircleType::LOCAL); mGroupStatus = circle.mMeta.mGroupStatus; mGroupSubscribeFlags = circle.mMeta.mSubscribeFlags; mOriginator = circle.mMeta.mOriginator ; diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index 26aca35a7..e92ca5023 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -145,7 +145,7 @@ class RsGxsCircleCache RsGxsCircleId mCircleId; std::string mCircleName; - uint32_t mCircleType; + RsGxsCircleType mCircleType; bool mIsExternal; RsGxsCircleId mRestrictedCircleId ; // circle ID that circle is restricted to. diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 7709fcbfa..1a56385de 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -433,12 +433,11 @@ void IdDialog::handleEvent_main_thread(std::shared_ptr event) switch(e->mCircleEventType) { - case RsGxsCircleEventCode::NEW_CIRCLE: case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST: case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_JOIN: - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST: + case RsGxsCircleEventCode::NEW_CIRCLE: case RsGxsCircleEventCode::CACHE_DATA_UPDATED: updateCircles(); diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index 033d4d942..6c6a0d761 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -309,10 +309,12 @@ void NewsFeed::handleCircleEvent(std::shared_ptr event) return; } - // Check if the circle is one of which we belong to. If so, then notify in the GUI about other members leaving/subscribing + if(!details.isGxsIdBased()) // not handled yet. + return; - // Notications received depending on wether you got a membership request, if you - // are admin of that circle, etc. + // Check if the circle is one of which we belong to or we are an admin of. + // If so, then notify in the GUI about other members leaving/subscribing, according + // to the following rules. The names correspond to the RS_FEED_CIRCLE_* variables: // // Message-based notifications: // @@ -321,57 +323,67 @@ void NewsFeed::handleCircleEvent(std::shared_ptr event) // +-------------+-------------+-------------+--------------+ // | Admin | Not admin | Admin | Not admin | // +--------------------+-------------+-------------+----------------------------+ - // | in invitee list | 0x04 | 0x04 | 0x03 | 0x03 | + // | in invitee list | MEMB_JOIN | MEMB_JOIN | MEMB_LEAVE | MEMB_LEAVE | // +--------------------+-------------+-------------+-------------+--------------+ - // |not in invitee list | 0x01 | X | X | X | + // |not in invitee list | MEMB_REQ | X | X | X | // +--------------------+-------------+-------------+-------------+--------------+ // // Note: in this case, the GxsId never belongs to you, since you dont need to handle // notifications for actions you took yourself (leave/join a circle) // - // Group-based notifications, the GxsId belongs to you: + // GroupData-based notifications, the GxsId belongs to you: // // +---------------------------+----------------------------+ // | GxsId joins invitee list | GxsId leaves invitee list | // +-------------+-------------+-------------+--------------+ // | Id is yours| Id is not | Id is yours | Id is not | // +--------------------+-------------+-------------+-------------+--------------+ - // | Has Member request | 0x06 | 0x04 | 0x05 | 0x03 | + // | Has Member request | MEMB_ACCEPT | (MEMB_JOIN) | MEMB_REVOKED| (MEMB_LEAVE) | // +--------------------+-------------+-------------+-------------+--------------+ - // | No Member request | 0x02 | X | 0x05 | X | + // | No Member request | INVITE_REC | X | INVITE_REM | X | // +--------------------+-------------+-------------+-------------+--------------+ // // Note: In this case you're never an admin of the circle, since these notification // would be a direct consequence of your own actions. - if(details.mAmIAllowed || details.mAmIAdmin) + switch(pe->mCircleEventType) { - switch(pe->mCircleEventType) - { - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: - // only show membership requests if we're an admin of that circle - if(details.mAmIAdmin) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ),true); - break; - - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_JOIN: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: + // only show membership requests if we're an admin of that circle + if(details.isIdInInviteeList(pe->mGxsId)) addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_JOIN),true); - break; + else if(details.mAmIAdmin) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ),true); - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: + break; + + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: + + if(details.isIdInInviteeList(pe->mGxsId)) addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_LEAVE),true); - break; + break; - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE: - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVIT_REC),true); - break; + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST: + if(rsIdentity->isOwnId(pe->mGxsId)) + { + if(details.isIdRequestingMembership(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED),true); + else + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_REC),true); + } + break; - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOKED: - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); - break; + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST: + if(rsIdentity->isOwnId(pe->mGxsId)) + { + if(details.isIdRequestingMembership(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); + else + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_CANCELLED),true); + } + break; - default: break; - } + default: break; } } diff --git a/retroshare-gui/src/gui/People/PeopleDialog.cpp b/retroshare-gui/src/gui/People/PeopleDialog.cpp index b90b2cfe9..c1ebd6329 100644 --- a/retroshare-gui/src/gui/People/PeopleDialog.cpp +++ b/retroshare-gui/src/gui/People/PeopleDialog.cpp @@ -287,9 +287,11 @@ void PeopleDialog::insertCircles(uint32_t token) continue ; }//if(!rsGxsCircles->getCircleDetails(RsGxsCircleId(git->mGroupId), details)) - if (details.mCircleType != GXS_CIRCLE_TYPE_EXTERNAL){ + if (details.mCircleType != RsGxsCircleType::EXTERNAL) + { std::map::iterator itFound; - if((itFound=_int_circles_widgets.find(gsItem.mGroupId)) == _int_circles_widgets.end()) { + if((itFound=_int_circles_widgets.find(gsItem.mGroupId)) == _int_circles_widgets.end()) + { std::cerr << "PeopleDialog::insertExtCircles() add new Internal GroupId: " << gsItem.mGroupId; std::cerr << " GroupName: " << gsItem.mGroupName; std::cerr << std::endl; @@ -307,7 +309,9 @@ void PeopleDialog::insertCircles(uint32_t token) QPixmap pixmap = gitem->getImage(); pictureFlowWidgetInternal->addSlide( pixmap ); _intListCir << gitem; - } else {//if((itFound=_int_circles_widgets.find(gsItem.mGroupId)) == _int_circles_widgets.end()) + } + else + { std::cerr << "PeopleDialog::insertExtCircles() Update GroupId: " << gsItem.mGroupId; std::cerr << " GroupName: " << gsItem.mGroupName; std::cerr << std::endl; @@ -318,8 +322,10 @@ void PeopleDialog::insertCircles(uint32_t token) //int index = _intListCir.indexOf(cirWidget); //QPixmap pixmap = cirWidget->getImage(); //pictureFlowWidgetInternal->setSlide(index, pixmap); - }//if((item=_int_circles_widgets.find(gsItem.mGroupId)) == _int_circles_widgets.end()) - } else {//if (!details.mIsExternal) + } + } + else + { std::map::iterator itFound; if((itFound=_ext_circles_widgets.find(gsItem.mGroupId)) == _ext_circles_widgets.end()) { std::cerr << "PeopleDialog::insertExtCircles() add new GroupId: " << gsItem.mGroupId; @@ -339,7 +345,9 @@ void PeopleDialog::insertCircles(uint32_t token) QPixmap pixmap = gitem->getImage(); pictureFlowWidgetExternal->addSlide( pixmap ); _extListCir << gitem; - } else {//if((itFound=_circles_widgets.find(gsItem.mGroupId)) == _circles_widgets.end()) + } + else + { std::cerr << "PeopleDialog::insertExtCircles() Update GroupId: " << gsItem.mGroupId; std::cerr << " GroupName: " << gsItem.mGroupName; std::cerr << std::endl; @@ -350,9 +358,9 @@ void PeopleDialog::insertCircles(uint32_t token) //int index = _extListCir.indexOf(cirWidget); //QPixmap pixmap = cirWidget->getImage(); //pictureFlowWidgetExternal->setSlide(index, pixmap); - }//if((item=_circles_items.find(gsItem.mGroupId)) == _circles_items.end()) - }//else (!details.mIsExternal) - }//for(gsIt = gSummaryList.begin(); gsIt != gSummaryList.end(); ++gsIt) + } + } + } } void PeopleDialog::requestIdList() diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp index 4ba0f48c6..4d4f3e031 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp @@ -77,34 +77,31 @@ void GxsCircleItem::setup() /* update circle information */ + ui->acceptButton->setToolTip(tr("Grant membership request")); + ui->revokeButton->setToolTip(tr("Revoke membership request")); + + connect(ui->acceptButton, SIGNAL(clicked()), this, SLOT(grantCircleMembership())); + connect(ui->revokeButton, SIGNAL(clicked()), this, SLOT(revokeCircleMembership())); + RsGxsCircleDetails circleDetails; if (rsGxsCircles->getCircleDetails(mCircleId, circleDetails)) { + // from here we can figure out if we already have requested membership or not if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REQ) { - ui->titleLabel->setText(tr("You received a membership request for circle:")); + ui->titleLabel->setText(tr("You received a membership request a circle you're administrating:")); ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); - if(circleDetails.mAmIAdmin) - { - ui->acceptButton->setToolTip(tr("Grant membership request")); - ui->revokeButton->setToolTip(tr("Revoke membership request")); - connect(ui->acceptButton, SIGNAL(clicked()), this, SLOT(grantCircleMembership())); - connect(ui->revokeButton, SIGNAL(clicked()), this, SLOT(revokeCircleMembership())); - } - else - { - ui->acceptButton->setEnabled(false); - ui->revokeButton->setEnabled(false); - } + ui->revokeButton->setHidden(true); + ui->acceptButton->setHidden(false); } - else if (mType == RS_FEED_ITEM_CIRCLE_INVIT_REC) + else if (mType == RS_FEED_ITEM_CIRCLE_INVITE_REC) { - ui->titleLabel->setText(tr("You received an invitation for circle:")); + ui->titleLabel->setText(tr("You received an invitation for this circle:")); ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); @@ -116,7 +113,7 @@ void GxsCircleItem::setup() } else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_LEAVE) { - ui->titleLabel->setText(idName + tr(" has left this circle you belong to.")); + ui->titleLabel->setText(idName + tr(" has left this circle.")); ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); @@ -127,21 +124,18 @@ void GxsCircleItem::setup() } else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_JOIN) { - ui->titleLabel->setText(idName + tr(" has join this circle you also belong to.")); + ui->titleLabel->setText(idName + tr(" which you invited, has join this circle you're administrating.")); ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); ui->acceptButton->setHidden(true); - ui->revokeButton->setHidden(true); + ui->revokeButton->setHidden(false); } else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REVOKED) { - if(rsIdentity->isOwnId(mGxsId)) - ui->titleLabel->setText(tr("Your identity %1 has been revoqued from this circle.").arg(idName)); - else - ui->titleLabel->setText(tr("Identity %1 has been revoqued from this circle you belong to.").arg(idName)); + ui->titleLabel->setText(tr("Your identity %1 has been revoked from this circle.").arg(idName)); ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); ui->gxsIdLabel->setText(idName); @@ -151,6 +145,19 @@ void GxsCircleItem::setup() ui->acceptButton->setHidden(true); ui->revokeButton->setHidden(true); } + else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED) + { + ui->titleLabel->setText(tr("Your identity %1 as been accepted in this circle.").arg(idName)); + + ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); + ui->gxsIdLabel->setText(idName); + ui->iconLabel->setPixmap(pixmap); + ui->gxsIdLabel->setId(mGxsId); + + ui->acceptButton->setHidden(true); + ui->revokeButton->setHidden(true); + } + } else { From efb26ce9c00669dc6e941732e65441bbf58fc713 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 2 May 2020 15:48:38 +0200 Subject: [PATCH 12/79] added warnign when notified CircleMsg cannot be retrieved from DB --- libretroshare/src/services/p3gxscircles.cc | 33 ++++++++++--------- .../src/gui/People/PeopleDialog.cpp | 10 +++--- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 97b19151e..7f3d1bf5e 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -559,22 +559,25 @@ void p3GxsCircles::notifyChanges(std::vector &changes) for (auto msgIdIt(mit->second.begin()), end(mit->second.end()); msgIdIt != end; ++msgIdIt) { RsGxsCircleMsg msg; - getCircleRequest(RsGxsGroupId(circle_id),*msgIdIt,msg); + if(getCircleRequest(RsGxsGroupId(circle_id),*msgIdIt,msg)) + { + auto ev = std::make_shared(); + ev->mCircleId = circle_id; + ev->mGxsId = msg.mMeta.mAuthorId; - auto ev = std::make_shared(); - ev->mCircleId = circle_id; - ev->mGxsId = msg.mMeta.mAuthorId; - - if (msg.stuff == "SUBSCRIPTION_REQUEST_UNSUBSCRIBE") - { - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE; - rsEvents->postEvent(ev); - } - else if(msg.stuff == "SUBSCRIPTION_REQUEST_SUBSCRIBE") - { - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST; - rsEvents->postEvent(ev); - } + if (msg.stuff == "SUBSCRIPTION_REQUEST_UNSUBSCRIBE") + { + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE; + rsEvents->postEvent(ev); + } + else if(msg.stuff == "SUBSCRIPTION_REQUEST_SUBSCRIBE") + { + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST; + rsEvents->postEvent(ev); + } + } + else + RsErr()<< __PRETTY_FUNCTION__<<" Cannot request CircleMsg " << *msgIdIt << ". Db not ready?" << std::endl; } mCircleCache.erase(circle_id); diff --git a/retroshare-gui/src/gui/People/PeopleDialog.cpp b/retroshare-gui/src/gui/People/PeopleDialog.cpp index c1ebd6329..5d6b9ee84 100644 --- a/retroshare-gui/src/gui/People/PeopleDialog.cpp +++ b/retroshare-gui/src/gui/People/PeopleDialog.cpp @@ -271,21 +271,23 @@ void PeopleDialog::insertCircles(uint32_t token) std::list gSummaryList; std::list::iterator gsIt; - if (!rsGxsCircles->getGroupSummary(token,gSummaryList)) { + if (!rsGxsCircles->getGroupSummary(token,gSummaryList)) + { std::cerr << "PeopleDialog::insertExtCircles() Error getting GroupSummary"; std::cerr << std::endl; return; - }//if (!rsGxsCircles->getGroupSummary(token,gSummaryList)) + } for(gsIt = gSummaryList.begin(); gsIt != gSummaryList.end(); ++gsIt) { RsGroupMetaData gsItem = (*gsIt); RsGxsCircleDetails details ; - if(!rsGxsCircles->getCircleDetails(RsGxsCircleId(gsItem.mGroupId), details)){ + if(!rsGxsCircles->getCircleDetails(RsGxsCircleId(gsItem.mGroupId), details)) + { std::cerr << "(EE) Cannot get details for circle id " << gsItem.mGroupId << ". Circle item is not created!" << std::endl; continue ; - }//if(!rsGxsCircles->getCircleDetails(RsGxsCircleId(git->mGroupId), details)) + } if (details.mCircleType != RsGxsCircleType::EXTERNAL) { From ce6abe5d66d77a256c3b3467fe5978e9e05520cf Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 3 May 2020 23:20:13 +0200 Subject: [PATCH 13/79] made GxsNotify for messages with more granularity. Removed RsGxsCircleMsg class that was not used. --- libretroshare/src/gxs/rsgenexchange.cc | 110 +++++++---------- libretroshare/src/gxs/rsgxsdataaccess.cc | 2 +- libretroshare/src/gxs/rsgxsnotify.h | 32 +++-- libretroshare/src/gxstrans/p3gxstrans.cc | 19 ++- libretroshare/src/retroshare/rsgxscircles.h | 12 +- .../src/retroshare/rsgxsifacetypes.h | 2 - libretroshare/src/retroshare/rsids.h | 1 + libretroshare/src/retroshare/rstypes.h | 1 - libretroshare/src/rsitems/rsgxscircleitems.cc | 18 +-- libretroshare/src/rsitems/rsgxscircleitems.h | 10 +- libretroshare/src/services/p3gxschannels.cc | 60 +++++----- libretroshare/src/services/p3gxscircles.cc | 113 ++++++++---------- libretroshare/src/services/p3gxscircles.h | 2 +- libretroshare/src/services/p3gxsforums.cc | 15 +-- libretroshare/src/services/p3idservice.cc | 17 +-- libretroshare/src/services/p3postbase.cc | 82 ++++--------- libretroshare/src/services/p3postbase.h | 2 +- .../gui/gxschannels/GxsChannelFilesWidget.cpp | 2 + retroshare-gui/src/gui/msgs/MessageModel.h | 1 - 19 files changed, 217 insertions(+), 284 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 18f62a4a3..aa2526548 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -238,9 +238,7 @@ void RsGenExchange::tick() { for(auto& groupId:grpIds) { - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_MESSAGES_DELETED, false); - - gc->mGroupId = groupId; + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_GROUP_DELETED,groupId, false); #ifdef GEN_EXCH_DEBUG std::cerr << " adding the following grp ids to notification: " << std::endl; @@ -256,12 +254,12 @@ void RsGenExchange::tick() mNetService->removeGroups(grpIds) ; } - if (!msgIds.empty()) - { - RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, false); - c->msgChangeMap = msgIds; - mNotifications.push_back(c); - } + for(auto it(msgIds.begin());it!=msgIds.end();++it) + for(auto& msgId:it->second) + { + RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_MESSAGE_DELETED,it->first, msgId, false); + mNotifications.push_back(c); + } delete mIntegrityCheck; mIntegrityCheck = NULL; @@ -775,7 +773,7 @@ int RsGenExchange::createMessage(RsNxsMsg* msg) hash.addData(allMsgData, allMsgDataLen); RsFileHash hashId; hash.Complete(hashId); - msg->msgId = hashId; + msg->msgId = RsGxsMessageId(hashId); // assign msg id to msg meta msg->metaData->mMsgId = msg->msgId; @@ -1690,9 +1688,7 @@ void RsGenExchange::notifyReceivePublishKey(const RsGxsGroupId &grpId) { RS_STACK_MUTEX(mGenMtx); - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY, true); - gc->mGroupId = grpId; - + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY,grpId, true); mNotifications.push_back(gc); } @@ -1700,8 +1696,7 @@ void RsGenExchange::notifyChangedGroupStats(const RsGxsGroupId &grpId) { RS_STACK_MUTEX(mGenMtx); - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_STATISTICS_CHANGED, false); - gc->mGroupId = grpId; + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_STATISTICS_CHANGED,grpId, false); mNotifications.push_back(gc); } @@ -2058,11 +2053,13 @@ void RsGenExchange::processMsgMetaChanges() } } - if (!msgIds.empty()) { + if (!msgIds.empty()) + { RS_STACK_MUTEX(mGenMtx); - RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, false); - c->msgChangeMap = msgIds; - mNotifications.push_back(c); + + for(auto it(msgIds.begin());it!=msgIds.end();++it) + for(auto& msg_id:it->second) + mNotifications.push_back(new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, it->first, msg_id, false)); } } @@ -2112,15 +2109,7 @@ void RsGenExchange::processGrpMetaChanges() { RS_STACK_MUTEX(mGenMtx); - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PROCESSED, true); - gc->mGroupId = groupId; - - mNotifications.push_back(gc); -#ifdef GEN_EXCH_DEBUG - std::cerr << " adding the following grp ids to notification: " << std::endl; - for(std::list::const_iterator it(grpChanged.begin());it!=grpChanged.end();++it) - std::cerr << " " << *it << std::endl; -#endif + mNotifications.push_back(new RsGxsGroupChange(RsGxsNotify::TYPE_PROCESSED,groupId, true)); } } @@ -2197,7 +2186,7 @@ void RsGenExchange::publishMsgs() mMsgsToPublish.insert(std::make_pair(sign_it->first, item.mItem)); } - std::map > msgChangeMap; + std::map > msgChangeMap; std::map::iterator mit = mMsgsToPublish.begin(); for(; mit != mMsgsToPublish.end(); ++mit) @@ -2326,9 +2315,12 @@ void RsGenExchange::publishMsgs() mPublishedMsgs[token] = *msg->metaData; + RsGxsMsgItem *msg_item = dynamic_cast(mSerialiser->deserialise(msg->msg.bin_data,&msg->msg.bin_len)) ; + msg_item->meta = *msg->metaData; + delete msg ; - msgChangeMap[grpId].insert(msgId); + msgChangeMap[grpId].push_back(msg_item); delete[] metaDataBuff; @@ -2367,13 +2359,14 @@ void RsGenExchange::publishMsgs() // entries are invalid mMsgsToPublish.clear(); - if(!msgChangeMap.empty()) - { - RsGxsMsgChange* ch = new RsGxsMsgChange(RsGxsNotify::TYPE_PUBLISHED, false); - ch->msgChangeMap = msgChangeMap; - mNotifications.push_back(ch); - } + for(auto it(msgChangeMap.begin());it!=msgChangeMap.end();++it) + for(auto& msg_item: it->second) + { + RsGxsMsgChange* ch = new RsGxsMsgChange(RsGxsNotify::TYPE_PUBLISHED,msg_item->meta.mGroupId, msg_item->meta.mMsgId, false); + ch->mNewMsgItem = msg_item; + mNotifications.push_back(ch); + } } RsGenExchange::ServiceCreate_Return RsGenExchange::service_CreateGroup(RsGxsGrpItem* /* grpItem */, @@ -2507,9 +2500,7 @@ void RsGenExchange::processGroupDelete() for(auto& groupId:grpDeleted) { - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_GROUP_DELETED, false); - gc->mGroupId = groupId; - + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_GROUP_DELETED, groupId,false); mNotifications.push_back(gc); } @@ -2551,12 +2542,7 @@ void RsGenExchange::processMessageDelete() for(uint32_t i=0;imGroupId = it->first; - - mNotifications.push_back(gc); - } + mNotifications.push_back(new RsGxsGroupChange(RsGxsNotify::TYPE_MESSAGE_DELETED,it->first, false)); mMsgDeletePublish.clear(); } @@ -2817,18 +2803,7 @@ void RsGenExchange::publishGrps() } for(auto& groupId:grpChanged) - { - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, true); - - gc->mGroupId = groupId; - - mNotifications.push_back(gc); -#ifdef GEN_EXCH_DEBUG - std::cerr << " adding the following grp ids to notification: " << std::endl; - for(std::list::const_iterator it(grpChanged.begin());it!=grpChanged.end();++it) - std::cerr << " " << *it << std::endl; -#endif - } + mNotifications.push_back(new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW,groupId, true)); } // This is done off-mutex to avoid possible cross deadlocks with the net service. @@ -3085,11 +3060,19 @@ void RsGenExchange::processRecvdMessages() #ifdef GEN_EXCH_DEBUG std::cerr << " storing remaining messages" << std::endl; #endif - mDataStore->storeMessage(msgs_to_store); - RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_RECEIVED_NEW, false); - c->msgChangeMap = msgIds; - mNotifications.push_back(c); + for(auto& nxs_msg: msgs_to_store) + { + RsGxsMsgItem *item = dynamic_cast(mSerialiser->deserialise(nxs_msg->msg.bin_data,&nxs_msg->msg.bin_len)); + item->meta = *nxs_msg->metaData; + + RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_RECEIVED_NEW, item->meta.mGroupId, item->meta.mMsgId,false); + c->mNewMsgItem = item; + + mNotifications.push_back(c); + } + + mDataStore->storeMessage(msgs_to_store); // we do that late because it destroys the items in msgs_to_store } } @@ -3222,9 +3205,8 @@ void RsGenExchange::processRecvdGroups() { for(auto Grp:grps_to_store) { - RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, false); + RsGxsGroupChange* c = new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW, Grp->grpId, false); - c->mGroupId = Grp->grpId; c->mNewGroupItem = dynamic_cast(mSerialiser->deserialise(Grp->grp.bin_data,&Grp->grp.bin_len)); mNotifications.push_back(c); @@ -3304,7 +3286,7 @@ void RsGenExchange::performUpdateValidation() // Now prepare notification of the client - RsGxsGroupChange *c = new RsGxsGroupChange(RsGxsNotify::TYPE_UPDATED,false); + RsGxsGroupChange *c = new RsGxsGroupChange(RsGxsNotify::TYPE_UPDATED,gu.newGrp->metaData->mGroupId,false); c->mNewGroupItem = dynamic_cast(mSerialiser->deserialise(gu.newGrp->grp.bin_data,&gu.newGrp->grp.bin_len)); c->mNewGroupItem->meta = *gu.newGrp->metaData; // gu.newGrp will be deleted because mDataStore will destroy it on update diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index d4cc5de84..6104b0b56 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -1038,7 +1038,7 @@ bool RsGxsDataAccess::getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokRe // Because msgs are stored in a std::vector we build a map to convert each vector to its position in metaV. std::vector keep(metaV.size(),true); // this vector will tell wether we keep or not a given Meta - std::map index_in_metaV; // holds the index of each group Id in metaV + std::map index_in_metaV; // holds the index of each group Id in metaV for(uint32_t i=0;imMsgId] = i; diff --git a/libretroshare/src/gxs/rsgxsnotify.h b/libretroshare/src/gxs/rsgxsnotify.h index 0e6d39877..5bd7e2cb3 100644 --- a/libretroshare/src/gxs/rsgxsnotify.h +++ b/libretroshare/src/gxs/rsgxsnotify.h @@ -20,14 +20,22 @@ * * *******************************************************************************/ +#pragma once + /*! * The aim of this class is to implement notifications internally to GXS, which are * mostly used by RsGenExchange to send information to specific services. These services * then interpret these changes and turn them into human-readable/processed service-specific changes. */ -struct RsGxsNotify +#include "retroshare/rsids.h" + +class RsGxsNotify { +public: + RsGxsNotify(const RsGxsGroupId& gid): mGroupId(gid){} + virtual ~RsGxsNotify()=default; + enum NotifyType { TYPE_UNKNOWN = 0x00, @@ -38,12 +46,14 @@ struct RsGxsNotify TYPE_RECEIVED_DISTANT_SEARCH_RESULTS = 0x05, TYPE_STATISTICS_CHANGED = 0x06, TYPE_UPDATED = 0x07, - TYPE_MESSAGES_DELETED = 0x08, + TYPE_MESSAGE_DELETED = 0x08, TYPE_GROUP_DELETED = 0x09, }; - virtual ~RsGxsNotify() {} virtual NotifyType getType() = 0; + + RsGxsGroupId mGroupId; // Group id of the group we're talking about. When the group is deleted, it's useful to know which group + // that was although there is no pointers to the actual group data anymore. }; /*! @@ -52,14 +62,12 @@ struct RsGxsNotify class RsGxsGroupChange : public RsGxsNotify { public: - RsGxsGroupChange(NotifyType type, bool metaChange) : mNewGroupItem(nullptr),mOldGroupItem(nullptr), mNotifyType(type), mMetaChange(metaChange) {} - virtual ~RsGxsGroupChange() { delete mOldGroupItem; delete mNewGroupItem ; } + RsGxsGroupChange(NotifyType type, const RsGxsGroupId& gid,bool metaChange) : RsGxsNotify(gid),mNewGroupItem(nullptr),mOldGroupItem(nullptr), mNotifyType(type), mMetaChange(metaChange) {} + virtual ~RsGxsGroupChange() override { delete mOldGroupItem; delete mNewGroupItem ; } NotifyType getType() override { return mNotifyType;} bool metaChange() { return mMetaChange; } - RsGxsGroupId mGroupId; // Group id of the group we're talking about. When the group is deleted, it's useful to know which group - // that was although there is no pointers to the actual group data anymore. RsGxsGrpItem *mNewGroupItem; // Valid when a group has changed, or a new group is received. RsGxsGrpItem *mOldGroupItem; // only valid when mNotifyType is TYPE_UPDATED @@ -71,12 +79,11 @@ protected: class RsGxsDistantSearchResultChange: public RsGxsNotify { public: - RsGxsDistantSearchResultChange(TurtleRequestId id,const RsGxsGroupId& group_id) : mRequestId(id),mGroupId(group_id){} + RsGxsDistantSearchResultChange(TurtleRequestId id,const RsGxsGroupId& gid) : RsGxsNotify(gid), mRequestId(id){} NotifyType getType() { return TYPE_RECEIVED_DISTANT_SEARCH_RESULTS ; } TurtleRequestId mRequestId ; - RsGxsGroupId mGroupId; }; /*! @@ -85,8 +92,11 @@ public: class RsGxsMsgChange : public RsGxsNotify { public: - RsGxsMsgChange(NotifyType type, bool metaChange) : NOTIFY_TYPE(type), mMetaChange(metaChange) {} - std::map > msgChangeMap; + RsGxsMsgChange(NotifyType type, const RsGxsGroupId& gid, const RsGxsMessageId& msg_id,bool metaChange) : RsGxsNotify(gid), mNewMsgItem(nullptr),NOTIFY_TYPE(type), mMetaChange(metaChange) {} + + RsGxsMessageId mMsgId; + RsGxsMsgItem *mNewMsgItem; + NotifyType getType(){ return NOTIFY_TYPE;} bool metaChange() { return mMetaChange; } private: diff --git a/libretroshare/src/gxstrans/p3gxstrans.cc b/libretroshare/src/gxstrans/p3gxstrans.cc index b85bcea9a..391a38e50 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.cc +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -657,6 +657,7 @@ void p3GxsTrans::notifyChanges(std::vector& changes) std::cout << "p3GxsTrans::notifyChanges(...)" << std::endl; #endif std::list grps_to_request; + GxsMsgReq msgs_to_request; for( auto it = changes.begin(); it != changes.end(); ++it ) { @@ -675,11 +676,8 @@ void p3GxsTrans::notifyChanges(std::vector& changes) #ifdef DEBUG_GXSTRANS std::cout << "p3GxsTrans::notifyChanges(...) msgChange" << std::endl; #endif - uint32_t token; - RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - RsGenExchange::getTokenService()->requestMsgInfo( token, 0xcaca, - opts, msgChange->msgChangeMap ); - GxsTokenQueue::queueRequest(token, MAILS_UPDATE); + + msgs_to_request[msgChange->mGroupId].insert(msgChange->mMsgId); #ifdef DEBUG_GXSTRANS for( GxsMsgReq::const_iterator it = msgChange->msgChangeMap.begin(); @@ -701,6 +699,17 @@ void p3GxsTrans::notifyChanges(std::vector& changes) delete *it; } + if(!msgs_to_request.empty()) + { + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + RsGenExchange::getTokenService()->requestMsgInfo( token, 0xcaca, opts, msgs_to_request); + + GxsTokenQueue::queueRequest(token, MAILS_UPDATE); + } + + if(!grps_to_request.empty()) requestGroupsData(&grps_to_request); } diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index 5120d5674..ebe5a0131 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -96,22 +96,32 @@ struct RsGxsCircleGroup : RsSerializable ~RsGxsCircleGroup() override; }; +enum class RsGxsCircleSubscriptionType:uint8_t { + UNKNOWN = 0x00, + SUBSCRIBE = 0x01, + UNSUBSCRIBE = 0x02 +}; + struct RsGxsCircleMsg : RsSerializable { RsMsgMetaData mMeta; +#ifdef TO_REMOVE + // This item is actually totally unused, so we can change it no problem #ifndef V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED /* This is horrible and should be changed into yet to be defined something * reasonable in next non-retrocompatible version */ std::string stuff; #endif +#endif + RsGxsCircleSubscriptionType mSubscriptionType; /// @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override { RS_SERIAL_PROCESS(mMeta); - RS_SERIAL_PROCESS(stuff); + RS_SERIAL_PROCESS(mSubscriptionType); } ~RsGxsCircleMsg() override; diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index 038906317..2550f3b82 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -34,8 +34,6 @@ #include "serialiser/rstypeserializer.h" #include "util/rstime.h" -typedef Sha1CheckSum RsGxsMessageId; - typedef std::map > GxsMsgIdResult; typedef std::pair RsGxsGrpMsgIdPair; typedef std::map > MsgRelatedIdResult; diff --git a/libretroshare/src/retroshare/rsids.h b/libretroshare/src/retroshare/rsids.h index 8c2cdc51e..d38ee4518 100644 --- a/libretroshare/src/retroshare/rsids.h +++ b/libretroshare/src/retroshare/rsids.h @@ -328,6 +328,7 @@ using Sha256CheckSum = t_RsGenericIdType<_RsIdSize::SHA256 , false, R using RsPgpFingerprint = t_RsGenericIdType<_RsIdSize::PGP_FINGERPRINT, true, RsGenericIdType::PGP_FINGERPRINT>; using Bias20Bytes = t_RsGenericIdType<_RsIdSize::SHA1 , true, RsGenericIdType::BIAS_20_BYTES >; using RsGxsGroupId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_GROUP >; +using RsGxsMessageId = t_RsGenericIdType<_RsIdSize::SHA1 , false, RsGenericIdType::GXS_MSG >; using RsGxsId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_ID >; using RsGxsCircleId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_CIRCLE >; using RsGxsTunnelId = t_RsGenericIdType<_RsIdSize::SSL_ID , false, RsGenericIdType::GXS_TUNNEL >; diff --git a/libretroshare/src/retroshare/rstypes.h b/libretroshare/src/retroshare/rstypes.h index 2daa25947..59474c99c 100644 --- a/libretroshare/src/retroshare/rstypes.h +++ b/libretroshare/src/retroshare/rstypes.h @@ -38,7 +38,6 @@ #define USE_NEW_CHUNK_CHECKING_CODE typedef Sha1CheckSum RsFileHash ; -typedef Sha1CheckSum RsMessageId ; const uint32_t FT_STATE_FAILED = 0x0000 ; const uint32_t FT_STATE_OKAY = 0x0001 ; diff --git a/libretroshare/src/rsitems/rsgxscircleitems.cc b/libretroshare/src/rsitems/rsgxscircleitems.cc index 0acdd03de..f93068b5b 100644 --- a/libretroshare/src/rsitems/rsgxscircleitems.cc +++ b/libretroshare/src/rsitems/rsgxscircleitems.cc @@ -35,7 +35,9 @@ RsItem *RsGxsCircleSerialiser::create_item(uint16_t service, uint8_t item_sub_id switch(item_sub_id) { case RS_PKT_SUBTYPE_GXSCIRCLE_GROUP_ITEM: return new RsGxsCircleGroupItem(); +#ifdef TO_REMOVE case RS_PKT_SUBTYPE_GXSCIRCLE_MSG_ITEM: return new RsGxsCircleMsgItem(); +#endif case RS_PKT_SUBTYPE_GXSCIRCLE_SUBSCRIPTION_REQUEST_ITEM: return new RsGxsCircleSubscriptionRequestItem(); default: return NULL ; @@ -46,20 +48,27 @@ void RsGxsCircleSubscriptionRequestItem::clear() { time_stamp = 0 ; time_out = 0 ; - subscription_type = SUBSCRIPTION_REQUEST_UNKNOWN; + subscription_type = RsGxsCircleSubscriptionType::UNKNOWN; } +#ifdef TO_REMOVE void RsGxsCircleMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { //RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_MSG,mMsg.stuff,"mMsg.stuff") ;//Should be this but not retrocompatible... RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_MSG,mMsg.stuff,"msg.stuff") ; } +void RsGxsCircleMsgItem::clear() +{ + mMsg.stuff.clear(); +} +#endif + void RsGxsCircleSubscriptionRequestItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process(j,ctx,time_stamp,"time_stamp") ; RsTypeSerializer::serial_process(j,ctx,time_out ,"time_out") ; - RsTypeSerializer::serial_process (j,ctx,subscription_type ,"subscription_type") ; + RsTypeSerializer::serial_process (j,ctx,subscription_type ,"subscription_type") ; } void RsGxsCircleGroupItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) @@ -69,11 +78,6 @@ void RsGxsCircleGroupItem::serial_process(RsGenericSerializer::SerializeJob j,Rs RsTypeSerializer::serial_process(j,ctx,subCircleSet,"subCircleSet") ; } -void RsGxsCircleMsgItem::clear() -{ - mMsg.stuff.clear(); -} - void RsGxsCircleGroupItem::clear() { pgpIdSet.TlvClear(); diff --git a/libretroshare/src/rsitems/rsgxscircleitems.h b/libretroshare/src/rsitems/rsgxscircleitems.h index 6338fb368..fb720e070 100644 --- a/libretroshare/src/rsitems/rsgxscircleitems.h +++ b/libretroshare/src/rsitems/rsgxscircleitems.h @@ -64,6 +64,7 @@ public: RsTlvGxsCircleIdSet subCircleSet; }; +#ifdef TO_REMOVE class RsGxsCircleMsgItem : public RsGxsMsgItem { public: @@ -76,6 +77,7 @@ public: RsGxsCircleMsg mMsg; }; +#endif class RsGxsCircleSubscriptionRequestItem: public RsGxsMsgItem { @@ -86,17 +88,11 @@ public: void clear(); - enum { - SUBSCRIPTION_REQUEST_UNKNOWN = 0x00, - SUBSCRIPTION_REQUEST_SUBSCRIBE = 0x01, - SUBSCRIPTION_REQUEST_UNSUBSCRIBE = 0x02 - }; - virtual void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx); uint32_t time_stamp ; uint32_t time_out ; - uint8_t subscription_type ; + RsGxsCircleSubscriptionType subscription_type ; }; class RsGxsCircleSerialiser : public RsServiceSerializer diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 40df82862..09004167d 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -239,7 +239,7 @@ void p3GxsChannels::notifyChanges(std::vector &changes) #endif /* iterate through and grab any new messages */ - std::list unprocessedGroups; + std::set unprocessedGroups; std::vector::iterator it; for(it = changes.begin(); it != changes.end(); ++it) @@ -253,16 +253,12 @@ void p3GxsChannels::notifyChanges(std::vector &changes) /* message received */ if (rsEvents) { - std::map > &msgChangeMap = msgChange->msgChangeMap; - for (auto mit = msgChangeMap.begin(); mit != msgChangeMap.end(); ++mit) - for (auto mit1 = mit->second.begin(); mit1 != mit->second.end(); ++mit1) - { - auto ev = std::make_shared(); - ev->mChannelMsgId = *mit1; - ev->mChannelGroupId = mit->first; - ev->mChannelEventCode = RsChannelEventCode::NEW_MESSAGE; - rsEvents->postEvent(ev); - } + auto ev = std::make_shared(); + + ev->mChannelMsgId = msgChange->mMsgId; + ev->mChannelGroupId = msgChange->mGroupId; + ev->mChannelEventCode = RsChannelEventCode::NEW_MESSAGE; + rsEvents->postEvent(ev); } } @@ -273,25 +269,21 @@ void p3GxsChannels::notifyChanges(std::vector &changes) std::cerr << std::endl; #endif - std::map > &msgChangeMap = msgChange->msgChangeMap; - for(auto mit = msgChangeMap.begin(); mit != msgChangeMap.end(); ++mit) +#ifdef GXSCHANNELS_DEBUG + std::cerr << "p3GxsChannels::notifyChanges() Msgs for Group: " << mit->first; + std::cerr << std::endl; +#endif { #ifdef GXSCHANNELS_DEBUG - std::cerr << "p3GxsChannels::notifyChanges() Msgs for Group: " << mit->first; + std::cerr << "p3GxsChannels::notifyChanges() AutoDownload for Group: " << mit->first; std::cerr << std::endl; #endif - bool enabled = false; - if (autoDownloadEnabled(mit->first, enabled) && enabled) - { -#ifdef GXSCHANNELS_DEBUG - std::cerr << "p3GxsChannels::notifyChanges() AutoDownload for Group: " << mit->first; - std::cerr << std::endl; -#endif - /* problem is most of these will be comments and votes, - * should make it occasional - every 5mins / 10minutes TODO */ - unprocessedGroups.push_back(mit->first); - } + /* problem is most of these will be comments and votes, should make it occasional - every 5mins / 10minutes TODO */ + // We do not call if(autoDownLoadEnabled()) here, because it would be too costly when + // many msgs are received from the same group. We back the groupIds and then request one by one. + + unprocessedGroups.insert(msgChange->mGroupId); } } } @@ -376,8 +368,16 @@ void p3GxsChannels::notifyChanges(std::vector &changes) delete *it; } - if(!unprocessedGroups.empty()) - request_SpecificSubscribedGroups(unprocessedGroups); + std::list grps; + for(auto& grp_id:unprocessedGroups) + { + bool enabled = false; + if (autoDownloadEnabled(grp_id, enabled) && enabled) // costly call, that's why it's packed down here. + grps.push_back(grp_id); + } + + if(!grps.empty()) + request_SpecificSubscribedGroups(grps); } void p3GxsChannels::service_tick() @@ -705,8 +705,7 @@ void p3GxsChannels::request_AllSubscribedGroups() } -void p3GxsChannels::request_SpecificSubscribedGroups( - const std::list &groups ) +void p3GxsChannels::request_SpecificSubscribedGroups( const std::list &groups ) { #ifdef GXSCHANNELS_DEBUG std::cerr << "p3GxsChannels::request_SpecificSubscribedGroups()"; @@ -719,8 +718,7 @@ void p3GxsChannels::request_SpecificSubscribedGroups( uint32_t token = 0; - if(!RsGenExchange::getTokenService()-> - requestGroupInfo(token, ansType, opts, groups)) + if(!RsGenExchange::getTokenService()-> requestGroupInfo(token, ansType, opts, groups)) { std::cerr << __PRETTY_FUNCTION__ << " Failed requesting groups info!" << std::endl; diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 7f3d1bf5e..0b1ac5270 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -535,57 +535,51 @@ void p3GxsCircles::notifyChanges(std::vector &changes) for(auto it = changes.begin(); it != changes.end(); ++it) { - RsGxsMsgChange *msgChange = dynamic_cast(*it); RsGxsNotify *c = *it; + RsGxsMsgChange *msgChange = dynamic_cast(c); if (msgChange) { #ifdef DEBUG_CIRCLES - std::cerr << " Found circle Message Change Notification" << std::endl; + std::cerr << " Found circle Message Change Notification for group " << msgChange->mGroupId << ", msg ID " << msgChange->mMsgId << std::endl; #endif - for(auto mit = msgChange->msgChangeMap.begin(); mit != msgChange->msgChangeMap.end(); ++mit) - { #ifdef DEBUG_CIRCLES - std::cerr << " Msgs for Group: " << mit->first << std::endl; + std::cerr << " Msgs for Group: " << mit->first << std::endl; #endif - RsGxsCircleId circle_id(mit->first); + RsGxsCircleId circle_id(msgChange->mGroupId); - force_cache_reload(circle_id); + if(rsEvents && (c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW)) + { + const RsGxsCircleSubscriptionRequestItem *item = dynamic_cast(msgChange->mNewMsgItem); - RsGxsCircleDetails details; - getCircleDetails(circle_id,details); + if(item) + { + auto ev = std::make_shared(); + ev->mCircleId = circle_id; + ev->mGxsId = msgChange->mNewMsgItem->meta.mAuthorId; - if(rsEvents && (c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW|| c->getType() == RsGxsNotify::TYPE_PUBLISHED) ) - for (auto msgIdIt(mit->second.begin()), end(mit->second.end()); msgIdIt != end; ++msgIdIt) + if (item->subscription_type == RsGxsCircleSubscriptionType::UNSUBSCRIBE) { - RsGxsCircleMsg msg; - if(getCircleRequest(RsGxsGroupId(circle_id),*msgIdIt,msg)) - { - auto ev = std::make_shared(); - ev->mCircleId = circle_id; - ev->mGxsId = msg.mMeta.mAuthorId; - - if (msg.stuff == "SUBSCRIPTION_REQUEST_UNSUBSCRIBE") - { - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE; - rsEvents->postEvent(ev); - } - else if(msg.stuff == "SUBSCRIPTION_REQUEST_SUBSCRIBE") - { - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST; - rsEvents->postEvent(ev); - } - } - else - RsErr()<< __PRETTY_FUNCTION__<<" Cannot request CircleMsg " << *msgIdIt << ". Db not ready?" << std::endl; + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE; + rsEvents->postEvent(ev); } - - mCircleCache.erase(circle_id); - mCacheUpdated = true; + else if(item->subscription_type == RsGxsCircleSubscriptionType::SUBSCRIBE) + { + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST; + rsEvents->postEvent(ev); + } + else + RsErr() << __PRETTY_FUNCTION__ << " Unknown subscription request type " << static_cast(item->subscription_type) << " in msg item" << std::endl; + } + else + RsErr() << __PRETTY_FUNCTION__ << ": missing SubscriptionRequestItem in msg notification for msg " << msgChange->mMsgId << std::endl; } + + mCircleCache.erase(circle_id); + mCacheUpdated = true; } - RsGxsGroupChange *groupChange = dynamic_cast(*it); + RsGxsGroupChange *groupChange = dynamic_cast(c); /* add groups to ExternalIdList (Might get Personal Circles here until NetChecks in place) */ if (groupChange) @@ -697,7 +691,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } } - delete *it; + delete c; } } @@ -930,8 +924,9 @@ bool p3GxsCircles::getMsgData(const uint32_t &token, std::vector for(; vit != msgItems.end(); ++vit) { +#ifdef TO_REMOVE RsGxsCircleMsgItem* item = dynamic_cast(*vit); - RsGxsCircleSubscriptionRequestItem* rsItem = dynamic_cast(*vit); + if(item) { RsGxsCircleMsg msg = item->mMsg; @@ -939,22 +934,16 @@ bool p3GxsCircles::getMsgData(const uint32_t &token, std::vector msgs.push_back(msg); delete item; } - else if (rsItem) +#endif + + RsGxsCircleSubscriptionRequestItem* rsItem = dynamic_cast(*vit); + + if (rsItem) { RsGxsCircleMsg msg ;//= rsItem->mMsg; msg.mMeta = rsItem->meta; - switch (rsItem->subscription_type) - { - case RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNKNOWN: - msg.stuff.clear(); - break; - case RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE: - msg.stuff="SUBSCRIPTION_REQUEST_SUBSCRIBE"; - break; - case RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNSUBSCRIBE: - msg.stuff="SUBSCRIPTION_REQUEST_UNSUBSCRIBE"; - break; - } + msg.mSubscriptionType = rsItem->subscription_type; + msgs.push_back(msg); delete rsItem; } @@ -2320,19 +2309,15 @@ void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel) bool p3GxsCircles::pushCircleMembershipRequest( const RsGxsId& own_gxsid, const RsGxsCircleId& circle_id, - uint32_t request_type ) + RsGxsCircleSubscriptionType request_type ) { Dbg3() << __PRETTY_FUNCTION__ << "own_gxsid = " << own_gxsid << ", circle=" << circle_id << ", req type=" << request_type << std::endl; - if( request_type != - RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE && - request_type != - RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNSUBSCRIBE ) + if( request_type != RsGxsCircleSubscriptionType::SUBSCRIBE && request_type != RsGxsCircleSubscriptionType::UNSUBSCRIBE ) { - RsErr() << __PRETTY_FUNCTION__ << " Unknown request type: " - << request_type << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " Unknown request type: " << static_cast(request_type) << std::endl; return false; } @@ -2368,7 +2353,7 @@ bool p3GxsCircles::pushCircleMembershipRequest( s->meta.mGroupId = RsGxsGroupId(circle_id) ; s->meta.mMsgId.clear(); - s->meta.mThreadId = RsDirUtil::sha1sum(tmpmem,tmpmem.size()); // make the ID from the hash of the cirle ID and the author ID + s->meta.mThreadId = RsGxsMessageId(RsDirUtil::sha1sum(tmpmem,tmpmem.size())); // make the ID from the hash of the cirle ID and the author ID s->meta.mAuthorId = own_gxsid; // msgItem->meta.mParentId = ; // leave these blank @@ -2382,7 +2367,7 @@ bool p3GxsCircles::pushCircleMembershipRequest( #endif uint32_t token ; - if(request_type == RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE) + if(request_type == RsGxsCircleSubscriptionType::SUBSCRIBE) RsGenExchange::subscribeToGroup(token, RsGxsGroupId(circle_id), true); RsGenExchange::publishMsg(token, s); @@ -2395,11 +2380,11 @@ bool p3GxsCircles::pushCircleMembershipRequest( bool p3GxsCircles::requestCircleMembership(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id) { - return pushCircleMembershipRequest(own_gxsid,circle_id,RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE) ; + return pushCircleMembershipRequest(own_gxsid,circle_id,RsGxsCircleSubscriptionType::SUBSCRIBE) ; } bool p3GxsCircles::cancelCircleMembership(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id) { - return pushCircleMembershipRequest(own_gxsid,circle_id,RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNSUBSCRIBE) ; + return pushCircleMembershipRequest(own_gxsid,circle_id,RsGxsCircleSubscriptionType::UNSUBSCRIBE) ; } @@ -2470,12 +2455,12 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) { info.last_subscription_TS = item->time_stamp ; - if(item->subscription_type == RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_SUBSCRIBE) + if(item->subscription_type == RsGxsCircleSubscriptionType::SUBSCRIBE) info.subscription_flags |= GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED; - else if(item->subscription_type == RsGxsCircleSubscriptionRequestItem::SUBSCRIPTION_REQUEST_UNSUBSCRIBE) + else if(item->subscription_type == RsGxsCircleSubscriptionType::UNSUBSCRIBE) info.subscription_flags &= ~GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED; else - std::cerr << " (EE) unknown subscription order type: " << item->subscription_type ; + std::cerr << " (EE) unknown subscription order type: " << static_cast(item->subscription_type) ; mCacheUpdated = true; #ifdef DEBUG_CIRCLES diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index e92ca5023..bad3eca3a 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -264,7 +264,7 @@ public: protected: - bool pushCircleMembershipRequest(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id,uint32_t request_type) ; + bool pushCircleMembershipRequest(const RsGxsId& own_gxsid, const RsGxsCircleId& circle_id, RsGxsCircleSubscriptionType request_type) ; static uint32_t circleAuthenPolicy(); /** Notifications **/ diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index b81a31479..85806d407 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -195,16 +195,11 @@ void p3GxsForums::notifyChanges(std::vector &changes) if (msgChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW || msgChange->getType() == RsGxsNotify::TYPE_PUBLISHED) /* message received */ if (rsEvents) { - std::map >& msgChangeMap = msgChange->msgChangeMap; - for (auto mit = msgChangeMap.begin(); mit != msgChangeMap.end(); ++mit) - for (auto mit1 = mit->second.begin(); mit1 != mit->second.end(); ++mit1) - { - auto ev = std::make_shared(); - ev->mForumMsgId = *mit1; - ev->mForumGroupId = mit->first; - ev->mForumEventCode = RsForumEventCode::NEW_MESSAGE; - rsEvents->postEvent(ev); - } + auto ev = std::make_shared(); + ev->mForumMsgId = msgChange->mMsgId; + ev->mForumGroupId = msgChange->mGroupId; + ev->mForumEventCode = RsForumEventCode::NEW_MESSAGE; + rsEvents->postEvent(ev); } #ifdef NOT_USED_YET diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 4c17a1dda..3ee089a97 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -606,22 +606,7 @@ void p3IdService::notifyChanges(std::vector &changes) RsGxsMsgChange *msgChange = dynamic_cast(changes[i]); if (msgChange && !msgChange->metaChange()) - { -#ifdef DEBUG_IDS - std::cerr << "p3IdService::notifyChanges() Found Message Change Notification"; - std::cerr << std::endl; -#endif - - std::map > &msgChangeMap = msgChange->msgChangeMap; - - for(auto mit = msgChangeMap.begin(); mit != msgChangeMap.end(); ++mit) - { -#ifdef DEBUG_IDS - std::cerr << "p3IdService::notifyChanges() Msgs for Group: " << mit->first; - std::cerr << std::endl; -#endif - } - } + RsWarn() << __PRETTY_FUNCTION__ << " Found a Msg data change in p3IdService. This is quite unexpected." << std::endl; RsGxsGroupChange *groupChange = dynamic_cast(changes[i]); diff --git a/libretroshare/src/services/p3postbase.cc b/libretroshare/src/services/p3postbase.cc index 9c11dcd64..c4c96f3b5 100644 --- a/libretroshare/src/services/p3postbase.cc +++ b/libretroshare/src/services/p3postbase.cc @@ -98,27 +98,22 @@ void p3PostBase::notifyChanges(std::vector &changes) std::cerr << std::endl; #endif - std::map > &msgChangeMap = msgChange->msgChangeMap; - for(auto mit = msgChangeMap.begin(); mit != msgChangeMap.end(); ++mit) - { #ifdef POSTBASE_DEBUG - std::cerr << "p3PostBase::notifyChanges() Msgs for Group: " << mit->first; - std::cerr << std::endl; + std::cerr << "p3PostBase::notifyChanges() Msgs for Group: " << mit->first; + std::cerr << std::endl; #endif - // To start with we are just going to trigger updates on these groups. - // FUTURE OPTIMISATION. - // It could be taken a step further and directly request these msgs for an update. - addGroupForProcessing(mit->first); + // To start with we are just going to trigger updates on these groups. + // FUTURE OPTIMISATION. + // It could be taken a step further and directly request these msgs for an update. + addGroupForProcessing(msgChange->mGroupId); - if (rsEvents && (msgChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW || msgChange->getType() == RsGxsNotify::TYPE_PUBLISHED)) - for (auto mit1 = mit->second.begin(); mit1 != mit->second.end(); ++mit1) - { - auto ev = std::make_shared(); - ev->mPostedMsgId = *mit1; - ev->mPostedGroupId = mit->first; - ev->mPostedEventCode = RsPostedEventCode::NEW_MESSAGE; - rsEvents->postEvent(ev); - } + if (rsEvents && (msgChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW || msgChange->getType() == RsGxsNotify::TYPE_PUBLISHED)) + { + auto ev = std::make_shared(); + ev->mPostedMsgId = msgChange->mMsgId; + ev->mPostedGroupId = msgChange->mGroupId; + ev->mPostedEventCode = RsPostedEventCode::NEW_MESSAGE; + rsEvents->postEvent(ev); } } @@ -336,11 +331,7 @@ void p3PostBase::addGroupForProcessing(RsGxsGroupId grpId) { RsStackMutex stack(mPostBaseMtx); /********** STACK LOCKED MTX ******/ // no point having multiple lookups queued. - if (mBgGroupList.end() == std::find(mBgGroupList.begin(), - mBgGroupList.end(), grpId)) - { - mBgGroupList.push_back(grpId); - } + mBgGroupList.insert(grpId); } } @@ -373,8 +364,8 @@ void p3PostBase::background_requestUnprocessedGroup() return; } - grpId = mBgGroupList.front(); - mBgGroupList.pop_front(); + grpId = *mBgGroupList.begin(); + mBgGroupList.erase(grpId); mBgProcessing = true; } @@ -468,8 +459,6 @@ void p3PostBase::background_loadMsgs(const uint32_t &token, bool unprocessed) // generate vector of changes to push to the GUI. std::vector changes; - RsGxsMsgChange *msgChanges = new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, false); - RsGxsGroupId groupId; std::map >::iterator mit; @@ -520,7 +509,7 @@ void p3PostBase::background_loadMsgs(const uint32_t &token, bool unprocessed) #endif /* but we need to notify GUI about them */ - msgChanges->msgChangeMap[mit->first].insert((*vit)->meta.mMsgId); + changes.push_back(new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, mit->first,(*vit)->meta.mMsgId, false)); } else if (NULL != (commentItem = dynamic_cast(*vit))) { @@ -616,22 +605,7 @@ void p3PostBase::background_loadMsgs(const uint32_t &token, bool unprocessed) } /* push updates of new Posts */ - if (msgChanges->msgChangeMap.size() > 0) - { -#ifdef POSTBASE_DEBUG - std::cerr << "p3PostBase::background_processNewMessages() -> receiveChanges()"; - std::cerr << std::endl; -#endif - - changes.push_back(msgChanges); - //receiveHelperChanges(changes); - - notifyChanges(changes); - } - else - { - delete(msgChanges); - } + notifyChanges(changes); /* request the summary info from the parents */ uint32_t token_b; @@ -696,7 +670,6 @@ void p3PostBase::background_updateVoteCounts(const uint32_t &token) // generate vector of changes to push to the GUI. std::vector changes; - RsGxsMsgChange *msgChanges = new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, false); for(mit = parentMsgList.begin(); mit != parentMsgList.end(); ++mit) { @@ -739,7 +712,8 @@ void p3PostBase::background_updateVoteCounts(const uint32_t &token) #endif stats.increment(it->second); - msgChanges->msgChangeMap[mit->first].insert(vit->mMsgId); + + changes.push_back(new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED,mit->first,vit->mMsgId, false)); } else { @@ -771,21 +745,7 @@ void p3PostBase::background_updateVoteCounts(const uint32_t &token) } } - if (msgChanges->msgChangeMap.size() > 0) - { -#ifdef POSTBASE_DEBUG - std::cerr << "p3PostBase::background_updateVoteCounts() -> receiveChanges()"; - std::cerr << std::endl; -#endif - - changes.push_back(msgChanges); - //receiveHelperChanges(changes); - notifyChanges(changes); - } - else - { - delete(msgChanges); - } + notifyChanges(changes); // DONE!. background_cleanup(); diff --git a/libretroshare/src/services/p3postbase.h b/libretroshare/src/services/p3postbase.h index d90f94a8a..40804be1f 100644 --- a/libretroshare/src/services/p3postbase.h +++ b/libretroshare/src/services/p3postbase.h @@ -125,7 +125,7 @@ private: bool mBgProcessing; bool mBgIncremental; - std::list mBgGroupList; + std::set mBgGroupList; std::map mBgStatsMap; std::map mKnownPosted; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp index 9931811f8..3aa6ccae9 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp @@ -46,6 +46,8 @@ #define ROLE_FILE_HASH Qt::UserRole + 3 #define ROLE_MSG Qt::UserRole + 4 +Q_DECLARE_METATYPE(Sha1CheckSum) + GxsChannelFilesWidget::GxsChannelFilesWidget(QWidget *parent) : QWidget(parent), ui(new Ui::GxsChannelFilesWidget) { diff --git a/retroshare-gui/src/gui/msgs/MessageModel.h b/retroshare-gui/src/gui/msgs/MessageModel.h index d6939fff1..be8872234 100644 --- a/retroshare-gui/src/gui/msgs/MessageModel.h +++ b/retroshare-gui/src/gui/msgs/MessageModel.h @@ -107,7 +107,6 @@ public: void setCurrentBox(BoxName bn) ; void setQuickViewFilter(QuickViewFilter fn) ; - const RsMessageId& currentMessageId() const; void setFilter(FilterType filter_type, const QStringList& strings) ; int rowCount(const QModelIndex& parent = QModelIndex()) const override; From 65fa29e78919a098fa10ccf1d042a722f12f5738 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 4 May 2020 20:54:08 +0200 Subject: [PATCH 14/79] fixed notifications on circle not working due to cache reload failure. That circle cache code needs a real cleanup --- libretroshare/src/services/p3gxscircles.cc | 9 +- retroshare-gui/src/gui/NewsFeed.cpp | 189 +++++---- .../src/gui/feeds/GxsCircleItem.cpp | 14 +- retroshare-gui/src/gui/feeds/GxsCircleItem.ui | 359 +++++++++--------- 4 files changed, 303 insertions(+), 268 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 0b1ac5270..6d5c1dcd5 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -103,7 +103,7 @@ #define MIN_CIRCLE_LOAD_GAP 5 #define GXS_CIRCLE_DELAY_TO_FORCE_MEMBERSHIP_UPDATE 60 // re-check every 1 mins. Normally this shouldn't be necessary since notifications inform abotu new messages. #define GXS_CIRCLE_DELAY_TO_CHECK_MEMBERSHIP_UPDATE 60 // re-check every 1 mins. Normally this shouldn't be necessary since notifications inform abotu new messages. -#define GXS_CIRCLE_DELAY_TO_SEND_CACHE_UPDATED_EVENT 10 // do not send cache update events more often than every 10 secs. +#define GXS_CIRCLE_DELAY_TO_SEND_CACHE_UPDATED_EVENT 2 // do not send cache update events more often than every 2 secs. /********************************************************************************/ /******************* Startup / Tick ******************************************/ @@ -532,6 +532,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) #endif p3Notify *notify = RsServer::notify(); + std::set circles_to_reload; for(auto it = changes.begin(); it != changes.end(); ++it) { @@ -576,6 +577,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } mCircleCache.erase(circle_id); + circles_to_reload.insert(circle_id); mCacheUpdated = true; } @@ -608,6 +610,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ mCircleCache.erase(RsGxsCircleId(*git)); mCacheUpdated = true; + circles_to_reload.insert(RsGxsCircleId(*git)); } } } @@ -686,6 +689,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ mCircleCache.erase(RsGxsCircleId(*git)); mCacheUpdated = true; + circles_to_reload.insert(RsGxsCircleId(*git)); } } @@ -693,6 +697,9 @@ void p3GxsCircles::notifyChanges(std::vector &changes) delete c; } + + for(auto& circle_id:circles_to_reload) + force_cache_reload(circle_id); } /********************************************************************************/ diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index 6c6a0d761..63d81c41e 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -294,97 +294,120 @@ void NewsFeed::handleChannelEvent(std::shared_ptr event) void NewsFeed::handleCircleEvent(std::shared_ptr event) { - const RsGxsCircleEvent *pe = dynamic_cast(event.get()); - if(!pe) - return; + // Gives the backend a few secs to load the cache data while not blocking the UI. This is not so nice, but there's no proper + // other way to do that. - RsGxsCircleDetails details; - - if(pe->mCircleId.isNull()) // probably an item for cache update - return ; - - if(!rsGxsCircles->getCircleDetails(pe->mCircleId,details)) + RsThread::async( [event,this]() { - std::cerr << "(EE) Cannot get information about circle " << pe->mCircleId << ". Not in cache?" << std::endl; - return; - } + const RsGxsCircleEvent *pe = dynamic_cast(event.get()); + if(!pe) + return; - if(!details.isGxsIdBased()) // not handled yet. - return; + if(pe->mCircleId.isNull()) // probably an item for cache update + return ; - // Check if the circle is one of which we belong to or we are an admin of. - // If so, then notify in the GUI about other members leaving/subscribing, according - // to the following rules. The names correspond to the RS_FEED_CIRCLE_* variables: - // - // Message-based notifications: - // - // +---------------------------+----------------------------+ - // | Membership request | Membership cancellation | - // +-------------+-------------+-------------+--------------+ - // | Admin | Not admin | Admin | Not admin | - // +--------------------+-------------+-------------+----------------------------+ - // | in invitee list | MEMB_JOIN | MEMB_JOIN | MEMB_LEAVE | MEMB_LEAVE | - // +--------------------+-------------+-------------+-------------+--------------+ - // |not in invitee list | MEMB_REQ | X | X | X | - // +--------------------+-------------+-------------+-------------+--------------+ - // - // Note: in this case, the GxsId never belongs to you, since you dont need to handle - // notifications for actions you took yourself (leave/join a circle) - // - // GroupData-based notifications, the GxsId belongs to you: - // - // +---------------------------+----------------------------+ - // | GxsId joins invitee list | GxsId leaves invitee list | - // +-------------+-------------+-------------+--------------+ - // | Id is yours| Id is not | Id is yours | Id is not | - // +--------------------+-------------+-------------+-------------+--------------+ - // | Has Member request | MEMB_ACCEPT | (MEMB_JOIN) | MEMB_REVOKED| (MEMB_LEAVE) | - // +--------------------+-------------+-------------+-------------+--------------+ - // | No Member request | INVITE_REC | X | INVITE_REM | X | - // +--------------------+-------------+-------------+-------------+--------------+ - // - // Note: In this case you're never an admin of the circle, since these notification - // would be a direct consequence of your own actions. + RsGxsCircleDetails details; + bool loaded = false; - switch(pe->mCircleEventType) - { - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: - // only show membership requests if we're an admin of that circle - if(details.isIdInInviteeList(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_JOIN),true); - else if(details.mAmIAdmin) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ),true); - - break; - - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: - - if(details.isIdInInviteeList(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_LEAVE),true); - break; - - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST: - if(rsIdentity->isOwnId(pe->mGxsId)) - { - if(details.isIdRequestingMembership(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED),true); + for(int i=0;i<5 && !loaded;++i) + if(rsGxsCircles->getCircleDetails(pe->mCircleId,details)) + { + std::cerr << "Cache item loaded for circle " << pe->mCircleId << std::endl; + loaded = true; + } else - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_REC),true); - } - break; + { + std::cerr << "Cache item for circle " << pe->mCircleId << " not loaded. Waiting " << i << "s" << std::endl; + rstime::rs_usleep(1000*1000); + } - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST: - if(rsIdentity->isOwnId(pe->mGxsId)) - { - if(details.isIdRequestingMembership(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); - else - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_CANCELLED),true); - } - break; + if(!loaded) + { + std::cerr << "(EE) Cannot get information about circle " << pe->mCircleId << ". Not in cache?" << std::endl; + return; + } - default: break; - } + if(!details.isGxsIdBased()) // not handled yet. + return; + + // Check if the circle is one of which we belong to or we are an admin of. + // If so, then notify in the GUI about other members leaving/subscribing, according + // to the following rules. The names correspond to the RS_FEED_CIRCLE_* variables: + // + // Message-based notifications: + // + // +---------------------------+----------------------------+ + // | Membership request | Membership cancellation | + // +-------------+-------------+-------------+--------------+ + // | Admin | Not admin | Admin | Not admin | + // +--------------------+-------------+-------------+----------------------------+ + // | in invitee list | MEMB_JOIN | MEMB_JOIN | MEMB_LEAVE | MEMB_LEAVE | + // +--------------------+-------------+-------------+-------------+--------------+ + // |not in invitee list | MEMB_REQ | X | X | X | + // +--------------------+-------------+-------------+-------------+--------------+ + // + // Note: in this case, the GxsId never belongs to you, since you dont need to handle + // notifications for actions you took yourself (leave/join a circle) + // + // GroupData-based notifications, the GxsId belongs to you: + // + // +---------------------------+----------------------------+ + // | GxsId joins invitee list | GxsId leaves invitee list | + // +-------------+-------------+-------------+--------------+ + // | Id is yours| Id is not | Id is yours | Id is not | + // +--------------------+-------------+-------------+-------------+--------------+ + // | Has Member request | MEMB_ACCEPT | (MEMB_JOIN) | MEMB_REVOKED| (MEMB_LEAVE) | + // +--------------------+-------------+-------------+-------------+--------------+ + // | No Member request | INVITE_REC | X | INVITE_REM | X | + // +--------------------+-------------+-------------+-------------+--------------+ + // + // Note: In this case you're never an admin of the circle, since these notification + // would be a direct consequence of your own actions. + + RsQThreadUtils::postToObject( [event,details,this]() + { + const RsGxsCircleEvent *pe = static_cast(event.get()); + + switch(pe->mCircleEventType) + { + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: + // only show membership requests if we're an admin of that circle + if(details.isIdInInviteeList(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_JOIN),true); + else if(details.mAmIAdmin) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ),true); + + break; + + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: + + if(details.isIdInInviteeList(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_LEAVE),true); + break; + + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST: + if(rsIdentity->isOwnId(pe->mGxsId)) + { + if(details.isIdRequestingMembership(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED),true); + else + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_REC),true); + } + break; + + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST: + if(rsIdentity->isOwnId(pe->mGxsId)) + { + if(details.isIdRequestingMembership(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); + else + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_CANCELLED),true); + } + break; + + default: break; + } + }, this ); }); // damn! } void NewsFeed::handleConnectionEvent(std::shared_ptr event) diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp index 4d4f3e031..f827b115e 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp @@ -86,13 +86,13 @@ void GxsCircleItem::setup() RsGxsCircleDetails circleDetails; if (rsGxsCircles->getCircleDetails(mCircleId, circleDetails)) { + ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str()) + " (ID: " + QString::fromStdString(circleDetails.mCircleId.toStdString()) + ")"); + // from here we can figure out if we already have requested membership or not if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REQ) { ui->titleLabel->setText(tr("You received a membership request a circle you're administrating:")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -102,8 +102,6 @@ void GxsCircleItem::setup() else if (mType == RS_FEED_ITEM_CIRCLE_INVITE_REC) { ui->titleLabel->setText(tr("You received an invitation for this circle:")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -114,8 +112,6 @@ void GxsCircleItem::setup() else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_LEAVE) { ui->titleLabel->setText(idName + tr(" has left this circle.")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -125,8 +121,6 @@ void GxsCircleItem::setup() else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_JOIN) { ui->titleLabel->setText(idName + tr(" which you invited, has join this circle you're administrating.")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -137,8 +131,6 @@ void GxsCircleItem::setup() { ui->titleLabel->setText(tr("Your identity %1 has been revoked from this circle.").arg(idName)); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -149,8 +141,6 @@ void GxsCircleItem::setup() { ui->titleLabel->setText(tr("Your identity %1 as been accepted in this circle.").arg(idName)); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.ui b/retroshare-gui/src/gui/feeds/GxsCircleItem.ui index 408781e9b..4cd6846e2 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.ui +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.ui @@ -7,7 +7,7 @@ 0 0 618 - 104 + 172 @@ -104,8 +104,8 @@ QFrame::Sunken - - + + @@ -130,154 +130,8 @@ - - - - - - for identity - - - - - - - - 20 - 20 - - - - TextLabel - - - true - - - - - - - name - - - true - - - - - - - Qt::Horizontal - - - - 358 - 20 - - - - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Accept - - - - :/images/accepted16.png:/images/accepted16.png - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Revoke - - - - :/images/cancel.png:/images/cancel.png - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Details - - - - :/images/informations_24x24.png:/images/informations_24x24.png - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 285 - 18 - - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Remove Item - - - - :/icons/png/exit2.png:/icons/png/exit2.png - - - - - + + @@ -294,32 +148,193 @@ - Circle + Circle msg - - - name - - - true - - + + + + + Circle name: + + + + + + + name + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + Identity: + + + + + + + + 20 + 20 + + + + TextLabel + + + true + + + + + + + name + + + true + + + + + + + Qt::Horizontal + + + + 358 + 20 + + + + + + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Accept + + + + :/images/accepted16.png:/images/accepted16.png + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Revoke + + + + :/images/cancel.png:/images/cancel.png + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Details + + + + :/images/informations_24x24.png:/images/informations_24x24.png + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 285 + 18 + + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Remove Item + + + + :/icons/png/exit2.png:/icons/png/exit2.png + + + + @@ -336,8 +351,8 @@ - + From 11a4b6540ffe2f8e18d43c19c8d4698c4ebd324e Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 7 May 2020 17:31:58 +0200 Subject: [PATCH 15/79] cleaned-up circles cache. Needs testing. --- libretroshare/src/services/p3gxscircles.cc | 1702 ++++++++++---------- libretroshare/src/services/p3gxscircles.h | 46 +- libretroshare/src/util/rsmemcache.h | 11 +- 3 files changed, 880 insertions(+), 879 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 6d5c1dcd5..43a16816d 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -43,6 +43,18 @@ /*extern*/ RsGxsCircles* rsGxsCircles = nullptr; +/*static*/ const std::string RsGxsCircles::DEFAULT_CIRCLE_BASE_URL = + "retroshare:///circles"; +/*static*/ const std::string RsGxsCircles::CIRCLE_URL_NAME_FIELD = "circleName"; +/*static*/ const std::string RsGxsCircles::CIRCLE_URL_ID_FIELD = "circleId"; +/*static*/ const std::string RsGxsCircles::CIRCLE_URL_DATA_FIELD = "circleData"; + +RsGxsCircles::~RsGxsCircles() = default; +RsGxsCircleMsg::~RsGxsCircleMsg() = default; +RsGxsCircleDetails::~RsGxsCircleDetails() = default; +RsGxsCircleGroup::~RsGxsCircleGroup() = default; +RsGxsCircleEvent::~RsGxsCircleEvent() = default; + /****** * * GxsCircles are used to limit the spread of Gxs Groups and Messages. @@ -73,8 +85,7 @@ * The data-types for the full system, however, will be in-place. */ - -#define CIRCLEREQ_CACHELOAD 0x0001 +#define CIRCLEREQ_CACHELOAD 0x0001 #define CIRCLEREQ_CIRCLE_LIST 0x0002 #define CIRCLEREQ_MESSAGE_DATA 0x0003 @@ -105,31 +116,26 @@ #define GXS_CIRCLE_DELAY_TO_CHECK_MEMBERSHIP_UPDATE 60 // re-check every 1 mins. Normally this shouldn't be necessary since notifications inform abotu new messages. #define GXS_CIRCLE_DELAY_TO_SEND_CACHE_UPDATED_EVENT 2 // do not send cache update events more often than every 2 secs. -/********************************************************************************/ -/******************* Startup / Tick ******************************************/ -/********************************************************************************/ +//====================================================================================// +// Startup // +//====================================================================================// -p3GxsCircles::p3GxsCircles( - RsGeneralDataService *gds, RsNetworkExchangeService *nes, - p3IdService *identities, PgpAuxUtils *pgpUtils) : - RsGxsCircleExchange( - gds, nes, new RsGxsCircleSerialiser(), RS_SERVICE_GXS_TYPE_GXSCIRCLE, - identities, circleAuthenPolicy() ), - RsGxsCircles(static_cast(*this)), GxsTokenQueue(this), - RsTickEvent(), mIdentities(identities), mPgpUtils(pgpUtils), - mCircleMtx("p3GxsCircles"), - mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache" ), - mCacheUpdated(false) +p3GxsCircles::p3GxsCircles( RsGeneralDataService *gds, RsNetworkExchangeService *nes, p3IdService *identities, PgpAuxUtils *pgpUtils) + : RsGxsCircleExchange( gds, nes, new RsGxsCircleSerialiser(), RS_SERVICE_GXS_TYPE_GXSCIRCLE, identities, circleAuthenPolicy() ), + RsGxsCircles(static_cast(*this)), GxsTokenQueue(this), + RsTickEvent(), mIdentities(identities), mPgpUtils(pgpUtils), + mCircleMtx("p3GxsCircles"), + mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache" ), + mCacheUpdated(false) { // Kick off Cache Testing, + Others. //RsTickEvent::schedule_in(CIRCLE_EVENT_CACHETEST, CACHETEST_PERIOD); - mLastCacheMembershipUpdateTS = 0 ; - mLastCacheUpdateEvent = 0; - + mLastCacheMembershipUpdateTS = 0 ; + mLastCacheUpdateEvent = 0; + mLastDebugPrintTS = 0; + RsTickEvent::schedule_now(CIRCLE_EVENT_LOADIDS); - // Dummy Circles. - // RsTickEvent::schedule_in(CIRCLE_EVENT_DUMMYSTART, CIRCLE_DUMMY_STARTPERIOD); mDummyIdToken = 0; } @@ -157,12 +163,18 @@ RsServiceInfo p3GxsCircles::getServiceInfo() GXS_CIRCLES_MIN_MINOR_VERSION); } +//====================================================================================// +// Synchroneous API from rsGxsCircles // +//====================================================================================// + bool p3GxsCircles::createCircle( const std::string& circleName, RsGxsCircleType circleType, RsGxsCircleId& circleId, const RsGxsCircleId& restrictedId, const RsGxsId& authorId, const std::set& gxsIdMembers, const std::set& localMembers ) { + // 1 - Check consistency of the request data + if(circleName.empty()) { RsErr() << __PRETTY_FUNCTION__ << " Circle name is empty" << std::endl; @@ -221,6 +233,8 @@ bool p3GxsCircles::createCircle( return false; } + // 2 - Create the actual request + RsGxsCircleGroup cData; cData.mMeta.mGroupName = circleName; cData.mMeta.mAuthorId = authorId; @@ -230,20 +244,20 @@ bool p3GxsCircles::createCircle( cData.mLocalFriends = localMembers; cData.mInvitedMembers = gxsIdMembers; + // 3 - Send it and wait, for a sync response. + uint32_t token; createGroup(token, cData); if(waitToken(token) != RsTokenService::COMPLETE) { - std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." - << std::endl; + std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." << std::endl; return false; } if(!RsGenExchange::getPublishedGroupMeta(token, cData.mMeta)) { - std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting created" - << " group data." << std::endl; + std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting created" << " group data." << std::endl; return false; } @@ -494,6 +508,9 @@ uint32_t p3GxsCircles::circleAuthenPolicy() return policy; } +//====================================================================================// +// Tick // +//====================================================================================// void p3GxsCircles::service_tick() { @@ -520,9 +537,18 @@ void p3GxsCircles::service_tick() checkCircleCache(); mLastCacheMembershipUpdateTS = now ; } + + if(now > mLastDebugPrintTS) + { + mLastDebugPrintTS = now; + debug_dumpCache(); + } return; } +//====================================================================================// +// Handling of GXS changes // +//====================================================================================// void p3GxsCircles::notifyChanges(std::vector &changes) { @@ -702,9 +728,9 @@ void p3GxsCircles::notifyChanges(std::vector &changes) force_cache_reload(circle_id); } -/********************************************************************************/ -/******************* RsCircles Interface ***************************************/ -/********************************************************************************/ +//====================================================================================// +// Synchroneous API using cache storage // +//====================================================================================// bool p3GxsCircles::getCircleDetails(const RsGxsCircleId& id, RsGxsCircleDetails& details) { @@ -714,49 +740,49 @@ bool p3GxsCircles::getCircleDetails(const RsGxsCircleId& id, RsGxsCircleDetails& std::cerr << std::endl; #endif // DEBUG_CIRCLES - { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - if (mCircleCache.is_cached(id)) - { - RsGxsCircleCache &data = mCircleCache.ref(id); + { + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - // should also have meta data.... - details.mCircleId = id; - details.mCircleName = data.mCircleName; + RsGxsCircleCache& data(mCircleCache[id]); - details.mCircleType = data.mCircleType; - details.mRestrictedCircleId = data.mRestrictedCircleId; + if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return false; - details.mAllowedNodes = data.mAllowedNodes; - details.mSubscriptionFlags.clear(); - details.mAllowedGxsIds.clear(); - details.mAmIAllowed = false ; - details.mAmIAdmin = bool(data.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); + // should also have meta data.... + details.mCircleId = id; + details.mCircleName = data.mCircleName; - for(std::map::const_iterator it(data.mMembershipStatus.begin());it!=data.mMembershipStatus.end();++it) - { - details.mSubscriptionFlags[it->first] = it->second.subscription_flags ; + details.mCircleType = data.mCircleType; + details.mRestrictedCircleId = data.mRestrictedCircleId; - if(it->second.subscription_flags == GXS_EXTERNAL_CIRCLE_FLAGS_ALLOWED) - { - details.mAllowedGxsIds.insert(it->first) ; - - if(rsIdentity->isOwnId(it->first)) - details.mAmIAllowed = true ; - } - } + details.mAllowedNodes = data.mAllowedNodes; + details.mSubscriptionFlags.clear(); + details.mAllowedGxsIds.clear(); + details.mAmIAllowed = false ; + details.mAmIAdmin = bool(data.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); - return true; - } - } + for(std::map::const_iterator it(data.mMembershipStatus.begin());it!=data.mMembershipStatus.end();++it) + { + details.mSubscriptionFlags[it->first] = it->second.subscription_flags ; + + if(it->second.subscription_flags == GXS_EXTERNAL_CIRCLE_FLAGS_ALLOWED) + { + details.mAllowedGxsIds.insert(it->first) ; + + if(rsIdentity->isOwnId(it->first)) + details.mAmIAllowed = true ; + } + } + + return true; + } /* it isn't there - add to public requests */ cache_request_load(id); - return false; } -bool p3GxsCircles:: getCircleExternalIdList(std::list &circleIds) +bool p3GxsCircles::getCircleExternalIdList(std::list &circleIds) { #ifdef DEBUG_CIRCLES std::cerr << "p3GxsCircles::getCircleIdList()"; @@ -765,30 +791,21 @@ bool p3GxsCircles:: getCircleExternalIdList(std::list &circleIds) RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ if (circleIds.empty()) - { circleIds = mCircleExternalIdList; - } else { std::list::const_iterator it; for(it = mCircleExternalIdList.begin(); it != mCircleExternalIdList.begin(); ++it) - { circleIds.push_back(*it); - } } return true; } - -/********************************************************************************/ -/******************* RsGcxs Interface ***************************************/ -/********************************************************************************/ - bool p3GxsCircles::isLoaded(const RsGxsCircleId &circleId) { RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - return mCircleCache.is_cached(circleId); + return (mCircleCache[circleId].mStatus >= RsGxsCircleCache::CircleEntryCacheStatus::UPDATING); } bool p3GxsCircles::loadCircle(const RsGxsCircleId &circleId) @@ -796,13 +813,16 @@ bool p3GxsCircles::loadCircle(const RsGxsCircleId &circleId) return cache_request_load(circleId); } - int p3GxsCircles::canSend(const RsGxsCircleId &circleId, const RsPgpId &id, bool& should_encrypt) { RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ if (mCircleCache.is_cached(circleId)) { - RsGxsCircleCache &data = mCircleCache.ref(circleId); + RsGxsCircleCache& data = mCircleCache.ref(circleId); + + if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return 0; + should_encrypt = (data.mCircleType == RsGxsCircleType::EXTERNAL); if (data.isAllowedPeer(id)) @@ -819,6 +839,10 @@ int p3GxsCircles::canReceive(const RsGxsCircleId &circleId, const RsPgpId &id) if (mCircleCache.is_cached(circleId)) { RsGxsCircleCache &data = mCircleCache.ref(circleId); + + if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return 0; + if (data.isAllowedPeer(id)) { return 1; @@ -834,6 +858,10 @@ bool p3GxsCircles::recipients(const RsGxsCircleId &circleId, std::list& if (mCircleCache.is_cached(circleId)) { RsGxsCircleCache &data = mCircleCache.ref(circleId); + + if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return 0; + data.getAllowedPeersList(friendlist); return true; } @@ -846,6 +874,10 @@ bool p3GxsCircles::isRecipient(const RsGxsCircleId &circleId, const RsGxsGroupId if (mCircleCache.is_cached(circleId)) { const RsGxsCircleCache &data = mCircleCache.ref(circleId); + + if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return 0; + return data.isAllowedPeer(id,destination_group); } return false; @@ -865,16 +897,20 @@ bool p3GxsCircles::recipients(const RsGxsCircleId& circleId, const RsGxsGroupId& const RsGxsCircleCache& cache = mCircleCache.ref(circleId); + if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return 0; + for(std::map::const_iterator it(cache.mMembershipStatus.begin());it!=cache.mMembershipStatus.end();++it) - if(allowedGxsIdFlagTest(it->second.subscription_flags, RsGxsCircleId(dest_group) == circleId)) + if(allowedGxsIdFlagTest(it->second.subscription_flags, RsGxsCircleId(dest_group) == circleId)) gxs_ids.push_back(it->first) ; return true; } -/********************************************************************************/ -/******************* Get/Set Data ******************************************/ -/********************************************************************************/ +//====================================================================================// +// Asynchroneous API using token system // +//====================================================================================// + bool p3GxsCircles::getGroupData(const uint32_t &token, std::vector &groups) { @@ -911,10 +947,6 @@ bool p3GxsCircles::getGroupData(const uint32_t &token, std::vector &msgs) { GxsMsgDataMap msgData; @@ -1019,54 +1051,47 @@ RsGenExchange::ServiceCreate_Return p3GxsCircles::service_CreateGroup(RsGxsGrpIt return SERVICE_CREATE_SUCCESS; } - - -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ - -/* - * Cache of recently used circles. - */ +//====================================================================================// +// Cache system management // +//====================================================================================// RsGxsCircleCache::RsGxsCircleCache() { mCircleType = RsGxsCircleType::EXTERNAL; mIsExternal = true; - mUpdateTime = 0; + mLastUpdateTime = 0; mGroupStatus = 0; mGroupSubscribeFlags = 0; mLastUpdatedMembershipTS = 0 ; + mStatus = CircleEntryCacheStatus::NO_DATA; + mAllIdsHere = false; return; } - -bool RsGxsCircleCache::loadBaseCircle(const RsGxsCircleGroup &circle) +bool RsGxsCircleCache::loadBaseCircle(const RsGxsCircleGroup& circle) { - mCircleId = RsGxsCircleId(circle.mMeta.mGroupId); mCircleName = circle.mMeta.mGroupName; - mUpdateTime = time(NULL); -// mProcessedCircles.insert(mCircleId); + // mProcessedCircles.insert(mCircleId); mCircleType = static_cast(circle.mMeta.mCircleType); mIsExternal = (mCircleType != RsGxsCircleType::LOCAL); mGroupStatus = circle.mMeta.mGroupStatus; mGroupSubscribeFlags = circle.mMeta.mSubscribeFlags; mOriginator = circle.mMeta.mOriginator ; - - mAllowedNodes = circle.mLocalFriends ; - mRestrictedCircleId = circle.mMeta.mCircleId ; - - mMembershipStatus.clear() ; - - for(std::set::const_iterator it(circle.mInvitedMembers.begin());it!=circle.mInvitedMembers.end();++it) - { - RsGxsCircleMembershipStatus& s(mMembershipStatus[*it]) ; - s.last_subscription_TS = 0 ; - s.subscription_flags = GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ; - } + + mAllowedNodes = circle.mLocalFriends ; + mRestrictedCircleId = circle.mMeta.mCircleId ; + + mMembershipStatus.clear() ; + + for(std::set::const_iterator it(circle.mInvitedMembers.begin());it!=circle.mInvitedMembers.end();++it) + { + RsGxsCircleMembershipStatus& s(mMembershipStatus[*it]) ; + s.last_subscription_TS = 0 ; + s.subscription_flags = GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ; + } #ifdef DEBUG_CIRCLES std::cerr << "RsGxsCircleCache::loadBaseCircle(" << mCircleId << ")"; @@ -1094,7 +1119,7 @@ bool RsGxsCircleCache::getAllowedPeersList(std::list& friendlist) const { friendlist.clear() ; - for(std::set::const_iterator it = mAllowedNodes.begin(); it != mAllowedNodes.end(); ++it) + for(auto it = mAllowedNodes.begin(); it != mAllowedNodes.end(); ++it) friendlist.push_back(*it) ; return true; @@ -1102,12 +1127,12 @@ bool RsGxsCircleCache::getAllowedPeersList(std::list& friendlist) const bool RsGxsCircleCache::isAllowedPeer(const RsGxsId& id,const RsGxsGroupId& destination_group) const { - std::map::const_iterator it = mMembershipStatus.find(id) ; - - if(it == mMembershipStatus.end()) - return false ; - - return allowedGxsIdFlagTest(it->second.subscription_flags, RsGxsGroupId(mCircleId) == destination_group) ; + auto it = mMembershipStatus.find(id) ; + + if(it == mMembershipStatus.end()) + return false ; + + return allowedGxsIdFlagTest(it->second.subscription_flags, RsGxsGroupId(mCircleId) == destination_group) ; } bool RsGxsCircleCache::isAllowedPeer(const RsPgpId &id) const @@ -1118,11 +1143,10 @@ bool RsGxsCircleCache::isAllowedPeer(const RsPgpId &id) const bool RsGxsCircleCache::addLocalFriend(const RsPgpId &pgpId) { /* empty list as no GxsID associated */ - mAllowedNodes.insert(pgpId) ; + mAllowedNodes.insert(pgpId) ; return true; } - /************************************************************************************/ /************************************************************************************/ @@ -1182,121 +1206,6 @@ bool p3GxsCircles::load_CircleIdList(uint32_t token) -/****************************************************************************/ -// ID STUFF. \/ \/ \/ \/ \/ \/ \/ :) -/****************************************************************************/ -#if 0 - -/************************************************************************************/ -/************************************************************************************/ - -bool p3GxsCircles::cachetest_getlist() -{ - std::cerr << "p3GxsCircles::cachetest_getlist() making request"; - std::cerr << std::endl; - - uint32_t ansType = RS_TOKREQ_ANSTYPE_LIST; - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_GROUP_IDS; - uint32_t token = 0; - - RsGenExchange::getTokenService()->requestGroupInfo(token, ansType, opts); - GxsTokenQueue::queueRequest(token, CIRCLEREQ_CACHETEST); - - // Schedule Next Event. - RsTickEvent::schedule_in(CIRCLE_EVENT_CACHETEST, CACHETEST_PERIOD); - return true; -} - -bool p3GxsCircles::cachetest_handlerequest(uint32_t token) -{ - std::cerr << "p3GxsCircles::cachetest_handlerequest() token: " << token; - std::cerr << std::endl; - - std::list grpIds; - bool ok = RsGenExchange::getGroupList(token, grpIds); - - if(ok) - { - std::list::iterator vit = grpIds.begin(); - for(; vit != grpIds.end(); ++vit) - { - /* 5% chance of checking it! */ - if (RSRandom::random_f32() < 0.25) - { - std::cerr << "p3GxsCircles::cachetest_request() Testing Id: " << *vit; - std::cerr << std::endl; - - /* try the cache! */ - if (!haveKey(*vit)) - { - std::list nullpeers; - requestKey(*vit, nullpeers); - - std::cerr << "p3GxsCircles::cachetest_request() Requested Key Id: " << *vit; - std::cerr << std::endl; - } - else - { - RsTlvSecurityKey seckey; - if (getKey(*vit, seckey)) - { - std::cerr << "p3GxsCircles::cachetest_request() Got Key OK Id: " << *vit; - std::cerr << std::endl; - - // success! - seckey.print(std::cerr, 10); - std::cerr << std::endl; - - - } - else - { - std::cerr << "p3GxsCircles::cachetest_request() ERROR no Key for Id: " << *vit; - std::cerr << std::endl; - } - } - - /* try private key too! */ - if (!havePrivateKey(*vit)) - { - requestPrivateKey(*vit); - std::cerr << "p3GxsCircles::cachetest_request() Requested PrivateKey Id: " << *vit; - std::cerr << std::endl; - } - else - { - RsTlvSecurityKey seckey; - if (getPrivateKey(*vit, seckey)) - { - // success! - std::cerr << "p3GxsCircles::cachetest_request() Got PrivateKey OK Id: " << *vit; - std::cerr << std::endl; - } - else - { - std::cerr << "p3GxsCircles::cachetest_request() ERROR no PrivateKey for Id: " << *vit; - std::cerr << std::endl; - } - } - } - } - } - else - { - std::cerr << "p3GxsCircles::cache_load_for_token() ERROR no data"; - std::cerr << std::endl; - - return false; - } - return true; -} - -/****************************************************************************/ -// ID STUFF. /\ /\ /\ /\ /\ /\ /\ /\ :) -/****************************************************************************/ -#endif - /************************************************************************************/ @@ -1310,25 +1219,7 @@ bool p3GxsCircles::force_cache_reload(const RsGxsCircleId& id) std::cerr << "p3GxsCircles::force_cache_reload(): Forcing cache reload of Circle ID " << id << std::endl; #endif - { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - -#ifdef DEBUG_CIRCLES - std::cerr << " clearing from existing cache entries..." << std::endl; -#endif - - std::map::iterator it = mLoadingCache.find(id); - if (it != mLoadingCache.end()) - { - mLoadingCache.erase(it) ; -#ifdef DEBUG_CIRCLES - std::cerr << " removed item from currently loading cache entries..." << std::endl; -#endif - } - mCircleCache.erase(id) ; - } cache_request_load(id) ; - return true ; } @@ -1342,44 +1233,35 @@ bool p3GxsCircles::cache_request_load(const RsGxsCircleId &id) { RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - /* check its not loaded */ - if (mCircleCache.is_cached(id)) - return true; - /* check it is not already being loaded */ - std::map::iterator it; - it = mLoadingCache.find(id); - if (it != mLoadingCache.end()) - { - // Already loading. - return true; - } + + RsGxsCircleCache& cache(mCircleCache[id]); + + if(cache.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::LOADING || cache.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return false; + // Put it into the Loading Cache - so we will detect it later. - mLoadingCache[id] = RsGxsCircleCache(); - mCacheLoad_ToCache.push_back(id); + + if(cache.mLastUpdateTime > 0) + cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::UPDATING; + else + cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::LOADING; + + mCirclesToLoad.insert(id); } - if (RsTickEvent::event_count(CIRCLE_EVENT_CACHELOAD) > 0) - { - /* its already scheduled */ + if (RsTickEvent::event_count(CIRCLE_EVENT_CACHELOAD) > 0) /* its already scheduled */ return true; - } int32_t age = 0; - if (RsTickEvent::prev_event_ago(CIRCLE_EVENT_CACHELOAD, age)) - { - if (age < MIN_CIRCLE_LOAD_GAP) - { - RsTickEvent::schedule_in(CIRCLE_EVENT_CACHELOAD, MIN_CIRCLE_LOAD_GAP - age); - return true; - } - } + if (RsTickEvent::prev_event_ago(CIRCLE_EVENT_CACHELOAD, age) && age a map so we can use it easily later, and create id list too */ - std::list::iterator it; - for(it = mCacheLoad_ToCache.begin(); it != mCacheLoad_ToCache.end(); ++it) + + for(auto& circle_id:mCirclesToLoad) { #ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::cache_start_load() GroupId: " << *it; - std::cerr << std::endl; + std::cerr << "p3GxsCircles::cache_start_load() GroupId: " << circle_id << std::endl; #endif // DEBUG_CIRCLES - groupIds.push_back(RsGxsGroupId(it->toStdString())); // might need conversion? + groupIds.push_back(RsGxsGroupId(circle_id.toStdString())); // might need conversion? } - mCacheLoad_ToCache.clear(); + mCirclesToLoad.clear(); } if (groupIds.size() > 0) @@ -1422,7 +1303,7 @@ bool p3GxsCircles::cache_start_load() RsGenExchange::getTokenService()->requestGroupInfo(token, ansType, opts, groupIds); GxsTokenQueue::queueRequest(token, CIRCLEREQ_CACHELOAD); } - return 1; + return true; } @@ -1442,11 +1323,10 @@ bool p3GxsCircles::cache_load_for_token(uint32_t token) return false; } - std::vector::iterator vit = grpData.begin(); - - for(; vit != grpData.end(); ++vit) + for(auto vit = grpData.begin(); vit != grpData.end(); ++vit) { RsGxsCircleGroupItem *item = dynamic_cast(*vit); + if (!item) { std::cerr << " Not a RsGxsCircleGroupItem Item, deleting!" << std::endl; @@ -1460,49 +1340,40 @@ bool p3GxsCircles::cache_load_for_token(uint32_t token) std::cerr << " Loaded Id with Meta: " << item->meta << std::endl; #endif // DEBUG_CIRCLES - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ /* should already have a LoadingCache entry */ RsGxsCircleId id = RsGxsCircleId(item->meta.mGroupId) ; - - // (cyril) I'm not sure this logic is needed. The token system would avoid duplicates normally. - - std::map::iterator it = mLoadingCache.find(id); - - if (it == mLoadingCache.end()) - { - std::cerr << "p3GxsCircles::cache_load_for_token() Load ERROR: "; - std::cerr << item->meta; - std::cerr << std::endl; - delete(item); - // ERROR. - continue; - } - - RsGxsCircleCache& cache = it->second; + RsGxsCircleCache& cache(mCircleCache[id]); cache.loadBaseCircle(group); delete item; - if(locked_processLoadingCacheEntry(it->second)) - { + if(locked_processLoadingCacheEntry(cache)) + { #ifdef DEBUG_CIRCLES - std::cerr << " All peers available. Moving to cache..." << std::endl; + std::cerr << " All peers available. Moving to cache..." << std::endl; #endif - mLoadingCache.erase(it); - } + cache.mAllIdsHere = true; + + // We can check for self inclusion in the circle right away, since own ids are always loaded. + // that allows to subscribe/unsubscribe uncomplete circles + + cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::CHECKING_MEMBERSHIP; + locked_checkCircleCacheForMembershipUpdate(cache); + } else { #ifdef DEBUG_CIRCLES std::cerr << " Unprocessed peers. Requesting reload..." << std::endl; #endif + cache.mAllIdsHere = false; /* schedule event to try reload gxsIds */ RsTickEvent::schedule_in(CIRCLE_EVENT_RELOADIDS, GXSID_LOAD_CYCLE, id.toStdString()); } - mCacheUpdated = true; + locked_checkCircleCacheForAutoSubscribe(cache); } return true; @@ -1515,122 +1386,67 @@ bool p3GxsCircles::locked_processLoadingCacheEntry(RsGxsCircleCache& cache) { //bool isUnprocessedPeers = false; - if (cache.mIsExternal) + if (!cache.mIsExternal) + return true; + +#ifdef DEBUG_CIRCLES + std::cerr << "Processing External Circle " << cache.mCircleId << std::endl; +#endif + bool all_ids_here = true; + + // Do we actually need to retrieve the missing keys for all members of a circle??? + // These keys are needed for subscribtion request signature checking. But this is only + // when a subscription msg is posted, which would trigger retrieval of the key anyway + // Maybe this can be made an option of p3GxsCircles, or of rsIdentity. + + // need to trigger the searches. + for(std::map::iterator pit = cache.mMembershipStatus.begin(); pit != cache.mMembershipStatus.end(); ++pit) { #ifdef DEBUG_CIRCLES - std::cerr << "Processing External Circle " << cache.mCircleId << std::endl; + std::cerr << " Member status: " << pit->first << " : " << pit->second.subscription_flags; #endif - // Do we actually need to retrieve the missing keys for all members of a circle??? - // These keys are needed for subscribtion request signature checking. But this is only - // when a subscription msg is posted, which would trigger retrieval of the key anyway - // Maybe this can be made an option of p3GxsCircles, or of rsIdentity. - - // need to trigger the searches. - for(std::map::iterator pit = cache.mMembershipStatus.begin(); pit != cache.mMembershipStatus.end(); ++pit) + /* check cache */ + if(!(pit->second.subscription_flags & GXS_EXTERNAL_CIRCLE_FLAGS_KEY_AVAILABLE)) { -#ifdef DEBUG_CIRCLES - std::cerr << " Member status: " << pit->first << " : " << pit->second.subscription_flags; -#endif - - /* check cache */ - if(!(pit->second.subscription_flags & GXS_EXTERNAL_CIRCLE_FLAGS_KEY_AVAILABLE)) + if(mIdentities->haveKey(pit->first)) { - if(mIdentities->haveKey(pit->first)) - { - pit->second.subscription_flags |= GXS_EXTERNAL_CIRCLE_FLAGS_KEY_AVAILABLE; + pit->second.subscription_flags |= GXS_EXTERNAL_CIRCLE_FLAGS_KEY_AVAILABLE; - mCacheUpdated = true; #ifdef DEBUG_CIRCLES - std::cerr << " Key is now available!"<< std::endl; + std::cerr << " Key is now available!"<< std::endl; #endif - } - else - { - std::list peers; - - if(!cache.mOriginator.isNull()) - { - peers.push_back(cache.mOriginator) ; -#ifdef DEBUG_CIRCLES - std::cerr << " Requesting unknown/unloaded identity: " << pit->first << " to originator " << cache.mOriginator << std::endl; -#endif - } - else - { - std::cerr << " (WW) cache entry for circle " << cache.mCircleId << " has empty originator. Asking info for GXS id " << pit->first << " to all connected friends." << std::endl; - - rsPeers->getOnlineList(peers) ; - } - - mIdentities->requestKey(pit->first, peers,RsIdentityUsage(serviceType(),RsIdentityUsage::CIRCLE_MEMBERSHIP_CHECK,RsGxsGroupId(cache.mCircleId))); - //isUnprocessedPeers = true; - } - } -#ifdef DEBUG_CIRCLES - else - std::cerr << " Key is available. Nothing to process." << std::endl; -#endif - } - -#ifdef HANDLE_SUBCIRCLES -#if 0 - std::list &circles = group.mSubCircles; - std::list::const_iterator cit; - for(cit = circles.begin(); cit != circles.end(); ++cit) - { - /* if its cached already -> then its complete. */ - if (mCircleCache.is_loaded(*cit)) - { - RsGxsCircleCache cachedCircle; - if (mCircleCache.fetch(&cit, cachedCircle)) - { - /* copy cached circle into circle */ - cache.loadSubCircle(cachedCircle); - } - else - { - /* error */ - continue; - } } else { - /* push into secondary processing queues */ - std::list &proc_circles = mCacheLoad_SubCircle[*cit]; - proc_circles.push_back(id); + std::list peers; - subCirclesToLoad.push_back(*cit); + if(!cache.mOriginator.isNull()) + { + peers.push_back(cache.mOriginator) ; +#ifdef DEBUG_CIRCLES + std::cerr << " Requesting unknown/unloaded identity: " << pit->first << " to originator " << cache.mOriginator << std::endl; +#endif + } + else + { + std::cerr << " (WW) cache entry for circle " << cache.mCircleId << " has empty originator. Asking info for GXS id " << pit->first << " to all connected friends." << std::endl; - isComplete = false; - isUnprocessedCircles = true; + rsPeers->getOnlineList(peers) ; + } + + mIdentities->requestKey(pit->first, peers,RsIdentityUsage(serviceType(),RsIdentityUsage::CIRCLE_MEMBERSHIP_CHECK,RsGxsGroupId(cache.mCircleId))); + + all_ids_here = false; } } -#endif +#ifdef DEBUG_CIRCLES + else + std::cerr << " Key is available. Nothing to process." << std::endl; #endif } -#ifdef DEBUG_CIRCLES - else - std::cerr << " Loading Personal Circle" << std::endl; -#endif - // We can check for self inclusion in the circle right away, since own ids are always loaded. - // that allows to subscribe/unsubscribe uncomplete circles - - locked_checkCircleCacheForAutoSubscribe(cache); - locked_checkCircleCacheForMembershipUpdate(cache); - - // always store in cache even if uncomplete. But do not remove the loading items so that they can be kept in loading state. -// if(isUnprocessedPeers) - // return false ; - - /* move straight into the cache */ - mCircleCache.store(cache.mCircleId, cache); - mCircleCache.resize(); - - std::cerr << " Loading complete." << std::endl; - - return true ; + return all_ids_here; } bool p3GxsCircles::cache_reloadids(const RsGxsCircleId &circleId) @@ -1642,26 +1458,34 @@ bool p3GxsCircles::cache_reloadids(const RsGxsCircleId &circleId) RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + RsGxsCircleCache& cache(mCircleCache[circleId]); + /* fetch from loadMap */ - std::map::iterator it; - it = mLoadingCache.find(circleId); - if (it == mLoadingCache.end()) - { - std::cerr << "p3GxsCircles::cache_reloadids() ERROR Id: " << circleId; - std::cerr << " Not in mLoadingCache Map"; - std::cerr << std::endl; - // ERROR - return false; - } + if(locked_processLoadingCacheEntry(cache)) + { + cache.mAllIdsHere = true; + + // We can check for self inclusion in the circle right away, since own ids are always loaded. + // that allows to subscribe/unsubscribe uncomplete circles + + locked_checkCircleCacheForAutoSubscribe(cache); + + cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::CHECKING_MEMBERSHIP; + locked_checkCircleCacheForMembershipUpdate(cache); + + /* move straight into the cache */ + mCircleCache.resize(); + + std::cerr << " Loading complete." << std::endl; + + return true ; + } - if(locked_processLoadingCacheEntry(it->second)) - { - /* remove from loading queue */ - mLoadingCache.erase(it); - } else { + cache.mAllIdsHere = false; + #ifdef DEBUG_CIRCLES std::cerr << " Unprocessed peers. Requesting reload for circle " << circleId << std::endl; #endif @@ -1676,20 +1500,22 @@ bool p3GxsCircles::cache_reloadids(const RsGxsCircleId &circleId) bool p3GxsCircles::checkCircleCache() { #ifdef DEBUG_CIRCLES - std::cerr << "checkCircleCache(): calling auto-subscribe check and membership update check." << std::endl; + std::cerr << "checkCircleCache(): calling auto-subscribe check and membership update check." << std::endl; #endif - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - - mCircleCache.applyToAllCachedEntries(*this,&p3GxsCircles::locked_checkCircleCacheForAutoSubscribe) ; -// mCircleCache.applyToAllCachedEntries(*this,&p3GxsCircles::locked_checkCircleCacheForMembershipUpdate) ; - - return true ; + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + + mCircleCache.applyToAllCachedEntries(*this,&p3GxsCircles::locked_checkCircleCacheForAutoSubscribe) ; + + return true ; } bool p3GxsCircles::locked_checkCircleCacheForMembershipUpdate(RsGxsCircleCache& cache) { rstime_t now = time(NULL) ; + if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return false; + if(cache.mLastUpdatedMembershipTS + GXS_CIRCLE_DELAY_TO_FORCE_MEMBERSHIP_UPDATE < now) { #ifdef DEBUG_CIRCLES @@ -1739,6 +1565,9 @@ bool p3GxsCircles::locked_checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cac return false; } + if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + return false; + /* if we appear in the group - then autosubscribe, and mark as processed. This also applies if we're the group admin */ std::list myOwnIds; @@ -1756,15 +1585,15 @@ bool p3GxsCircles::locked_checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cac bool member_request = false ; for(std::list::const_iterator it(myOwnIds.begin());it!=myOwnIds.end() && (!in_admin_list) && (!member_request);++it) - { - std::map::const_iterator it2 = cache.mMembershipStatus.find(*it) ; - - if(it2 != cache.mMembershipStatus.end()) - { - in_admin_list = in_admin_list || bool(it2->second.subscription_flags & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST) ; - member_request= member_request|| bool(it2->second.subscription_flags & GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED) ; - } - } + { + std::map::const_iterator it2 = cache.mMembershipStatus.find(*it) ; + + if(it2 != cache.mMembershipStatus.end()) + { + in_admin_list = in_admin_list || bool(it2->second.subscription_flags & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST) ; + member_request= member_request|| bool(it2->second.subscription_flags & GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED) ; + } + } bool am_I_admin( cache.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) ; @@ -1799,24 +1628,24 @@ bool p3GxsCircles::locked_checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cac else { /* we know all the peers - we are not part - we can flag as PROCESSED. */ - uint32_t token,token2; + uint32_t token,token2; RsGenExchange::setGroupStatusFlags(token, RsGxsGroupId(cache.mCircleId.toStdString()), 0, GXS_SERV::GXS_GRP_STATUS_UNPROCESSED); - - if(cache.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) - { + + if(cache.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) + { RsGenExchange::subscribeToGroup(token2, RsGxsGroupId(cache.mCircleId), false); #ifdef DEBUG_CIRCLES - std::cerr << " Not part of the group! Let's unsubscribe this circle of unfriendly Napoleons!" << std::endl; + std::cerr << " Not part of the group! Let's unsubscribe this circle of unfriendly Napoleons!" << std::endl; #endif - } + } #ifdef DEBUG_CIRCLES - else + else std::cerr << " Not part of the group, and not subscribed either." << std::endl; #endif - + cache.mGroupStatus &= ~GXS_SERV::GXS_GRP_STATUS_UNPROCESSED; - - mCacheUpdated = true; + + mCacheUpdated = true; return true ; } } @@ -1839,350 +1668,9 @@ void p3GxsCircles::addCircleIdToList(const RsGxsCircleId &circleId, uint32_t cir } } - - -#ifdef HANDLE_SUBCIRCLES -#if 0 -/**** TODO BELOW ****/ - -bool p3GxsCircles::cache_load_subcircles(uint32_t token) -{ - std::cerr << "p3GxsCircles::cache_load_subcircles() : " << token; - std::cerr << std::endl; - - std::vector grpData; - bool ok = RsGenExchange::getGroupData(token, grpData); - - if(ok) - { - std::vector::iterator vit = grpData.begin(); - - for(; vit != grpData.end(); ++vit) - { - RsGxsIdGroupItem* item = dynamic_cast(*vit); - - RsGxsCircleId id = item->meta.mGroupId; - RsGxsCircleGroup group = item->group; - group.mMeta = item->meta; - delete item; - - std::cerr << "p3GxsCircles::cache_load_subcircles() Loaded Id with Meta: "; - std::cerr << item->meta; - std::cerr << std::endl; - - - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - - /* stage 2 of loading, load subcircles */ - std::map >::iterator sit; - sit = mCacheLoad_SubCircle.find(id) - if (sit == mCacheLoad_SubCircle.end()) - { - /* ERROR */ - continue; - } - - std::list updateCaches = sit->second; - // cleanup while we're here. - mCacheLoad_SubCircle.erase(sit); - - /* Now iterate through peers / subcircles, and apply - * - similarly to base load function - */ - - - RsGxsCircleCache &cache = it->second; - cache.loadBaseCircle(group); - - bool isComplete = true; - - std::list &peers = group.peers; - std::list::const_iterator pit; - - // need to trigger the searches. - for(pit = peers.begin(); pit != peers.end(); ++pit) - { - /* check cache */ - if (mIdentities->is_cached(*pit)) - { - /* we can process now! */ - RsIdentityDetails details; - if (mIdentities->getDetails(*pit, details)) - { - if (details.isPgpKnown) - { - // Problem - could have multiple GxsIds here! - // TODO. - //cache.mAllowedPeers[details.mPgpId] = *pit; - - for(uit = updateCaches.begin(); uit != updateCaches.end(); ++uit) - { - /* fetch the cache - and update */ - mLoadingCache[id] = RsGxsCircleCache(); - std::map::iterator it; - it = mLoadingCache.find(id); - } - - } - else - { - //cache.mUnknownPeers.push_back(*pit); - } - } - else - { - // ERROR. - } - } - else - { - /* store in to_process queue. */ - cache.mUnprocessedPeers.push_back(*pit); - - if (isComplete) - { - /* store reference to update */ - isComplete = false; - mCacheLoad_KeyWait.push_back(id); - } - } - } - - std::list &circles = group.circles; - std::list::const_iterator cit; - for(cit = circles.begin(); cit != circles.end(); ++cit) - { - /* if its cached already -> then its complete. */ - if (mCircleCache.is_loaded(*cit)) - { - RsGxsCircleCache cachedCircle; - if (mCircleCache.fetch(&cit, cachedCircle)) - { - /* copy cached circle into circle */ - cache.loadSubCircle(cachedCircle); - } - else - { - /* error */ - continue; - } - } - else - { - /* push into secondary processing queues */ - std::list &proc_circles = mCacheLoad_SubCircle[id]; - proc_circles.push_back(id); - - subCirclesToLoad.push_back(id); - - isComplete = false; - } - } - - if (isComplete) - { - /* move straight into the cache */ - mCircleCache.store(id, cache); - - /* remove from loading queue */ - mLoadingCache.erase(it); - } - } - } - else - { - std::cerr << "p3GxsCircles::cache_load_for_token() ERROR no data"; - std::cerr << std::endl; - - return false; - } - - if (!keysToLoad.empty()) - { - /* schedule event to try reload gxsIds */ - - } - - if (!subCirclesToLoad.empty()) - { - /* request load of subcircles */ - - - } - return true; -} - -#endif -#endif - - -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ - -std::string p3GxsCircles::genRandomId() -{ - std::string randomId; - for(int i = 0; i < 20; i++) - { - randomId += (char) ('a' + (RSRandom::random_u32() % 26)); - } - - return randomId; -} - -void p3GxsCircles::generateDummyData() -{ - // request Id Data... -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::generateDummyData() getting Id List"; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - - uint32_t ansType = RS_TOKREQ_ANSTYPE_DATA; - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; - - uint32_t token; - rsIdentity->getTokenService()->requestGroupInfo(token, ansType, opts); - - { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - mDummyIdToken = token; - } - - RsTickEvent::schedule_in(CIRCLE_EVENT_DUMMYLOAD, CIRCLE_DUMMY_GENPERIOD); -} - - -void p3GxsCircles::checkDummyIdData() -{ -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::checkDummyIdData()"; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - - // check the token. - uint32_t status = rsIdentity->getTokenService()->requestStatus(mDummyIdToken); - if ( (RsTokenService::FAILED == status) || - (RsTokenService::COMPLETE == status) ) - { - std::vector ids; - if (!rsIdentity->getGroupData(mDummyIdToken, ids)) - { - std::cerr << "p3GxsCircles::checkDummyIdData() ERROR getting data"; - std::cerr << std::endl; - /* error */ - return; - } - - std::vector::iterator it; - for(it = ids.begin(); it != ids.end(); ++it) - { - if (it->mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility) - { -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::checkDummyIdData() PgpLinkedId: " << it->mMeta.mGroupId; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - mDummyPgpLinkedIds.push_back(RsGxsId(it->mMeta.mGroupId.toStdString())); - - if (it->mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) - { -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::checkDummyIdData() OwnId: " << it->mMeta.mGroupId; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - mDummyOwnIds.push_back(RsGxsId(it->mMeta.mGroupId.toStdString())); - } - } - else - { -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::checkDummyIdData() Other Id: " << it->mMeta.mGroupId; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - } - } - - /* schedule the generate events */ -#define MAX_CIRCLES 10 - for(int i = 0; i < MAX_CIRCLES; i++) - { - RsTickEvent::schedule_in(CIRCLE_EVENT_DUMMYGEN, i * CIRCLE_DUMMY_GENPERIOD); - } - return; - } - - // Otherwise - reschedule to come back here. - RsTickEvent::schedule_in(CIRCLE_EVENT_DUMMYLOAD, CIRCLE_DUMMY_GENPERIOD); - return; -} - - -void p3GxsCircles::generateDummyCircle() -{ -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::generateDummyCircle()"; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - - int npgps = mDummyPgpLinkedIds.size(); - - if(npgps == 0) - return ; - - RsGxsCircleGroup group; - - std::set idset; - // select a random number of them. -#define MAX_PEERS_PER_CIRCLE_GROUP 20 - int nIds = 1 + (RSRandom::random_u32() % MAX_PEERS_PER_CIRCLE_GROUP); - for(int i = 0; i < nIds; i++) - { - - int selection = (RSRandom::random_u32() % npgps); - std::list::iterator it = mDummyPgpLinkedIds.begin(); - for(int j = 0; (it != mDummyPgpLinkedIds.end()) && (j < selection); j++, ++it) ; - if (it != mDummyPgpLinkedIds.end()) - { - idset.insert(*it); - } - } - - /* be sure to add one of our IDs too (otherwise we wouldn't get the group) - */ - { - - int selection = (RSRandom::random_u32() % mDummyOwnIds.size()); - std::list::iterator it = mDummyOwnIds.begin(); - mDummyOwnIds.push_back(*it); - for(int j = 0; (it != mDummyOwnIds.end()) && (j < selection); j++, ++it) ; - if (it != mDummyOwnIds.end()) - { - idset.insert(*it); - } - } - - group.mMeta.mGroupName = genRandomId(); -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::generateDummyCircle() Name: " << group.mMeta.mGroupName; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - - std::set::iterator it; - for(it = idset.begin(); it != idset.end(); ++it) - { - group.mInvitedMembers.insert(*it); -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::generateDummyCircle() Adding: " << *it; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - } - - uint32_t dummyToken; - createGroup(dummyToken, group); -} +//====================================================================================// +// Event handling // +//====================================================================================// // Overloaded from GxsTokenQueue for Request callbacks. void p3GxsCircles::handleResponse(uint32_t token, uint32_t req_type) @@ -2255,6 +1743,10 @@ void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel) } } +//====================================================================================// +// Membership request handling // +//====================================================================================// + // Circle membership is requested/denied by posting a message into the cicle group, according to the following rules: // // - a subscription request is a RsItem (which serialises into a radix64 message, that is further signed by the group message publishing system) @@ -2394,7 +1886,6 @@ bool p3GxsCircles::cancelCircleMembership(const RsGxsId& own_gxsid,const RsGxsCi return pushCircleMembershipRequest(own_gxsid,circle_id,RsGxsCircleSubscriptionType::UNSUBSCRIBE) ; } - bool p3GxsCircles::processMembershipRequests(uint32_t token) { // Go through membership request messages and process them according to the following rule: @@ -2416,75 +1907,68 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) GxsMsgReq messages_to_delete ; for(GxsMsgDataMap::const_iterator it(msgItems.begin());it!=msgItems.end();++it) - { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + { + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ #ifdef DEBUG_CIRCLES - std::cerr << " Circle ID: " << it->first << std::endl; + std::cerr << " Circle ID: " << it->first << std::endl; +#endif + // Find the circle ID in cache and process the list of messages to keep the latest order in time. + + RsGxsCircleId circle_id(it->first); + RsGxsCircleCache& cache( mCircleCache[circle_id] ); +#ifdef DEBUG_CIRCLES + std::cerr << " Circle found in cache!" << std::endl; + std::cerr << " Retrieving messages..." << std::endl; #endif - RsGxsCircleId cid ( it->first ); - - if (!mCircleCache.is_cached(cid)) - { - std::cerr << " (EE) Circle is not in cache!" << std::endl; - continue ; - } - - // Find the circle ID in cache and process the list of messages to keep the latest order in time. - - RsGxsCircleCache& data = mCircleCache.ref(cid); -#ifdef DEBUG_CIRCLES - std::cerr << " Circle found in cache!" << std::endl; - std::cerr << " Retrieving messages..." << std::endl; -#endif - - for(uint32_t i=0;isecond.size();++i) - { -#ifdef DEBUG_CIRCLES - std::cerr << " Group ID: " << it->second[i]->meta.mGroupId << ", Message ID: " << it->second[i]->meta.mMsgId << ": " ; -#endif - - RsGxsCircleSubscriptionRequestItem *item = dynamic_cast(it->second[i]) ; - - if(item == NULL) + for(uint32_t i=0;isecond.size();++i) { - std::cerr << " (EE) item is not a RsGxsCircleSubscriptionRequestItem. Weird." << std::endl; - continue ; - } - - RsGxsCircleMembershipStatus& info(data.mMembershipStatus[item->meta.mAuthorId]) ; - #ifdef DEBUG_CIRCLES - std::cerr << " is from id " << item->meta.mAuthorId << " " << time(NULL) - item->time_stamp << " seconds ago, " ; + std::cerr << " Group ID: " << it->second[i]->meta.mGroupId << ", Message ID: " << it->second[i]->meta.mMsgId << ": " ; #endif - - if(info.last_subscription_TS < item->time_stamp) - { - info.last_subscription_TS = item->time_stamp ; - - if(item->subscription_type == RsGxsCircleSubscriptionType::SUBSCRIBE) - info.subscription_flags |= GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED; - else if(item->subscription_type == RsGxsCircleSubscriptionType::UNSUBSCRIBE) - info.subscription_flags &= ~GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED; - else - std::cerr << " (EE) unknown subscription order type: " << static_cast(item->subscription_type) ; - - mCacheUpdated = true; + + RsGxsCircleSubscriptionRequestItem *item = dynamic_cast(it->second[i]) ; + + if(item == NULL) + { + std::cerr << " (EE) item is not a RsGxsCircleSubscriptionRequestItem. Weird." << std::endl; + continue ; + } + + RsGxsCircleMembershipStatus& info(cache.mMembershipStatus[item->meta.mAuthorId]) ; + #ifdef DEBUG_CIRCLES - std::cerr << " UPDATING" << std::endl; + std::cerr << " is from id " << item->meta.mAuthorId << " " << time(NULL) - item->time_stamp << " seconds ago, " ; #endif - } - else if(info.last_subscription_TS > item->time_stamp) - { + + if(info.last_subscription_TS < item->time_stamp) + { + info.last_subscription_TS = item->time_stamp ; + + if(item->subscription_type == RsGxsCircleSubscriptionType::SUBSCRIBE) + info.subscription_flags |= GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED; + else if(item->subscription_type == RsGxsCircleSubscriptionType::UNSUBSCRIBE) + info.subscription_flags &= ~GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED; + else + std::cerr << " (EE) unknown subscription order type: " << static_cast(item->subscription_type) ; + + mCacheUpdated = true; #ifdef DEBUG_CIRCLES - std::cerr << " Older than last known (" << time(NULL)-info.last_subscription_TS << " seconds ago): deleting." << std::endl; + std::cerr << " UPDATING" << std::endl; #endif - messages_to_delete[RsGxsGroupId(cid)].insert(it->second[i]->meta.mMsgId) ; - } - } - - data.mLastUpdatedMembershipTS = time(NULL) ; - mCacheUpdated = true; + } + else if(info.last_subscription_TS > item->time_stamp) + { +#ifdef DEBUG_CIRCLES + std::cerr << " Older than last known (" << time(NULL)-info.last_subscription_TS << " seconds ago): deleting." << std::endl; +#endif + messages_to_delete[RsGxsGroupId(circle_id)].insert(it->second[i]->meta.mMsgId) ; + } + } + + cache.mLastUpdatedMembershipTS = time(NULL) ; + cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::UP_TO_DATE; + cache.mLastUpdateTime = time(NULL); } RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ @@ -2494,14 +1978,512 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) return true ; } -/*static*/ const std::string RsGxsCircles::DEFAULT_CIRCLE_BASE_URL = - "retroshare:///circles"; -/*static*/ const std::string RsGxsCircles::CIRCLE_URL_NAME_FIELD = "circleName"; -/*static*/ const std::string RsGxsCircles::CIRCLE_URL_ID_FIELD = "circleId"; -/*static*/ const std::string RsGxsCircles::CIRCLE_URL_DATA_FIELD = "circleData"; +//====================================================================================// +// DEBUG STUFF // +//====================================================================================// -RsGxsCircles::~RsGxsCircles() = default; -RsGxsCircleMsg::~RsGxsCircleMsg() = default; -RsGxsCircleDetails::~RsGxsCircleDetails() = default; -RsGxsCircleGroup::~RsGxsCircleGroup() = default; -RsGxsCircleEvent::~RsGxsCircleEvent() = default; +bool p3GxsCircles::debug_dumpCacheEntry(RsGxsCircleCache& cache) +{ + std::cerr << " Circle: " << cache.mCircleId << " status: " << cache.mStatus << " MembershipTS: " << cache.mLastUpdatedMembershipTS + << " UpdateTS: " << cache.mLastUpdateTime << " All Ids here: " << cache.mAllIdsHere << std::endl; + + return true; +} + +void p3GxsCircles::debug_dumpCache() +{ + std::cerr << "Debug dump of CircleCache:" << std::endl; + + mCircleCache.printStats(std::cerr); + mCircleCache.applyToAllCachedEntries(*this,&p3GxsCircles::debug_dumpCacheEntry); +} + +std::string p3GxsCircles::genRandomId() +{ + std::string randomId; + for(int i = 0; i < 20; i++) + { + randomId += (char) ('a' + (RSRandom::random_u32() % 26)); + } + + return randomId; +} + +void p3GxsCircles::generateDummyData() +{ + // request Id Data... +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::generateDummyData() getting Id List"; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + + uint32_t ansType = RS_TOKREQ_ANSTYPE_DATA; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + + uint32_t token; + rsIdentity->getTokenService()->requestGroupInfo(token, ansType, opts); + + { + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + mDummyIdToken = token; + } + + RsTickEvent::schedule_in(CIRCLE_EVENT_DUMMYLOAD, CIRCLE_DUMMY_GENPERIOD); +} + + +void p3GxsCircles::checkDummyIdData() +{ +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::checkDummyIdData()"; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + + // check the token. + uint32_t status = rsIdentity->getTokenService()->requestStatus(mDummyIdToken); + if ( (RsTokenService::FAILED == status) || + (RsTokenService::COMPLETE == status) ) + { + std::vector ids; + if (!rsIdentity->getGroupData(mDummyIdToken, ids)) + { + std::cerr << "p3GxsCircles::checkDummyIdData() ERROR getting data"; + std::cerr << std::endl; + /* error */ + return; + } + + std::vector::iterator it; + for(it = ids.begin(); it != ids.end(); ++it) + { + if (it->mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility) + { +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::checkDummyIdData() PgpLinkedId: " << it->mMeta.mGroupId; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + mDummyPgpLinkedIds.push_back(RsGxsId(it->mMeta.mGroupId.toStdString())); + + if (it->mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) + { +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::checkDummyIdData() OwnId: " << it->mMeta.mGroupId; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + mDummyOwnIds.push_back(RsGxsId(it->mMeta.mGroupId.toStdString())); + } + } + else + { +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::checkDummyIdData() Other Id: " << it->mMeta.mGroupId; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + } + } + + /* schedule the generate events */ +#define MAX_CIRCLES 10 + for(int i = 0; i < MAX_CIRCLES; i++) + { + RsTickEvent::schedule_in(CIRCLE_EVENT_DUMMYGEN, i * CIRCLE_DUMMY_GENPERIOD); + } + return; + } + + // Otherwise - reschedule to come back here. + RsTickEvent::schedule_in(CIRCLE_EVENT_DUMMYLOAD, CIRCLE_DUMMY_GENPERIOD); + return; +} + + +void p3GxsCircles::generateDummyCircle() +{ +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::generateDummyCircle()"; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + + int npgps = mDummyPgpLinkedIds.size(); + + if(npgps == 0) + return ; + + RsGxsCircleGroup group; + + std::set idset; + // select a random number of them. +#define MAX_PEERS_PER_CIRCLE_GROUP 20 + int nIds = 1 + (RSRandom::random_u32() % MAX_PEERS_PER_CIRCLE_GROUP); + for(int i = 0; i < nIds; i++) + { + + int selection = (RSRandom::random_u32() % npgps); + std::list::iterator it = mDummyPgpLinkedIds.begin(); + for(int j = 0; (it != mDummyPgpLinkedIds.end()) && (j < selection); j++, ++it) ; + if (it != mDummyPgpLinkedIds.end()) + { + idset.insert(*it); + } + } + + /* be sure to add one of our IDs too (otherwise we wouldn't get the group) + */ + { + + int selection = (RSRandom::random_u32() % mDummyOwnIds.size()); + std::list::iterator it = mDummyOwnIds.begin(); + mDummyOwnIds.push_back(*it); + for(int j = 0; (it != mDummyOwnIds.end()) && (j < selection); j++, ++it) ; + if (it != mDummyOwnIds.end()) + { + idset.insert(*it); + } + } + + group.mMeta.mGroupName = genRandomId(); +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::generateDummyCircle() Name: " << group.mMeta.mGroupName; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + + std::set::iterator it; + for(it = idset.begin(); it != idset.end(); ++it) + { + group.mInvitedMembers.insert(*it); +#ifdef DEBUG_CIRCLES + std::cerr << "p3GxsCircles::generateDummyCircle() Adding: " << *it; + std::cerr << std::endl; +#endif // DEBUG_CIRCLES + } + + uint32_t dummyToken; + createGroup(dummyToken, group); +} + + +/****************************************************************************/ +// ID STUFF. \/ \/ \/ \/ \/ \/ \/ :) +/****************************************************************************/ +#if 0 + +/************************************************************************************/ +/************************************************************************************/ + +bool p3GxsCircles::cachetest_getlist() +{ + std::cerr << "p3GxsCircles::cachetest_getlist() making request"; + std::cerr << std::endl; + + uint32_t ansType = RS_TOKREQ_ANSTYPE_LIST; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_IDS; + uint32_t token = 0; + + RsGenExchange::getTokenService()->requestGroupInfo(token, ansType, opts); + GxsTokenQueue::queueRequest(token, CIRCLEREQ_CACHETEST); + + // Schedule Next Event. + RsTickEvent::schedule_in(CIRCLE_EVENT_CACHETEST, CACHETEST_PERIOD); + return true; +} + +bool p3GxsCircles::cachetest_handlerequest(uint32_t token) +{ + std::cerr << "p3GxsCircles::cachetest_handlerequest() token: " << token; + std::cerr << std::endl; + + std::list grpIds; + bool ok = RsGenExchange::getGroupList(token, grpIds); + + if(ok) + { + std::list::iterator vit = grpIds.begin(); + for(; vit != grpIds.end(); ++vit) + { + /* 5% chance of checking it! */ + if (RSRandom::random_f32() < 0.25) + { + std::cerr << "p3GxsCircles::cachetest_request() Testing Id: " << *vit; + std::cerr << std::endl; + + /* try the cache! */ + if (!haveKey(*vit)) + { + std::list nullpeers; + requestKey(*vit, nullpeers); + + std::cerr << "p3GxsCircles::cachetest_request() Requested Key Id: " << *vit; + std::cerr << std::endl; + } + else + { + RsTlvSecurityKey seckey; + if (getKey(*vit, seckey)) + { + std::cerr << "p3GxsCircles::cachetest_request() Got Key OK Id: " << *vit; + std::cerr << std::endl; + + // success! + seckey.print(std::cerr, 10); + std::cerr << std::endl; + + + } + else + { + std::cerr << "p3GxsCircles::cachetest_request() ERROR no Key for Id: " << *vit; + std::cerr << std::endl; + } + } + + /* try private key too! */ + if (!havePrivateKey(*vit)) + { + requestPrivateKey(*vit); + std::cerr << "p3GxsCircles::cachetest_request() Requested PrivateKey Id: " << *vit; + std::cerr << std::endl; + } + else + { + RsTlvSecurityKey seckey; + if (getPrivateKey(*vit, seckey)) + { + // success! + std::cerr << "p3GxsCircles::cachetest_request() Got PrivateKey OK Id: " << *vit; + std::cerr << std::endl; + } + else + { + std::cerr << "p3GxsCircles::cachetest_request() ERROR no PrivateKey for Id: " << *vit; + std::cerr << std::endl; + } + } + } + } + } + else + { + std::cerr << "p3GxsCircles::cache_load_for_token() ERROR no data"; + std::cerr << std::endl; + + return false; + } + return true; +} + +/****************************************************************************/ +// ID STUFF. /\ /\ /\ /\ /\ /\ /\ /\ :) +/****************************************************************************/ +#endif + +#ifdef HANDLE_SUBCIRCLES +#if 0 +/**** TODO BELOW ****/ + +bool p3GxsCircles::cache_load_subcircles(uint32_t token) +{ + std::cerr << "p3GxsCircles::cache_load_subcircles() : " << token; + std::cerr << std::endl; + + std::vector grpData; + bool ok = RsGenExchange::getGroupData(token, grpData); + + if(ok) + { + std::vector::iterator vit = grpData.begin(); + + for(; vit != grpData.end(); ++vit) + { + RsGxsIdGroupItem* item = dynamic_cast(*vit); + + RsGxsCircleId id = item->meta.mGroupId; + RsGxsCircleGroup group = item->group; + group.mMeta = item->meta; + delete item; + + std::cerr << "p3GxsCircles::cache_load_subcircles() Loaded Id with Meta: "; + std::cerr << item->meta; + std::cerr << std::endl; + + + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + + /* stage 2 of loading, load subcircles */ + std::map >::iterator sit; + sit = mCacheLoad_SubCircle.find(id) + if (sit == mCacheLoad_SubCircle.end()) + { + /* ERROR */ + continue; + } + + std::list updateCaches = sit->second; + // cleanup while we're here. + mCacheLoad_SubCircle.erase(sit); + + /* Now iterate through peers / subcircles, and apply + * - similarly to base load function + */ + + + RsGxsCircleCache &cache = it->second; + cache.loadBaseCircle(group); + + bool isComplete = true; + + std::list &peers = group.peers; + std::list::const_iterator pit; + + // need to trigger the searches. + for(pit = peers.begin(); pit != peers.end(); ++pit) + { + /* check cache */ + if (mIdentities->is_cached(*pit)) + { + /* we can process now! */ + RsIdentityDetails details; + if (mIdentities->getDetails(*pit, details)) + { + if (details.isPgpKnown) + { + // Problem - could have multiple GxsIds here! + // TODO. + //cache.mAllowedPeers[details.mPgpId] = *pit; + + for(uit = updateCaches.begin(); uit != updateCaches.end(); ++uit) + { + /* fetch the cache - and update */ + mLoadingCache[id] = RsGxsCircleCache(); + std::map::iterator it; + it = mLoadingCache.find(id); + } + + } + else + { + //cache.mUnknownPeers.push_back(*pit); + } + } + else + { + // ERROR. + } + } + else + { + /* store in to_process queue. */ + cache.mUnprocessedPeers.push_back(*pit); + + if (isComplete) + { + /* store reference to update */ + isComplete = false; + mCacheLoad_KeyWait.push_back(id); + } + } + } + + std::list &circles = group.circles; + std::list::const_iterator cit; + for(cit = circles.begin(); cit != circles.end(); ++cit) + { + /* if its cached already -> then its complete. */ + if (mCircleCache.is_loaded(*cit)) + { + RsGxsCircleCache cachedCircle; + if (mCircleCache.fetch(&cit, cachedCircle)) + { + /* copy cached circle into circle */ + cache.loadSubCircle(cachedCircle); + } + else + { + /* error */ + continue; + } + } + else + { + /* push into secondary processing queues */ + std::list &proc_circles = mCacheLoad_SubCircle[id]; + proc_circles.push_back(id); + + subCirclesToLoad.push_back(id); + + isComplete = false; + } + } + + if (isComplete) + { + /* move straight into the cache */ + mCircleCache.store(id, cache); + + /* remove from loading queue */ + mLoadingCache.erase(it); + } + } + } + else + { + std::cerr << "p3GxsCircles::cache_load_for_token() ERROR no data"; + std::cerr << std::endl; + + return false; + } + + if (!keysToLoad.empty()) + { + /* schedule event to try reload gxsIds */ + + } + + if (!subCirclesToLoad.empty()) + { + /* request load of subcircles */ + + + } + return true; +} + +#endif +#endif + +#ifdef HANDLE_SUBCIRCLES +#if 0 + std::list &circles = group.mSubCircles; + std::list::const_iterator cit; + for(cit = circles.begin(); cit != circles.end(); ++cit) + { + /* if its cached already -> then its complete. */ + if (mCircleCache.is_loaded(*cit)) + { + RsGxsCircleCache cachedCircle; + if (mCircleCache.fetch(&cit, cachedCircle)) + { + /* copy cached circle into circle */ + cache.loadSubCircle(cachedCircle); + } + else + { + /* error */ + continue; + } + } + else + { + /* push into secondary processing queues */ + std::list &proc_circles = mCacheLoad_SubCircle[*cit]; + proc_circles.push_back(id); + + subCirclesToLoad.push_back(*cit); + + isComplete = false; + isUnprocessedCircles = true; + } + } +#endif +#endif diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index bad3eca3a..bf875fed6 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -130,9 +130,9 @@ public: class RsGxsCircleCache { - public: - +public: RsGxsCircleCache(); + bool loadBaseCircle(const RsGxsCircleGroup &circle); bool loadSubCircle(const RsGxsCircleCache &subcircle); @@ -142,28 +142,44 @@ class RsGxsCircleCache bool addAllowedPeer(const RsPgpId &pgpid); bool addLocalFriend(const RsPgpId &pgpid); + // Cache related data + + enum CircleEntryCacheStatus: uint8_t // This enum + { + UNKNOWN = 0x00, // Used to detect uninitialized memory + NO_DATA = 0x01, // Used in the constuctor + LOADING = 0x02, // When the token request to load cache has been sent and no data is present + UPDATING = 0x03, // Starting from this level the cache entry can be used + CHECKING_MEMBERSHIP = 0x04, // Means we're actually looking into msgs to update membership status + UP_TO_DATE = 0x05, // Everything should be loaded here. + }; + rstime_t mLastUpdatedMembershipTS ; // Last time the subscribe messages have been requested. Should be reset when new messages arrive. + rstime_t mLastUpdateTime; // Last time the cache entry was loaded + CircleEntryCacheStatus mStatus; // Overall state of the cache entry + bool mAllIdsHere ; // True when all ids are knwon and available. + + // GxsCircle related data + RsGxsCircleId mCircleId; std::string mCircleName; RsGxsCircleType mCircleType; bool mIsExternal; - RsGxsCircleId mRestrictedCircleId ; // circle ID that circle is restricted to. + RsGxsCircleId mRestrictedCircleId ; // circle ID that circle is restricted to. uint32_t mGroupStatus; uint32_t mGroupSubscribeFlags; - rstime_t mUpdateTime; #ifdef SUBSCIRCLES std::set mUnprocessedCircles; std::set mProcessedCircles; #endif std::map mMembershipStatus; - rstime_t mLastUpdatedMembershipTS ; // last time the subscribe messages have been requested. Should be reset when new messages arrive. - + std::set mAllowedGxsIds; // IDs that are allowed in the circle and have requested membership. This is the official members list. std::set mAllowedNodes; - - RsPeerId mOriginator ; // peer who sent the data, in case we need to ask for ids + + RsPeerId mOriginator ; // peer who sent the data, in case we need to ask for ids }; @@ -319,20 +335,17 @@ public: std::list mCirclePersonalIdList; /***** Caching Circle Info, *****/ - // initial load queue - std::list mCacheLoad_ToCache; // waiting for subcircle to load. (first is part of each of the second list) // TODO. //std::map > mCacheLoad_SubCircle; - // Circles that are being loaded. - std::map mLoadingCache; + std::set mCirclesToLoad; // list of circles to update/load, so that we can treat them by groups. + RsMemCache mCircleCache; // actual cache data - // actual cache. - RsMemCache mCircleCache; - - private: + void debug_dumpCache(); // debug method to overview what's going on + bool debug_dumpCacheEntry(RsGxsCircleCache &cache); +private: std::string genRandomId(); @@ -347,6 +360,7 @@ public: std::list mDummyOwnIds; bool mCacheUpdated ; rstime_t mLastCacheUpdateEvent; + rstime_t mLastDebugPrintTS; RS_SET_CONTEXT_DEBUG_LEVEL(2) }; diff --git a/libretroshare/src/util/rsmemcache.h b/libretroshare/src/util/rsmemcache.h index 95249c28e..53d5efa27 100644 --- a/libretroshare/src/util/rsmemcache.h +++ b/libretroshare/src/util/rsmemcache.h @@ -60,7 +60,12 @@ public: bool is_cached(const Key &key) const; bool fetch(const Key &key, Value &data); - Value &ref(const Key &key); // like map[] installs empty one if non-existent. + + // Like map[] installs empty one if non-existent. + + Value& ref(const Key &key); + Value& operator[](const Key& key) { return ref(key); } + bool store(const Key &key, const Value &data); bool erase(const Key &key); // clean up cache. @@ -70,7 +75,8 @@ public: template bool applyToAllCachedEntries(ClientClass& c,bool (ClientClass::*method)(Value&)); - uint32_t size() const { return mDataMap.size() ; } + uint32_t size() const { return mDataMap.size() ; } + void printStats(std::ostream& out); private: bool update_lrumap(const Key &key, rstime_t old_ts, rstime_t new_ts); @@ -96,7 +102,6 @@ private: std::string mName; // some statistics. - void printStats(std::ostream &out); void clearStats(); mutable uint32_t mStats_inserted; From 5f5c2be64bc64bc5d80bdccbe46af027a5d016d8 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 7 May 2020 20:35:02 +0200 Subject: [PATCH 16/79] fixed a few bugs in the new circle cache system --- libretroshare/src/gxs/rsgxsnotify.h | 3 +- libretroshare/src/services/p3gxscircles.cc | 142 +++++++++++---------- libretroshare/src/services/p3gxscircles.h | 2 +- 3 files changed, 78 insertions(+), 69 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnotify.h b/libretroshare/src/gxs/rsgxsnotify.h index 5bd7e2cb3..4640f133a 100644 --- a/libretroshare/src/gxs/rsgxsnotify.h +++ b/libretroshare/src/gxs/rsgxsnotify.h @@ -92,7 +92,8 @@ public: class RsGxsMsgChange : public RsGxsNotify { public: - RsGxsMsgChange(NotifyType type, const RsGxsGroupId& gid, const RsGxsMessageId& msg_id,bool metaChange) : RsGxsNotify(gid), mNewMsgItem(nullptr),NOTIFY_TYPE(type), mMetaChange(metaChange) {} + RsGxsMsgChange(NotifyType type, const RsGxsGroupId& gid, const RsGxsMessageId& msg_id,bool metaChange) + : RsGxsNotify(gid), mMsgId(msg_id), mNewMsgItem(nullptr),NOTIFY_TYPE(type), mMetaChange(metaChange) {} RsGxsMessageId mMsgId; RsGxsMsgItem *mNewMsgItem; diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 43a16816d..69bcac53e 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -40,6 +40,7 @@ /**** * #define DEBUG_CIRCLES 1 ****/ +#define DEBUG_CIRCLES 1 /*extern*/ RsGxsCircles* rsGxsCircles = nullptr; @@ -126,7 +127,7 @@ p3GxsCircles::p3GxsCircles( RsGeneralDataService *gds, RsNetworkExchangeService RsTickEvent(), mIdentities(identities), mPgpUtils(pgpUtils), mCircleMtx("p3GxsCircles"), mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache" ), - mCacheUpdated(false) + mShouldSendCacheUpdateNotification(false) { // Kick off Cache Testing, + Others. //RsTickEvent::schedule_in(CIRCLE_EVENT_CACHETEST, CACHETEST_PERIOD); @@ -519,7 +520,7 @@ void p3GxsCircles::service_tick() rstime_t now = time(NULL); - if(mCacheUpdated && now > mLastCacheUpdateEvent + GXS_CIRCLE_DELAY_TO_SEND_CACHE_UPDATED_EVENT) + if(mShouldSendCacheUpdateNotification && now > mLastCacheUpdateEvent + GXS_CIRCLE_DELAY_TO_SEND_CACHE_UPDATED_EVENT) { if(rsEvents) { @@ -529,7 +530,7 @@ void p3GxsCircles::service_tick() } mLastCacheUpdateEvent = now; - mCacheUpdated = false; + mShouldSendCacheUpdateNotification = false; } if(now > mLastCacheMembershipUpdateTS + GXS_CIRCLE_DELAY_TO_CHECK_MEMBERSHIP_UPDATE) @@ -569,9 +570,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) { #ifdef DEBUG_CIRCLES std::cerr << " Found circle Message Change Notification for group " << msgChange->mGroupId << ", msg ID " << msgChange->mMsgId << std::endl; -#endif -#ifdef DEBUG_CIRCLES - std::cerr << " Msgs for Group: " << mit->first << std::endl; + std::cerr << " Msgs for Group: " << msgChange->mGroupId << std::endl; #endif RsGxsCircleId circle_id(msgChange->mGroupId); @@ -602,9 +601,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsErr() << __PRETTY_FUNCTION__ << ": missing SubscriptionRequestItem in msg notification for msg " << msgChange->mMsgId << std::endl; } - mCircleCache.erase(circle_id); circles_to_reload.insert(circle_id); - mCacheUpdated = true; } RsGxsGroupChange *groupChange = dynamic_cast(c); @@ -614,32 +611,36 @@ void p3GxsCircles::notifyChanges(std::vector &changes) { const RsGxsGroupId *git(&groupChange->mGroupId); - if(!groupChange->metaChange()) +#ifdef DEBUG_CIRCLES + std::cerr << " Found Group Change Notification of type " << c->getType() << std::endl; +#endif + switch(c->getType()) + { + case RsGxsNotify::TYPE_RECEIVED_NEW: + case RsGxsNotify::TYPE_UPDATED: + case RsGxsNotify::TYPE_PUBLISHED: { #ifdef DEBUG_CIRCLES - std::cerr << " Found Group Change Notification" << std::endl; -#endif - //for(std::list::iterator git = groupChange->mGrpIdList.begin(); git != groupChange->mGrpIdList.end(); ++git) - { -#ifdef DEBUG_CIRCLES - std::cerr << " Incoming Group: " << *git << ". Forcing cache load." << std::endl; + std::cerr << " Incoming/created/updated Group: " << *git << ". Forcing cache load." << std::endl; #endif - // for new circles we need to add them to the list. - // we don't know the type of this circle here - // original behavior was to add all ids to the external ids list + // for new circles we need to add them to the list. + // we don't know the type of this circle here + // original behavior was to add all ids to the external ids list - addCircleIdToList(RsGxsCircleId(*git), 0); + addCircleIdToList(RsGxsCircleId(*git), 0); - // reset the cached circle data for this id - { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - mCircleCache.erase(RsGxsCircleId(*git)); - mCacheUpdated = true; - circles_to_reload.insert(RsGxsCircleId(*git)); - } - } + circles_to_reload.insert(RsGxsCircleId(*git)); } + break; + default: +#ifdef DEBUG_CIRCLES + std::cerr << " Type: " << c->getType() << " is ignored" << std::endl; +#endif + break; + } + + // Now compute which events should be sent. if(rsEvents) { @@ -709,15 +710,6 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } } - - // reset circle from cache since the number of invitee may have changed. - { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - mCircleCache.erase(RsGxsCircleId(*git)); - mCacheUpdated = true; - circles_to_reload.insert(RsGxsCircleId(*git)); - } - } } @@ -736,50 +728,57 @@ bool p3GxsCircles::getCircleDetails(const RsGxsCircleId& id, RsGxsCircleDetails& { #ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::getCircleDetails(" << id << ")"; - std::cerr << std::endl; + std::cerr << "p3GxsCircles::getCircleDetails(" << id << ")"; + std::cerr << std::endl; #endif // DEBUG_CIRCLES { - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + bool should_reload = false; + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ RsGxsCircleCache& data(mCircleCache[id]); - if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::LOADING) + should_reload = true; + + if(data.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::LOADING) return false; // should also have meta data.... - details.mCircleId = id; - details.mCircleName = data.mCircleName; - details.mCircleType = data.mCircleType; - details.mRestrictedCircleId = data.mRestrictedCircleId; - - details.mAllowedNodes = data.mAllowedNodes; - details.mSubscriptionFlags.clear(); - details.mAllowedGxsIds.clear(); - details.mAmIAllowed = false ; - details.mAmIAdmin = bool(data.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); - - for(std::map::const_iterator it(data.mMembershipStatus.begin());it!=data.mMembershipStatus.end();++it) + if(!should_reload) { - details.mSubscriptionFlags[it->first] = it->second.subscription_flags ; + details.mCircleId = id; + details.mCircleName = data.mCircleName; - if(it->second.subscription_flags == GXS_EXTERNAL_CIRCLE_FLAGS_ALLOWED) + details.mCircleType = data.mCircleType; + details.mRestrictedCircleId = data.mRestrictedCircleId; + + details.mAllowedNodes = data.mAllowedNodes; + details.mSubscriptionFlags.clear(); + details.mAllowedGxsIds.clear(); + details.mAmIAllowed = false ; + details.mAmIAdmin = bool(data.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); + + for(std::map::const_iterator it(data.mMembershipStatus.begin());it!=data.mMembershipStatus.end();++it) { - details.mAllowedGxsIds.insert(it->first) ; + details.mSubscriptionFlags[it->first] = it->second.subscription_flags ; - if(rsIdentity->isOwnId(it->first)) - details.mAmIAllowed = true ; + if(it->second.subscription_flags == GXS_EXTERNAL_CIRCLE_FLAGS_ALLOWED) + { + details.mAllowedGxsIds.insert(it->first) ; + + if(rsIdentity->isOwnId(it->first)) + details.mAmIAllowed = true ; + } } - } - return true; + return true; + } } - /* it isn't there - add to public requests */ - cache_request_load(id); - return false; + cache_request_load(id); + return false; } bool p3GxsCircles::getCircleExternalIdList(std::list &circleIds) @@ -805,7 +804,8 @@ bool p3GxsCircles::getCircleExternalIdList(std::list &circleIds) bool p3GxsCircles::isLoaded(const RsGxsCircleId &circleId) { RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - return (mCircleCache[circleId].mStatus >= RsGxsCircleCache::CircleEntryCacheStatus::UPDATING); + + return mCircleCache.is_cached(circleId) && (mCircleCache[circleId].mStatus >= RsGxsCircleCache::CircleEntryCacheStatus::UPDATING); } bool p3GxsCircles::loadCircle(const RsGxsCircleId &circleId) @@ -1237,6 +1237,9 @@ bool p3GxsCircles::cache_request_load(const RsGxsCircleId &id) RsGxsCircleCache& cache(mCircleCache[id]); + if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::LOADING) + cache.mCircleId = id; + if(cache.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::LOADING || cache.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) return false; @@ -1248,6 +1251,7 @@ bool p3GxsCircles::cache_request_load(const RsGxsCircleId &id) cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::LOADING; mCirclesToLoad.insert(id); + mShouldSendCacheUpdateNotification = true; } if (RsTickEvent::event_count(CIRCLE_EVENT_CACHELOAD) > 0) /* its already scheduled */ @@ -1360,6 +1364,7 @@ bool p3GxsCircles::cache_load_for_token(uint32_t token) // that allows to subscribe/unsubscribe uncomplete circles cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::CHECKING_MEMBERSHIP; + cache.mLastUpdatedMembershipTS = 0; // force processing of membership request locked_checkCircleCacheForMembershipUpdate(cache); } else @@ -1372,6 +1377,7 @@ bool p3GxsCircles::cache_load_for_token(uint32_t token) /* schedule event to try reload gxsIds */ RsTickEvent::schedule_in(CIRCLE_EVENT_RELOADIDS, GXSID_LOAD_CYCLE, id.toStdString()); } + mShouldSendCacheUpdateNotification = true; locked_checkCircleCacheForAutoSubscribe(cache); } @@ -1504,6 +1510,7 @@ bool p3GxsCircles::checkCircleCache() #endif RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + mCircleCache.applyToAllCachedEntries(*this,&p3GxsCircles::locked_checkCircleCacheForMembershipUpdate) ; mCircleCache.applyToAllCachedEntries(*this,&p3GxsCircles::locked_checkCircleCacheForAutoSubscribe) ; return true ; @@ -1595,7 +1602,7 @@ bool p3GxsCircles::locked_checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cac } } - bool am_I_admin( cache.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) ; + bool am_I_admin( cache.mGroupSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) ; #ifdef DEBUG_CIRCLES std::cerr << " own ID in circle: " << in_admin_list << ", own subscribe request: " << member_request << ", am I admin?: " << am_I_admin << std::endl; @@ -1621,7 +1628,7 @@ bool p3GxsCircles::locked_checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cac cache.mGroupStatus &= ~GXS_SERV::GXS_GRP_STATUS_UNPROCESSED; - mCacheUpdated = true; + mShouldSendCacheUpdateNotification = true; return true; } @@ -1645,7 +1652,7 @@ bool p3GxsCircles::locked_checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cac cache.mGroupStatus &= ~GXS_SERV::GXS_GRP_STATUS_UNPROCESSED; - mCacheUpdated = true; + mShouldSendCacheUpdateNotification = true; return true ; } } @@ -1952,7 +1959,7 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) else std::cerr << " (EE) unknown subscription order type: " << static_cast(item->subscription_type) ; - mCacheUpdated = true; + mShouldSendCacheUpdateNotification = true; #ifdef DEBUG_CIRCLES std::cerr << " UPDATING" << std::endl; #endif @@ -1969,6 +1976,7 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) cache.mLastUpdatedMembershipTS = time(NULL) ; cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::UP_TO_DATE; cache.mLastUpdateTime = time(NULL); + mShouldSendCacheUpdateNotification = true; } RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index bf875fed6..aaeab9af1 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -358,7 +358,7 @@ private: uint32_t mDummyIdToken; std::list mDummyPgpLinkedIds; std::list mDummyOwnIds; - bool mCacheUpdated ; + bool mShouldSendCacheUpdateNotification ; rstime_t mLastCacheUpdateEvent; rstime_t mLastDebugPrintTS; From 59df44535a7f4bdc0e3494e2d7cf2c02acf3785d Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 8 May 2020 11:24:49 +0200 Subject: [PATCH 17/79] put enum outside class in RsGxsCircleCache --- libretroshare/src/services/p3gxscircles.cc | 34 +++++++++++----------- libretroshare/src/services/p3gxscircles.h | 18 ++++++------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 69bcac53e..57dcbb1c9 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -738,10 +738,10 @@ bool p3GxsCircles::getCircleDetails(const RsGxsCircleId& id, RsGxsCircleDetails& RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ RsGxsCircleCache& data(mCircleCache[id]); - if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::LOADING) + if(data.mStatus < CircleEntryCacheStatus::LOADING) should_reload = true; - if(data.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::LOADING) + if(data.mStatus == CircleEntryCacheStatus::LOADING) return false; // should also have meta data.... @@ -805,7 +805,7 @@ bool p3GxsCircles::isLoaded(const RsGxsCircleId &circleId) { RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - return mCircleCache.is_cached(circleId) && (mCircleCache[circleId].mStatus >= RsGxsCircleCache::CircleEntryCacheStatus::UPDATING); + return mCircleCache.is_cached(circleId) && (mCircleCache[circleId].mStatus >= CircleEntryCacheStatus::UPDATING); } bool p3GxsCircles::loadCircle(const RsGxsCircleId &circleId) @@ -820,7 +820,7 @@ int p3GxsCircles::canSend(const RsGxsCircleId &circleId, const RsPgpId &id, bool { RsGxsCircleCache& data = mCircleCache.ref(circleId); - if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(data.mStatus < CircleEntryCacheStatus::UPDATING) return 0; should_encrypt = (data.mCircleType == RsGxsCircleType::EXTERNAL); @@ -840,7 +840,7 @@ int p3GxsCircles::canReceive(const RsGxsCircleId &circleId, const RsPgpId &id) { RsGxsCircleCache &data = mCircleCache.ref(circleId); - if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(data.mStatus < CircleEntryCacheStatus::UPDATING) return 0; if (data.isAllowedPeer(id)) @@ -859,7 +859,7 @@ bool p3GxsCircles::recipients(const RsGxsCircleId &circleId, std::list& { RsGxsCircleCache &data = mCircleCache.ref(circleId); - if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(data.mStatus < CircleEntryCacheStatus::UPDATING) return 0; data.getAllowedPeersList(friendlist); @@ -875,7 +875,7 @@ bool p3GxsCircles::isRecipient(const RsGxsCircleId &circleId, const RsGxsGroupId { const RsGxsCircleCache &data = mCircleCache.ref(circleId); - if(data.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(data.mStatus < CircleEntryCacheStatus::UPDATING) return 0; return data.isAllowedPeer(id,destination_group); @@ -897,7 +897,7 @@ bool p3GxsCircles::recipients(const RsGxsCircleId& circleId, const RsGxsGroupId& const RsGxsCircleCache& cache = mCircleCache.ref(circleId); - if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(cache.mStatus < CircleEntryCacheStatus::UPDATING) return 0; for(std::map::const_iterator it(cache.mMembershipStatus.begin());it!=cache.mMembershipStatus.end();++it) @@ -1237,18 +1237,18 @@ bool p3GxsCircles::cache_request_load(const RsGxsCircleId &id) RsGxsCircleCache& cache(mCircleCache[id]); - if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::LOADING) + if(cache.mStatus < CircleEntryCacheStatus::LOADING) cache.mCircleId = id; - if(cache.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::LOADING || cache.mStatus == RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(cache.mStatus == CircleEntryCacheStatus::LOADING || cache.mStatus == CircleEntryCacheStatus::UPDATING) return false; // Put it into the Loading Cache - so we will detect it later. if(cache.mLastUpdateTime > 0) - cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::UPDATING; + cache.mStatus = CircleEntryCacheStatus::UPDATING; else - cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::LOADING; + cache.mStatus = CircleEntryCacheStatus::LOADING; mCirclesToLoad.insert(id); mShouldSendCacheUpdateNotification = true; @@ -1363,7 +1363,7 @@ bool p3GxsCircles::cache_load_for_token(uint32_t token) // We can check for self inclusion in the circle right away, since own ids are always loaded. // that allows to subscribe/unsubscribe uncomplete circles - cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::CHECKING_MEMBERSHIP; + cache.mStatus = CircleEntryCacheStatus::CHECKING_MEMBERSHIP; cache.mLastUpdatedMembershipTS = 0; // force processing of membership request locked_checkCircleCacheForMembershipUpdate(cache); } @@ -1477,7 +1477,7 @@ bool p3GxsCircles::cache_reloadids(const RsGxsCircleId &circleId) locked_checkCircleCacheForAutoSubscribe(cache); - cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::CHECKING_MEMBERSHIP; + cache.mStatus = CircleEntryCacheStatus::CHECKING_MEMBERSHIP; locked_checkCircleCacheForMembershipUpdate(cache); /* move straight into the cache */ @@ -1520,7 +1520,7 @@ bool p3GxsCircles::locked_checkCircleCacheForMembershipUpdate(RsGxsCircleCache& { rstime_t now = time(NULL) ; - if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(cache.mStatus < CircleEntryCacheStatus::UPDATING) return false; if(cache.mLastUpdatedMembershipTS + GXS_CIRCLE_DELAY_TO_FORCE_MEMBERSHIP_UPDATE < now) @@ -1572,7 +1572,7 @@ bool p3GxsCircles::locked_checkCircleCacheForAutoSubscribe(RsGxsCircleCache &cac return false; } - if(cache.mStatus < RsGxsCircleCache::CircleEntryCacheStatus::UPDATING) + if(cache.mStatus < CircleEntryCacheStatus::UPDATING) return false; /* if we appear in the group - then autosubscribe, and mark as processed. This also applies if we're the group admin */ @@ -1974,7 +1974,7 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) } cache.mLastUpdatedMembershipTS = time(NULL) ; - cache.mStatus = RsGxsCircleCache::CircleEntryCacheStatus::UP_TO_DATE; + cache.mStatus = CircleEntryCacheStatus::UP_TO_DATE; cache.mLastUpdateTime = time(NULL); mShouldSendCacheUpdateNotification = true; } diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index aaeab9af1..eaefdf0e8 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -128,6 +128,15 @@ public: uint32_t subscription_flags ; // combination of GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST and GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED }; +enum CircleEntryCacheStatus: uint8_t { + UNKNOWN = 0x00, // Used to detect uninitialized memory + NO_DATA = 0x01, // Used in the constuctor + LOADING = 0x02, // When the token request to load cache has been sent and no data is present + UPDATING = 0x03, // Starting from this level the cache entry can be used + CHECKING_MEMBERSHIP = 0x04, // Means we're actually looking into msgs to update membership status + UP_TO_DATE = 0x05, // Everything should be loaded here. +}; + class RsGxsCircleCache { public: @@ -144,15 +153,6 @@ public: // Cache related data - enum CircleEntryCacheStatus: uint8_t // This enum - { - UNKNOWN = 0x00, // Used to detect uninitialized memory - NO_DATA = 0x01, // Used in the constuctor - LOADING = 0x02, // When the token request to load cache has been sent and no data is present - UPDATING = 0x03, // Starting from this level the cache entry can be used - CHECKING_MEMBERSHIP = 0x04, // Means we're actually looking into msgs to update membership status - UP_TO_DATE = 0x05, // Everything should be loaded here. - }; rstime_t mLastUpdatedMembershipTS ; // Last time the subscribe messages have been requested. Should be reset when new messages arrive. rstime_t mLastUpdateTime; // Last time the cache entry was loaded CircleEntryCacheStatus mStatus; // Overall state of the cache entry From 8e52f0762185b68d635dfb3a9868d8f6627a9977 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 8 May 2020 14:49:25 +0200 Subject: [PATCH 18/79] changed NO_DATA enum to NO_DATA_YET. Seems that this is an existing define on windows --- libretroshare/src/services/p3gxscircles.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index eaefdf0e8..e57cd7652 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -128,13 +128,13 @@ public: uint32_t subscription_flags ; // combination of GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST and GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED }; -enum CircleEntryCacheStatus: uint8_t { +typedef enum CircleEntryCacheStatus: uint8_t { UNKNOWN = 0x00, // Used to detect uninitialized memory - NO_DATA = 0x01, // Used in the constuctor + NO_DATA_YET = 0x01, // Used in the constuctor LOADING = 0x02, // When the token request to load cache has been sent and no data is present UPDATING = 0x03, // Starting from this level the cache entry can be used CHECKING_MEMBERSHIP = 0x04, // Means we're actually looking into msgs to update membership status - UP_TO_DATE = 0x05, // Everything should be loaded here. + UP_TO_DATE = 0x05 // Everything should be loaded here. }; class RsGxsCircleCache From bc69e8c1ace90daa39bca553acafbfe52f1c57c2 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 8 May 2020 16:06:23 +0200 Subject: [PATCH 19/79] forgot to update file in previous commit --- libretroshare/src/services/p3gxscircles.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 57dcbb1c9..c94ecc0d8 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -1063,7 +1063,7 @@ RsGxsCircleCache::RsGxsCircleCache() mGroupStatus = 0; mGroupSubscribeFlags = 0; mLastUpdatedMembershipTS = 0 ; - mStatus = CircleEntryCacheStatus::NO_DATA; + mStatus = CircleEntryCacheStatus::NO_DATA_YET; mAllIdsHere = false; return; From d7dab2ae88182ba5f421882793ce82226c22c6ae Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 9 May 2020 10:55:19 +0200 Subject: [PATCH 20/79] fixed uninitialized memory read causing a crash (reportted y sehraf) --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 1a56385de..97a00440f 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -180,8 +180,9 @@ IdDialog::IdDialog(QWidget *parent) : MainPage(parent), ui(new Ui::IdDialog) ui->treeWidget_membership->clear(); ui->treeWidget_membership->setItemDelegateForColumn(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,new GxsIdTreeItemDelegate()); - mExternalOtherCircleItem = NULL ; - mExternalBelongingCircleItem = NULL ; + mExternalOtherCircleItem = NULL ; + mExternalBelongingCircleItem = NULL ; + mMyCircleItem = NULL ; /* Setup UI helper */ mStateHelper = new UIStateHelper(this); From 0c3b8641af987c12cc515263fc610ae3ddd8f4f5 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 9 May 2020 18:07:56 +0200 Subject: [PATCH 21/79] fixing some bugs in circles backend --- libretroshare/src/gxs/rsgenexchange.cc | 4 +- libretroshare/src/gxs/rsgxsnetservice.cc | 18 ++++--- libretroshare/src/services/p3gxscircles.cc | 58 ++++++++++++++------- libretroshare/src/services/p3gxscircles.h | 27 +++++++++- retroshare-gui/src/gui/Identity/IdDialog.ui | 12 ++--- 5 files changed, 83 insertions(+), 36 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index aa2526548..bcd197abe 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -61,7 +61,7 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key #define GXS_MASK "GXS_MASK_HACK" -//#define GEN_EXCH_DEBUG 1 +#define GEN_EXCH_DEBUG 1 static const uint32_t MSG_CLEANUP_PERIOD = 60*59; // 59 minutes static const uint32_t INTEGRITY_CHECK_PERIOD = 60*31; // 31 minutes @@ -937,7 +937,7 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin RsReputationLevel::LOCALLY_NEGATIVE ) { #ifdef GEN_EXCH_DEBUG - std::cerr << "RsGenExchange::validateMsg(): message from " << metaData.mAuthorId << ", rejected because reputation level (" << details.mReputation.mOverallReputationLevel <<") indicate that you banned this ID." << std::endl; + std::cerr << "RsGenExchange::validateMsg(): message from " << metaData.mAuthorId << ", rejected because reputation level (" << static_cast(details.mReputation.mOverallReputationLevel) <<") indicate that you banned this ID." << std::endl; #endif idValidate = false ; } diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index ba2e287ad..5fac5d731 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -274,12 +274,12 @@ NXS_NET_DEBUG_8 gxs distant sync ***/ -//#define NXS_NET_DEBUG_0 1 -//#define NXS_NET_DEBUG_1 1 +#define NXS_NET_DEBUG_0 1 +#define NXS_NET_DEBUG_1 1 //#define NXS_NET_DEBUG_2 1 //#define NXS_NET_DEBUG_3 1 -//#define NXS_NET_DEBUG_4 1 -//#define NXS_NET_DEBUG_5 1 +#define NXS_NET_DEBUG_4 1 +#define NXS_NET_DEBUG_5 1 //#define NXS_NET_DEBUG_6 1 //#define NXS_NET_DEBUG_7 1 //#define NXS_NET_DEBUG_8 1 @@ -320,9 +320,9 @@ static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_GXS_KEY_MISSING = 0x05 ; || defined(NXS_NET_DEBUG_4) || defined(NXS_NET_DEBUG_5) || defined(NXS_NET_DEBUG_6) || defined(NXS_NET_DEBUG_7) \ || defined(NXS_NET_DEBUG_8) -static const RsPeerId peer_to_print = RsPeerId(std::string("")) ; -static const RsGxsGroupId group_id_to_print = RsGxsGroupId(std::string("")) ; // use this to allow to this group id only, or "" for all IDs -static const uint32_t service_to_print = RS_SERVICE_GXS_TYPE_CHANNELS ; // use this to allow to this service id only, or 0 for all services +static const RsPeerId peer_to_print = RsPeerId();//std::string("a97fef0e2dc82ddb19200fb30f9ac575")) ; +static const RsGxsGroupId group_id_to_print = RsGxsGroupId(std::string("66052380f5d1d0c5992e2b55dc402ce6")) ; // use this to allow to this group id only, or "" for all IDs +static const uint32_t service_to_print = RS_SERVICE_GXS_TYPE_GXSCIRCLE; // use this to allow to this service id only, or 0 for all services // warning. Numbers should be SERVICE IDS (see serialiser/rsserviceids.h. E.g. 0x0215 for forums) class nullstream: public std::ostream {}; @@ -3598,6 +3598,10 @@ void RsGxsNetService::locked_genSendMsgsTransaction(NxsTransaction* tr) msg->count = 1; // only one piece. This is to keep compatibility if we ever implement fragmenting in the future. msg->pos = 0; +#ifdef NXS_NET_DEBUG_0 + GXSNETDEBUG_PG(tr->mTransaction->PeerId(),msg->grpId) << " sending msg Id " << msg->msgId << " in Group " << msg->grpId << std::endl; +#endif + newTr->mItems.push_back(msg); msgSize++; #endif diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index c94ecc0d8..04fcac3e8 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -126,7 +126,7 @@ p3GxsCircles::p3GxsCircles( RsGeneralDataService *gds, RsNetworkExchangeService RsGxsCircles(static_cast(*this)), GxsTokenQueue(this), RsTickEvent(), mIdentities(identities), mPgpUtils(pgpUtils), mCircleMtx("p3GxsCircles"), - mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache" ), +// mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache" ), mShouldSendCacheUpdateNotification(false) { // Kick off Cache Testing, + Others. @@ -1071,6 +1071,10 @@ RsGxsCircleCache::RsGxsCircleCache() bool RsGxsCircleCache::loadBaseCircle(const RsGxsCircleGroup& circle) { +#ifdef DEBUG_CIRCLES + std::cerr << "RsGxsCircleCache::loadBaseCircle(" << mCircleId << "):" << std::endl; +#endif // DEBUG_CIRCLES + mCircleId = RsGxsCircleId(circle.mMeta.mGroupId); mCircleName = circle.mMeta.mGroupName; // mProcessedCircles.insert(mCircleId); @@ -1084,19 +1088,23 @@ bool RsGxsCircleCache::loadBaseCircle(const RsGxsCircleGroup& circle) mAllowedNodes = circle.mLocalFriends ; mRestrictedCircleId = circle.mMeta.mCircleId ; - mMembershipStatus.clear() ; + // We do not clear mMembershipStatus because this might be an update and if we do, it will clear membership requests + // that are not in the invited list! for(std::set::const_iterator it(circle.mInvitedMembers.begin());it!=circle.mInvitedMembers.end();++it) { RsGxsCircleMembershipStatus& s(mMembershipStatus[*it]) ; + s.subscription_flags |= GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ; + + // This one can be cleared because it will anyway be updated to the latest when loading subscription request messages and it wil only + // be used there as well. + s.last_subscription_TS = 0 ; - s.subscription_flags = GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ; - } #ifdef DEBUG_CIRCLES - std::cerr << "RsGxsCircleCache::loadBaseCircle(" << mCircleId << ")"; - std::cerr << std::endl; + std::cerr << " Invited member " << *it << " Initializing/updating membership status to " << std::hex << s.subscription_flags << std::dec << std::endl; #endif // DEBUG_CIRCLES + } return true; } @@ -1251,7 +1259,6 @@ bool p3GxsCircles::cache_request_load(const RsGxsCircleId &id) cache.mStatus = CircleEntryCacheStatus::LOADING; mCirclesToLoad.insert(id); - mShouldSendCacheUpdateNotification = true; } if (RsTickEvent::event_count(CIRCLE_EVENT_CACHELOAD) > 0) /* its already scheduled */ @@ -1480,9 +1487,6 @@ bool p3GxsCircles::cache_reloadids(const RsGxsCircleId &circleId) cache.mStatus = CircleEntryCacheStatus::CHECKING_MEMBERSHIP; locked_checkCircleCacheForMembershipUpdate(cache); - /* move straight into the cache */ - mCircleCache.resize(); - std::cerr << " Loading complete." << std::endl; return true ; @@ -1923,6 +1927,7 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) RsGxsCircleId circle_id(it->first); RsGxsCircleCache& cache( mCircleCache[circle_id] ); + #ifdef DEBUG_CIRCLES std::cerr << " Circle found in cache!" << std::endl; std::cerr << " Retrieving messages..." << std::endl; @@ -1931,24 +1936,26 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) for(uint32_t i=0;isecond.size();++i) { #ifdef DEBUG_CIRCLES - std::cerr << " Group ID: " << it->second[i]->meta.mGroupId << ", Message ID: " << it->second[i]->meta.mMsgId << ": " ; + std::cerr << " Group ID: " << it->second[i]->meta.mGroupId << ", Message ID: " << it->second[i]->meta.mMsgId << ", thread ID: " << it->second[i]->meta.mThreadId << ", author: " << it->second[i]->meta.mAuthorId << ": " ; #endif RsGxsCircleSubscriptionRequestItem *item = dynamic_cast(it->second[i]) ; if(item == NULL) { - std::cerr << " (EE) item is not a RsGxsCircleSubscriptionRequestItem. Weird." << std::endl; + std::cerr << " (EE) item is not a RsGxsCircleSubscriptionRequestItem. Weird. Scheduling for deletion." << std::endl; + + messages_to_delete[RsGxsGroupId(circle_id)].insert(it->second[i]->meta.mMsgId); continue ; } RsGxsCircleMembershipStatus& info(cache.mMembershipStatus[item->meta.mAuthorId]) ; #ifdef DEBUG_CIRCLES - std::cerr << " is from id " << item->meta.mAuthorId << " " << time(NULL) - item->time_stamp << " seconds ago, " ; + std::cerr << " " << time(NULL) - item->time_stamp << " seconds ago, " ; #endif - if(info.last_subscription_TS < item->time_stamp) + if(info.last_subscription_TS <= item->time_stamp) // the <= here allows to make sure we update the flags is something happenned { info.last_subscription_TS = item->time_stamp ; @@ -1961,15 +1968,28 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) mShouldSendCacheUpdateNotification = true; #ifdef DEBUG_CIRCLES - std::cerr << " UPDATING" << std::endl; + std::cerr << " UPDATING status to " << std::hex << info.subscription_flags << std::dec << std::endl; #endif } - else if(info.last_subscription_TS > item->time_stamp) + else if(info.last_subscription_TS > item->time_stamp) + std::cerr << " Too old: item->TS=" << item->time_stamp << ", last_subscription_TS=" << info.last_subscription_TS << ". IGNORING." << std::endl; + } + + // now do another sweep and remove all msgs that are older than the latest + + std::cerr << " Cleaning old messages..." << std::endl; + + for(uint32_t i=0;isecond.size();++i) + { + RsGxsCircleMembershipStatus& info(cache.mMembershipStatus[it->second[i]->meta.mAuthorId]) ; + RsGxsCircleSubscriptionRequestItem *item = dynamic_cast(it->second[i]) ; + + if(item && info.last_subscription_TS > item->time_stamp) { #ifdef DEBUG_CIRCLES - std::cerr << " Older than last known (" << time(NULL)-info.last_subscription_TS << " seconds ago): deleting." << std::endl; + std::cerr << " " << item->meta.mMsgId << ": Older than last known (" << (long int)info.last_subscription_TS - (long int)item->time_stamp << " seconds before): deleting." << std::endl; #endif - messages_to_delete[RsGxsGroupId(circle_id)].insert(it->second[i]->meta.mMsgId) ; + messages_to_delete[RsGxsGroupId(circle_id)].insert(item->meta.mMsgId) ; } } @@ -2002,7 +2022,7 @@ void p3GxsCircles::debug_dumpCache() { std::cerr << "Debug dump of CircleCache:" << std::endl; - mCircleCache.printStats(std::cerr); + mCircleCache.printStats(); mCircleCache.applyToAllCachedEntries(*this,&p3GxsCircles::debug_dumpCacheEntry); } diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index e57cd7652..1b7986014 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -128,7 +128,7 @@ public: uint32_t subscription_flags ; // combination of GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST and GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED }; -typedef enum CircleEntryCacheStatus: uint8_t { +enum CircleEntryCacheStatus: uint8_t { UNKNOWN = 0x00, // Used to detect uninitialized memory NO_DATA_YET = 0x01, // Used in the constuctor LOADING = 0x02, // When the token request to load cache has been sent and no data is present @@ -185,6 +185,28 @@ public: class PgpAuxUtils; +class RsCirclesMemCache : public std::map +{ +public: + RsCirclesMemCache() : std::map(){} + + bool is_cached(const RsGxsCircleId& id) { return end() != find(id) ; } + RsGxsCircleCache& ref(const RsGxsCircleId& id) { return operator[](id) ; } + + void printStats() { std::cerr << "CircleMemCache: " << size() << " elements." << std::endl; } + + template void applyToAllCachedEntries(ClientClass& c,bool (ClientClass::*method)(RsGxsCircleCache&)) + { + for(auto& it:*this) + (c.*method)(it.second); + } + template void applyToAllCachedEntries(ClientClass& c,bool (ClientClass::*method)(const RsGxsCircleCache&)) + { + for(const auto& it:*this) + (c.*method)(it.second); + } +}; + class p3GxsCircles: public RsGxsCircleExchange, public RsGxsCircles, public GxsTokenQueue, public RsTickEvent { @@ -341,7 +363,8 @@ public: //std::map > mCacheLoad_SubCircle; std::set mCirclesToLoad; // list of circles to update/load, so that we can treat them by groups. - RsMemCache mCircleCache; // actual cache data + RsCirclesMemCache mCircleCache; + //RsMemCache mCircleCache; // actual cache data void debug_dumpCache(); // debug method to overview what's going on bool debug_dumpCacheEntry(RsGxsCircleCache &cache); diff --git a/retroshare-gui/src/gui/Identity/IdDialog.ui b/retroshare-gui/src/gui/Identity/IdDialog.ui index c881ed39f..127f7a85a 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.ui +++ b/retroshare-gui/src/gui/Identity/IdDialog.ui @@ -120,7 +120,7 @@ Qt::NoFocus - + :/icons/help_64.png:/icons/help_64.png @@ -268,7 +268,7 @@ - 0 + 1 @@ -289,8 +289,8 @@ 0 0 - 634 - 523 + 1372 + 719 @@ -1052,7 +1052,7 @@ border-image: url(:/images/closepressed.png) - + :/images/toaster/chat.png:/images/toaster/chat.png @@ -1094,8 +1094,8 @@ border-image: url(:/images/closepressed.png) idTreeWidget - + From df2899bae943e4e37d9534813f702eae77eab633 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 9 May 2020 21:30:07 +0200 Subject: [PATCH 22/79] added warning about keys tht are out of range when checking a msg signature --- libretroshare/src/gxs/gxssecurity.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libretroshare/src/gxs/gxssecurity.cc b/libretroshare/src/gxs/gxssecurity.cc index 608e938fc..1a2d115c8 100644 --- a/libretroshare/src/gxs/gxssecurity.cc +++ b/libretroshare/src/gxs/gxssecurity.cc @@ -419,10 +419,8 @@ bool GxsSecurity::validateNxsMsg(const RsNxsMsg& msg, const RsTlvKeySignature& s /* check signature timeperiod */ if ((msgMeta.mPublishTs < key.startTS) || (key.endTS != 0 && msgMeta.mPublishTs > key.endTS)) { - #ifdef GXS_SECURITY_DEBUG - std::cerr << " GxsSecurity::validateNxsMsg() TS out of range"; - std::cerr << std::endl; - #endif + RsWarn() << __PRETTY_FUNCTION__ << " GxsSecurity::validateNxsMsg() TS out of range for key " << msgMeta.mAuthorId + << " usage is limited to TS=[" << key.startTS << "," << key.endTS << "] and msg publish time is " << msgMeta.mPublishTs << std::endl; return false; } From e09bf7c2610e1d9f0d39bb91210542fc5c7760f8 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 9 May 2020 21:30:51 +0200 Subject: [PATCH 23/79] added a check to prevent SEGV when sending a notification about a group we updated --- libretroshare/src/services/p3gxscircles.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 04fcac3e8..78cff13b0 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -656,16 +656,17 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsGxsCircleGroupItem *new_circle_grp_item = dynamic_cast(groupChange->mNewGroupItem); - for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) - { - auto ev = std::make_shared(); + if(new_circle_grp_item) // groups published by us do not come in the mNewGroupItem field. It's possible to add them, in rsgenexchange.cc:2806 + for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) + { + auto ev = std::make_shared(); - ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST; - ev->mCircleId = RsGxsCircleId(*git); - ev->mGxsId = gxs_id; + ev->mCircleEventType = RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST; + ev->mCircleId = RsGxsCircleId(*git); + ev->mGxsId = gxs_id; - rsEvents->sendEvent(ev); - } + rsEvents->sendEvent(ev); + } } else if(c->getType()==RsGxsNotify::TYPE_UPDATED) { From 8f12dd63227d958fffee1f16d3625cbd026ecc4a Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 10 May 2020 13:33:20 +0200 Subject: [PATCH 24/79] fixed bug in chat room notify --- retroshare-gui/src/gui/chat/ChatLobbyUserNotify.h | 1 + retroshare-gui/src/gui/common/UserNotify.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.h b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.h index fd95511b4..620d49fbe 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.h +++ b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.h @@ -63,6 +63,7 @@ public: QString textToNotify() { return _textToNotify.join("\n");} void setTextCaseSensitive(bool value); bool isTextCaseSensitive() {return _bTextCaseSensitive;} + virtual QString textInfo() const override { return tr("mention(s)"); } signals: void countChanged(ChatLobbyId id, unsigned int count); diff --git a/retroshare-gui/src/gui/common/UserNotify.cpp b/retroshare-gui/src/gui/common/UserNotify.cpp index dc95127a8..8884caea3 100644 --- a/retroshare-gui/src/gui/common/UserNotify.cpp +++ b/retroshare-gui/src/gui/common/UserNotify.cpp @@ -167,9 +167,17 @@ void UserNotify::update() if (mMainAction) { mMainAction->setIcon(getMainIcon(count > 0)); + if(count > 0) + { + if(!mButtonText2.isNull()) + mMainAction->setToolTip(QString("%1 (%2 %3)").arg(mButtonText).arg(count).arg(mButtonText2)); + else + mMainAction->setToolTip(QString("%1 (%2)").arg(mButtonText).arg(count)); - mMainAction->setText((count > 0) ? (!mButtonText2.isNull())?QString("%1 (%2)").arg(mButtonText).arg(count).arg(mButtonText2) : QString("%1 (%2 %3)").arg(mButtonText).arg(count) : mButtonText); - mMainAction->setToolTip((count > 0) ? (!mButtonText2.isNull())?QString("%1 %2").arg(count).arg(mButtonText2) : QString("%1").arg(count) : mButtonText); + mMainAction->setText(QString("%1 (%2)").arg(mButtonText).arg(count)); + } + else + mMainAction->setText(mButtonText); QFont font = mMainAction->font(); font.setBold(count > 0); From 3ae173f104fb1b21de6fd1f1582db4119e674497 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 10 May 2020 13:47:53 +0200 Subject: [PATCH 25/79] removed debug info in circles --- libretroshare/src/services/p3gxscircles.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 536ef5433..89b5433b3 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -538,12 +538,13 @@ void p3GxsCircles::service_tick() mLastCacheMembershipUpdateTS = now ; } +#ifdef DEBUG_CIRCLES if(now > mLastDebugPrintTS) { mLastDebugPrintTS = now; debug_dumpCache(); } - return; +#endif } //====================================================================================// From a7d89f1fbbfbc1d7a1ca699174b81aa51c22e00f Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 10 May 2020 13:48:57 +0200 Subject: [PATCH 26/79] hide moderator list in new forum feed item --- retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp index 99a7f61a0..4a559e001 100644 --- a/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsForumGroupItem.cpp @@ -220,7 +220,10 @@ void GxsForumGroupItem::fill() } } else + { ui->titleLabel->setText(tr("New Forum")); + ui->moderatorList_GB->hide(); + } // else // { From 766da8117a31e7bbca3921d7fa7bb5835c86c341 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 10 May 2020 18:37:03 +0200 Subject: [PATCH 27/79] added missing update of membership status flags when an id is removed from the invitee list --- libretroshare/src/gxs/rsgenexchange.cc | 41 +++++++++++----------- libretroshare/src/gxs/rsgxsnetservice.cc | 2 +- libretroshare/src/services/p3gxscircles.cc | 12 +++++++ 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index bcd197abe..8debf99f4 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -61,7 +61,7 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key #define GXS_MASK "GXS_MASK_HACK" -#define GEN_EXCH_DEBUG 1 +//#define GEN_EXCH_DEBUG 1 static const uint32_t MSG_CLEANUP_PERIOD = 60*59; // 59 minutes static const uint32_t INTEGRITY_CHECK_PERIOD = 60*31; // 31 minutes @@ -1794,19 +1794,20 @@ void RsGenExchange::publishGroup(uint32_t& token, RsGxsGrpItem *grpItem) void RsGenExchange::updateGroup(uint32_t& token, RsGxsGrpItem* grpItem) { - if(!checkGroupMetaConsistency(grpItem->meta)) - { - std::cerr << "(EE) Cannot update group. Some information was not supplied." << std::endl; - return ; - } + if(!checkGroupMetaConsistency(grpItem->meta)) + { + std::cerr << "(EE) Cannot update group. Some information was not supplied." << std::endl; + delete grpItem; + return ; + } - RS_STACK_MUTEX(mGenMtx) ; + RS_STACK_MUTEX(mGenMtx) ; token = mDataAccess->generatePublicToken(); - mGroupUpdatePublish.push_back(GroupUpdatePublish(grpItem, token)); + mGroupUpdatePublish.push_back(GroupUpdatePublish(grpItem, token)); #ifdef GEN_EXCH_DEBUG - std::cerr << "RsGenExchange::updateGroup() token: " << token; - std::cerr << std::endl; + std::cerr << "RsGenExchange::updateGroup() token: " << token; + std::cerr << std::endl; #endif } @@ -2385,15 +2386,14 @@ RsGenExchange::ServiceCreate_Return RsGenExchange::service_CreateGroup(RsGxsGrpI void RsGenExchange::processGroupUpdatePublish() { - RS_STACK_MUTEX(mGenMtx) ; + RS_STACK_MUTEX(mGenMtx) ; // get keys for group update publish // first build meta request map for groups to be updated RsGxsGrpMetaTemporaryMap grpMeta; - std::vector::iterator vit = mGroupUpdatePublish.begin(); - for(; vit != mGroupUpdatePublish.end(); ++vit) + for(auto vit = mGroupUpdatePublish.begin(); vit != mGroupUpdatePublish.end(); ++vit) { GroupUpdatePublish& gup = *vit; const RsGxsGroupId& groupId = gup.grpItem->meta.mGroupId; @@ -2406,8 +2406,7 @@ void RsGenExchange::processGroupUpdatePublish() mDataStore->retrieveGxsGrpMetaData(grpMeta); // now - vit = mGroupUpdatePublish.begin(); - for(; vit != mGroupUpdatePublish.end(); ++vit) + for(auto vit = mGroupUpdatePublish.begin(); vit != mGroupUpdatePublish.end(); ++vit) { GroupUpdatePublish& gup = *vit; const RsGxsGroupId& groupId = gup.grpItem->meta.mGroupId; @@ -2425,14 +2424,14 @@ void RsGenExchange::processGroupUpdatePublish() meta = mit->second; //gup.grpItem->meta = *meta; - GxsGrpPendingSign ggps(gup.grpItem, gup.mToken); + GxsGrpPendingSign ggps(gup.grpItem, gup.mToken); if(checkKeys(meta->keys)) { ggps.mKeys = meta->keys; - - GxsSecurity::createPublicKeysFromPrivateKeys(ggps.mKeys) ; - + + GxsSecurity::createPublicKeysFromPrivateKeys(ggps.mKeys) ; + ggps.mHaveKeys = true; ggps.mStartTS = time(NULL); ggps.mLastAttemptTS = 0; @@ -2442,8 +2441,8 @@ void RsGenExchange::processGroupUpdatePublish() } else { - std::cerr << "(EE) publish group fails because RS cannot find the private publish and author keys" << std::endl; - + std::cerr << "(EE) publish group fails because RS cannot find the private publish and author keys" << std::endl; + delete gup.grpItem; mDataAccess->updatePublicRequestStatus(gup.mToken, RsTokenService::FAILED); } diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 9937b1729..3259a060c 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -321,7 +321,7 @@ static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_GXS_KEY_MISSING = 0x05 ; || defined(NXS_NET_DEBUG_8) static const RsPeerId peer_to_print = RsPeerId();//std::string("a97fef0e2dc82ddb19200fb30f9ac575")) ; -static const RsGxsGroupId group_id_to_print = RsGxsGroupId() ; // use this to allow to this group id only, or "" for all IDs +static const RsGxsGroupId group_id_to_print = RsGxsGroupId(std::string("66052380f5d1d0c5992e2b55dc402ce6")) ; // use this to allow to this group id only, or "" for all IDs static const uint32_t service_to_print = RS_SERVICE_GXS_TYPE_GXSCIRCLE; // use this to allow to this service id only, or 0 for all services // warning. Numbers should be SERVICE IDS (see serialiser/rsserviceids.h. E.g. 0x0215 for forums) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 89b5433b3..9c8053f74 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -40,6 +40,7 @@ /**** * #define DEBUG_CIRCLES 1 ****/ +#define DEBUG_CIRCLES 1 /*extern*/ RsGxsCircles* rsGxsCircles = nullptr; @@ -1107,6 +1108,17 @@ bool RsGxsCircleCache::loadBaseCircle(const RsGxsCircleGroup& circle) #endif // DEBUG_CIRCLES } + // also sweep through the list of subscribed members and remove the membership to those who are not in the invitee list anymore + + for(auto& m:mMembershipStatus) + if(circle.mInvitedMembers.find(m.first) == circle.mInvitedMembers.end()) + { + m.second.subscription_flags &= ~GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST; +#ifdef DEBUG_CIRCLES + std::cerr << " member " << m.first << " is not in invitee list. Updating flags to " << std::hex << m.second.subscription_flags << std::dec << std::endl; +#endif // DEBUG_CIRCLES + } + return true; } From cb1fe154f35132f2b08f0af51126a0d07354230a Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 10 May 2020 18:40:31 +0200 Subject: [PATCH 28/79] removed debug info --- libretroshare/src/services/p3gxscircles.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 9c8053f74..55d5adb6e 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -40,7 +40,6 @@ /**** * #define DEBUG_CIRCLES 1 ****/ -#define DEBUG_CIRCLES 1 /*extern*/ RsGxsCircles* rsGxsCircles = nullptr; From 2bfaadce0b46a3ebcd09543e8101c001b09018fa Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 11 May 2020 19:02:33 +0200 Subject: [PATCH 29/79] attempt to fix crash in revoke ids from circle --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 22 +++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 929f45f5d..f829cf07f 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -941,14 +941,26 @@ void IdDialog::revokeCircleMembership() if(!getItemCircleId(ui->treeWidget_membership->currentItem(),circle_id)) return; + if(circle_id.isNull()) + { + RsErr() << __PRETTY_FUNCTION__ << " : got a null circle ID. Cannot revoke an identity from that circle!" << std::endl; + return ; + } + RsGxsId gxs_id_to_revoke(qobject_cast(sender())->data().toString().toStdString()); - RsThread::async([circle_id,gxs_id_to_revoke]() - { - // 1 - get message data from p3GxsForums + if(gxs_id_to_revoke.isNull()) + RsErr() << __PRETTY_FUNCTION__ << " : got a null ID. Cannot revoke it from circle " << circle_id << "!" << std::endl; + else + RsThread::async([circle_id,gxs_id_to_revoke]() + { + // 1 - get message data from p3GxsForums - rsGxsCircles->revokeIdsFromCircle(std::set( { gxs_id_to_revoke } ),circle_id); - }); + std::set ids; + ids.insert(gxs_id_to_revoke); + + rsGxsCircles->revokeIdsFromCircle(ids,circle_id); + }); } void IdDialog::acceptCircleSubscription() From 12a9dc5a79fae8a1d34ac8ca94f92536765bb973 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 12 May 2020 18:53:51 +0200 Subject: [PATCH 30/79] fixed UI bugs reported by jolavillette --- .../src/gui/feeds/GxsCircleItem.cpp | 105 ++++++++++++------ retroshare-gui/src/gui/feeds/GxsCircleItem.h | 6 +- retroshare-gui/src/gui/feeds/GxsCircleItem.ui | 6 +- 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp index f827b115e..8c355de35 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp @@ -77,13 +77,14 @@ void GxsCircleItem::setup() /* update circle information */ - ui->acceptButton->setToolTip(tr("Grant membership request")); - ui->revokeButton->setToolTip(tr("Revoke membership request")); + ui->membershipButton->setToolTip(tr("Grant membership request")); + ui->inviteeButton->setToolTip(tr("Revoke membership")); - connect(ui->acceptButton, SIGNAL(clicked()), this, SLOT(grantCircleMembership())); - connect(ui->revokeButton, SIGNAL(clicked()), this, SLOT(revokeCircleMembership())); + connect(ui->membershipButton, SIGNAL(clicked()), this, SLOT(toggleCircleMembership())); + connect(ui->inviteeButton, SIGNAL(clicked()), this, SLOT(toggleCircleInvite())); RsGxsCircleDetails circleDetails; + if (rsGxsCircles->getCircleDetails(mCircleId, circleDetails)) { ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str()) + " (ID: " + QString::fromStdString(circleDetails.mCircleId.toStdString()) + ")"); @@ -96,18 +97,24 @@ void GxsCircleItem::setup() ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); - ui->revokeButton->setHidden(true); - ui->acceptButton->setHidden(false); + ui->inviteeButton->setHidden(false); + ui->inviteeButton->setText(tr("Grant membership")); + ui->inviteeButton->setToolTip(tr("Grant membership to this circle, for this identity")); + + ui->membershipButton->setHidden(true); } else if (mType == RS_FEED_ITEM_CIRCLE_INVITE_REC) { - ui->titleLabel->setText(tr("You received an invitation for this circle:")); + ui->titleLabel->setText(tr("You received an invitation to join this circle:")); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); - ui->acceptButton->setToolTip(tr("Accept invitation")); - connect(ui->acceptButton, SIGNAL(clicked()), this, SLOT(acceptCircleSubscription())); - ui->revokeButton->setHidden(true); + ui->membershipButton->setText(tr("Accept")); + ui->membershipButton->setToolTip(tr("Accept invitation")); + ui->membershipButton->setHidden(false); + + connect(ui->membershipButton, SIGNAL(clicked()), this, SLOT(requestCircleSubscription())); + ui->inviteeButton->setHidden(true); } else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_LEAVE) { @@ -115,17 +122,28 @@ void GxsCircleItem::setup() ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); - ui->acceptButton->setHidden(true); - ui->revokeButton->setHidden(true); + ui->membershipButton->setHidden(true); + ui->inviteeButton->setHidden(true); } else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_JOIN) { - ui->titleLabel->setText(idName + tr(" which you invited, has join this circle you're administrating.")); + if(circleDetails.mAmIAdmin) + { + ui->titleLabel->setText(idName + tr(" which you invited, has join this circle you're administrating.")); + ui->inviteeButton->setHidden(false); + ui->inviteeButton->setText(tr("Revoke membership")); + ui->inviteeButton->setToolTip(tr("Revoke membership for that identity")); + } + else + { + ui->inviteeButton->setHidden(true); + ui->titleLabel->setText(idName + tr(" has join this circle.")); + } + ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); - ui->acceptButton->setHidden(true); - ui->revokeButton->setHidden(false); + ui->membershipButton->setHidden(true); } else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REVOKED) { @@ -134,8 +152,11 @@ void GxsCircleItem::setup() ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); - ui->acceptButton->setHidden(true); - ui->revokeButton->setHidden(true); + ui->membershipButton->setHidden(false); + ui->membershipButton->setText(tr("Cancel membership request")); + ui->membershipButton->setToolTip(tr("Cancel your membership request from that circle")); + + ui->inviteeButton->setHidden(true); } else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED) { @@ -144,8 +165,11 @@ void GxsCircleItem::setup() ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); - ui->acceptButton->setHidden(true); - ui->revokeButton->setHidden(true); + ui->membershipButton->setHidden(false); + ui->membershipButton->setText(tr("Cancel membership")); + ui->membershipButton->setToolTip(tr("Cancel your membership from that circle")); + + ui->inviteeButton->setHidden(true); } } @@ -160,7 +184,7 @@ void GxsCircleItem::setup() uint64_t GxsCircleItem::uniqueIdentifier() const { - return hash_64bits("GxsCircle " + mCircleId.toStdString() + " " + mGxsId.toStdString() + " " + QString::number(mType).toStdString()); + return hash_64bits("GxsCircle " + mCircleId.toStdString() + " " + mGxsId.toStdString()); } /*********** SPECIFIC FUNCTIONS ***********************/ @@ -173,25 +197,40 @@ void GxsCircleItem::showCircleDetails() dlg.exec(); } -void GxsCircleItem::acceptCircleSubscription() +void GxsCircleItem::requestCircleSubscription() { - if (rsGxsCircles->requestCircleMembership(mGxsId, mCircleId)) - removeItem(); + rsGxsCircles->requestCircleMembership(mGxsId, mCircleId); } -void GxsCircleItem::grantCircleMembership() +void GxsCircleItem::toggleCircleMembership() { - RsThread::async([this]() - { - rsGxsCircles->inviteIdsToCircle(std::set( { mGxsId } ),mCircleId); - }); + if(!rsIdentity->isOwnId(mGxsId)) + { + RsErr() << __PRETTY_FUNCTION__ << ": inconsistent call: identity " << mGxsId << " doesn't belong to you" << std::endl; + return; + } + + if(mType == RS_FEED_ITEM_CIRCLE_INVITE_REC) + rsGxsCircles->requestCircleMembership(mGxsId,mCircleId); + else if(mType == RS_FEED_ITEM_CIRCLE_MEMB_REVOKED) + rsGxsCircles->cancelCircleMembership(mGxsId,mCircleId); + else + RsErr() << __PRETTY_FUNCTION__ << ": inconsistent call. mType is " << mType << std::endl; } -void GxsCircleItem::revokeCircleMembership() +void GxsCircleItem::toggleCircleInvite() { - RsThread::async([this]() - { - rsGxsCircles->revokeIdsFromCircle(std::set( { mGxsId } ),mCircleId); - }); + if(mType == RS_FEED_ITEM_CIRCLE_MEMB_JOIN) + RsThread::async([this]() + { + rsGxsCircles->revokeIdsFromCircle(std::set( { mGxsId } ),mCircleId); + }); + else if(mType == RS_FEED_ITEM_CIRCLE_MEMB_REQ) + RsThread::async([this]() + { + rsGxsCircles->inviteIdsToCircle(std::set( { mGxsId } ),mCircleId); + }); + else + RsErr() << __PRETTY_FUNCTION__ << ": inconsistent call. mType is " << mType << std::endl; } diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.h b/retroshare-gui/src/gui/feeds/GxsCircleItem.h index 6a7852caa..857c898f9 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.h +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.h @@ -65,9 +65,9 @@ protected: private slots: void showCircleDetails(); - void acceptCircleSubscription(); - void grantCircleMembership() ; - void revokeCircleMembership(); + void requestCircleSubscription(); + void toggleCircleMembership() ; + void toggleCircleInvite(); private: void setup(); diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.ui b/retroshare-gui/src/gui/feeds/GxsCircleItem.ui index 4cd6846e2..fa8d30014 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.ui +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.ui @@ -7,7 +7,7 @@ 0 0 618 - 172 + 217 @@ -239,7 +239,7 @@ - + 0 @@ -259,7 +259,7 @@ - + 0 From f6260a95ae2e7baee7877f984d569c291b459612 Mon Sep 17 00:00:00 2001 From: Phenom Date: Mon, 27 Apr 2020 17:24:36 +0200 Subject: [PATCH 31/79] Add Votes when calling getPostData. --- libretroshare/src/retroshare/rsgxschannels.h | 10 +- libretroshare/src/retroshare/rsposted.h | 11 +- libretroshare/src/services/p3gxschannels.cc | 93 ++++++++---- libretroshare/src/services/p3gxschannels.h | 15 +- libretroshare/src/services/p3posted.cc | 141 +++++++++++------- libretroshare/src/services/p3posted.h | 19 ++- retroshare-gui/src/gui/Posted/PostedItem.cpp | 6 +- .../src/gui/Posted/PostedListWidget.cpp | 6 +- .../src/gui/feeds/GxsChannelPostItem.cpp | 3 +- .../gui/gxschannels/CreateGxsChannelMsg.cpp | 13 +- .../gui/gxschannels/GxsChannelPostsWidget.cpp | 8 +- 11 files changed, 208 insertions(+), 117 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 0fcde2960..bef322a4a 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -314,7 +314,8 @@ public: */ virtual bool getChannelAllContent( const RsGxsGroupId& channelId, std::vector& posts, - std::vector& comments ) = 0; + std::vector& comments, + std::vector& votes ) = 0; /** * @brief Get channel messages and comments corresponding to the given IDs. @@ -326,12 +327,14 @@ public: * @param[in] contentsIds ids of requested contents * @param[out] posts storage for posts * @param[out] comments storage for the comments + * @param[out] votes storage for the votes * @return false if something failed, true otherwhise */ virtual bool getChannelContent( const RsGxsGroupId& channelId, const std::set& contentsIds, std::vector& posts, - std::vector& comments ) = 0; + std::vector& comments, + std::vector& votes ) = 0; /** * @brief Get channel comments corresponding to the given IDs. @@ -571,6 +574,9 @@ public: RS_DEPRECATED_FOR(getChannelsInfo) virtual bool getGroupData(const uint32_t &token, std::vector &groups) = 0; + RS_DEPRECATED_FOR(getChannelContent) + virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts, std::vector &votes) = 0; + RS_DEPRECATED_FOR(getChannelContent) virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts) = 0; diff --git a/libretroshare/src/retroshare/rsposted.h b/libretroshare/src/retroshare/rsposted.h index 1a089de8e..4cd6e8cf4 100644 --- a/libretroshare/src/retroshare/rsposted.h +++ b/libretroshare/src/retroshare/rsposted.h @@ -154,13 +154,15 @@ public: virtual bool getBoardAllContent( const RsGxsGroupId& boardId, std::vector& posts, - std::vector& comments ) = 0; + std::vector& comments, + std::vector& votes ) = 0; virtual bool getBoardContent( const RsGxsGroupId& boardId, const std::set& contentsIds, std::vector& posts, - std::vector& comments ) = 0; + std::vector& comments, + std::vector& votes ) = 0; virtual bool editBoard(RsPostedGroup& board) =0; @@ -176,6 +178,11 @@ public: virtual bool getGroupData( const uint32_t& token, std::vector &groups ) = 0; + RS_DEPRECATED_FOR(getBoardsContent) + virtual bool getPostData( + const uint32_t& token, std::vector& posts, + std::vector& cmts, std::vector& vots) = 0; + RS_DEPRECATED_FOR(getBoardsContent) virtual bool getPostData( const uint32_t& token, std::vector& posts, diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index a813c92e8..8ec075cb2 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -471,22 +471,23 @@ bool p3GxsChannels::groupShareKeys( bool p3GxsChannels::getPostData( const uint32_t &token, std::vector &msgs, - std::vector &cmts ) + std::vector &cmts, + std::vector &vots) { #ifdef GXSCHANNELS_DEBUG - std::cerr << __PRETTY_FUNCTION__ << std::cerr << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << std::endl; #endif GxsMsgDataMap msgData; if(!RsGenExchange::getMsgData(token, msgData)) { - std::cerr << __PRETTY_FUNCTION__ <<" ERROR in request" << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " ERROR in request" << std::endl; return false; } GxsMsgDataMap::iterator mit = msgData.begin(); - for(; mit != msgData.end(); ++mit) + for(; mit != msgData.end(); ++mit) { std::vector& msgItems = mit->second; std::vector::iterator vit = msgItems.begin(); @@ -514,7 +515,7 @@ bool p3GxsChannels::getPostData( cmt = cmtItem->mMsg; cmt.mMeta = mi->meta; #ifdef GXSCOMMENT_DEBUG - std::cerr << "p3GxsChannels::getPostData Found Comment:" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " Found Comment:" << std::endl; cmt.print(std::cerr," ", "cmt"); #endif cmts.push_back(cmt); @@ -522,18 +523,33 @@ bool p3GxsChannels::getPostData( } else { - RsGxsMsgItem* msg = (*vit); - //const uint16_t RS_SERVICE_GXS_TYPE_CHANNELS = 0x0217; - //const uint8_t RS_PKT_SUBTYPE_GXSCHANNEL_POST_ITEM = 0x03; - //const uint8_t RS_PKT_SUBTYPE_GXSCOMMENT_COMMENT_ITEM = 0xf1; - std::cerr << __PRETTY_FUNCTION__ - << " Not a GxsChannelPostItem neither a " - << "RsGxsCommentItem PacketService=" << std::hex - << (int)msg->PacketService() << std::dec - << " PacketSubType=" << std::hex - << (int)msg->PacketSubType() << std::dec - << " , deleting!" << std::endl; - delete *vit; + RsGxsVoteItem* votItem = + dynamic_cast(*vit); + if(votItem) + { + RsGxsVote vot; + RsGxsMsgItem *mi = (*vit); + vot = votItem->mMsg; + vot.mMeta = mi->meta; + vots.push_back(vot); + delete votItem; + } + else + { + RsGxsMsgItem* msg = (*vit); + //const uint16_t RS_SERVICE_GXS_TYPE_CHANNELS = 0x0217; + //const uint8_t RS_PKT_SUBTYPE_GXSCHANNEL_POST_ITEM = 0x03; + //const uint8_t RS_PKT_SUBTYPE_GXSCOMMENT_COMMENT_ITEM = 0xf1; + //const uint8_t RS_PKT_SUBTYPE_GXSCOMMENT_VOTE_ITEM = 0xf2; + RsErr() << __PRETTY_FUNCTION__ + << " Not a GxsChannelPostItem neither a " + << "RsGxsCommentItem neither a RsGxsVoteItem" + << " PacketService=" << std::hex << (int)msg->PacketService() << std::dec + << " PacketSubType=" << std::hex << (int)msg->PacketSubType() << std::dec + << " type name =" << typeid(*msg).name() + << " , deleting!" << std::endl; + delete *vit; + } } } } @@ -542,11 +558,19 @@ bool p3GxsChannels::getPostData( return true; } +bool p3GxsChannels::getPostData( + const uint32_t& token, std::vector& posts, std::vector& cmts ) +{ + std::vector vots; + return getPostData(token, posts, cmts, vots); +} + bool p3GxsChannels::getPostData( const uint32_t& token, std::vector& posts ) { std::vector cmts; - return getPostData(token, posts, cmts); + std::vector vots; + return getPostData(token, posts, cmts, vots); } //Not currently used @@ -1112,22 +1136,24 @@ bool p3GxsChannels::getContentSummaries( bool p3GxsChannels::getChannelAllContent( const RsGxsGroupId& channelId, std::vector& posts, - std::vector& comments ) + std::vector& comments, + std::vector& votes ) { uint32_t token; RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - if( !requestMsgInfo(token, opts,std::list({channelId})) || waitToken(token) != RsTokenService::COMPLETE ) - return false; + if( !requestMsgInfo(token, opts,std::list({channelId})) || waitToken(token) != RsTokenService::COMPLETE ) + return false; - return getPostData(token, posts, comments); + return getPostData(token, posts, comments,votes); } bool p3GxsChannels::getChannelContent( const RsGxsGroupId& channelId, const std::set& contentIds, std::vector& posts, - std::vector& comments ) + std::vector& comments, + std::vector& votes ) { uint32_t token; RsTokReqOptions opts; @@ -1139,7 +1165,7 @@ bool p3GxsChannels::getChannelContent( const RsGxsGroupId& channelId, if( !requestMsgInfo(token, opts, msgIds) || waitToken(token) != RsTokenService::COMPLETE ) return false; - return getPostData(token, posts, comments); + return getPostData(token, posts, comments, votes); } bool p3GxsChannels::getChannelComments(const RsGxsGroupId &channelId, @@ -1314,8 +1340,9 @@ bool p3GxsChannels::createVoteV2( std::set s({commentId}); std::vector posts; std::vector comments; + std::vector votes; - if(!getChannelContent(channelId, s, posts, comments)) + if(!getChannelContent(channelId, s, posts, comments, votes)) { errorMessage = "You cannot vote on comment " + commentId.toStdString() + " of channel with Id " @@ -1475,8 +1502,9 @@ bool p3GxsChannels::createPostV2( std::set s({origPostId}); std::vector posts; std::vector comments; + std::vector votes; - if(!getChannelContent(channelId,s,posts,comments)) + if(!getChannelContent(channelId,s,posts,comments,votes)) { errorMessage = "You cannot edit post " + origPostId.toStdString() + " of channel with Id " + channelId.toStdString() @@ -1546,9 +1574,11 @@ bool p3GxsChannels::createCommentV2( std::vector posts; std::vector comments; + std::vector votes; if(!getChannelContent( // does the post thread exist? - channelId,std::set({threadId}), posts, comments )) + channelId, std::set({threadId}), + posts, comments, votes) ) return failure( "You cannot comment post " + threadId.toStdString() + " of channel with Id " + channelId.toStdString() + ": this post does not exists locally!" ); @@ -1560,19 +1590,18 @@ bool p3GxsChannels::createCommentV2( ": supplied threadId is not a thread, or parentMsgId is" " not a comment!"); - if(!getChannelContent( // does the post thread exist? + if(!getChannelContent( // does the post parent exist? channelId, std::set({parentId}), - posts, comments )) + posts, comments, votes) ) return failure( "You cannot comment post " + parentId.toStdString() + ": supplied parent doesn't exists locally!" ); if(!origCommentId.isNull()) { std::set s({origCommentId}); - std::vector posts; - std::vector comments; + std::vector cmts; - if( !getChannelContent(channelId, s, posts, comments) || + if( !getChannelContent(channelId, s, posts, cmts, votes) || comments.size() != 1 ) return failure( "You cannot edit comment " + origCommentId.toStdString() + diff --git a/libretroshare/src/services/p3gxschannels.h b/libretroshare/src/services/p3gxschannels.h index d85372e65..e6917e252 100644 --- a/libretroshare/src/services/p3gxschannels.h +++ b/libretroshare/src/services/p3gxschannels.h @@ -82,9 +82,10 @@ virtual void handle_event(uint32_t event_type, const std::string &elabel); public: -virtual bool getGroupData(const uint32_t &token, std::vector &groups); -virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts); -virtual bool getPostData(const uint32_t &token, std::vector &posts); +virtual bool getGroupData(const uint32_t &token, std::vector &groups ) override; +virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts, std::vector &vots) override; +virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts) override; +virtual bool getPostData(const uint32_t &token, std::vector &posts) override; //Not currently used //virtual bool getRelatedPosts(const uint32_t &token, std::vector &posts); @@ -187,14 +188,16 @@ virtual bool ExtraFileRemove(const RsFileHash &hash); /// Implementation of @see RsGxsChannels::getChannelAllMessages bool getChannelAllContent(const RsGxsGroupId& channelId, - std::vector& posts, - std::vector& comments ) override; + std::vector& posts, + std::vector& comments, + std::vector& votes ) override; /// Implementation of @see RsGxsChannels::getChannelMessages bool getChannelContent(const RsGxsGroupId& channelId, const std::set& contentIds, std::vector& posts, - std::vector& comments ) override; + std::vector& comments, + std::vector& votes ) override; /// Implementation of @see RsGxsChannels::getChannelComments virtual bool getChannelComments(const RsGxsGroupId &channelId, diff --git a/libretroshare/src/services/p3posted.cc b/libretroshare/src/services/p3posted.cc index db1de62ca..88ff25808 100644 --- a/libretroshare/src/services/p3posted.cc +++ b/libretroshare/src/services/p3posted.cc @@ -94,55 +94,75 @@ bool p3Posted::getGroupData(const uint32_t &token, std::vector &g return ok; } -bool p3Posted::getPostData(const uint32_t &token, std::vector &msgs, std::vector &cmts) +bool p3Posted::getPostData( + const uint32_t &token, std::vector &msgs, + std::vector &cmts, + std::vector &vots) { #ifdef POSTED_DEBUG - std::cerr << "p3Posted::getPostData()"; - std::cerr << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << std::endl; #endif GxsMsgDataMap msgData; - bool ok = RsGenExchange::getMsgData(token, msgData); rstime_t now = time(NULL); - - if(ok) + if(!RsGenExchange::getMsgData(token, msgData)) { - GxsMsgDataMap::iterator mit = msgData.begin(); - - for(; mit != msgData.end(); ++mit) + RsErr() << __PRETTY_FUNCTION__ << " ERROR in request" << std::endl; + return false; + } + + GxsMsgDataMap::iterator mit = msgData.begin(); + + for(; mit != msgData.end(); ++mit) + { + std::vector& msgItems = mit->second; + std::vector::iterator vit = msgItems.begin(); + + for(; vit != msgItems.end(); ++vit) { - std::vector& msgItems = mit->second; - std::vector::iterator vit = msgItems.begin(); - - for(; vit != msgItems.end(); ++vit) + RsGxsPostedPostItem* postItem = + dynamic_cast(*vit); + + if(postItem) { - RsGxsPostedPostItem* postItem = dynamic_cast(*vit); + // TODO Really needed all of these lines? + RsPostedPost msg = postItem->mPost; + msg.mMeta = postItem->meta; + postItem->toPostedPost(msg, true); + msg.calculateScores(now); - if(postItem) + msgs.push_back(msg); + delete postItem; + } + else + { + RsGxsCommentItem* cmtItem = + dynamic_cast(*vit); + if(cmtItem) { - RsPostedPost msg = postItem->mPost; - msg.mMeta = postItem->meta; - postItem->toPostedPost(msg, true); - msg.calculateScores(now); - - msgs.push_back(msg); - delete postItem; + RsGxsComment cmt; + RsGxsMsgItem *mi = (*vit); + cmt = cmtItem->mMsg; + cmt.mMeta = mi->meta; +#ifdef GXSCOMMENT_DEBUG + RsDbg() << __PRETTY_FUNCTION__ << " Found Comment:" << std::endl; + cmt.print(std::cerr," ", "cmt"); +#endif + cmts.push_back(cmt); + delete cmtItem; } else { - RsGxsCommentItem* cmtItem = dynamic_cast(*vit); - if(cmtItem) + RsGxsVoteItem* votItem = + dynamic_cast(*vit); + if(votItem) { - RsGxsComment cmt; + RsGxsVote vot; RsGxsMsgItem *mi = (*vit); - cmt = cmtItem->mMsg; - cmt.mMeta = mi->meta; -#ifdef GXSCOMMENT_DEBUG - std::cerr << "p3Posted::getPostData Found Comment:" << std::endl; - cmt.print(std::cerr," ", "cmt"); -#endif - cmts.push_back(cmt); - delete cmtItem; + vot = votItem->mMsg; + vot.mMeta = mi->meta; + vots.push_back(vot); + delete votItem; } else { @@ -150,24 +170,37 @@ bool p3Posted::getPostData(const uint32_t &token, std::vector &msg //const uint16_t RS_SERVICE_GXS_TYPE_CHANNELS = 0x0217; //const uint8_t RS_PKT_SUBTYPE_GXSCHANNEL_POST_ITEM = 0x03; //const uint8_t RS_PKT_SUBTYPE_GXSCOMMENT_COMMENT_ITEM = 0xf1; - std::cerr << "Not a PostedPostItem neither a RsGxsCommentItem" - << " PacketService=" << std::hex << (int)msg->PacketService() << std::dec - << " PacketSubType=" << std::hex << (int)msg->PacketSubType() << std::dec - << " type name =" << typeid(*msg).name() - << " , deleting!" << std::endl; + //const uint8_t RS_PKT_SUBTYPE_GXSCOMMENT_VOTE_ITEM = 0xf2; + RsErr() << __PRETTY_FUNCTION__ + << "Not a PostedPostItem neither a " + << "RsGxsCommentItem neither a RsGxsVoteItem" + << " PacketService=" << std::hex << (int)msg->PacketService() << std::dec + << " PacketSubType=" << std::hex << (int)msg->PacketSubType() << std::dec + << " type name =" << typeid(*msg).name() + << " , deleting!" << std::endl; delete *vit; } } } } } - else - { - std::cerr << "p3GxsChannels::getPostData() ERROR in request"; - std::cerr << std::endl; - } - return ok; + return true; +} + +bool p3Posted::getPostData( + const uint32_t &token, std::vector &posts, std::vector &cmts) +{ + std::vector vots; + return getPostData( token, posts, cmts, vots); +} + +bool p3Posted::getPostData( + const uint32_t &token, std::vector &posts) +{ + std::vector cmts; + std::vector vots; + return getPostData( token, posts, cmts, vots); } //Not currently used @@ -323,23 +356,25 @@ bool p3Posted::getBoardsInfo( } bool p3Posted::getBoardAllContent( const RsGxsGroupId& groupId, - std::vector& posts, - std::vector& comments ) + std::vector& posts, + std::vector& comments, + std::vector& votes ) { uint32_t token; RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; - if( !requestMsgInfo(token, opts, std::list({groupId})) || waitToken(token) != RsTokenService::COMPLETE ) - return false; + if( !requestMsgInfo(token, opts, std::list({groupId})) || waitToken(token) != RsTokenService::COMPLETE ) + return false; - return getPostData(token, posts, comments); + return getPostData(token, posts, comments, votes); } bool p3Posted::getBoardContent( const RsGxsGroupId& groupId, - const std::set& contentsIds, - std::vector& posts, - std::vector& comments ) + const std::set& contentsIds, + std::vector& posts, + std::vector& comments, + std::vector& votes ) { uint32_t token; RsTokReqOptions opts; @@ -351,7 +386,7 @@ bool p3Posted::getBoardContent( const RsGxsGroupId& groupId, if( !requestMsgInfo(token, opts, msgIds) || waitToken(token) != RsTokenService::COMPLETE ) return false; - return getPostData(token, posts, comments); + return getPostData(token, posts, comments, votes); } bool p3Posted::getBoardsSummaries(std::list& boards ) diff --git a/libretroshare/src/services/p3posted.h b/libretroshare/src/services/p3posted.h index b6f3ccee5..2fbc780bf 100644 --- a/libretroshare/src/services/p3posted.h +++ b/libretroshare/src/services/p3posted.h @@ -62,13 +62,15 @@ virtual void receiveHelperChanges(std::vector& changes) std::vector& groupsInfo ) override; bool getBoardAllContent(const RsGxsGroupId& groupId, - std::vector& posts, - std::vector& comments ) override; + std::vector& posts, + std::vector& comments, + std::vector& votes ) override; bool getBoardContent(const RsGxsGroupId& groupId, - const std::set& contentsIds, - std::vector& posts, - std::vector& comments ) override; + const std::set& contentsIds, + std::vector& posts, + std::vector& comments, + std::vector& votes ) override; bool getBoardsSummaries(std::list& groupInfo) override; @@ -80,9 +82,10 @@ virtual void receiveHelperChanges(std::vector& changes) bool createBoard(RsPostedGroup& board) override; - virtual bool getGroupData(const uint32_t &token, std::vector &groups); -virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts); -virtual bool getPostData(const uint32_t &token, std::vector &posts) { std::vector cmts; return getPostData( token, posts, cmts);} + virtual bool getGroupData(const uint32_t &token, std::vector &groups) override; + virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts, std::vector &vots) override; + virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts) override; + virtual bool getPostData(const uint32_t &token, std::vector &posts) override; //Not currently used //virtual bool getRelatedPosts(const uint32_t &token, std::vector &posts); diff --git a/retroshare-gui/src/gui/Posted/PostedItem.cpp b/retroshare-gui/src/gui/Posted/PostedItem.cpp index a8e7b0341..751f68ee5 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.cpp +++ b/retroshare-gui/src/gui/Posted/PostedItem.cpp @@ -167,8 +167,9 @@ void BasePostedItem::loadMessage() std::vector posts; std::vector comments; + std::vector votes; - if(! rsPosted->getBoardContent( groupId(), std::set( { messageId() } ),posts,comments)) + if(! rsPosted->getBoardContent( groupId(), std::set( { messageId() } ),posts,comments,votes)) { RsErr() << "BasePostedItem::loadMessage() ERROR getting data" << std::endl; mIsLoadingMessage = false; @@ -227,8 +228,9 @@ void BasePostedItem::loadComment() std::vector posts; std::vector comments; + std::vector votes; - if(! rsPosted->getBoardContent( groupId(),msgIds,posts,comments)) + if(! rsPosted->getBoardContent( groupId(),msgIds,posts,comments,votes)) { RsErr() << "BasePostedItem::loadGroup() ERROR getting data" << std::endl; mIsLoadingComment = false; diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp index 53f97b7ad..92b322c8b 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp @@ -1033,8 +1033,9 @@ void PostedListWidget::getMsgData(const std::set& msgIds,std::ve { std::vector posts; std::vector comments; + std::vector votes; - rsPosted->getBoardContent( groupId(),msgIds,posts,comments ); + rsPosted->getBoardContent( groupId(),msgIds,posts,comments,votes ); psts.clear(); @@ -1046,8 +1047,9 @@ void PostedListWidget::getAllMsgData(std::vector& psts) { std::vector posts; std::vector comments; + std::vector votes; - rsPosted->getBoardAllContent( groupId(),posts,comments ); + rsPosted->getBoardAllContent( groupId(),posts,comments,votes ); psts.clear(); diff --git a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp index 01c0b227b..25b93ac8d 100644 --- a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp @@ -319,8 +319,9 @@ void GxsChannelPostItem::loadMessage() std::vector posts; std::vector comments; + std::vector votes; - if(! rsGxsChannels->getChannelContent( groupId(), std::set( { messageId() } ),posts,comments)) + if(! rsGxsChannels->getChannelContent( groupId(), std::set( { messageId() } ),posts,comments,votes)) { RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl; return; diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp index 70edf9abf..56c910237 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp @@ -738,14 +738,15 @@ void CreateGxsChannelMsg::loadOriginalChannelPostInfo() { std::vector posts; std::vector comments; + std::vector votes; - if( !rsGxsChannels->getChannelContent(mChannelId,std::set({mOrigPostId}),posts,comments) || posts.size() != 1) - { - std::cerr << "Cannot get channel post data for channel " << mChannelId << " and post " << mOrigPostId << std::endl; - return; - } + if( !rsGxsChannels->getChannelContent(mChannelId,std::set({mOrigPostId}),posts,comments,votes) || posts.size() != 1) + { + std::cerr << "Cannot get channel post data for channel " << mChannelId << " and post " << mOrigPostId << std::endl; + return; + } - RsQThreadUtils::postToObject( [posts,this]() + RsQThreadUtils::postToObject( [posts,this]() { /* Here it goes any code you want to be executed on the Qt Gui * thread, for example to update the data model with new information diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp index ff412f9ca..48b620775 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp @@ -694,7 +694,7 @@ void GxsChannelPostsWidget::insertChannelPosts(std::vector& po break; if (thread) - thread->emitAddPost(qVariantFromValue(*it), related, ++pos, count); + thread->emitAddPost(QVariant::fromValue(*it), related, ++pos, count); else createPostItem(*it, related); } @@ -812,8 +812,9 @@ void GxsChannelPostsWidget::getMsgData(const std::set& msgIds,st { std::vector posts; std::vector comments; + std::vector votes; - rsGxsChannels->getChannelContent( groupId(),msgIds,posts,comments ); + rsGxsChannels->getChannelContent( groupId(),msgIds,posts,comments,votes ); psts.clear(); @@ -825,8 +826,9 @@ void GxsChannelPostsWidget::getAllMsgData(std::vector& pst { std::vector posts; std::vector comments; + std::vector votes; - rsGxsChannels->getChannelAllContent( groupId(),posts,comments ); + rsGxsChannels->getChannelAllContent( groupId(),posts,comments,votes ); psts.clear(); From 65631353e85d9274511d0a67700d576ce68b7528 Mon Sep 17 00:00:00 2001 From: Phenom Date: Wed, 13 May 2020 11:01:55 +0200 Subject: [PATCH 32/79] Fix FriendsFiles list when on FlatView --- retroshare-gui/src/gui/RemoteDirModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/RemoteDirModel.cpp b/retroshare-gui/src/gui/RemoteDirModel.cpp index ac4a34d37..b69929778 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.cpp +++ b/retroshare-gui/src/gui/RemoteDirModel.cpp @@ -335,12 +335,13 @@ QString RetroshareDirModel::getAgeIndicatorString(const DirDetails &details) con const QIcon& RetroshareDirModel::getFlagsIcon(FileStorageFlags flags) { static QIcon *static_icons[8] = {NULL}; + if(static_icons[0] == NULL) + static_icons[0] = new QIcon(); int n=0; if(flags & DIR_FLAGS_ANONYMOUS_DOWNLOAD) n += 1 ; if(flags & DIR_FLAGS_ANONYMOUS_SEARCH ) n += 2 ; if(flags & DIR_FLAGS_BROWSABLE ) n += 4 ; - n-= 1; if(static_icons[n] == NULL) { From c4315851d514362ab1f3773f06a9e9976c941212 Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 13 May 2020 12:10:17 +0200 Subject: [PATCH 33/79] Disabled uneeded qproperty-textColorQuote --- retroshare-gui/src/gui/qss/stylesheet/qss.default | 2 +- retroshare-gui/src/qss/qdarkstyle-v2.qss | 2 +- retroshare-gui/src/qss/qdarkstyle.qss | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/qss/stylesheet/qss.default b/retroshare-gui/src/gui/qss/stylesheet/qss.default index 0fb500b14..f71a4b435 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/qss.default +++ b/retroshare-gui/src/gui/qss/stylesheet/qss.default @@ -186,7 +186,7 @@ NetworkDialog RSTextBrowser, MimeTextEdit { - qproperty-textColorQuote: rgb(120, 153, 34); + /*qproperty-textColorQuote: rgb(120, 153, 34);*/ qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970); } diff --git a/retroshare-gui/src/qss/qdarkstyle-v2.qss b/retroshare-gui/src/qss/qdarkstyle-v2.qss index 6a1863ede..97a331ac9 100644 --- a/retroshare-gui/src/qss/qdarkstyle-v2.qss +++ b/retroshare-gui/src/qss/qdarkstyle-v2.qss @@ -2151,6 +2151,6 @@ GxsChannelDialog GroupTreeWidget QTreeWidget#treeWidget::item{ RSTextBrowser, MimeTextEdit { - qproperty-textColorQuote: rgb(125, 125, 255); + /*qproperty-textColorQuote: rgb(125, 125, 255);*/ qproperty-textColorQuotes: ColorList(#0000ff #00ff00 #00ffff #ff0000 #ff00ff #ffff00 #ffffff); } diff --git a/retroshare-gui/src/qss/qdarkstyle.qss b/retroshare-gui/src/qss/qdarkstyle.qss index 62212ab31..75b012389 100644 --- a/retroshare-gui/src/qss/qdarkstyle.qss +++ b/retroshare-gui/src/qss/qdarkstyle.qss @@ -1298,6 +1298,6 @@ WireGroupItem QFrame#frame{ RSTextBrowser, MimeTextEdit { - qproperty-textColorQuote: rgb(125, 125, 255); + /*qproperty-textColorQuote: rgb(125, 125, 255);*/ qproperty-textColorQuotes: ColorList(#0000ff #00ff00 #00ffff #ff0000 #ff00ff #ffff00 #ffffff); } From 86ec01e991f9253e7715c19147c81cbde70cb51e Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 13 May 2020 19:37:44 +0200 Subject: [PATCH 34/79] Added forum settings for Font size & contrast --- .../gui/gxsforums/GxsForumThreadWidget.cpp | 6 +- .../src/gui/gxsforums/GxsForumThreadWidget.ui | 5 + retroshare-gui/src/gui/settings/ForumPage.cpp | 14 +++ retroshare-gui/src/gui/settings/ForumPage.h | 3 + retroshare-gui/src/gui/settings/ForumPage.ui | 96 +++++++++++++++---- 5 files changed, 99 insertions(+), 25 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index e248d4d25..02eb74334 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1165,16 +1165,14 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg) flags |= RSHTML_OPTIMIZEHTML_MASK; QColor backgroundColor = ui->postText->palette().base().color(); - qreal desiredContrast = Settings->valueFromGroup("Chat", + qreal desiredContrast = Settings->valueFromGroup("Forum", "MinimumContrast", 4.5).toDouble(); - int desiredMinimumFontSize = Settings->valueFromGroup("Chat", + int desiredMinimumFontSize = Settings->valueFromGroup("Forum", "MinimumFontSize", 10).toInt(); QString extraTxt = RsHtml().formatText(ui->postText->document(), QString::fromUtf8(msg.mMsg.c_str()), flags - #ifndef DEBUG_FORUMS \ , backgroundColor, desiredContrast, desiredMinimumFontSize - #endif ); ui->postText->setHtml(extraTxt); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui index 5fa0c36dd..088c50cf7 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.ui @@ -506,6 +506,11 @@ 10 + + + MS Sans Serif + + Qt::CustomContextMenu diff --git a/retroshare-gui/src/gui/settings/ForumPage.cpp b/retroshare-gui/src/gui/settings/ForumPage.cpp index 8039a087c..ee0d32566 100644 --- a/retroshare-gui/src/gui/settings/ForumPage.cpp +++ b/retroshare-gui/src/gui/settings/ForumPage.cpp @@ -35,6 +35,8 @@ ForumPage::ForumPage(QWidget * parent, Qt::WindowFlags flags) connect(ui.expandNewMessages , SIGNAL(toggled(bool)), this, SLOT( updateExpandNewMessages())); connect(ui.loadEmbeddedImages , SIGNAL(toggled(bool)), this, SLOT(updateLoadEmbeddedImages() )); connect(ui.loadEmoticons , SIGNAL(toggled(bool)), this, SLOT( updateLoadEmoticons() )); + connect(ui.minimumFontSize , SIGNAL(valueChanged(int)), this, SLOT(updateFonts())); + connect(ui.minimumContrast , SIGNAL(valueChanged(int)), this, SLOT(updateFonts())); ui.groupFrameSettingsWidget->setType(GroupFrameSettings::Forum) ; } @@ -51,10 +53,22 @@ void ForumPage::updateLoadEmoticons() { Settings->setForumLoadEmoticons( /** Loads the settings for this page */ void ForumPage::load() { + Settings->beginGroup(QString("Forum")); whileBlocking(ui.setMsgToReadOnActivate)->setChecked(Settings->getForumMsgSetToReadOnActivate()); whileBlocking(ui.expandNewMessages)->setChecked(Settings->getForumExpandNewMessages()); whileBlocking(ui.loadEmbeddedImages)->setChecked(Settings->getForumLoadEmbeddedImages()); whileBlocking(ui.loadEmoticons)->setChecked(Settings->getForumLoadEmoticons()); + whileBlocking(ui.minimumFontSize)->setValue(Settings->value("MinimumFontSize", 10).toInt()); + whileBlocking(ui.minimumContrast)->setValue(Settings->value("MinimumContrast", 4.5).toDouble()); + Settings->endGroup(); ui.groupFrameSettingsWidget->loadSettings(GroupFrameSettings::Forum); } + +void ForumPage::updateFonts() +{ + Settings->beginGroup(QString("Forum")); + Settings->setValue("MinimumFontSize", ui.minimumFontSize->value()); + Settings->setValue("MinimumContrast", ui.minimumContrast->value()); + Settings->endGroup(); +} diff --git a/retroshare-gui/src/gui/settings/ForumPage.h b/retroshare-gui/src/gui/settings/ForumPage.h index 19027c303..880f66f04 100644 --- a/retroshare-gui/src/gui/settings/ForumPage.h +++ b/retroshare-gui/src/gui/settings/ForumPage.h @@ -45,6 +45,9 @@ protected slots: void updateLoadEmbeddedImages(); void updateLoadEmoticons(); +private slots: + void updateFonts(); + private: Ui::ForumPage ui; }; diff --git a/retroshare-gui/src/gui/settings/ForumPage.ui b/retroshare-gui/src/gui/settings/ForumPage.ui index 4fb74d888..a52638987 100644 --- a/retroshare-gui/src/gui/settings/ForumPage.ui +++ b/retroshare-gui/src/gui/settings/ForumPage.ui @@ -17,6 +17,16 @@ Misc + + + + <html><head/><body><p>This option is costly and it's in the dev's plans to improve it. In the mean time it's disabled by default. If you enable it and long forum posts take a while to display, then disable it again. </p></body></html> + + + Load emoticons (costly) + + + @@ -38,15 +48,71 @@ - - - - <html><head/><body><p>This option is costly and it's in the dev's plans to improve it. In the mean time it's disabled by default. If you enable it and long forum posts take a while to display, then disable it again. </p></body></html> - - - Load emoticons (costly) - - + + + + + + Minimum font size + + + + + + + 1 + + + 64 + + + + + + + Qt::Horizontal + + + + 40 + 38 + + + + + + + + Minimum text contrast + + + + + + + 1.000000000000000 + + + 21.000000000000000 + + + 0.500000000000000 + + + + + + + + + + + + Tabs + + + + @@ -64,18 +130,6 @@ - - - - Tabs - - - - - - - - From f6f508d1ba03a688821b3ac9abe989c5233da77c Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 14 May 2020 16:22:39 +0200 Subject: [PATCH 35/79] Added second icon for inactivity status --- retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp | 8 ++++++-- retroshare-gui/src/gui/chat/ChatLobbyDialog.h | 2 +- retroshare-gui/src/gui/msgs/MessagesDialog.cpp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index 8b5ab7fde..c8cc87380 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -59,12 +59,14 @@ #define ROLE_SORT Qt::UserRole + 1 const static uint32_t timeToInactivity = 60 * 10; // in seconds +const static uint32_t timeToInactivity2 = 60 * 5; // in seconds /** Default constructor */ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::WindowFlags flags) : ChatDialog(parent, flags), lobbyId(lid), mWindowedSetted(false), mPCWindow(nullptr), bullet_red_128(":/icons/bullet_red_128.png"), bullet_grey_128(":/icons/bullet_grey_128.png"), - bullet_green_128(":/icons/bullet_green_128.png"), bullet_yellow_128(":/icons/bullet_yellow_128.png") + bullet_green_128(":/icons/bullet_green_128.png"), bullet_yellow_128(":/icons/bullet_yellow_128.png"), + bullet_blue_128(":/icons/bullet_blue_128.png") { /* Invoke Qt Designer generated QObject setup routine */ ui.setupUi(this); @@ -630,13 +632,15 @@ void ChatLobbyDialog::updateParticipantsList() widgetitem->setIcon(COLUMN_ICON, bullet_red_128); else if (tLastAct + timeToInactivity < now) widgetitem->setIcon(COLUMN_ICON, bullet_grey_128); + else if (tLastAct + timeToInactivity2 < now) + widgetitem->setIcon(COLUMN_ICON, bullet_yellow_128); else widgetitem->setIcon(COLUMN_ICON, bullet_green_128); RsGxsId gxs_id; rsMsgs->getIdentityForChatLobby(lobbyId, gxs_id); - if (RsGxsId(participant.toStdString()) == gxs_id) widgetitem->setIcon(COLUMN_ICON, bullet_yellow_128); + if (RsGxsId(participant.toStdString()) == gxs_id) widgetitem->setIcon(COLUMN_ICON, bullet_blue_128); widgetitem->updateBannedState(); diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h index 1f22284f9..429a5bfb4 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h @@ -134,7 +134,7 @@ private: GxsIdChooser *ownIdChooser ; //icons cache - QIcon bullet_red_128, bullet_grey_128, bullet_green_128, bullet_yellow_128; + QIcon bullet_red_128, bullet_grey_128, bullet_green_128, bullet_yellow_128, bullet_blue_128; }; #endif diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 6da79533d..fac374edc 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -57,7 +57,7 @@ #define IMAGE_MESSAGEREMOVE ":/icons/mail/delete.png" #define IMAGE_STAR_ON ":/images/star-on-16.png" #define IMAGE_STAR_OFF ":/images/star-off-16.png" -#define IMAGE_SYSTEM ":/images/user/user_request16.png" +#define IMAGE_SYSTEM ":/icons/notification.png" #define IMAGE_DECRYPTMESSAGE ":/images/decrypt-mail.png" #define IMAGE_AUTHOR_INFO ":/images/info16.png" #define IMAGE_NOTFICATION ":/icons/notification.png" From 1f547aaefecefbf6a470f1f59a53b9a9fcd65a5d Mon Sep 17 00:00:00 2001 From: jolavillette Date: Thu, 14 May 2020 23:13:36 +0200 Subject: [PATCH 36/79] bandwidth control improvement --- libretroshare/src/ft/fttransfermodule.cc | 6 +- libretroshare/src/pqi/pqihandler.cc | 173 +++++++++-------------- 2 files changed, 71 insertions(+), 108 deletions(-) diff --git a/libretroshare/src/ft/fttransfermodule.cc b/libretroshare/src/ft/fttransfermodule.cc index 8c6ae1f08..ab9900762 100644 --- a/libretroshare/src/ft/fttransfermodule.cc +++ b/libretroshare/src/ft/fttransfermodule.cc @@ -789,16 +789,16 @@ bool ftTransferModule::locked_tickPeerTransfer(peerInfo &info) std::cerr << std::endl; #endif - if (next_req > info.desiredRate * 1.1) + // cap next_req to desiredRate in order to respect the bandwidth limit and to avoid clogging our outqueue + if (next_req > info.desiredRate) { - next_req = info.desiredRate * 1.1; + next_req = info.desiredRate; #ifdef FT_DEBUG std::cerr << "locked_tickPeerTransfer() Reached MaxRate: next_req: " << next_req; std::cerr << std::endl; #endif } - if (next_req > FT_TM_MAX_PEER_RATE) { next_req = FT_TM_MAX_PEER_RATE; diff --git a/libretroshare/src/pqi/pqihandler.cc b/libretroshare/src/pqi/pqihandler.cc index 1e86fa9d1..72d7dbf9d 100644 --- a/libretroshare/src/pqi/pqihandler.cc +++ b/libretroshare/src/pqi/pqihandler.cc @@ -42,39 +42,19 @@ using std::dec; #include #endif -//#define PQI_HDL_DEBUG_UR 1 - -#ifdef PQI_HDL_DEBUG_UR -static double getCurrentTS() -{ - -#ifndef WINDOWS_SYS - struct timeval cts_tmp; - gettimeofday(&cts_tmp, NULL); - double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0; -#else - struct _timeb timebuf; - _ftime( &timebuf); - double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0; -#endif - return cts; -} -#endif - struct RsLog::logInfo pqihandlerzoneInfo = {RsLog::Default, "pqihandler"}; #define pqihandlerzone &pqihandlerzoneInfo //static const int PQI_HANDLER_NB_PRIORITY_LEVELS = 10 ; //static const float PQI_HANDLER_NB_PRIORITY_RATIO = 2 ; -/**** -#define DEBUG_TICK 1 -#define RSITEM_DEBUG 1 -****/ +//#define UPDATE_RATES_DEBUG 1 +// #define DEBUG_TICK 1 +// #define RSITEM_DEBUG 1 pqihandler::pqihandler() : coreMtx("pqihandler") { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // setup minimal total+individual rates. rateIndiv_out = 0.01; @@ -97,7 +77,7 @@ int pqihandler::tick() int moreToTick = 0; { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // tick all interfaces... std::map::iterator it; @@ -127,9 +107,13 @@ int pqihandler::tick() if(now > mLastRateCapUpdate + 5) { + std::map rateMap; + std::map::iterator it; + + // every 5 secs, update the max rates for all modules - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ for(std::map::iterator it = mods.begin(); it != mods.end(); ++it) { // This is rather inelegant, but pqihandler has searchModules that are dynamically allocated, so the max rates @@ -149,7 +133,7 @@ int pqihandler::tick() bool pqihandler::queueOutRsItem(RsItem *item) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ uint32_t size ; locked_HandleRsItem(item, size); @@ -166,7 +150,7 @@ bool pqihandler::queueOutRsItem(RsItem *item) int pqihandler::status() { std::map::iterator it; - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ { // for output std::string out = "pqihandler::status() Active Modules:\n"; @@ -192,7 +176,7 @@ int pqihandler::status() bool pqihandler::AddSearchModule(SearchModule *mod) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // if peerid used -> error. //std::map::iterator it; if (mod->peerid != mod->pqi->PeerId()) @@ -223,7 +207,7 @@ bool pqihandler::AddSearchModule(SearchModule *mod) bool pqihandler::RemoveSearchModule(SearchModule *mod) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) { @@ -313,7 +297,7 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat total.mQueueOut = 0; /* Lock once rates have been retrieved */ - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) @@ -340,10 +324,6 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat // internal fn to send updates int pqihandler::UpdateRates() { -#ifdef PQI_HDL_DEBUG_UR - uint64_t t_now; -#endif - std::map::iterator it; float avail_in = getMaxRate(true); @@ -353,18 +333,15 @@ int pqihandler::UpdateRates() float used_bw_out = 0; /* Lock once rates have been retrieved */ - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ int num_sm = mods.size(); float used_bw_in_table[num_sm]; /* table of in bandwidth currently used by each module */ float used_bw_out_table[num_sm]; /* table of out bandwidth currently used by each module */ - int effectiveUploadsSm = 0; - int effectiveDownloadsSm = 0; - - // loop through modules to get the used bandwith and the number of modules that are affectively transfering -#ifdef PQI_HDL_DEBUG_UR - std::cerr << "Looping through modules" << std::endl; + // loop through modules to get the used bandwidth +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Looping through modules" << std::endl; #endif int index = 0; @@ -372,49 +349,33 @@ int pqihandler::UpdateRates() for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - float crate_in = mod -> pqi -> getRate(true); traffInSum += mod -> pqi -> getTraffic(true); traffOutSum += mod -> pqi -> getTraffic(false); -#ifdef PQI_HDL_DEBUG_UR - if(crate_in > 0.0) - std::cerr << " got in rate for peer " << it->first << " : " << crate_in << std::endl; -#endif - - if ((crate_in > 0.01 * avail_in) || (crate_in > 0.1)) - { - ++effectiveDownloadsSm; - } - + float crate_in = mod -> pqi -> getRate(true); float crate_out = mod -> pqi -> getRate(false); - if ((crate_out > 0.01 * avail_out) || (crate_out > 0.1)) - { - ++effectiveUploadsSm; - } used_bw_in += crate_in; used_bw_out += crate_out; - /* fill the table of bandwidth */ + /* fill the table of used bandwidths */ used_bw_in_table[index] = crate_in; used_bw_out_table[index] = crate_out; + ++index; } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; #endif /* Sort the used bw in/out table in ascending order */ std::sort(used_bw_in_table, used_bw_in_table + num_sm); std::sort(used_bw_out_table, used_bw_out_table + num_sm); -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): Done." << std::endl; - std::cerr << dec << t_now << " pqihandler::UpdateRates(): used_bw_out " << used_bw_out << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates used_bw_out " << used_bw_out << std::endl; #endif /* Calculate the optimal out_max value, taking into account avail_out and the out bw requested by modules */ @@ -441,9 +402,8 @@ int pqihandler::UpdateRates() } } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; #endif /* Allocate only half the remaining out bw, if any, to make it smoother */ @@ -473,67 +433,70 @@ int pqihandler::UpdateRates() } } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; #endif /* Allocate only half the remaining in bw, if any, to make it smoother */ in_max_bw = in_max_bw + in_remaining_bw / 2; - -#ifdef DEBUG_QOS -// std::cerr << "Totals (In) Used B/W " << used_bw_in; -// std::cerr << " Available B/W " << avail_in; -// std::cerr << " Effective transfers " << effectiveDownloadsSm << std::endl; -// std::cerr << "Totals (Out) Used B/W " << used_bw_out; -// std::cerr << " Available B/W " << avail_out; -// std::cerr << " Effective transfers " << effectiveUploadsSm << std::endl; -#endif - + // store current total in and ou used bw locked_StoreCurrentRates(used_bw_in, used_bw_out); - //computing average rates for effective transfers - float max_in_effective = avail_in / num_sm; - if (effectiveDownloadsSm != 0) { - max_in_effective = avail_in / effectiveDownloadsSm; - } - float max_out_effective = avail_out / num_sm; - if (effectiveUploadsSm != 0) { - max_out_effective = avail_out / effectiveUploadsSm; - } - - //modify the in and out limit -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; #endif + // retrieve down (from peer point of view) bandwidth limits set by peers in their own settings + std::map rateMap; + rsConfig->getAllBandwidthRates(rateMap); + std::map::iterator rateMap_it; + +#ifdef UPDATE_RATES_DEBUG + // Dump RsConfigurationDataRates + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates RsConfigDataRates dump" << std::endl; + for (rateMap_it = rateMap.begin(); rateMap_it != rateMap.end(); rateMap_it++) + RsDbg () << "UPDATE_RATES pqihandler::UpdateRates PeerId " << rateMap_it->first.toStdString() << " mAllowedOut " << rateMap_it->second.mAllowedOut << std::endl; +#endif + + // update max rates taking into account the limits set by peers in their own settings for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - - mod -> pqi -> setMaxRate(true, in_max_bw); - mod -> pqi -> setMaxRate(false, out_max_bw); + + // for our down bandwidth we set the max to the calculated value without taking into account the max set by peers: they will control their up bw on their side + mod -> pqi -> setMaxRate(true, in_max_bw); + + // for our up bandwidth we limit to the maximum down bw provided by peers via BwCtrl because we don't want to clog our outqueues, the SSL buffers, and our friends inbound queues + if ((rateMap_it = rateMap.find(mod->pqi->PeerId())) != rateMap.end()) + { + if (rateMap_it->second.mAllowedOut > 0) + { + if (out_max_bw > rateMap_it->second.mAllowedOut) + mod -> pqi -> setMaxRate(false, rateMap_it->second.mAllowedOut); + else + mod -> pqi -> setMaxRate(false, out_max_bw); + } + else + mod -> pqi -> setMaxRate(false, out_max_bw); + } } - - //cap the rates +#ifdef UPDATE_RATES_DEBUG + // dump maxRates for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - if (mod -> pqi -> getMaxRate(false) < max_out_effective) mod -> pqi -> setMaxRate(false, max_out_effective); - if (mod -> pqi -> getMaxRate(false) > avail_out) mod -> pqi -> setMaxRate(false, avail_out); - if (mod -> pqi -> getMaxRate(true) < max_in_effective) mod -> pqi -> setMaxRate(true, max_in_effective); - if (mod -> pqi -> getMaxRate(true) > avail_in) mod -> pqi -> setMaxRate(true, avail_in); + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates PeerID " << (mod ->pqi -> PeerId()).toStdString() << " new bandwidth limits up " << mod -> pqi -> getMaxRate(false) << " down " << mod -> pqi -> getMaxRate(true) << std::endl; } +#endif return 1; } void pqihandler::getCurrentRates(float &in, float &out) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ in = rateTotal_in; out = rateTotal_out; From 6008599f02cc361802e61812aee06270b11079de Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 16 May 2020 13:12:37 +0200 Subject: [PATCH 37/79] fixed wrong call to std::set::erase(iterator,iterator) where the iterator comes from another set, causing inconsistencies --- libretroshare/src/services/p3gxscircles.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 55d5adb6e..92b0c669e 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -415,7 +415,15 @@ bool p3GxsCircles::revokeIdsFromCircle( const std::set& identities, con return false; } - circleGrp.mInvitedMembers.erase(identities.begin(), identities.end()); + // /!\ AVOID calling circleGrp.mInvitedMembers.erase(identities.begin(),identities.end()), because it is not the same set. Consequently + // STL code would corrupt the structure of mInvitedMembers. + + std::set new_invited_members; + for(auto& gxs_id: circleGrp.mInvitedMembers) + if(identities.find(gxs_id) == identities.end()) + new_invited_members.insert(gxs_id); + + circleGrp.mInvitedMembers = new_invited_members; return editCircle(circleGrp); } From dc03f8ff498c98c25be311a08393465ae68d3e26 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 16 May 2020 13:13:48 +0200 Subject: [PATCH 38/79] imprved readability of the logic in rstlvidset serialization --- libretroshare/src/serialiser/rstlvidset.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libretroshare/src/serialiser/rstlvidset.h b/libretroshare/src/serialiser/rstlvidset.h index 732eee64c..2e8a3f882 100644 --- a/libretroshare/src/serialiser/rstlvidset.h +++ b/libretroshare/src/serialiser/rstlvidset.h @@ -92,11 +92,15 @@ template class RS_DEPRECATED_FOR(std::set<>) t ids.insert(id) ; } if(*offset != tlvend) + { std::cerr << "(EE) deserialisaiton error in " << __PRETTY_FUNCTION__ << std::endl; - else if(!ok) + ok = false; + } + + if(!ok) std::cerr << "(WW) something wrong in ID_CLASS.deserialise in " << __PRETTY_FUNCTION__ << std::endl; - return *offset == tlvend ; + return ok; } virtual std::ostream &print(std::ostream &out, uint16_t /* indent */) const { From 384ae46706d6cd1c186035e9fa074354a909186f Mon Sep 17 00:00:00 2001 From: Phenom Date: Sat, 16 May 2020 19:43:27 +0200 Subject: [PATCH 39/79] Fix RSElidedItemDelegate to use StyleSheet as default but defined colors if they are. If none, use Base Delegate. --- plugins/FeedReader/gui/FeedReaderDialog.cpp | 2 +- retroshare-gui/src/gui/ChatLobbyWidget.cpp | 8 +- .../src/gui/FileTransfer/SearchDialog.cpp | 9 +- retroshare-gui/src/gui/Identity/IdDialog.cpp | 48 +-- retroshare-gui/src/gui/ShareManager.cpp | 26 +- .../src/gui/chat/ChatLobbyDialog.cpp | 6 +- retroshare-gui/src/gui/common/ElidedLabel.cpp | 5 +- retroshare-gui/src/gui/common/FriendList.cpp | 10 +- .../src/gui/common/FriendSelectionWidget.cpp | 20 +- .../src/gui/common/GroupTreeWidget.cpp | 17 +- .../src/gui/common/RSElidedItemDelegate.cpp | 338 +++++++++++------- .../src/gui/common/RsCollectionDialog.cpp | 3 +- .../src/gui/msgs/MessagesDialog.cpp | 6 +- .../src/gui/settings/MessagePage.cpp | 6 +- 14 files changed, 301 insertions(+), 203 deletions(-) diff --git a/plugins/FeedReader/gui/FeedReaderDialog.cpp b/plugins/FeedReader/gui/FeedReaderDialog.cpp index 5a00cdd6d..b795eb33b 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.cpp +++ b/plugins/FeedReader/gui/FeedReaderDialog.cpp @@ -452,7 +452,7 @@ void FeedReaderDialog::calculateFeedItem(QTreeWidgetItem *item, uint32_t &unread font.setBold(unreadCountItem != 0); item->setFont(i, font); - item->setTextColor(COLUMN_FEED_NAME, deactivated ? colorDeactivated : colorActivated); + item->setData(COLUMN_FEED_NAME, Qt::ForegroundRole, deactivated ? colorDeactivated : colorActivated); } QIcon icon = item->data(COLUMN_FEED_DATA, ROLE_FEED_ICON).value(); diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.cpp b/retroshare-gui/src/gui/ChatLobbyWidget.cpp index 25c476953..bd802bae4 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.cpp +++ b/retroshare-gui/src/gui/ChatLobbyWidget.cpp @@ -27,6 +27,7 @@ #include "chat/ChatTabWidget.h" #include "chat/CreateLobbyDialog.h" #include "common/RSTreeWidgetItem.h" +#include "common/RSElidedItemDelegate.h" #include "gui/RetroShareLink.h" #include "gui/gxs/GxsIdDetails.h" #include "gui/Identity/IdEditDialog.h" @@ -157,6 +158,7 @@ ChatLobbyWidget::ChatLobbyWidget(QWidget *parent, Qt::WindowFlags flags) ui.lobbyTreeWidget->setColumnHidden(COLUMN_USER_COUNT,true) ; ui.lobbyTreeWidget->setColumnHidden(COLUMN_TOPIC,true) ; ui.lobbyTreeWidget->setSortingEnabled(true) ; + ui.lobbyTreeWidget->setItemDelegateForColumn(COLUMN_NAME, new RSElidedItemDelegate()); float fact = QFontMetricsF(font()).height()/14.0f; @@ -386,6 +388,8 @@ static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobby item->setData(COLUMN_DATA, ROLE_FLAGS, lobby_flags.toUInt32()); item->setData(COLUMN_DATA, ROLE_AUTOSUBSCRIBE, autoSubscribe); + //TODO (Phenom): Add qproperty for these text colors in stylesheets + // As palette is not updated by stylesheet QColor color = treeWidget->palette().color(QPalette::Active, QPalette::Text); if (!subscribed) { @@ -395,7 +399,7 @@ static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobby } for (int column = 0; column < COLUMN_COUNT; ++column) { - item->setTextColor(column, color); + item->setData(column, Qt::ForegroundRole, color); } QString tooltipstr = QObject::tr("Subject:")+" "+item->text(COLUMN_TOPIC)+"\n" +QObject::tr("Participants:")+" "+QString::number(count)+"\n" @@ -407,7 +411,7 @@ static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobby 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->setData(column, Qt::ForegroundRole, foreground); } item->setToolTip(0,tooltipstr) ; } diff --git a/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp b/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp index fb72135ed..9a28a2cf3 100644 --- a/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp +++ b/retroshare-gui/src/gui/FileTransfer/SearchDialog.cpp @@ -415,9 +415,8 @@ void SearchDialog::download() std::cout << *it << "-" << std::endl; QColor foreground = textColorDownloading(); - QBrush brush(foreground); for (int i = 0; i < item->columnCount(); ++i) - item->setForeground(i, brush); + item->setData(i, Qt::ForegroundRole, foreground ); } } } @@ -1269,10 +1268,9 @@ void SearchDialog::insertFile(qulonglong searchId, const FileDetail& file, int s foreground = textColorHighSources(); } - QBrush brush(foreground); for (int i = 0; i < item->columnCount(); ++i) { - item->setForeground(i, brush); + item->setData(i, Qt::ForegroundRole, foreground); } } @@ -1355,10 +1353,9 @@ void SearchDialog::insertFile(qulonglong searchId, const FileDetail& file, int s } if (setForeground) { - QBrush brush(foreground); for (int i = 0; i < item->columnCount(); ++i) { - item->setForeground(i, brush); + item->setData(i, Qt::ForegroundRole, foreground); } } diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index c143b36dd..49f73aadb 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -1369,23 +1369,24 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item, item->setData(RSID_COL_NICKNAME, Qt::UserRole, QString::fromStdString(data.mMeta.mGroupId.toStdString())); item->setText(RSID_COL_KEYID, QString::fromStdString(data.mMeta.mGroupId.toStdString())); - if(isBanned) - { - item->setForeground(RSID_COL_NICKNAME,QBrush(Qt::red)); - item->setForeground(RSID_COL_KEYID,QBrush(Qt::red)); - item->setForeground(RSID_COL_IDTYPE,QBrush(Qt::red)); - item->setForeground(RSID_COL_VOTES,QBrush(Qt::red)); - } - else - { - item->setForeground(RSID_COL_NICKNAME,QBrush(Qt::black)); - item->setForeground(RSID_COL_KEYID,QBrush(Qt::black)); - item->setForeground(RSID_COL_IDTYPE,QBrush(Qt::black)); - item->setForeground(RSID_COL_VOTES,QBrush(Qt::black)); - } + if(isBanned) + { + //TODO (Phenom): Add qproperty for these text colors in stylesheets + item->setData(RSID_COL_NICKNAME, Qt::ForegroundRole, QColor(Qt::red)); + item->setData(RSID_COL_KEYID , Qt::ForegroundRole, QColor(Qt::red)); + item->setData(RSID_COL_IDTYPE , Qt::ForegroundRole, QColor(Qt::red)); + item->setData(RSID_COL_VOTES , Qt::ForegroundRole, QColor(Qt::red)); + } + else + { + item->setData(RSID_COL_NICKNAME, Qt::ForegroundRole, QVariant()); + item->setData(RSID_COL_KEYID , Qt::ForegroundRole, QVariant()); + item->setData(RSID_COL_IDTYPE , Qt::ForegroundRole, QVariant()); + item->setData(RSID_COL_VOTES , Qt::ForegroundRole, QVariant()); + } - item->setData(RSID_COL_KEYID, Qt::UserRole,QVariant(item_flags)) ; - item->setTextAlignment(RSID_COL_VOTES, Qt::AlignRight | Qt::AlignVCenter); + item->setData(RSID_COL_KEYID, Qt::UserRole,QVariant(item_flags)) ; + item->setTextAlignment(RSID_COL_VOTES, Qt::AlignRight | Qt::AlignVCenter); item->setData( RSID_COL_VOTES,Qt::DecorationRole, static_cast(idd.mReputation.mOverallReputationLevel)); @@ -1404,14 +1405,15 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item, QString tooltip = tr("This identity is owned by you"); - if(idd.mFlags & RS_IDENTITY_FLAGS_IS_DEPRECATED) - { - item->setForeground(RSID_COL_NICKNAME,QBrush(Qt::red)); - item->setForeground(RSID_COL_KEYID,QBrush(Qt::red)); - item->setForeground(RSID_COL_IDTYPE,QBrush(Qt::red)); + if(idd.mFlags & RS_IDENTITY_FLAGS_IS_DEPRECATED) + { + //TODO (Phenom): Add qproperty for these text colors in stylesheets + item->setData(RSID_COL_NICKNAME, Qt::ForegroundRole, QColor(Qt::red)); + item->setData(RSID_COL_KEYID , Qt::ForegroundRole, QColor(Qt::red)); + item->setData(RSID_COL_IDTYPE , Qt::ForegroundRole, QColor(Qt::red)); - tooltip += tr("\nThis identity has a unsecure fingerprint (It's probably quite old).\nYou should get rid of it now and use a new one.\nThese identities will soon be not supported anymore.") ; - } + tooltip += tr("\nThis identity has a unsecure fingerprint (It's probably quite old).\nYou should get rid of it now and use a new one.\nThese identities will soon be not supported anymore.") ; + } item->setToolTip(RSID_COL_NICKNAME, tooltip) ; item->setToolTip(RSID_COL_KEYID, tooltip) ; diff --git a/retroshare-gui/src/gui/ShareManager.cpp b/retroshare-gui/src/gui/ShareManager.cpp index c0b234999..7ebb67b3b 100644 --- a/retroshare-gui/src/gui/ShareManager.cpp +++ b/retroshare-gui/src/gui/ShareManager.cpp @@ -250,21 +250,23 @@ void ShareManager::load() listWidget->item(row,COLUMN_GROUPS)->setText(getGroupString(mDirInfos[row].parent_groups)); - QFont font = listWidget->item(row,COLUMN_GROUPS)->font(); - font.setBold(mDirInfos[row].shareflags & DIR_FLAGS_BROWSABLE) ; - listWidget->item(row,COLUMN_GROUPS)->setTextColor( (mDirInfos[row].shareflags & DIR_FLAGS_BROWSABLE)? (Qt::black):(Qt::lightGray)) ; - listWidget->item(row,COLUMN_GROUPS)->setFont(font); + //TODO (Phenom): Add qproperty for these text colors in stylesheets + // As palette is not updated by stylesheet + QFont font = listWidget->item(row,COLUMN_GROUPS)->font(); + font.setBold(mDirInfos[row].shareflags & DIR_FLAGS_BROWSABLE) ; + listWidget->item(row,COLUMN_GROUPS)->setData(Qt::ForegroundRole, QColor((mDirInfos[row].shareflags & DIR_FLAGS_BROWSABLE) ? (Qt::black):(Qt::lightGray)) ); + listWidget->item(row,COLUMN_GROUPS)->setFont(font); - if(QDir(QString::fromUtf8(mDirInfos[row].filename.c_str())).exists()) - { - listWidget->item(row,COLUMN_PATH)->setTextColor(Qt::black); + if(QDir(QString::fromUtf8(mDirInfos[row].filename.c_str())).exists()) + { + listWidget->item(row,COLUMN_PATH)->setData(Qt::ForegroundRole, QColor(Qt::black)); listWidget->item(row,COLUMN_PATH)->setToolTip(tr("Double click to change shared directory path")) ; - } - else - { - listWidget->item(row,COLUMN_PATH)->setTextColor(Qt::lightGray); + } + else + { + listWidget->item(row,COLUMN_PATH)->setData(Qt::ForegroundRole, QColor(Qt::lightGray)); listWidget->item(row,COLUMN_PATH)->setToolTip(tr("Directory does not exist! Double click to change shared directory path")) ; - } + } } listWidget->setColumnWidth(COLUMN_SHARE_FLAGS,132 * QFontMetricsF(font()).height()/14.0) ; diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index 8b5ab7fde..308770144 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -614,10 +614,12 @@ void ChatLobbyDialog::updateParticipantsList() else widgetitem = dynamic_cast(qlFoundParticipants.at(0)); + //TODO (Phenom): Add qproperty for these text colors in stylesheets + // As palette is not updated by stylesheet if (isParticipantMuted(it2->first)) { - widgetitem->setTextColor(COLUMN_NAME,QColor(255,0,0)); + widgetitem->setData(COLUMN_NAME, Qt::ForegroundRole, QColor(255,0,0)); } else { - widgetitem->setTextColor(COLUMN_NAME,ui.participantsList->palette().color(QPalette::Active, QPalette::Text)); + widgetitem->setData(COLUMN_NAME, Qt::ForegroundRole, QVariant()); } time_t tLastAct=widgetitem->text(COLUMN_ACTIVITY).toInt(); diff --git a/retroshare-gui/src/gui/common/ElidedLabel.cpp b/retroshare-gui/src/gui/common/ElidedLabel.cpp index 9700c1200..796852ad3 100644 --- a/retroshare-gui/src/gui/common/ElidedLabel.cpp +++ b/retroshare-gui/src/gui/common/ElidedLabel.cpp @@ -239,7 +239,10 @@ bool ElidedLabel::paintElidedLine( QPainter* painter, QString plainText *rectElision = mRectElision; if(drawRoundedRect) - if (painter) painter->drawRoundedRect(mRectElision, 2 , 2); + if (painter) { + painter->setBrush(QBrush(Qt::transparent)); + painter->drawRoundedRect(mRectElision, 2 , 2); + } } if (painter) painter->restore(); diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index c3cddc5dd..967d8df5d 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -717,7 +717,7 @@ void FriendList::insertPeers() groupItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); groupItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); groupItem->setIcon(COLUMN_NAME, QIcon(IMAGE_GROUP24)); - groupItem->setForeground(COLUMN_NAME, QBrush(textColorGroup())); + groupItem->setData(COLUMN_NAME, Qt::ForegroundRole, textColorGroup()); /* used to find back the item */ QString strID = QString::fromStdString(groupInfo->id.toStdString()); @@ -1110,8 +1110,8 @@ void FriendList::insertPeers() for (int i = 0; i < columnCount; ++i) { sslItem->setData(i, ROLE_SORT_STATE, peerState); - sslItem->setTextColor(i, sslColor); - sslItem->setFont(i, sslFont); + sslItem->setData(i, Qt::ForegroundRole, sslColor); + sslItem->setData(i, Qt::FontRole, sslFont); } } @@ -1222,8 +1222,8 @@ void FriendList::insertPeers() for (int i = 0; i < columnCount; ++i) { gpgItem->setData(i, ROLE_SORT_STATE, bestPeerState); - gpgItem->setTextColor(i, gpgColor); - gpgItem->setFont(i, gpgFont); + gpgItem->setData(i, Qt::ForegroundRole, gpgColor); + gpgItem->setData(i, Qt::FontRole, gpgFont); } if (openPeers.find(gpgId) != openPeers.end()) { diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp index 43179518a..bd737a609 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp @@ -215,7 +215,7 @@ static void initSslItem(QTreeWidgetItem *item, const RsPeerDetails &detail, cons } if (state != (int) RS_STATUS_OFFLINE) { - item->setTextColor(COLUMN_NAME, textColorOnline); + item->setData(COLUMN_NAME, Qt::ForegroundRole, textColorOnline); } item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(state))); @@ -434,7 +434,7 @@ void FriendSelectionWidget::secured_fillList() } if (state != (int) RS_STATUS_OFFLINE) { - gpgItem->setTextColor(COLUMN_NAME, textColorOnline()); + gpgItem->setData(COLUMN_NAME, Qt::ForegroundRole, textColorOnline()); } gpgItem->setFlags(Qt::ItemIsUserCheckable | gpgItem->flags()); @@ -571,7 +571,7 @@ void FriendSelectionWidget::secured_fillList() QString name = QString::fromUtf8(detail.mNickname.c_str()); gxsItem->setText(COLUMN_NAME, name + " ("+QString::fromStdString( (*gxsIt).toStdString() )+")"); - //gxsItem->setTextColor(COLUMN_NAME, textColorOnline()); + //gxsItem->setData(COLUMN_NAME, Qt::ForegroundRole, textColorOnline()); gxsItem->setFlags(Qt::ItemIsUserCheckable | gxsItem->flags()); gxsItem->setIcon(COLUMN_NAME, identicon); gxsItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.mId.toStdString())); @@ -625,7 +625,7 @@ void FriendSelectionWidget::secured_fillList() QString name = QString::fromUtf8(detail.mNickname.c_str()); gxsItem->setText(COLUMN_NAME, name + " ("+QString::fromStdString( (*gxsIt).toStdString() )+")"); - //gxsItem->setTextColor(COLUMN_NAME, textColorOnline()); + //gxsItem->setData(COLUMN_NAME, Qt::ForegroundRole, textColorOnline()); gxsItem->setFlags(Qt::ItemIsUserCheckable | gxsItem->flags()); gxsItem->setIcon(COLUMN_NAME, identicon); gxsItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.mId.toStdString())); @@ -746,14 +746,12 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) case IDTYPE_GPG: { if (item->data(COLUMN_DATA, ROLE_ID).toString() == gpgId) { - QColor color; if (status != (int) RS_STATUS_OFFLINE) { - color = textColorOnline(); + item->setData(COLUMN_NAME, Qt::ForegroundRole, textColorOnline()); } else { - color = ui->friendList->palette().color(QPalette::Text); + item->setData(COLUMN_NAME, Qt::ForegroundRole, QVariant()); } - item->setTextColor(COLUMN_NAME, color); item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(gpgStatus))); item->setData(COLUMN_NAME, ROLE_SORT_STATE, gpgStatus); @@ -765,14 +763,12 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) case IDTYPE_SSL: { if (item->data(COLUMN_DATA, ROLE_ID).toString() == peerId) { - QColor color; if (status != (int) RS_STATUS_OFFLINE) { - color = textColorOnline(); + item->setData(COLUMN_NAME, Qt::ForegroundRole, textColorOnline()); } else { - color = ui->friendList->palette().color(QPalette::Text); + item->setData(COLUMN_NAME, Qt::ForegroundRole, QVariant()); } - item->setTextColor(COLUMN_NAME, color); item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(status))); item->setData(COLUMN_NAME, ROLE_SORT_STATE, status); diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp index 063b8cb91..a867c95d9 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp @@ -287,9 +287,6 @@ void GroupTreeWidget::initDisplayMenu(QToolButton *toolButton) void GroupTreeWidget::updateColors() { - QBrush brush; - QBrush standardBrush = ui->treeWidget->palette().color(QPalette::Text); - QTreeWidgetItemIterator itemIterator(ui->treeWidget); QTreeWidgetItem *item; while ((item = *itemIterator) != NULL) { @@ -297,12 +294,11 @@ void GroupTreeWidget::updateColors() int color = item->data(COLUMN_DATA, ROLE_COLOR).toInt(); if (color >= 0) { - brush = QBrush(mTextColor[color]); + item->setData(COLUMN_NAME, Qt::TextColorRole, mTextColor[color]); } else { - brush = standardBrush; + item->setData(COLUMN_NAME, Qt::TextColorRole, QVariant()); } - item->setForeground(COLUMN_NAME, brush); } } @@ -356,7 +352,7 @@ QTreeWidgetItem *GroupTreeWidget::addCategoryItem(const QString &name, const QIc int S = QFontMetricsF(font).height(); item->setSizeHint(COLUMN_NAME, QSize(S*1.9, S*1.9)); - item->setForeground(COLUMN_NAME, QBrush(textColorCategory())); + item->setData(COLUMN_NAME, Qt::TextColorRole, textColorCategory()); item->setData(COLUMN_DATA, ROLE_COLOR, GROUPTREEWIDGET_COLOR_CATEGORY); item->setExpanded(expand); @@ -513,15 +509,14 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< item->setData(COLUMN_DATA, ROLE_SUBSCRIBE_FLAGS, itemInfo.subscribeFlags); /* Set color */ - QBrush brush; if (itemInfo.publishKey) { - brush = QBrush(textColorPrivateKey()); item->setData(COLUMN_DATA, ROLE_COLOR, GROUPTREEWIDGET_COLOR_PRIVATEKEY); + item->setData(COLUMN_NAME, Qt::BackgroundRole, QBrush(textColorPrivateKey())); } else { - brush = ui->treeWidget->palette().color(QPalette::Text); + // Let StyleSheet color item->setData(COLUMN_DATA, ROLE_COLOR, GROUPTREEWIDGET_COLOR_STANDARD); + item->setData(COLUMN_NAME, Qt::BackgroundRole, QVariant()); } - item->setForeground(COLUMN_NAME, brush); /* Calculate score */ calculateScore(item, filterText); diff --git a/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp b/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp index 66ceb2072..89a2ebe8a 100644 --- a/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp +++ b/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp @@ -36,6 +36,36 @@ #include #include +//#define DEBUG_EID_PAINT 1 + +/* To test it you can make an empty.qss file with: +QTreeView::item, QTreeWidget::item{ + color: #AB0000; + background-color: #00DC00; +} +QTreeView::item:selected, QTreeWidget::item:selected{ + color: #00CD00; + background-color: #0000BA; +} +QTreeView::item:hover, QTreeWidget::item:hover{ + color: #0000EF; + background-color: #FEDCBA; +} +QQTreeView::item:selected:hover, TreeWidget::item:selected:hover{ + color: #ABCDEF; + background-color: #FE0000; +} + +ForumsDialog, GxsForumThreadWidget +{ + qproperty-textColorRead: darkgray; + qproperty-textColorUnread: white; + qproperty-textColorUnreadChildren: red; + qproperty-textColorNotSubscribed: white; + qproperty-textColorMissing: darkred; +} +*/ + RSElidedItemDelegate::RSElidedItemDelegate(QObject *parent) : RSStyledItemDelegate(parent) , mOnlyPlainText(false), mPaintRoundedRect(true) @@ -63,6 +93,18 @@ QSize RSElidedItemDelegate::sizeHint(const QStyleOptionViewItem &option, const Q return contSize; } +inline QColor getImagePixelColor(QImage img, int x, int y) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5,6,0) +#ifdef DEBUG_EID_PAINT +// RsDbg() << " RSEID: Found Color " << img.pixelColor(x,y).name(QColor::HexArgb).toStdString() << " at " << x << "," << y << std::endl; +#endif + return img.pixelColor(x,y); +#else + return img.pixel(x,y); +#endif +} + void RSElidedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(!index.isValid()) @@ -71,15 +113,16 @@ void RSElidedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & return ; } painter->save(); - // To draw with default for debug purpose - //QStyledItemDelegate::paint(painter, option, index); - QStyleOptionViewItem ownOption (option); initStyleOption(&ownOption, index); //Prefer use icon from option if (!option.icon.isNull()) ownOption.icon = option.icon; +#ifdef DEBUG_EID_PAINT + RsDbg() << __PRETTY_FUNCTION__ << std::endl << " RSEID: Enter for item with text:" << ownOption.text.toStdString() << std::endl; +#endif + const QWidget* widget = option.widget; QStyle* ownStyle = widget ? widget->style() : QApplication::style(); @@ -89,28 +132,180 @@ void RSElidedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & td.setHtml(ownOption.text); ownOption.text = td.toPlainText(); } - //Get Font as option.font is not accurate + // Get Font as option.font is not accurate if (index.data(Qt::FontRole).type() == QVariant::Font) { QFont font = index.data(Qt::FontRole).value(); ownOption.font = font; ownOption.fontMetrics = QFontMetrics(font); +#ifdef DEBUG_EID_PAINT + QFontInfo info(font); + RsDbg() << " RSEID: Found font in model:" << info.family().toStdString() << std::endl; +#endif } + // Get Text color from model if one exists QColor textColor; - if (index.data(Qt::TextColorRole).canConvert(QMetaType::QColor)) { - textColor = QColor(index.data(Qt::TextColorRole).toString());//Needs to pass from string else loose RBG format. + if (index.data(Qt::TextColorRole).isValid()) { + //textColor = QColor(index.data(Qt::TextColorRole).toString());//Needs to pass from string else loose RBG format. + textColor = index.data(Qt::TextColorRole).value(); +#ifdef DEBUG_EID_PAINT + RsDbg() << " RSEID: Found text color in model:" << textColor.name().toStdString() << std::endl; +#endif } - if (index.data(Qt::BackgroundRole).canConvert(QMetaType::QBrush)) { - QBrush brush(index.data(Qt::BackgroundRole).convert(QMetaType::QBrush)); - ownOption.backgroundBrush = brush; + // Get Brush from model if one exists + QBrush bgBrush; + bgBrush.setColor(QColor());// To get color().spec()==QColor::Invalid) + if (index.data(Qt::BackgroundRole).isValid()) { + bgBrush = index.data(Qt::BackgroundRole).value(); +#ifdef DEBUG_EID_PAINT + RsDbg() << " RSEID: Found bg brush in model:" << bgBrush.color().name().toStdString() << std::endl; +#endif } - //Code from: https://code.woboq.org/qt5/qtbase/src/widgets/styles/qcommonstyle.cpp.html#2271 + // If we get text and bg color from model, no need to retrieve it from base + if ( (bgBrush.color().spec()==QColor::Invalid) || (textColor.spec()!=QColor::Invalid) ) + { +#ifdef DEBUG_EID_PAINT + RsDbg() << " RSEID:" + << ((bgBrush.color().spec()==QColor::Invalid) ? " Brush not defined" : "") + << ((textColor.spec()==QColor::Invalid) ? " Text Color not defined" : "") + << " so get it from base image." << std::endl; +#endif + // QPalette is not updated by StyleSheet all occurs in internal class. (QRenderRule) + // https://code.woboq.org/qt5/qtbase/src/widgets/styles/qstylesheetstyle.cpp.html#4138 + // void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p, const QWidget *w) const + // case CE_ItemViewItem: + // So we have to print it in Image to get colors by pixel + QSize moSize=sizeHint(option,index); + if (moSize.width() <= 20) + moSize.setWidth(20); +#ifdef DEBUG_EID_PAINT + RsDbg() << " RSEID: for item size = " << moSize.width() << "x" << moSize.height() << std::endl; +#endif + + QImage moImg(moSize,QImage::Format_ARGB32); + QPainter moPnt; + moPnt.begin(&moImg); + moPnt.setCompositionMode (QPainter::CompositionMode_Source); + moPnt.fillRect(moImg.rect(), Qt::transparent); + moPnt.setCompositionMode (QPainter::CompositionMode_SourceOver); + + QStyleOptionViewItem moOption (option); + // Define option to get only what we want + { + moOption.rect = QRect(QPoint(0,0),moSize); + moOption.state = ownOption.state; + moOption.text = " ████████████████";//Add a blank char to get BackGround Color at top left + // Remove unwanted info. Yes it can draw without that all public data ... + moOption.backgroundBrush = QBrush(); + moOption.checkState = Qt::Unchecked; + moOption.decorationAlignment = Qt::AlignLeft; + moOption.decorationPosition = QStyleOptionViewItem::Left; + moOption.decorationSize = QSize(); + moOption.displayAlignment = Qt::AlignLeft | Qt::AlignTop; + moOption.features=0; + moOption.font = QFont(); + moOption.icon = QIcon(); + moOption.index = QModelIndex(); + moOption.locale = QLocale(); + moOption.showDecorationSelected = false; + moOption.textElideMode = Qt::ElideNone; + moOption.viewItemPosition = QStyleOptionViewItem::Middle; + //moOption.widget = nullptr; //Needed. + + moOption.direction = Qt::LayoutDirectionAuto; + moOption.fontMetrics = QFontMetrics(QFont()); + moOption.palette = QPalette(); + moOption.styleObject = nullptr; + } + QStyledItemDelegate::paint(&moPnt, moOption, QModelIndex()); + + //// But these lines doesn't works. + { + //QStyleOptionViewItem moOptionsState; + //moOptionsState.initFrom(moOption.widget); + //moOptionsState.rect = QRect(QPoint(0,0),moSize); + //moOptionsState.state = QStyle::State_MouseOver | QStyle::State_Enabled | QStyle::State_Sibling; + //moOptionsState.text = "████████"; + //moOptionsState.widget = option.widget; + //QStyledItemDelegate::paint(&moPnt, moOptionsState, QModelIndex()); + } + + moPnt.end(); +#ifdef DEBUG_EID_PAINT + // To save what it paint in application path + moImg.save("image.png"); +#endif + // Get Color in this rect. + { + QColor moColor; + QColor moBGColor=getImagePixelColor(moImg,1,1); // BackGround may be paint. + QColor moColorBorder;// To avoid Border pixel + int moWidth = moImg.size().width(), moHeight = moImg.size().height(); + for (int x = 0; (xsetPen(textColor); + painter->setBrush(bgBrush); + ownOption.backgroundBrush = bgBrush; + + // Code from: https://code.woboq.org/qt5/qtbase/src/widgets/styles/qcommonstyle.cpp.html#2271 QRect checkRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &ownOption, widget); QRect iconRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemDecoration, &ownOption, widget); QRect textRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemText, &ownOption, widget); - // draw the background - ownStyle->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, widget); + // Draw the background + if (bgBrush.color().alpha() == 0) + // No BackGround Color found, use default delegate to draw it. + ownStyle->proxy()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, widget);// This prefer draw StyleSheet bg than item one. + else + painter->fillRect(ownOption.rect,bgBrush); + +#ifdef DEBUG_EID_PAINT + { + QStyleOptionViewItem tstOption = option; + // Reduce rect to get this item bg color external and base internal + tstOption.rect.adjust(3,3,-6,-6); + // To draw with base for debug purpose + QStyledItemDelegate::paint(painter, tstOption, index); + } +#endif + // draw the check mark if (ownOption.features & QStyleOptionViewItem::HasCheckIndicator) { QStyleOptionViewItem option(*&ownOption); @@ -165,130 +360,31 @@ void RSElidedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & qreal add = 120*(time/(duration*1000.0))*std::abs(sin(qDegreesToRadians(angle/2))); painter->setPen(QPen(QBrush(ownOption.palette.color(QPalette::Normal, QPalette::WindowText)),diag/10,Qt::DotLine,Qt::RoundCap)); painter->drawEllipse( iconRect.x()+iconRect.width() /2 + (diag/4)*cos(qDegreesToRadians(angle )) - , iconRect.y()+iconRect.height()/2 + (diag/4)*sin(qDegreesToRadians(angle )), 1, 1); + , iconRect.y()+iconRect.height()/2 + (diag/4)*sin(qDegreesToRadians(angle )), 1, 1); painter->setPen(QPen(QBrush(ownOption.palette.color(QPalette::Normal, QPalette::Midlight)),diag/10,Qt::DotLine,Qt::RoundCap)); painter->drawEllipse( iconRect.x()+iconRect.width() /2 + (diag/4)*cos(qDegreesToRadians(angle- add)) - , iconRect.y()+iconRect.height()/2 + (diag/4)*sin(qDegreesToRadians(angle- add)), 1, 1); + , iconRect.y()+iconRect.height()/2 + (diag/4)*sin(qDegreesToRadians(angle- add)), 1, 1); painter->setPen(QPen(QBrush(ownOption.palette.color(QPalette::Normal, QPalette::Window)),diag/10,Qt::DotLine,Qt::RoundCap)); painter->drawEllipse( iconRect.x()+iconRect.width() /2 + (diag/4)*cos(qDegreesToRadians(angle-2*add)) - , iconRect.y()+iconRect.height()/2 + (diag/4)*sin(qDegreesToRadians(angle-2*add)), 1, 1); + , iconRect.y()+iconRect.height()/2 + (diag/4)*sin(qDegreesToRadians(angle-2*add)), 1, 1); } } } // draw the text if (!ownOption.text.isEmpty()) { - QPalette::ColorGroup cg = ownOption.state & QStyle::State_Enabled - ? QPalette::Normal : QPalette::Disabled; - if (cg == QPalette::Normal && !(ownOption.state & QStyle::State_Active)) - cg = QPalette::Inactive; - if (ownOption.state & QStyle::State_Selected) { - painter->setPen(ownOption.palette.color(cg, QPalette::HighlightedText)); - } else { -#if QT_VERSION >= QT_VERSION_CHECK(5,6,0) - if (ownOption.state & QStyle::State_MouseOver) { - //TODO: Manage to get palette with HOVER css pseudoclass - // For now this is hidden by Qt: https://code.woboq.org/qt5/qtbase/src/widgets/styles/qstylesheetstyle.cpp.html#6103 - // So we print default in image and get it's color... - QSize moSize=sizeHint(option,index); - QImage moImg(moSize,QImage::Format_ARGB32); - QPainter moPnt; - moPnt.begin(&moImg); - moPnt.setPen(Qt::black);//Fill Image with Black - moPnt.setBrush(Qt::black); - moPnt.drawRect(moImg.rect()); - - QStyleOptionViewItem moOption (option); - // Define option to get only what we want - { - moOption.rect = QRect(QPoint(0,0),moSize); - moOption.state = QStyle::State_MouseOver | QStyle::State_Enabled | QStyle::State_Sibling; - moOption.text = " ████████████████";//Add a blank char to get BackGround Color at top left - // Remove unwanted info. Yes it can draw without that all public data ... - moOption.backgroundBrush = QBrush(); - moOption.checkState = Qt::Unchecked; - moOption.decorationAlignment = Qt::AlignLeft; - moOption.decorationPosition = QStyleOptionViewItem::Left; - moOption.decorationSize = QSize(); - moOption.displayAlignment = Qt::AlignLeft | Qt::AlignTop; - moOption.features=0; - moOption.font = QFont(); - moOption.icon = QIcon(); - moOption.index = QModelIndex(); - moOption.locale = QLocale(); - moOption.showDecorationSelected = false; - moOption.textElideMode = Qt::ElideNone; - moOption.viewItemPosition = QStyleOptionViewItem::Middle; - //moOption.widget = nullptr; //Needed. - - moOption.direction = Qt::LayoutDirectionAuto; - moOption.fontMetrics = QFontMetrics(QFont()); - moOption.palette = QPalette(); - moOption.styleObject = nullptr; - } - QStyledItemDelegate::paint(&moPnt, moOption, QModelIndex()); - - //// But these lines doesn't works. - { - //QStyleOptionViewItem moOptionsState; - //moOptionsState.initFrom(moOption.widget); - //moOptionsState.rect = QRect(QPoint(0,0),moSize); - //moOptionsState.state = QStyle::State_MouseOver | QStyle::State_Enabled | QStyle::State_Sibling; - //moOptionsState.text = "████████"; - //moOptionsState.widget = option.widget; - //QStyledItemDelegate::paint(&moPnt, moOptionsState, QModelIndex()); - } - - moPnt.end(); - // To save what it paint - //moImg.save("image.bmp"); - - // Get Color in this black rect. - QColor moColor; - QColor moBGColor=moImg.pixelColor(1,1); //BackGround may be paint. - QColor moColorBorder;// To avoid Border pixel - int moWidth = moImg.size().width(), moHeight = moImg.size().height(); - for (int x = 0; (xsetPen(moColor); - } - else +#ifdef DEBUG_EID_PAINT + // To draw text near base one. + ownOption.text = ownOption.text.prepend("__"); #endif - if (textColor.spec()==QColor::Invalid) { - painter->setPen(ownOption.palette.color(cg, QPalette::Text)); - } else { //Only get color from index for unselected(as Qt does) - painter->setPen(textColor); - } - } - if (ownOption.state & QStyle::State_Editing) { - painter->setPen(ownOption.palette.color(cg, QPalette::Text)); - painter->drawRect(textRect.adjusted(0, 0, -1, -1)); - } - //d->viewItemDrawText(p, &ownOption, textRect); + QTextLayout textLayout(ownOption.text, painter->font()); QTextOption to = textLayout.textOption(); StyledElidedLabel::paintElidedLine(painter,ownOption.text,textRect,ownOption.font,ownOption.displayAlignment,to.wrapMode()&QTextOption::WordWrap,mPaintRoundedRect); } painter->restore(); +#ifdef DEBUG_EID_PAINT + RsDbg() << " RSEID: Finished" << std::endl; +#endif } bool RSElidedItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) diff --git a/retroshare-gui/src/gui/common/RsCollectionDialog.cpp b/retroshare-gui/src/gui/common/RsCollectionDialog.cpp index 6012bd832..b9a84b7a1 100644 --- a/retroshare-gui/src/gui/common/RsCollectionDialog.cpp +++ b/retroshare-gui/src/gui/common/RsCollectionDialog.cpp @@ -537,8 +537,9 @@ bool RsCollectionDialog::addChild(QTreeWidgetItem* parent, const std::vectorsetTextColor(COLUMN_FILE, QColor(255,80,120)) ; + item->setData(COLUMN_FILE, Qt::ForegroundRole, QColor(255,80,120)) ; } if (parentsFounds.empty()) { diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 6da79533d..36f7c37c2 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -451,7 +451,7 @@ void MessagesDialog::fillQuickView() text = TagDefs::name(tag->first, tag->second.first); item = new QListWidgetItem (text, ui.quickViewWidget); - item->setForeground(QBrush(QColor(tag->second.second))); + item->setData(Qt::ForegroundRole, QColor(tag->second.second)); item->setIcon(QIcon(":/images/foldermail.png")); item->setData(ROLE_QUICKVIEW_TYPE, QUICKVIEW_TYPE_TAG); item->setData(ROLE_QUICKVIEW_ID, tag->first); @@ -1262,7 +1262,7 @@ void MessagesDialog::updateMessageSummaryList() qf.setBold(true); item->setFont(qf); item->setIcon(QIcon(":/images/folder-inbox-new.png")); - item->setForeground(QBrush(mTextColorInbox)); + item->setData(Qt::ForegroundRole, mTextColorInbox); } else { @@ -1272,7 +1272,7 @@ void MessagesDialog::updateMessageSummaryList() qf.setBold(false); item->setFont(qf); item->setIcon(QIcon(":/images/folder-inbox.png")); - item->setForeground(QBrush(ui.messageTreeWidget->palette().color(QPalette::Text))); + item->setData(Qt::ForegroundRole, QVariant()); } //QList QListWidget::findItems ( const QString & text, Qt::MatchFlags flags ) const diff --git a/retroshare-gui/src/gui/settings/MessagePage.cpp b/retroshare-gui/src/gui/settings/MessagePage.cpp index 908a765c3..eb0eabccc 100644 --- a/retroshare-gui/src/gui/settings/MessagePage.cpp +++ b/retroshare-gui/src/gui/settings/MessagePage.cpp @@ -140,7 +140,7 @@ void MessagePage::fillTags() QString text = TagDefs::name(Tag->first, Tag->second.first); QListWidgetItem *pItemWidget = new QListWidgetItem(text, ui.tags_listWidget); - pItemWidget->setTextColor(QColor(Tag->second.second)); + pItemWidget->setData(Qt::ForegroundRole, QColor(Tag->second.second)); pItemWidget->setData(Qt::UserRole, Tag->first); } } @@ -155,7 +155,7 @@ void MessagePage::addTag() QString text = TagDefs::name(Tag->first, Tag->second.first); QListWidgetItem *pItemWidget = new QListWidgetItem(text, ui.tags_listWidget); - pItemWidget->setTextColor(QColor(Tag->second.second)); + pItemWidget->setData(Qt::ForegroundRole, QColor(Tag->second.second)); pItemWidget->setData(Qt::UserRole, TagDlg.m_nId); m_changedTagIds.push_back(TagDlg.m_nId); @@ -186,7 +186,7 @@ void MessagePage::editTag() if (Tag->first >= RS_MSGTAGTYPE_USER) { pItemWidget->setText(QString::fromStdString(Tag->second.first)); } - pItemWidget->setTextColor(QColor(Tag->second.second)); + pItemWidget->setData(Qt::ForegroundRole, QColor(Tag->second.second)); if (std::find(m_changedTagIds.begin(), m_changedTagIds.end(), TagDlg.m_nId) == m_changedTagIds.end()) { m_changedTagIds.push_back(TagDlg.m_nId); From 089ea76a6e3623023253e2e031648f8cfdd6e801 Mon Sep 17 00:00:00 2001 From: b1rdG Date: Sun, 17 May 2020 09:18:12 -0500 Subject: [PATCH 40/79] Add lobby_identity check --- libretroshare/src/chat/distributedchat.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index 0aa16b20e..97654e200 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -1606,6 +1606,13 @@ ChatLobbyId DistributedChatService::createChatLobby(const std::string& lobby_nam { RsStackMutex stack(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + if (!rsIdentity->isOwnId(lobby_identity)) + { + RsErr() << __PRETTY_FUNCTION__ << " lobby_identity RsGxsId id must be own" << std::endl; + lobby_id = 00000000000000000000; + return lobby_id; + } + // create a unique id. // do { lobby_id = RSRandom::random_u64() ; } while(_chat_lobbys.find(lobby_id) != _chat_lobbys.end()) ; From dafd975b513c3b7c945181d35f3b8c10cd390476 Mon Sep 17 00:00:00 2001 From: b1rdG Date: Sun, 17 May 2020 14:06:07 -0500 Subject: [PATCH 41/79] Verify before lock the mutex --- libretroshare/src/chat/distributedchat.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index 97654e200..3f5ecc74e 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -1604,15 +1604,14 @@ ChatLobbyId DistributedChatService::createChatLobby(const std::string& lobby_nam #endif ChatLobbyId lobby_id ; { - RsStackMutex stack(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ - if (!rsIdentity->isOwnId(lobby_identity)) { RsErr() << __PRETTY_FUNCTION__ << " lobby_identity RsGxsId id must be own" << std::endl; - lobby_id = 00000000000000000000; - return lobby_id; + return 0; } + RsStackMutex stack(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + // create a unique id. // do { lobby_id = RSRandom::random_u64() ; } while(_chat_lobbys.find(lobby_id) != _chat_lobbys.end()) ; From f1864228331a113498a2f70a6bc771065914c040 Mon Sep 17 00:00:00 2001 From: sehraf Date: Sun, 17 May 2020 23:43:03 +0200 Subject: [PATCH 42/79] fix RawMemoryWrapper serialisation to json, reported by b1rdG --- libretroshare/src/serialiser/rstypeserializer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/serialiser/rstypeserializer.cc b/libretroshare/src/serialiser/rstypeserializer.cc index 7ed98bd7f..1ea3add9a 100644 --- a/libretroshare/src/serialiser/rstypeserializer.cc +++ b/libretroshare/src/serialiser/rstypeserializer.cc @@ -599,7 +599,8 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( RsBase64::encode(first, second, encodedValue, true, false); ctx.mJson.SetString( encodedValue.data(), - static_cast(encodedValue.length()) ); + static_cast(encodedValue.length()), + ctx.mJson.GetAllocator()); break; } case RsGenericSerializer::FROM_JSON: From edae2faf2c78c8ed7ad7873f2ec5dcdfbc28445c Mon Sep 17 00:00:00 2001 From: defnax Date: Mon, 18 May 2020 01:24:37 +0200 Subject: [PATCH 43/79] Fixing background of a frame to be transparent --- retroshare-gui/src/qss/qdarkstyle.qss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/retroshare-gui/src/qss/qdarkstyle.qss b/retroshare-gui/src/qss/qdarkstyle.qss index 75b012389..059c87f9d 100644 --- a/retroshare-gui/src/qss/qdarkstyle.qss +++ b/retroshare-gui/src/qss/qdarkstyle.qss @@ -1301,3 +1301,8 @@ RSTextBrowser, MimeTextEdit /*qproperty-textColorQuote: rgb(125, 125, 255);*/ qproperty-textColorQuotes: ColorList(#0000ff #00ff00 #00ffff #ff0000 #ff00ff #ffff00 #ffffff); } + +ChatWidget QFrame#pluginTitleFrame +{ + background: transparent; +} From 0a83e7efc5aa329339c197278bbc76fbf09beadd Mon Sep 17 00:00:00 2001 From: Phenom Date: Tue, 19 May 2020 19:37:09 +0200 Subject: [PATCH 44/79] Fix Messages Quick View unselect. --- .../src/gui/msgs/MessagesDialog.cpp | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index feb3e81bd..68553e95d 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -93,7 +93,7 @@ class MessageSortFilterProxyModel: public QSortFilterProxyModel { public: - MessageSortFilterProxyModel(const QHeaderView *header,QObject *parent = NULL): QSortFilterProxyModel(parent),m_header(header) , m_sortingEnabled(false) {} + MessageSortFilterProxyModel(QObject *parent = NULL): QSortFilterProxyModel(parent), m_sortingEnabled(false) {} bool lessThan(const QModelIndex& left, const QModelIndex& right) const override { @@ -113,7 +113,6 @@ public: void setSortingEnabled(bool b) { m_sortingEnabled = b ; } private: - const QHeaderView *m_header ; bool m_sortingEnabled; }; @@ -138,7 +137,7 @@ MessagesDialog::MessagesDialog(QWidget *parent) listMode = LIST_NOTHING; mMessageModel = new RsMessageModel(this); - mMessageProxyModel = new MessageSortFilterProxyModel(ui.messageTreeWidget->header(),this); + mMessageProxyModel = new MessageSortFilterProxyModel(this); mMessageProxyModel->setSourceModel(mMessageModel); mMessageProxyModel->setSortRole(RsMessageModel::SortRole); mMessageProxyModel->setDynamicSortFilter(false); @@ -663,17 +662,17 @@ void MessagesDialog::messageTreeWidgetCustomPopupMenu(QPoint /*point*/) void MessagesDialog::showAuthorInPeopleTab() { std::string cid; - std::string mid; + std::string mid; - if(!getCurrentMsg(cid, mid)) - return ; + if(!getCurrentMsg(cid, mid)) + return ; - MessageInfo msgInfo; - if (!rsMail->getMessage(mid, msgInfo)) - return; + MessageInfo msgInfo; + if (!rsMail->getMessage(mid, msgInfo)) + return; if(msgInfo.rsgxsid_srcId.isNull()) - return ; + return ; /* window will destroy itself! */ IdDialog *idDialog = dynamic_cast(MainWindow::getPage(MainWindow::People)); @@ -779,8 +778,9 @@ void MessagesDialog::changeBox(int box_row) inChange = true; - ui.quickViewWidget->setCurrentItem(NULL); - listMode = LIST_BOX; + ui.quickViewWidget->setCurrentItem(NULL); + changeQuickView(-1); + listMode = LIST_BOX; switch(box_row) { @@ -813,10 +813,10 @@ void MessagesDialog::changeBox(int box_row) void MessagesDialog::changeQuickView(int newrow) { - Q_UNUSED(newrow); - ui.listWidget->setCurrentItem(NULL); - listMode = LIST_QUICKVIEW; + ui.listWidget->setCurrentItem(NULL); + changeBox(-1); + listMode = LIST_QUICKVIEW; RsMessageModel::QuickViewFilter f = RsMessageModel::QUICK_VIEW_ALL ; @@ -870,17 +870,14 @@ void MessagesDialog::messagesTagsChanged() mMessageModel->updateMessages(); } -static void InitIconAndFont(QTreeWidgetItem *item) -{ -} // click in messageTreeWidget -void MessagesDialog::currentChanged(const QModelIndex& new_proxy_index,const QModelIndex& old_proxy_index) +void MessagesDialog::currentChanged(const QModelIndex& new_proxy_index,const QModelIndex& /*old_proxy_index*/) { - if(!new_proxy_index.isValid()) - return; + if(!new_proxy_index.isValid()) + return; - // show current message directly + // show current message directly insertMsgTxtAndFiles(new_proxy_index); } From f96f1cf8b12f71c1c4e6cdfa6769b631d565333e Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 20 May 2020 02:03:18 +0200 Subject: [PATCH 45/79] Quick view for Messages with Attachments --- retroshare-gui/src/gui/icons.qrc | 1 + .../src/gui/icons/mail/attach16.png | Bin 0 -> 628 bytes retroshare-gui/src/gui/msgs/MessageModel.cpp | 3 +- retroshare-gui/src/gui/msgs/MessageModel.h | 1 + .../src/gui/msgs/MessagesDialog.cpp | 31 +++++++++++++++--- 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 retroshare-gui/src/gui/icons/mail/attach16.png diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index a2d5b89d2..311530b03 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -311,6 +311,7 @@ icons/mail/foward.png icons/mail/reply.png icons/mail/reply-all.png + icons/mail/attach16.png icons/mail/attach24.png icons/mail/write-mail.png icons/textedit/align.png diff --git a/retroshare-gui/src/gui/icons/mail/attach16.png b/retroshare-gui/src/gui/icons/mail/attach16.png new file mode 100644 index 0000000000000000000000000000000000000000..3d983309a2887ed4ff5e345679ee209dc75b3677 GIT binary patch literal 628 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>ng*N+YGZWg4naKG0(XQL=3Ypv&_BQ#oBXP9SQ0qX(^0?}pW zIaiqGTxFUCH0LtQOrQxM#4_g!&=98CR~c6QX96mlb(LlAb)Y!I^y>_>Z?Mk3#xx6T z=4`M=pg7QQpl4RK{RdJ8B|(0{41zJyd@_&MZoDr(v9+&bhc^#v@P?gULCbS;eQe&m zww_Fdh=gjHCaiMdjm=?73K!_&nvMB;LC0t2I)TACP}%7IhI&K*42s&e4$;R6Rw zx2qh`SI|(=QBvU$7Z80cApTrHca(z9mH9uxZ*2giwyo}G@7ta=Mp zEjxE$!NO&o1-qwh>+9R5x2gW>*Dqfbbr>FWamH?6B()f5r)r67L`h0wNvc(HQ7VvP zFfuSQ&^0jCHM9&dGPW`>vNAB%HZZU08-nxG qO3D+9QW?t2%k?tzvWt@w3sUv+i_&MmvylQSV(@hJb6Mw<&;$So?%5*% literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/msgs/MessageModel.cpp b/retroshare-gui/src/gui/msgs/MessageModel.cpp index 74f4c2579..5ddef2283 100644 --- a/retroshare-gui/src/gui/msgs/MessageModel.cpp +++ b/retroshare-gui/src/gui/msgs/MessageModel.cpp @@ -342,7 +342,8 @@ bool RsMessageModel::passesFilter(const Rs::Msgs::MsgInfoSummary& fmpe,int colum || (std::find(fmpe.msgtags.begin(),fmpe.msgtags.end(),mQuickViewFilter) != fmpe.msgtags.end()) || (mQuickViewFilter==QUICK_VIEW_STARRED && (fmpe.msgflags & RS_MSG_STAR)) || (mQuickViewFilter==QUICK_VIEW_SYSTEM && (fmpe.msgflags & RS_MSG_SYSTEM)) - || (mQuickViewFilter==QUICK_VIEW_SPAM && (fmpe.msgflags & RS_MSG_SPAM)); + || (mQuickViewFilter==QUICK_VIEW_SPAM && (fmpe.msgflags & RS_MSG_SPAM)) + || (mQuickViewFilter==QUICK_VIEW_ATTACHMENT && (fmpe.count >= 1)); #ifdef DEBUG_MESSAGE_MODEL std::cerr << "Passes filter: type=" << mFilterType << " s=\"" << s.toStdString() << "MsgFlags=" << fmpe.msgflags << " msgtags=" ; foreach(uint32_t i,fmpe.msgtags) std::cerr << i << " " ; diff --git a/retroshare-gui/src/gui/msgs/MessageModel.h b/retroshare-gui/src/gui/msgs/MessageModel.h index 51912db8b..8a74ed4b3 100644 --- a/retroshare-gui/src/gui/msgs/MessageModel.h +++ b/retroshare-gui/src/gui/msgs/MessageModel.h @@ -76,6 +76,7 @@ public: QUICK_VIEW_STARRED = 0x06, QUICK_VIEW_SYSTEM = 0x07, QUICK_VIEW_SPAM = 0x08, + QUICK_VIEW_ATTACHMENT = 0x09, QUICK_VIEW_USER = 100 }; diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 68553e95d..cbe2172f2 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -63,6 +63,8 @@ #define IMAGE_NOTFICATION ":/icons/notification.png" #define IMAGE_SPAM_ON ":/images/junk_on.png" #define IMAGE_SPAM_OFF ":/images/junk_off.png" +#define IMAGE_ATTACHMENTS ":/icons/mail/attach24.png" +#define IMAGE_ATTACHMENT ":/icons/mail/attach16.png" #define IMAGE_INBOX ":/images/folder-inbox.png" #define IMAGE_OUTBOX ":/images/folder-outbox.png" @@ -82,6 +84,7 @@ #define QUICKVIEW_STATIC_ID_STARRED 1 #define QUICKVIEW_STATIC_ID_SYSTEM 2 #define QUICKVIEW_STATIC_ID_SPAM 3 +#define QUICKVIEW_STATIC_ID_ATTACHMENT 4 #define ROW_INBOX 0 #define ROW_OUTBOX 1 @@ -446,6 +449,16 @@ void MessagesDialog::fillQuickView() itemToSelect = item; } + item = new QListWidgetItem(tr("Attachment"), ui.quickViewWidget); + item->setIcon(QIcon(IMAGE_ATTACHMENT)); + item->setData(ROLE_QUICKVIEW_TYPE, QUICKVIEW_TYPE_STATIC); + item->setData(ROLE_QUICKVIEW_ID, QUICKVIEW_STATIC_ID_ATTACHMENT); + item->setData(ROLE_QUICKVIEW_TEXT, item->text()); // for updateMessageSummaryList + + if (selectedType == QUICKVIEW_TYPE_STATIC && selectedId == QUICKVIEW_STATIC_ID_ATTACHMENT) { + itemToSelect = item; + } + for (tag = tags.types.begin(); tag != tags.types.end(); ++tag) { text = TagDefs::name(tag->first, tag->second.first); @@ -835,23 +848,27 @@ void MessagesDialog::changeQuickView(int newrow) ui.tabWidget->setTabText(0, tr("Spam")); ui.tabWidget->setTabIcon(0, QIcon(IMAGE_SPAM_ON)); break; - case 0x03: f = RsMessageModel::QUICK_VIEW_IMPORTANT; + case 0x03: f = RsMessageModel::QUICK_VIEW_ATTACHMENT ; + ui.tabWidget->setTabText(0, tr("Attachment")); + ui.tabWidget->setTabIcon(0, QIcon(IMAGE_ATTACHMENT)); + break; + case 0x04: f = RsMessageModel::QUICK_VIEW_IMPORTANT; ui.tabWidget->setTabText(0, tr("Important")); ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); break; - case 0x04: f = RsMessageModel::QUICK_VIEW_WORK ; + case 0x05: f = RsMessageModel::QUICK_VIEW_WORK ; ui.tabWidget->setTabText(0, tr("Work")); ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); break; - case 0x05: f = RsMessageModel::QUICK_VIEW_PERSONAL ; + case 0x06: f = RsMessageModel::QUICK_VIEW_PERSONAL ; ui.tabWidget->setTabText(0, tr("Personal")); ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); break; - case 0x06: f = RsMessageModel::QUICK_VIEW_TODO ; + case 0x07: f = RsMessageModel::QUICK_VIEW_TODO ; ui.tabWidget->setTabText(0, tr("Todo")); ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); break; - case 0x07: f = RsMessageModel::QUICK_VIEW_LATER ; + case 0x08: f = RsMessageModel::QUICK_VIEW_LATER ; ui.tabWidget->setTabText(0, tr("Later")); ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); break; @@ -1160,6 +1177,7 @@ void MessagesDialog::updateMessageSummaryList() unsigned int starredCount = 0; unsigned int systemCount = 0; unsigned int spamCount = 0; + unsigned int attachmentCount = 0; /* calculating the new messages */ @@ -1354,6 +1372,9 @@ void MessagesDialog::updateMessageSummaryList() case QUICKVIEW_STATIC_ID_SPAM: text += " (" + QString::number(spamCount) + ")"; break; + case QUICKVIEW_STATIC_ID_ATTACHMENT: + text += " (" + QString::number(attachmentCount) + ")"; + break; } item->setText(text); From b3caf76c4bc82c53fd7ba6d117d9e9fde8593d26 Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 20 May 2020 23:38:21 +0200 Subject: [PATCH 46/79] Added to use the tag colors as icon --- retroshare-gui/src/gui/msgs/MessagesDialog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index cbe2172f2..ca67ff67a 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -461,10 +461,12 @@ void MessagesDialog::fillQuickView() for (tag = tags.types.begin(); tag != tags.types.end(); ++tag) { text = TagDefs::name(tag->first, tag->second.first); + QPixmap tagpixmap(18,18); + tagpixmap.fill(QColor(tag->second.second)); item = new QListWidgetItem (text, ui.quickViewWidget); item->setData(Qt::ForegroundRole, QColor(tag->second.second)); - item->setIcon(QIcon(":/images/foldermail.png")); + item->setIcon(tagpixmap); item->setData(ROLE_QUICKVIEW_TYPE, QUICKVIEW_TYPE_TAG); item->setData(ROLE_QUICKVIEW_ID, tag->first); item->setData(ROLE_QUICKVIEW_TEXT, text); // for updateMessageSummaryList From ba8d2268eab9aae73dd7ef59f3362ed24431442c Mon Sep 17 00:00:00 2001 From: Phenom Date: Thu, 21 May 2020 12:55:38 +0200 Subject: [PATCH 47/79] Fix Message QuickView Selection for user tags --- .../src/gui/msgs/MessagesDialog.cpp | 119 ++++++++---------- 1 file changed, 51 insertions(+), 68 deletions(-) diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index ca67ff67a..508e08e7e 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -833,54 +833,35 @@ void MessagesDialog::changeQuickView(int newrow) changeBox(-1); listMode = LIST_QUICKVIEW; - RsMessageModel::QuickViewFilter f = RsMessageModel::QUICK_VIEW_ALL ; + RsMessageModel::QuickViewFilter f = RsMessageModel::QUICK_VIEW_ALL ; + QListWidgetItem* item = ui.quickViewWidget->item(newrow); - if(newrow >= 0) // -1 means that nothing is selected - switch(newrow) - { - case 0x00: f = RsMessageModel::QUICK_VIEW_STARRED ; - ui.tabWidget->setTabText(0, tr("Starred")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_STAR_ON)); - break; - case 0x01: f = RsMessageModel::QUICK_VIEW_SYSTEM ; - ui.tabWidget->setTabText(0, tr("System")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_SYSTEM)); - break; - case 0x02: f = RsMessageModel::QUICK_VIEW_SPAM ; - ui.tabWidget->setTabText(0, tr("Spam")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_SPAM_ON)); - break; - case 0x03: f = RsMessageModel::QUICK_VIEW_ATTACHMENT ; - ui.tabWidget->setTabText(0, tr("Attachment")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_ATTACHMENT)); - break; - case 0x04: f = RsMessageModel::QUICK_VIEW_IMPORTANT; - ui.tabWidget->setTabText(0, tr("Important")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); - break; - case 0x05: f = RsMessageModel::QUICK_VIEW_WORK ; - ui.tabWidget->setTabText(0, tr("Work")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); - break; - case 0x06: f = RsMessageModel::QUICK_VIEW_PERSONAL ; - ui.tabWidget->setTabText(0, tr("Personal")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); - break; - case 0x07: f = RsMessageModel::QUICK_VIEW_TODO ; - ui.tabWidget->setTabText(0, tr("Todo")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); - break; - case 0x08: f = RsMessageModel::QUICK_VIEW_LATER ; - ui.tabWidget->setTabText(0, tr("Later")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_FOLDER)); - break; - default: - f = RsMessageModel::QuickViewFilter( (int)RsMessageModel::QUICK_VIEW_USER + newrow - 0x07); + if(item ) + { + switch (item->data(ROLE_QUICKVIEW_TYPE).toInt()) { + case QUICKVIEW_TYPE_TAG: + f = RsMessageModel::QuickViewFilter( item->data(ROLE_QUICKVIEW_ID).toUInt()); + break; + case QUICKVIEW_TYPE_STATIC: + switch (item->data(ROLE_QUICKVIEW_ID).toInt()) { + case QUICKVIEW_STATIC_ID_STARRED: f = RsMessageModel::QUICK_VIEW_STARRED; + break; + case QUICKVIEW_STATIC_ID_SYSTEM: f = RsMessageModel::QUICK_VIEW_SYSTEM; + break; + case QUICKVIEW_STATIC_ID_SPAM: f = RsMessageModel::QUICK_VIEW_SPAM; + break; + case QUICKVIEW_STATIC_ID_ATTACHMENT: f = RsMessageModel::QUICK_VIEW_ATTACHMENT; + } } - mMessageModel->setQuickViewFilter(f); + + ui.tabWidget->setTabText(0, item->data(ROLE_QUICKVIEW_TEXT).toString()); + ui.tabWidget->setTabIcon(0, item->icon()); + } + + mMessageModel->setQuickViewFilter(f); mMessageProxyModel->setFilterRegExp(QRegExp(RsMessageModel::FilterString)); // this triggers the update of the proxy model - insertMsgTxtAndFiles(ui.messageTreeWidget->currentIndex()); + insertMsgTxtAndFiles(ui.messageTreeWidget->currentIndex()); } void MessagesDialog::messagesTagsChanged() @@ -903,32 +884,34 @@ void MessagesDialog::currentChanged(const QModelIndex& new_proxy_index,const QMo // click in messageTreeWidget void MessagesDialog::clicked(const QModelIndex& proxy_index) { - if(!proxy_index.isValid()) - return; + if(!proxy_index.isValid()) + return; - QModelIndex real_index = mMessageProxyModel->mapToSource(proxy_index); + QModelIndex real_index = mMessageProxyModel->mapToSource(proxy_index); - switch (proxy_index.column()) - { - case RsMessageModel::COLUMN_THREAD_READ: - { - mMessageModel->setMsgReadStatus(real_index, !isMessageRead(proxy_index)); - //Already updated by currentChanged - //insertMsgTxtAndFiles(proxy_index); - updateMessageSummaryList(); - return; - } - case RsMessageModel::COLUMN_THREAD_STAR: - { - mMessageModel->setMsgStar(real_index, !hasMessageStar(proxy_index)); - return; - } - case RsMessageModel::COLUMN_THREAD_SPAM: - { - mMessageModel->setMsgJunk(real_index, !hasMessageSpam(proxy_index)); - return; - } - } + switch (proxy_index.column()) + { + case RsMessageModel::COLUMN_THREAD_READ: + { + mMessageModel->setMsgReadStatus(real_index, !isMessageRead(proxy_index)); + //Already updated by currentChanged + //insertMsgTxtAndFiles(proxy_index); + updateMessageSummaryList(); + return; + } + case RsMessageModel::COLUMN_THREAD_STAR: + { + mMessageModel->setMsgStar(real_index, !hasMessageStar(proxy_index)); + updateMessageSummaryList(); + return; + } + case RsMessageModel::COLUMN_THREAD_SPAM: + { + mMessageModel->setMsgJunk(real_index, !hasMessageSpam(proxy_index)); + updateMessageSummaryList(); + return; + } + } // show current message directly //Already updated by currentChanged From 60615e45328a99ac7a76d36c9945faf304ea966a Mon Sep 17 00:00:00 2001 From: Phenom Date: Thu, 21 May 2020 15:30:02 +0200 Subject: [PATCH 48/79] Add PlaceHolder in Message Tree. And fix some mistakes. --- retroshare-gui/src/gui/msgs/MessageWidget.cpp | 2 + .../src/gui/msgs/MessagesDialog.cpp | 145 +++++++++++------- retroshare-gui/src/gui/msgs/MessagesDialog.ui | 8 +- 3 files changed, 99 insertions(+), 56 deletions(-) diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.cpp b/retroshare-gui/src/gui/msgs/MessageWidget.cpp index 001866927..3c085c3c8 100644 --- a/retroshare-gui/src/gui/msgs/MessageWidget.cpp +++ b/retroshare-gui/src/gui/msgs/MessageWidget.cpp @@ -511,6 +511,7 @@ void MessageWidget::fill(const std::string &msgId) ui.inviteFrame->hide(); ui.expandFilesButton->setChecked(false); + ui.downloadButton->setEnabled(false); togglefileview(true); ui.replyButton->setEnabled(false); @@ -566,6 +567,7 @@ void MessageWidget::fill(const std::string &msgId) /* add the items in! */ ui.msgList->insertTopLevelItems(0, items); ui.expandFilesButton->setChecked(expandFiles && (items.count()>0) ); + ui.downloadButton->setEnabled(items.count()>0); togglefileview(true); /* iterate through the sources */ diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 508e08e7e..bf9716850 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -487,15 +487,22 @@ void MessagesDialog::fillQuickView() int MessagesDialog::getSelectedMessages(QList& mid) { - //To check if the selection has more than one row. + //To check if the selection has more than one row. - mid.clear(); - QModelIndexList qmil = ui.messageTreeWidget->selectionModel()->selectedRows(); + mid.clear(); + QModelIndexList qmil = ui.messageTreeWidget->selectionModel()->selectedRows(); - foreach(const QModelIndex& m, qmil) + foreach(const QModelIndex& m, qmil) mid.push_back(m.sibling(m.row(),RsMessageModel::COLUMN_THREAD_MSGID).data(RsMessageModel::MsgIdRole).toString()) ; - return mid.size(); + if (mid.isEmpty()) + { + const QModelIndex& m = ui.messageTreeWidget->currentIndex(); + if (m.isValid()) + mid.push_back(m.sibling(m.row(),RsMessageModel::COLUMN_THREAD_MSGID).data(RsMessageModel::MsgIdRole).toString()) ; + } + + return mid.size(); } int MessagesDialog::getSelectedMsgCount (QList *items, QList *itemsRead, QList *itemsUnread, QList *itemsStar, QList *itemsJunk) @@ -786,65 +793,78 @@ void MessagesDialog::editmessage() void MessagesDialog::changeBox(int box_row) { - if (inChange) { - // already in change method - return; - } + if (inChange) { + // already in change method + return; + } - inChange = true; + inChange = true; - ui.quickViewWidget->setCurrentItem(NULL); - changeQuickView(-1); - listMode = LIST_BOX; + QListWidgetItem* item = ui.listWidget->item(box_row); - switch(box_row) - { - case 0: mMessageModel->setCurrentBox(RsMessageModel::BOX_INBOX ); - ui.tabWidget->setTabText(0, tr("Inbox")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_INBOX)); - break; - case 1: mMessageModel->setCurrentBox(RsMessageModel::BOX_OUTBOX); - ui.tabWidget->setTabText(0, tr("Outbox")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_OUTBOX)); - break; - case 2: mMessageModel->setCurrentBox(RsMessageModel::BOX_DRAFTS); - ui.tabWidget->setTabText(0, tr("Drafts")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_DRAFTS)); - break; - case 3: mMessageModel->setCurrentBox(RsMessageModel::BOX_SENT ); - ui.tabWidget->setTabText(0, tr("Sent")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_SENT)); - break; - case 4: mMessageModel->setCurrentBox(RsMessageModel::BOX_TRASH ); - ui.tabWidget->setTabText(0, tr("Trash")); - ui.tabWidget->setTabIcon(0, QIcon(IMAGE_TRASH)); - break; - default: - mMessageModel->setCurrentBox(RsMessageModel::BOX_NONE); break; - } - inChange = false; - insertMsgTxtAndFiles(ui.messageTreeWidget->currentIndex()); + if (item) + { + ui.quickViewWidget->setCurrentItem(NULL); + changeQuickView(-1); + + listMode = LIST_BOX; + + QString placeholderText = tr("No message available in your %1.").arg(item->text()); + switch(box_row) + { + case ROW_INBOX: mMessageModel->setCurrentBox(RsMessageModel::BOX_INBOX ); + break; + case ROW_OUTBOX: mMessageModel->setCurrentBox(RsMessageModel::BOX_OUTBOX); + break; + case ROW_DRAFTBOX: mMessageModel->setCurrentBox(RsMessageModel::BOX_DRAFTS); + break; + case ROW_SENTBOX: mMessageModel->setCurrentBox(RsMessageModel::BOX_SENT ); + break; + case ROW_TRASHBOX: mMessageModel->setCurrentBox(RsMessageModel::BOX_TRASH ); + break; + default: + mMessageModel->setCurrentBox(RsMessageModel::BOX_NONE); + } + + insertMsgTxtAndFiles(ui.messageTreeWidget->currentIndex()); + ui.messageTreeWidget->setPlaceholderText(placeholderText); + } + else + { + mMessageModel->setCurrentBox(RsMessageModel::BOX_NONE); + } + inChange = false; } void MessagesDialog::changeQuickView(int newrow) { - ui.listWidget->setCurrentItem(NULL); - changeBox(-1); - listMode = LIST_QUICKVIEW; - RsMessageModel::QuickViewFilter f = RsMessageModel::QUICK_VIEW_ALL ; QListWidgetItem* item = ui.quickViewWidget->item(newrow); if(item ) { + ui.listWidget->setCurrentItem(NULL); + changeBox(-1); + + listMode = LIST_QUICKVIEW; + + QString placeholderText; switch (item->data(ROLE_QUICKVIEW_TYPE).toInt()) { case QUICKVIEW_TYPE_TAG: + { + placeholderText = tr("No message using %1 tag available.").arg(item->data(ROLE_QUICKVIEW_TEXT).toString()); f = RsMessageModel::QuickViewFilter( item->data(ROLE_QUICKVIEW_ID).toUInt()); + } break; case QUICKVIEW_TYPE_STATIC: + { + placeholderText = tr("No %1 message available.").arg(item->data(ROLE_QUICKVIEW_TEXT).toString()); switch (item->data(ROLE_QUICKVIEW_ID).toInt()) { - case QUICKVIEW_STATIC_ID_STARRED: f = RsMessageModel::QUICK_VIEW_STARRED; + case QUICKVIEW_STATIC_ID_STARRED:{ + f = RsMessageModel::QUICK_VIEW_STARRED; + placeholderText = tr("No starred message available. Stars let you give messages a special status to make them easier to find. To star a message, click on the light gray star beside any message."); + } break; case QUICKVIEW_STATIC_ID_SYSTEM: f = RsMessageModel::QUICK_VIEW_SYSTEM; break; @@ -852,16 +872,15 @@ void MessagesDialog::changeQuickView(int newrow) break; case QUICKVIEW_STATIC_ID_ATTACHMENT: f = RsMessageModel::QUICK_VIEW_ATTACHMENT; } + } } - ui.tabWidget->setTabText(0, item->data(ROLE_QUICKVIEW_TEXT).toString()); - ui.tabWidget->setTabIcon(0, item->icon()); + insertMsgTxtAndFiles(ui.messageTreeWidget->currentIndex()); + ui.messageTreeWidget->setPlaceholderText(placeholderText); } mMessageModel->setQuickViewFilter(f); mMessageProxyModel->setFilterRegExp(QRegExp(RsMessageModel::FilterString)); // this triggers the update of the proxy model - - insertMsgTxtAndFiles(ui.messageTreeWidget->currentIndex()); } void MessagesDialog::messagesTagsChanged() @@ -1037,9 +1056,8 @@ void MessagesDialog::insertMsgTxtAndFiles(const QModelIndex& proxy_index) else if ((msgInfo.msgflags & RS_MSG_UNREAD_BY_USER) && bSetToReadOnActive) // set to read mMessageModel->setMsgReadStatus(real_index, true); - updateInterface(); + msgWidget->fill(mid); updateMessageSummaryList(); - msgWidget->fill(mid); } bool MessagesDialog::getCurrentMsg(std::string &cid, std::string &mid) @@ -1367,6 +1385,7 @@ void MessagesDialog::updateMessageSummaryList() break; } } + updateInterface(); } void MessagesDialog::tagAboutToShow() @@ -1500,12 +1519,12 @@ void MessagesDialog::updateInterface() int tab = ui.tabWidget->currentIndex(); if (tab == 0) - { - QList msgs; + { + QList msgs; count = getSelectedMessages(msgs); } - else - { + else + { MessageWidget *msg = dynamic_cast(ui.tabWidget->widget(tab)); if (msg && msg->msgId().empty() == false) count = 1; @@ -1515,4 +1534,20 @@ void MessagesDialog::updateInterface() ui.actionPrintPreview->setEnabled(count == 1); ui.actionSaveAs->setEnabled(count == 1); ui.tagButton->setEnabled(count >= 1); + + if (ui.listWidget->currentItem()) + { + ui.tabWidget->setTabText(0, ui.listWidget->currentItem()->text()); + ui.tabWidget->setTabIcon(0, ui.listWidget->currentItem()->icon()); + } + else if (ui.quickViewWidget->currentItem()) + { + ui.tabWidget->setTabText(0, ui.quickViewWidget->currentItem()->text()); + ui.tabWidget->setTabIcon(0, ui.quickViewWidget->currentItem()->icon()); + } + else + { + ui.tabWidget->setTabText(0, tr("No Box selected.")); + ui.tabWidget->setTabIcon(0, QIcon(":/icons/warning_yellow_128.png")); + } } diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.ui b/retroshare-gui/src/gui/msgs/MessagesDialog.ui index 2c5568bcc..0f4ef4b79 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.ui +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.ui @@ -367,7 +367,7 @@ Qt::Vertical - + Qt::CustomContextMenu @@ -462,6 +462,12 @@
gui/common/RSTabWidget.h
1 + + RSTreeView + QTreeView +
gui/common/RSTreeView.h
+ 1 +
listWidget From 0a9f7882a501027bfa25c1aa811ecca9327bd27f Mon Sep 17 00:00:00 2001 From: Phenom Date: Thu, 21 May 2020 16:32:25 +0200 Subject: [PATCH 49/79] Fix Indent in Chat Message --- retroshare-gui/src/util/HandleRichText.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index d8870eb50..466e540de 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -31,6 +31,8 @@ #include "gui/RetroShareLink.h" #include "util/ObjectPainter.h" #include "util/imageutil.h" + +#include "util/rsdebug.h" #include "util/rstime.h" #ifdef USE_CMARK @@ -40,6 +42,8 @@ #include +//#define DEBUG_SAVESPACE 1 + /** * The type of embedding we'd like to do */ @@ -554,18 +558,24 @@ static QString saveSpace(const QString text) if(cursChar==QLatin1Char('>')) { if(!echapChar && i>0) {outBrackets=true; firstOutBracket=true;} } else if(cursChar==QLatin1Char('\t')) { - if(outBrackets && firstOutBracket && (keyName!="style")) savedSpaceText.replace(i, 1, "  "); + if(outBrackets && firstOutBracket && (keyName!="style")) { savedSpaceText.replace(i, 1, "  "); i+= 11; } } else if(cursChar==QLatin1Char(' ')) { - if(outBrackets && firstOutBracket && (keyName!="style")) savedSpaceText.replace(i, 1, " "); + if(outBrackets && firstOutBracket && (keyName!="style")) { savedSpaceText.replace(i, 1, " "); i+= 5; } } else if(cursChar==QChar(0xA0)) { - if(outBrackets && firstOutBracket && (keyName!="style")) savedSpaceText.replace(i, 1, " "); + if(outBrackets && firstOutBracket && (keyName!="style")) { savedSpaceText.replace(i, 1, " "); i+= 5; } } else if(cursChar==QLatin1Char('<')) { if(!echapChar) {outBrackets=false; getKeyName=true; keyName.clear();} } else firstOutBracket=false; echapChar=(cursChar==QLatin1Char('\\')); } - +#ifdef DEBUG_SAVESPACE + RsDbg() << __PRETTY_FUNCTION__ << "Text to save:" << std::endl + << text.toStdString() << std::endl + << "---------------------- Saved Text:" << std::endl + << savedSpaceText.toStdString() << std::endl; +#endif + return savedSpaceText; } From 9b5ab4bbd98563ba1d33fec04d6c0186e5d6bd9c Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 21 May 2020 17:23:56 +0200 Subject: [PATCH 50/79] cosmetic changes --- retroshare-gui/src/gui/msgs/MessagesDialog.cpp | 2 +- retroshare-gui/src/gui/msgs/MessagesDialog.ui | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index bf9716850..73cb1e887 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -461,7 +461,7 @@ void MessagesDialog::fillQuickView() for (tag = tags.types.begin(); tag != tags.types.end(); ++tag) { text = TagDefs::name(tag->first, tag->second.first); - QPixmap tagpixmap(18,18); + QPixmap tagpixmap(16,16); tagpixmap.fill(QColor(tag->second.second)); item = new QListWidgetItem (text, ui.quickViewWidget); diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.ui b/retroshare-gui/src/gui/msgs/MessagesDialog.ui index 0f4ef4b79..183396a2c 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.ui +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.ui @@ -205,6 +205,9 @@ QFrame::Raised + + 3 + 3 From 319ebd66f69f1fc065833443e014aef23dbaf6c4 Mon Sep 17 00:00:00 2001 From: Phenom Date: Thu, 21 May 2020 19:07:03 +0200 Subject: [PATCH 51/79] Fix GxsForumModel::setMsgReadStatus dataChanged call --- .../src/gui/gxsforums/GxsForumModel.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index e949a8c30..f72649dfc 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1225,7 +1225,7 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo if(!i.isValid()) return ; - // no need to call preMods()/postMods() here because we'renot changing the model + // no need to call preMods()/postMods() here because we'renot changing the model void *ref = i.internalPointer(); uint32_t entry = 0; @@ -1233,18 +1233,10 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) return ; - bool has_unread_below,has_read_below; - recursSetMsgReadStatus(entry,read_status,with_children) ; + bool has_unread_below, has_read_below; + recursSetMsgReadStatus(entry,read_status,with_children) ; recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below); - // Normally we should only update the parents up to the top of the tree, but it's complicated and the update here doesn't really cost, - // so we blindly update the whole widget. - - if(mTreeMode == TREE_MODE_FLAT) - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mPosts.size(),COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - else - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mPosts[0].mChildren.size(),COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); - } void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children) @@ -1270,6 +1262,9 @@ void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status, } else rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read_status); + + QModelIndex itemIndex = createIndex(i - 1, 0, &mPosts[i]); + emit dataChanged(itemIndex, itemIndex); } if(!with_children) From d4010dd8d9ae22341c951d28efc7a3468e3e2ef6 Mon Sep 17 00:00:00 2001 From: Phenom Date: Thu, 21 May 2020 19:55:29 +0200 Subject: [PATCH 52/79] Add Message set HideTabBarWithOneTab --- retroshare-gui/src/gui/msgs/MessagesDialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index bf9716850..242092b80 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -242,8 +242,9 @@ MessagesDialog::MessagesDialog(QWidget *parent) //ui.messageTreeWidget->installEventFilter(this); - // remove close button of the the first tab - ui.tabWidget->hideCloseButton(0); + // remove close button of the the first tab + ui.tabWidget->hideCloseButton(0); + ui.tabWidget->setHideTabBarWithOneTab(true); int S = QFontMetricsF(font()).height(); QString help_str = tr( From 180a43150b4fdb458b9165a81f7fedfac5eccffa Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 21 May 2020 21:58:23 +0200 Subject: [PATCH 53/79] Fixing Group Tree item text color --- retroshare-gui/src/gui/common/GroupTreeWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp index a867c95d9..fa12ebf54 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp @@ -511,7 +511,7 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< /* Set color */ if (itemInfo.publishKey) { item->setData(COLUMN_DATA, ROLE_COLOR, GROUPTREEWIDGET_COLOR_PRIVATEKEY); - item->setData(COLUMN_NAME, Qt::BackgroundRole, QBrush(textColorPrivateKey())); + item->setData(COLUMN_NAME, Qt::ForegroundRole, QBrush(textColorPrivateKey())); } else { // Let StyleSheet color item->setData(COLUMN_DATA, ROLE_COLOR, GROUPTREEWIDGET_COLOR_STANDARD); From 82690561b6e22d288426867091a7531843c396aa Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 21 May 2020 22:45:49 +0200 Subject: [PATCH 54/79] fixed compilaiton of photoshare due to changes in GxsChange class --- libretroshare/src/services/p3photoservice.cc | 9 +++------ retroshare-gui/src/gui/feeds/GxsCircleItem.cpp | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libretroshare/src/services/p3photoservice.cc b/libretroshare/src/services/p3photoservice.cc index 014c0d319..1547e5a7d 100644 --- a/libretroshare/src/services/p3photoservice.cc +++ b/libretroshare/src/services/p3photoservice.cc @@ -117,11 +117,7 @@ void p3PhotoService::groupsChanged(std::list& grpIds) while(!mGroupChange.empty()) { RsGxsGroupChange* gc = mGroupChange.back(); - std::list& gList = gc->mGrpIdList; - std::list::iterator lit = gList.begin(); - for(; lit != gList.end(); ++lit) { - grpIds.push_back(*lit); - } + grpIds.push_back(gc->mGroupId); mGroupChange.pop_back(); delete gc; @@ -136,7 +132,8 @@ void p3PhotoService::msgsChanged(GxsMsgIdResult& msgs) while(!mMsgChange.empty()) { RsGxsMsgChange* mc = mMsgChange.back(); - msgs = mc->msgChangeMap; + + msgs[mc->mGroupId].insert(mc->mMsgId); mMsgChange.pop_back(); delete mc; } diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp index 8c355de35..18997a084 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp @@ -129,7 +129,7 @@ void GxsCircleItem::setup() { if(circleDetails.mAmIAdmin) { - ui->titleLabel->setText(idName + tr(" which you invited, has join this circle you're administrating.")); + ui->titleLabel->setText(idName + tr(" which you invited, has joined this circle you're administrating.")); ui->inviteeButton->setHidden(false); ui->inviteeButton->setText(tr("Revoke membership")); ui->inviteeButton->setToolTip(tr("Revoke membership for that identity")); @@ -137,7 +137,7 @@ void GxsCircleItem::setup() else { ui->inviteeButton->setHidden(true); - ui->titleLabel->setText(idName + tr(" has join this circle.")); + ui->titleLabel->setText(idName + tr(" has joined this circle.")); } ui->iconLabel->setPixmap(pixmap); From d872dd56ff23041fb677d7ad53cb0b46fa6a995f Mon Sep 17 00:00:00 2001 From: defnax Date: Fri, 22 May 2020 01:28:07 +0200 Subject: [PATCH 55/79] Moved Fonts to bottom & Chat notify to top --- retroshare-gui/src/gui/chat/ChatWidget.cpp | 5 ++-- retroshare-gui/src/gui/chat/ChatWidget.ui | 31 ++++++++++++++++++--- retroshare-gui/src/gui/icons/png/font.png | Bin 5524 -> 2366 bytes 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 2cf0e1edf..6c36a392b 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -115,6 +115,7 @@ ChatWidget::ChatWidget(QWidget *parent) //ui->sendButton->setFixedHeight(iconHeight); ui->sendButton->setIconSize(iconSize); ui->typingLabel->setMaximumHeight(QFontMetricsF(font()).height()*1.2); + ui->fontcolorButton->setIconSize(iconSize); //Initialize search iCharToStartSearch=Settings->getChatSearchCharToStartSearch(); @@ -189,7 +190,7 @@ ChatWidget::ChatWidget(QWidget *parent) ui->hashBox->setDropWidget(this); ui->hashBox->setAutoHide(true); - QMenu *fontmenu = new QMenu(tr("Set text font & color")); + QMenu *fontmenu = new QMenu(); fontmenu->addAction(ui->actionChooseFont); fontmenu->addAction(ui->actionChooseColor); fontmenu->addAction(ui->actionResetFont); @@ -198,10 +199,10 @@ ChatWidget::ChatWidget(QWidget *parent) #ifdef USE_CMARK fontmenu->addAction(ui->actionSend_as_CommonMark); #endif + ui->fontcolorButton->setMenu(fontmenu); QMenu *menu = new QMenu(); menu->addAction(ui->actionMessageHistory); - menu->addMenu(fontmenu); menu->addSeparator(); menu->addAction(ui->actionSaveChatHistory); menu->addAction(ui->actionClearChatHistory); diff --git a/retroshare-gui/src/gui/chat/ChatWidget.ui b/retroshare-gui/src/gui/chat/ChatWidget.ui index 4a191f80c..f4d070c11 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.ui +++ b/retroshare-gui/src/gui/chat/ChatWidget.ui @@ -455,13 +455,13 @@ border-image: url(:/images/closepressed.png)
- - - Qt::NoFocus + + + Set font & color - :/icons/png/chat-bubble-notify.png:/icons/png/chat-bubble-notify.png + :/icons/png/font.png:/icons/png/font.png @@ -469,6 +469,9 @@ border-image: url(:/images/closepressed.png) 28 + + QToolButton::InstantPopup + true @@ -769,6 +772,26 @@ border-image: url(:/images/closepressed.png) + + + + Qt::NoFocus + + + + :/icons/png/chat-bubble-notify.png:/icons/png/chat-bubble-notify.png + + + + 28 + 28 + + + + true + + + diff --git a/retroshare-gui/src/gui/icons/png/font.png b/retroshare-gui/src/gui/icons/png/font.png index 3c71acc5f8a8a5c5a53338244285eb03a86eeefe..f9b3dd48ce0465f7670d9dd861abb6cffec84076 100644 GIT binary patch literal 2366 zcmZ`(c|4SB8@^{X*&

h_uNPk)|?+(L`h|3K>c1d}Lx2PBkOPRv9gvGBcJ)meWFx z3ekkpdLm{V9HI0nOUc$r4&U<*-yh!}-|zRn@AKUEb6wYcU-!K8CcExrD#>ff1Avml zc7{7zdDu-Mpyyckh3{w~9-=$b0ZLO9rUFPP)(zb5?hFvK65)OUn8ffO0U}KS`dI+f zD*%hwqDr?d0C=velcznVA(UX3KmvkRyg*98_EN}_pbfgzLI+Fru)T{NJ`gCIY{{ zfsB{fRg9WJ9b(D|Pm)zf_VL0N$eL4ttT%AE4Qp5+!DH1Wkli&aPRwi}$(*7PjcZl} zcn>j5G18pPNa4z?DJf)2ARQ}&Dk5tLkGYUtGP8(+hAgw6{hE{^W1+febeL0=pYx8I zK_On2M0j#WD;hGIIg%v_Tjw01637%*2!YWU=af-M!X`f}i0KezouJX79?=~u^)eO28F4c%0qS4TO&#PAd5=k=^rR-*wT|46cLjQqbyx+28%6<3V*cdlVF340R$rHS`|DJEv z5q47j<+Pr5UBdB$lrP`u>wnAQ?|e%fB6~Ze8I)gNtT@)rX1%JeO^ga^{-$D9oSo`C zvd8h_-SMLVe;6f2+nMK_-y6RF^~2`YL#?!`w5rPIHEo6UlHRWqFRLTI(0y;U=~VRn^-o}#^q}-XU-+i*-lt7n zuBGn`95wQ}YxG78{W#M>QxQ-YQlUp+Ut)eZ`~0D;jj@gW6N=-n6T4aGt>6h|Ey;r( z@2No+FQ%)Hr2Fp*fDl#BQ91DRTMRx#i}N&zqB>cuPG3yS*;@-&^e7F}3zsYNR-Jyg z63PcC1Xi-{om=xjq9!L+rKe@kB#W>O!GrfP;T??WQ_id>0#=bmioX+Wj zK=LE4WlP&t15(x~f_Gh@-+MAoC)Gp|JnQDE`QDnKtP^$7R3*dpqPV*h)&iRNK(Dz$ zAFF=@+tuq6H#6T=$>sLgz%>h7;iDm%TE)weCFKleSq1Ljx|b`m@*1PNldAZaT$NT8 z^e(exvPYwF8oH@1U5N@!J$n0ikDux{T7}}3^DeU|3yeq_FGk)fSlULt*o51yo9G_h zP{Q{L$6q7F`CEh(TH_V_MiVU_tnISdN-Pn~XDL;3Lu+up4R&oHjU8wWdrDJ{RXKa~ zdl=(h*oan9{5H!7TnPPM*tk|~ZYIGRO-IHtAT0}@-azS>~@k%y-r|@a5e?} zK*HEi^3FnnsCT%)qd)S5fW%9CSR0wpko`w7UaWOw%Om$bv7^&@0ryQbyN&ed=g(&; zR3D}81(gGLSfAu$s5Ql8UX8K+A%;(@*xe@g3|FLczrT__M6RtV!m|}R(+qsIqqJ{y zy5a6C7(3oy^|mTi{G;t#qQwc{{a>%fOKzI-wKYrZ!@DcO{4qyivhlL*!e%_*m OK;U4%lX1(Ib^1SjD;yL6 delta 5514 zcmV;56?N*q5|k^D87&3?006^2Vaosj00eVFNmK|32nc)#WQYI&010qNS#tmY79{`x z79{~mQY7$`4GAZI6%k29K~#90?VWp+9A%Zjf48c-ryui5CYi~bJP4SXgrH)0BnmMI zL3R;2fCdo^kYvFXAGor*9u4H|3ajWI_9)~fZU7|#QIu6c1bIY(gs?E_2_%pNGnu?5 zkD1B5daC-{KYE7DOjpfJcUM*SK>yCkIhlHV_jZ4`zxwWf{qA>5c)y{Pa9`~d-IQvD zHbv8ztQ3=g(F!UADu56W1ftz{wE}UVL&0Hz!@xli_9PPQ7EN|qnz@a|vvwh(a`VBw zL2|7?*4*>fcwIN=iZEBf$AFnYiAT~}Kx#$QCIuTU(KmAahZ;PRovuy_|lqKu9a~jFAcz0 z8JnjxxfRsKf zZ>ZjyD+O|604p~~3_ZL;DQ*Ugoam50bcs?wF^`um=Nl8-{TA-K0T`?5&R3#V0#p5# zo#(uNEwId7QuBR$lOH@U+L1+2Cb?O$iv8Et+D^u+*zt7}g) z(S9jVCJ97>#hN;uC3D0{vhxXSKBSn!>g8QewrI+A9Slh_YB~k zZIg8)@h9M9*V-(Qf(SdzF6{ztoUz-L_S|TMpYIrLSn(GWoa#z@1qS0C%U~XhYxZY< z+fepy-~&5KH7ou^q4RxZnr6zA-1k~}whd)x02^XKy*>U&;hFD0f;vs_3O>r+JBqSt zCvyW>t~9-g2Y^pyqdOCnciQ(C4@_jW3m6p{Pqmc z*Tk+u@nEJx3%HH~K5H$hc`V%<(>8#A;Og4bEVRD?k#z4Z;3s( z+_x)aqCG&N^Yf7kJ)u3!%FTgvZc57l^scra3d~ARFLxOqHMsN4Dt>X^c>eJuuQmV; zQxsm^~Z4#t24Lvn6~MHt)N+Aq zPe~1YO)UxX@v(&|NpF-;t!a@VY0fKq~Ro9ilNz{Qh_866rp+{p!1Ffps(I`Danc(IcF%(_;bfbnOYL`L7U-*I>%TY`?%9tM*~oQqQ2*iLg`T% zHn?bF@u1fUaP{=UC}4+D@?EEMwgzCVsyjblwrDS!R!Tri_4E(6##4@6J-w_D6R<IdlkflZ&PMh$w?inxx;N@m&KF_=&M3I9{~AFb z1JL!*LST%qS~=k4`>%VW9zqd_l=0L%hp2B(-7Qs!2{Y|Oezjg zY-kh*wDLz^Hx)w+9Mt8Xi9ZqedL%`Mip1q#GzMx9>Z!oPvt@9 z16(z&%+~i`_eMR0i<6xX5GkeZ;NRKQaEypNmxGrgP@TMprNEw)={kK&foDi~Rm zaV9oS>)O!njCk#OH z!vF^I{Z$|cM!#o!ILbp?8|W}o>nFG!6PQ0XI`~EDwmB}!#!IGf$DAs3znt%0KlY>n z-1F9WrI_x2llTD{$oD5~lLQ(n=4hwM@3$XFIpuatU`Mkzg}`-zZ=P1c`UMjS8{S)i z5~^8QHx|0*0J>q#^IYl>7}WQ#9G!ZT2!x7R_eMQeRFCa*swXDkR?_I2y2D&NCcuKp z74IEuXz5_*(Khxpcd);;gDy+a+-V{}Ns&Qu&|qqRd4!WkMmTxoz$3_|lS^24-gvHf zI`xs}Ho7FvvEbJRfS}IFhr+dk`u>{3vo~DKQ}67jp{0XyC4C-`|Pun81TuJ&p+^lJkt(gU$Tk{^qngAK*Z1ClAFMxZuH;nX~pq>Kc#R zUU%o5D#nDpEugAI%>mF@t~7GI*#n@WNN1tVy8rrE18o)%9Au^(j&lF&sY9o$c>-bg zCV^Y_HF4J37x~l9)L2E>5WYIA!saelnTb+=qA{UvDlmA)g~wbyy^P>ce19jxCDb(@ zXH!G!aDUD8a(7m@0wEYtl{Cg+C^;&Xj7%P@7zd*!K;XUXd$f?Y2ppj+)`EoS|Vi{M-8ePUr>%L*B;(iXt$7 za!j&Q%SJ)8EO{(Y1V$h^PZ3G})AaZBB2ofnqoMMo{!WCVzQqK8Tp?Tn<&_+do4jc=Aw0Rv+XXERHAU-wsbbDB zG~x5pQkNi3tox@i@e&O}(czUR5Q;)5!oHT&AX8bu+gX5ulQf{xQz?UR@x)@PY+Rl} zeSasyB|P=cAsSkSQJz4woYpQg^|03imSVJ~lCM(D8Q0h(eGbX@cOn?V(sb{CV*+jx zC_>rI`4g!*k8YwwDhz>jiXz=M=fAATp!wEpcBEC?9_@((w1^yv@&#|IAe5}N6w$A7)`QLbdDmff9&P1NTO5_fGyLmkP36q-zCRLwJ9Ao;%i=i1p5vdR+(YQp{JjdvV19rEd8wWCfnaAbTV{>8v8qn&u z)B$~em$8(}Iwo-Q%#lpD3CkXjn=E>C3yU7zl2zyDkXB8Bx2Y%naPs}v#~Nre6A%cx z`%gEr$`dFHYJBIzsi|mxomPU&9)6XF>ug3W5zqta>6wG=m`ZWj5Twx$hqH$P*Zm`< z$@O(Nu}ta??a6rWz?D4&eOPo98Zh|s8kY8?Dh z_sDwPKV5VqtGxpkPfFFPzPW>+ytFg^q*Cc;S>M;IvNFr3HuWu-_X~OT;u5 z&)S8;b0^mIb^mk;hA_oQK5qKq6ccEU+rO`Q%!oY9EJ~jy7SF8L5K)M1^-|J+zW-2i z{@o%RW!>wkZ&Y!L2^?&X)7F)mlyQ31`@jH%T11ovAfh&Zc_}OFoPW27lv3AtoXtbr zJCHCfUftJ}a_uEk^C-hOLqzd1bngyUu+d9lzWe@8q+3rw#MX0|J0{B6Rl~a;p;EFD zx(&b*-7^EoneXpJILbpqjR|O)&Sr8GE1>=cJ@o;u|4@TKYUxcE$eHi& zL^?46(RllRSO zbeD1qMW99FmZ$2NT~*526H*^(XH|xI@scULa7U^f!Q%y#t~_w4BbCBV7LQt8836m&xV! zy3eV93^OO+M*_v8Jv9QMf2B~-Hn=6{%4wzf;rlz$9TTvtC$MN*S<1EO1_xR@IqT;y z^8CApeNxhWL{F^m{dXS&u<8#y3AmD!S6!a!`n`3ym6!bX{hb&fCNQlu*mq(llHA)5 zG`7XL=$EhXv(4{frIYoU0dX5wHB0uJX6Lhiy$|#q0hZ4)Cazji9bEA{-!OWH+HpD8-uB z_Hf6hdQ_2XuClUpYcY@AbF}wC+fLS3$Nm@ibXMY8jzDV@#X$pIlCysxSvM!2(x#dk zp}hrNgwfF;`;T`fhy1F^&i8b*Len9CoD%=biVP|unU8XZTI00D&E%u9%%(PCX8hh- zQgccFgSJ~-1nyGV8bCM4sl4?i}mJ`nr8;OV9=S1C480S4&nmC zix$f?27LqU;8WKdYTg#5{>v4W3iyUnEa%2kQ&XV(F(lu`JYKdOcspCA3iyM9SVFb` z_fW1Kn)CXNiR}W*@N*k+flNtgaAW_NzY{}_UYJX2o)O{h%=IeZ2LgA0I0b#|NGp70 zwgqohir3RutAJ0uWG32|r*lKvD}KRMu^LNw8OT9KXMq7|v@k!+lG$m!aVqTqc6@0~ z3?*NrFdxV#6pHK9?R?0<0069|)xQz=aVGZ`a34|JVJ)rsT_*Qtyo6=$t^O9Ue$WdG zc#Eiq%!cakW_o+(YnaP_C1EAnzX&{;aT^7)ln*uQ*msI9o7%gVP#8JhW`f>T{-ufSluW09E4l37`2q`H&Fvh37G z)6^DVHu3c~9E^z#)%XM)(UXo|5`1 zv@G$a(A||aajU-O3!>D2QivF4gA&CLti3a?@S^j`2Kd+srnR1ng+yqR@wK{3C zPej(4mbIFHWwYFU9jc4uw*mC9{8_`8P^61zC3_OcE=|-f6WQiwB1XRO{|XEhIep Date: Fri, 22 May 2020 12:30:46 +0200 Subject: [PATCH 56/79] Fix Channels Mark All as Un/Read. --- .../src/gui/feeds/GxsChannelPostItem.cpp | 22 ++++++++----- .../src/gui/feeds/GxsChannelPostItem.h | 10 +++--- .../gui/gxschannels/GxsChannelPostsWidget.cpp | 32 +++++++++++-------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp index 25b93ac8d..aa35fc0cc 100644 --- a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp @@ -141,7 +141,7 @@ GxsChannelPostItem::~GxsChannelPostItem() bool GxsChannelPostItem::isUnread() const { - return IS_MSG_UNREAD(mPost.mMeta.mMsgStatus) ; + return IS_MSG_UNREAD(mPost.mMeta.mMsgStatus) ; } void GxsChannelPostItem::setup() @@ -427,7 +427,7 @@ void GxsChannelPostItem::fill() QString title; - float f = QFontMetricsF(font()).height()/14.0 ; + //float f = QFontMetricsF(font()).height()/14.0 ; if(mPost.mThumbnail.mData != NULL) { @@ -629,14 +629,21 @@ QString GxsChannelPostItem::messageName() void GxsChannelPostItem::setReadStatus(bool isNew, bool isUnread) { + if (isNew) + mPost.mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_NEW; + else + mPost.mMeta.mMsgStatus &= ~GXS_SERV::GXS_MSG_STATUS_GUI_NEW; + if (isUnread) { - ui->readButton->setChecked(true); + mPost.mMeta.mMsgStatus |= GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; + whileBlocking(ui->readButton)->setChecked(true); ui->readButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png")); } else { - ui->readButton->setChecked(false); + mPost.mMeta.mMsgStatus &= ~GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; + whileBlocking(ui->readButton)->setChecked(false); ui->readButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-read.png")); } @@ -835,7 +842,7 @@ void GxsChannelPostItem::play() } } -void GxsChannelPostItem::readToggled(bool checked) +void GxsChannelPostItem::readToggled(bool /*checked*/) { if (mInFill) { return; @@ -845,10 +852,9 @@ void GxsChannelPostItem::readToggled(bool checked) RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId()); - uint32_t token; - rsGxsChannels->setMessageReadStatus(token, msgPair, !checked); + rsGxsChannels->markRead(msgPair, isUnread()); - setReadStatus(false, checked); + //setReadStatus(false, checked); // Updated by events } void GxsChannelPostItem::makeDownVote() diff --git a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.h b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.h index 86aa20371..315972bb1 100644 --- a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.h +++ b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.h @@ -62,10 +62,13 @@ public: QString getMsgLabel(); const std::list &getFileItems() {return mFileItems; } - bool isUnread() const ; - const std::set& olderVersions() const { return mPost.mOlderVersions; } + bool isLoaded() const {return mLoaded;}; + bool isUnread() const ; + void setReadStatus(bool isNew, bool isUnread); - static uint64_t computeIdentifier(const RsGxsMessageId& msgid) { return hash64("GxsChannelPostItem " + msgid.toStdString()) ; } + const std::set& olderVersions() const { return mPost.mOlderVersions; } + + static uint64_t computeIdentifier(const RsGxsMessageId& msgid) { return hash64("GxsChannelPostItem " + msgid.toStdString()) ; } protected: //void init(const RsGxsMessageId& messageId,const std::set& older_versions); @@ -112,7 +115,6 @@ private: void setup(); void fill(); void fillExpandFrame(); - void setReadStatus(bool isNew, bool isUnread); private: bool mInFill; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp index 48b620775..d4e6192e2 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp @@ -144,18 +144,24 @@ void GxsChannelPostsWidget::handleEvent_main_thread(std::shared_ptrmChannelEventCode) - { - case RsChannelEventCode::UPDATED_CHANNEL: - case RsChannelEventCode::NEW_CHANNEL: - case RsChannelEventCode::UPDATED_MESSAGE: - case RsChannelEventCode::NEW_MESSAGE: - if(e->mChannelGroupId == groupId()) + switch(e->mChannelEventCode) + { + case RsChannelEventCode::NEW_CHANNEL: // [[fallthrough]]; + case RsChannelEventCode::UPDATED_CHANNEL: // [[fallthrough]]; + case RsChannelEventCode::NEW_MESSAGE: // [[fallthrough]]; + case RsChannelEventCode::UPDATED_MESSAGE: + if(e->mChannelGroupId == groupId()) updateDisplay(true); - break; - default: - break; - } + break; + case RsChannelEventCode::READ_STATUS_CHANGED: + if (FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(e->mChannelMsgId))) + if (GxsChannelPostItem *channelPostItem = dynamic_cast(feedItem)) + channelPostItem->setReadStatus(false,!channelPostItem->isUnread()); + //channelPostItem->setReadStatus(false,e->Don't get read status. Will be more easier and accurate); + break; + default: + break; + } } GxsChannelPostsWidget::~GxsChannelPostsWidget() @@ -909,9 +915,9 @@ static void setAllMessagesReadCallback(FeedItem *feedItem, void *data) } GxsChannelPostsReadData *readData = (GxsChannelPostsReadData*) data; - bool is_not_new = !channelPostItem->isUnread() ; + bool isRead = !channelPostItem->isUnread() ; - if(is_not_new == readData->mRead) + if(channelPostItem->isLoaded() && (isRead == readData->mRead)) return ; RsGxsGrpMsgIdPair msgPair = std::make_pair(channelPostItem->groupId(), channelPostItem->messageId()); From 77f818f0b37236f0a2994b9f607a3810fa5bf33f Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 22 May 2020 17:52:05 +0200 Subject: [PATCH 57/79] Fix JSON API compilation error introduces in f6260a95ae2e7baee7877f984d569c291b459612 --- libretroshare/src/retroshare/rsgxschannels.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index bef322a4a..4b188ad01 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -310,6 +310,7 @@ public: * @param[in] channelId id of the channel of which the content is requested * @param[out] posts storage for posts * @param[out] comments storage for the comments + * @param[out] votes storage for votes * @return false if something failed, true otherwhise */ virtual bool getChannelAllContent( const RsGxsGroupId& channelId, From 74646413c4f82db31c1bb5f13fc6c771dd59b59d Mon Sep 17 00:00:00 2001 From: defnax Date: Sat, 23 May 2020 00:16:49 +0200 Subject: [PATCH 58/79] Added mail settings for emoticons --- retroshare-gui/src/gui/msgs/MessageWidget.cpp | 10 +++++--- .../src/gui/settings/MessagePage.cpp | 7 +++++- retroshare-gui/src/gui/settings/MessagePage.h | 1 + .../src/gui/settings/MessagePage.ui | 23 ++++++++++++------- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.cpp b/retroshare-gui/src/gui/msgs/MessageWidget.cpp index 3c085c3c8..a9a004a51 100644 --- a/retroshare-gui/src/gui/msgs/MessageWidget.cpp +++ b/retroshare-gui/src/gui/msgs/MessageWidget.cpp @@ -667,10 +667,14 @@ void MessageWidget::fill(const std::string &msgId) } ui.subjectText->setText(QString::fromUtf8(msgInfo.title.c_str())); + + unsigned int formatTextFlag = RSHTML_FORMATTEXT_EMBED_LINKS ; - // emoticons disabled because of crazy cost. - //text = RsHtmlMsg(msgInfo.msgflags).formatText(ui.msgText->document(), QString::fromUtf8(msgInfo.msg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); - text = RsHtmlMsg(msgInfo.msgflags).formatText(ui.msgText->document(), QString::fromUtf8(msgInfo.msg.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS); + // embed smileys ? + if (Settings->valueFromGroup(QString("Messages"), QString::fromUtf8("Emoticons"), true).toBool()) { + formatTextFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS ; + } + text = RsHtmlMsg(msgInfo.msgflags).formatText(ui.msgText->document(), QString::fromUtf8(msgInfo.msg.c_str()), formatTextFlag); ui.msgText->resetImagesStatus(Settings->getMsgLoadEmbeddedImages() || (msgInfo.msgflags & RS_MSG_LOAD_EMBEDDED_IMAGES)); ui.msgText->setHtml(text); diff --git a/retroshare-gui/src/gui/settings/MessagePage.cpp b/retroshare-gui/src/gui/settings/MessagePage.cpp index eb0eabccc..91a24ab02 100644 --- a/retroshare-gui/src/gui/settings/MessagePage.cpp +++ b/retroshare-gui/src/gui/settings/MessagePage.cpp @@ -39,7 +39,6 @@ MessagePage::MessagePage(QWidget * parent, Qt::WindowFlags flags) connect (ui.editpushButton, SIGNAL(clicked(bool)), this, SLOT (editTag())); connect (ui.deletepushButton, SIGNAL(clicked(bool)), this, SLOT (deleteTag())); connect (ui.defaultTagButton, SIGNAL(clicked(bool)), this, SLOT (defaultTag())); - //connect (ui.encryptedMsgs_CB, SIGNAL(toggled(bool)), this, SLOT (toggleEnableEncryptedDistantMsgs(bool))); connect (ui.tags_listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(currentRowChangedTag(int))); @@ -54,6 +53,7 @@ MessagePage::MessagePage(QWidget * parent, Qt::WindowFlags flags) connect(ui.setMsgToReadOnActivate,SIGNAL(toggled(bool)), this,SLOT(updateMsgToReadOnActivate())); connect(ui.loadEmbeddedImages, SIGNAL(toggled(bool)), this,SLOT(updateLoadEmbededImages() )); connect(ui.openComboBox, SIGNAL(currentIndexChanged(int)),this,SLOT(updateMsgOpen() )); + connect(ui.emoticonscheckBox, SIGNAL(toggled(bool)), this,SLOT(updateLoadEmoticons() )); } MessagePage::~MessagePage() @@ -84,6 +84,7 @@ void MessagePage::updateMsgToReadOnActivate() { Settings->setMsgSetToReadOnActiv void MessagePage::updateLoadEmbededImages() { Settings->setMsgLoadEmbeddedImages(ui.loadEmbeddedImages->isChecked()); } void MessagePage::updateMsgOpen() { Settings->setMsgOpen( static_cast(ui.openComboBox->itemData(ui.openComboBox->currentIndex()).toInt()) ); } void MessagePage::updateDistantMsgs() { Settings->setValue("DistantMessages", ui.comboBox->currentIndex()); } +void MessagePage::updateLoadEmoticons() { Settings->setValueToGroup("Messages", "Emoticons", ui.emoticonscheckBox->isChecked()); } void MessagePage::updateMsgTags() { @@ -110,9 +111,12 @@ void MessagePage::updateMsgTags() void MessagePage::load() { + Settings->beginGroup(QString("Messages")); whileBlocking(ui.setMsgToReadOnActivate)->setChecked(Settings->getMsgSetToReadOnActivate()); whileBlocking(ui.loadEmbeddedImages)->setChecked(Settings->getMsgLoadEmbeddedImages()); whileBlocking(ui.openComboBox)->setCurrentIndex(ui.openComboBox->findData(Settings->getMsgOpen())); + whileBlocking(ui.emoticonscheckBox)->setChecked(Settings->value("Emoticons", true).toBool()); + Settings->endGroup(); // state of filter combobox @@ -267,3 +271,4 @@ void MessagePage::currentRowChangedTag(int row) ui.editpushButton->setEnabled(bEditEnable); ui.deletepushButton->setEnabled(bDeleteEnable); } + diff --git a/retroshare-gui/src/gui/settings/MessagePage.h b/retroshare-gui/src/gui/settings/MessagePage.h index b4c2e9c67..6dd6f87df 100644 --- a/retroshare-gui/src/gui/settings/MessagePage.h +++ b/retroshare-gui/src/gui/settings/MessagePage.h @@ -58,6 +58,7 @@ private slots: void updateMsgOpen() ; void updateDistantMsgs() ; void updateMsgTags() ; + void updateLoadEmoticons(); private: void fillTags(); diff --git a/retroshare-gui/src/gui/settings/MessagePage.ui b/retroshare-gui/src/gui/settings/MessagePage.ui index 57d801bed..58da48b9f 100644 --- a/retroshare-gui/src/gui/settings/MessagePage.ui +++ b/retroshare-gui/src/gui/settings/MessagePage.ui @@ -65,14 +65,7 @@ - - - - Load embedded images - - - - + @@ -86,6 +79,20 @@ + + + + Load embedded images + + + + + + + Load Emoticons + + + From f5306fd5490fd554abe5844b655978d63a8a47ff Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 23 May 2020 16:10:11 +0200 Subject: [PATCH 59/79] Dump the active build configuration into a file --- build_scripts/Windows-msys2/build/build.bat | 6 ++++++ build_scripts/Windows-msys2/build/pack.bat | 3 +++ 2 files changed, 9 insertions(+) diff --git a/build_scripts/Windows-msys2/build/build.bat b/build_scripts/Windows-msys2/build/build.bat index d15e5babc..84cb0c83c 100644 --- a/build_scripts/Windows-msys2/build/build.bat +++ b/build_scripts/Windows-msys2/build/build.bat @@ -52,6 +52,12 @@ set RS_QMAKE_CONFIG=%RS_QMAKE_CONFIG% "CONFIG+=%RsBuildConfig%" if "%ParamAutologin%"=="1" set RS_QMAKE_CONFIG=%RS_QMAKE_CONFIG% "CONFIG+=rs_autologin" if "%ParamPlugins%"=="1" set RS_QMAKE_CONFIG=%RS_QMAKE_CONFIG% "CONFIG+=retroshare_plugins" +:: Dump the active build config into a file +echo %RS_QMAKE_CONFIG% > buildinfo.txt +echo %RsBuildConfig% >> buildinfo.txt +echo %RsArchitecture% >> buildinfo.txt +echo Qt %QtVersion% >> buildinfo.txt + call "%ToolsPath%\msys2-path.bat" "%SourcePath%" MSYS2SourcePath call "%ToolsPath%\msys2-path.bat" "%EnvMSYS2Path%" MSYS2EnvMSYS2Path %EnvMSYS2Cmd% "qmake "%MSYS2SourcePath%/RetroShare.pro" -r -spec win32-g++ %RS_QMAKE_CONFIG%" diff --git a/build_scripts/Windows-msys2/build/pack.bat b/build_scripts/Windows-msys2/build/pack.bat index e8c9761bc..3b2a79b8f 100644 --- a/build_scripts/Windows-msys2/build/pack.bat +++ b/build_scripts/Windows-msys2/build/pack.bat @@ -161,6 +161,9 @@ copy "%SourcePath%\libbitdht\src\bitdht\bdboot.txt" "%RsDeployPath%" %Quite% echo copy changelog.txt copy "%SourcePath%\retroshare-gui\src\changelog.txt" "%RsDeployPath%" %Quite% +echo copy buildinfo.txt +copy "%RsBuildPath%\buildinfo.txt" "%RsDeployPath%" %Quite% + if exist "%SourcePath%\libresapi\src\webui" ( echo copy webui mkdir "%RsDeployPath%\webui" From c05f5e83293a58fddf0a7afa7b501f121fbd5bff Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 23 May 2020 16:53:59 +0200 Subject: [PATCH 60/79] Use ntldd instead of depends.exe Check all exe and dll for dependencies Deploy cmark.dll --- build_scripts/Windows-msys2/build/pack.bat | 17 +++++----- build_scripts/Windows-msys2/env/env.bat | 1 - .../Windows-msys2/env/tools/prepare-tools.bat | 18 ---------- build_scripts/Windows-msys2/tools/depends.bat | 34 +++++-------------- 4 files changed, 16 insertions(+), 54 deletions(-) diff --git a/build_scripts/Windows-msys2/build/pack.bat b/build_scripts/Windows-msys2/build/pack.bat index 3b2a79b8f..440916afd 100644 --- a/build_scripts/Windows-msys2/build/pack.bat +++ b/build_scripts/Windows-msys2/build/pack.bat @@ -17,6 +17,9 @@ call "%~dp0env.bat" %* if errorlevel 2 exit /B 2 if errorlevel 1 goto error_env +:: Install ntldd +%EnvMSYS2Cmd% "pacman --noconfirm --needed -S make git mingw-w64-%RsMSYS2Architecture%-ntldd-git" + :: Remove deploy path if exist "%RsDeployPath%" rmdir /S /Q "%RsDeployPath%" @@ -100,16 +103,13 @@ echo copy binaries copy "%RsBuildPath%\retroshare-gui\src\%RsBuildConfig%\RetroShare*.exe" "%RsDeployPath%" %Quite% copy "%RsBuildPath%\retroshare-nogui\src\%RsBuildConfig%\retroshare*-nogui.exe" "%RsDeployPath%" %Quite% copy "%RsBuildPath%\retroshare-service\src\%RsBuildConfig%\retroshare*-service.exe" "%RsDeployPath%" %Quite% +copy "%RsBuildPath%\supportlibs\cmark\build\src\libcmark.dll" "%RsDeployPath%" %Quite% echo copy extensions for /D %%D in ("%RsBuildPath%\plugins\*") do ( call :copy_extension "%%D" "%RsDeployPath%\Data\%Extensions%" - call :copy_dependencies "%RsDeployPath%\Data\%Extensions%\%%~nxD.dll" "%RsDeployPath%" ) -echo copy dependencies -call :copy_dependencies "%RsDeployPath%\retroshare.exe" "%RsDeployPath%" - echo copy Qt DLL's copy "%RsMinGWPath%\bin\Qt%QtMainVersion1%Svg%QtMainVersion2%.dll" "%RsDeployPath%" %Quite% @@ -128,7 +128,9 @@ if exist "%QtSharePath%\plugins\styles\qwindowsvistastyle.dll" ( copy "%QtSharePath%\plugins\imageformats\*.dll" "%RsDeployPath%\imageformats" %Quite% del /Q "%RsDeployPath%\imageformats\*d?.dll" %Quite% -for %%D in ("%RsDeployPath%\imageformats\*.dll") do ( + +echo copy dependencies +for /R "%RsDeployPath%" %%D in (*.dll, *.exe) do ( call :copy_dependencies "%%D" "%RsDeployPath%" ) @@ -207,14 +209,11 @@ if exist "%~1\%RsBuildConfig%\%~n1.dll" ( goto :EOF :copy_dependencies -set CopyDependenciesCopiedSomething=0 -for /F "usebackq" %%A in (`%ToolsPath%\depends.bat list %1`) do ( +for /F "usebackq" %%A in (`%ToolsPath%\depends.bat %1`) do ( if not exist "%~2\%%A" ( if exist "%RsMinGWPath%\bin\%%A" ( - set CopyDependenciesCopiedSomething=1 copy "%RsMinGWPath%\bin\%%A" %2 %Quite% ) ) ) -if "%CopyDependenciesCopiedSomething%"=="1" goto copy_dependencies goto :EOF diff --git a/build_scripts/Windows-msys2/env/env.bat b/build_scripts/Windows-msys2/env/env.bat index 810715ad2..f374f2420 100644 --- a/build_scripts/Windows-msys2/env/env.bat +++ b/build_scripts/Windows-msys2/env/env.bat @@ -9,7 +9,6 @@ set EnvDownloadPath=%EnvRootPath%\download set EnvWgetExe=%EnvToolsPath%\wget.exe set EnvSevenZipExe=%EnvToolsPath%\7z.exe -set EnvDependsExe=%EnvToolsPath%\depends.exe set EnvCEchoExe=%EnvToolsPath%\cecho.exe set cecho=call "%ToolsPath%\cecho.bat" diff --git a/build_scripts/Windows-msys2/env/tools/prepare-tools.bat b/build_scripts/Windows-msys2/env/tools/prepare-tools.bat index d2014a7f1..e6f9386cd 100644 --- a/build_scripts/Windows-msys2/env/tools/prepare-tools.bat +++ b/build_scripts/Windows-msys2/env/tools/prepare-tools.bat @@ -8,8 +8,6 @@ set SevenZipUrl=https://sourceforge.net/projects/sevenzip/files/7-Zip/18.05/7z18 set SevenZipInstall=7z1805.msi set WgetUrl=https://eternallybored.org/misc/wget/1.19.4/32/wget.exe set WgetInstall=wget.exe -set DependsUrl=http://www.dependencywalker.com/depends22_x86.zip -set DependsInstall=depends22_x86.zip set SigcheckInstall=Sigcheck.zip set SigcheckUrl=https://download.sysinternals.com/files/%SigcheckInstall% @@ -56,22 +54,6 @@ if not exist "%EnvToolsPath%\cecho.exe" ( call "%ToolsPath%\remove-dir.bat" "%EnvTempPath%" ) -if not exist "%EnvToolsPath%\depends.exe" ( - call "%ToolsPath%\remove-dir.bat" "%EnvTempPath%" - mkdir "%EnvTempPath%" - - %cecho% info "Download Dependency Walker installation" - - if not exist "%EnvDownloadPath%\%DependsInstall%" call "%ToolsPath%\winhttpjs.bat" %DependsUrl% -saveTo "%EnvDownloadPath%\%DependsInstall%" - if not exist "%EnvDownloadPath%\%DependsInstall%" %cecho% error "Cannot download Dependendy Walker installation" & goto error - - %cecho% info "Unpack Dependency Walker" - "%EnvSevenZipExe%" x -o"%EnvTempPath%" "%EnvDownloadPath%\%DependsInstall%" - copy "%EnvTempPath%\*" "%EnvToolsPath%" - - call "%ToolsPath%\remove-dir.bat" "%EnvTempPath%" -) - if not exist "%EnvToolsPath%\sigcheck.exe" ( %cecho% info "Download Sigcheck installation" diff --git a/build_scripts/Windows-msys2/tools/depends.bat b/build_scripts/Windows-msys2/tools/depends.bat index a5295ccb1..a92fd3364 100644 --- a/build_scripts/Windows-msys2/tools/depends.bat +++ b/build_scripts/Windows-msys2/tools/depends.bat @@ -1,40 +1,22 @@ :: Usage: -:: call depends.bat [list^|missing] file +:: call depends.bat file -if "%2"=="" ( - echo Usage: %~nx0 [list^|missing] File +if "%1"=="" ( + echo Usage: %~nx0 File exit /B 1 ) setlocal +pushd %~dp1 -if not exist "%EnvDependsExe%" echo depends.exe not found in %EnvToolsPath%.& exit /B 1 +%EnvMSYS2Cmd% "ntldd --recursive $0 | cut -f1 -d"=" | awk '{$1=$1};1'" %~nx1 > %~sdp0depends.tmp -set CutPath= -call "%ToolsPath%\find-in-path.bat" CutPath cut.exe -if "%CutPath%"=="" echo cut.exe not found in PATH.& exit /B 1 - -start /wait "" "%EnvDependsExe%" /c /oc:"%~dp0depends.tmp" %2 -if "%1"=="missing" ( - cut.exe --delimiter=, --fields=1,2 "%~dp0depends.tmp" >"%~dp0depends1.tmp" - for /F "tokens=1,2 delims=," %%A in (%~sdp0depends1.tmp) do ( - if "%%A"=="?" ( - echo %%~B - ) - ) -) - -if "%1"=="list" ( - cut.exe --delimiter=, --fields=2 "%~dp0depends.tmp" >"%~dp0depends1.tmp" - for /F "tokens=1 delims=," %%A in (%~sdp0depends1.tmp) do ( - if "%%A" NEQ "Module" ( - echo %%~A - ) - ) +for /F %%A in (%~sdp0depends.tmp) do ( + echo %%~A ) if exist "%~dp0depends.tmp" del /Q "%~dp0depends.tmp" -if exist "%~dp0depends1.tmp" del /Q "%~dp0depends1.tmp" +popd endlocal exit /B 0 \ No newline at end of file From 1d298e20bad420b7d7ffbd33d9974852cd1b8051 Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 23 May 2020 17:13:01 +0200 Subject: [PATCH 61/79] Removed sigcheck Use powershell to extract the version information --- build_scripts/Windows-msys2/build/git-log.bat | 2 +- build_scripts/Windows-msys2/build/pack.bat | 2 +- build_scripts/Windows-msys2/tools/get-rs-version.bat | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build_scripts/Windows-msys2/build/git-log.bat b/build_scripts/Windows-msys2/build/git-log.bat index e3b42bf80..010ff190b 100644 --- a/build_scripts/Windows-msys2/build/git-log.bat +++ b/build_scripts/Windows-msys2/build/git-log.bat @@ -23,7 +23,7 @@ call "%ToolsPath%\find-in-path.bat" GitPath git.exe if "%GitPath%"=="" echo Git executable not found in PATH.& exit /B 1 :: Get compiled revision -set GetRsVersion=%SourcePath%\build_scripts\Windows\tools\get-rs-version.bat +set GetRsVersion=%SourcePath%\build_scripts\Windows-msys2\tools\get-rs-version.bat if not exist "%GetRsVersion%" ( echo File not found echo %GetRsVersion% diff --git a/build_scripts/Windows-msys2/build/pack.bat b/build_scripts/Windows-msys2/build/pack.bat index 440916afd..b023f5d5b 100644 --- a/build_scripts/Windows-msys2/build/pack.bat +++ b/build_scripts/Windows-msys2/build/pack.bat @@ -27,7 +27,7 @@ if exist "%RsDeployPath%" rmdir /S /Q "%RsDeployPath%" if not exist "%RsBuildPath%\Makefile" echo Project is not compiled.& goto error :: Get compiled revision -set GetRsVersion=%SourcePath%\build_scripts\Windows\tools\get-rs-version.bat +set GetRsVersion=%SourcePath%\build_scripts\Windows-msys2\tools\get-rs-version.bat if not exist "%GetRsVersion%" ( %cecho% error "File not found" echo %GetRsVersion% diff --git a/build_scripts/Windows-msys2/tools/get-rs-version.bat b/build_scripts/Windows-msys2/tools/get-rs-version.bat index 2398baf93..cc4e53ff8 100644 --- a/build_scripts/Windows-msys2/tools/get-rs-version.bat +++ b/build_scripts/Windows-msys2/tools/get-rs-version.bat @@ -27,7 +27,7 @@ set VersionMinor= set VersionMini= set VersionExtra= -for /F "tokens=1,2,3,* delims=.-" %%A in ('%EnvToolsPath%\sigcheck.exe -nobanner -n %Executable%') do ( +for /F "USEBACKQ tokens=1,2,3,* delims=.-" %%A in (`powershell -NoLogo -NoProfile -Command ^(Get-Item "%Executable%"^).VersionInfo.FileVersion`) do ( set VersionMajor=%%A set VersionMinor=%%B set VersionMini=%%C From 81a7d5a365edd6e394a02d8b0cbb3b4e939440e9 Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 23 May 2020 17:57:59 +0200 Subject: [PATCH 62/79] Removed winhttpjs and wget Winhhtpjs triggered some antivirus software Use powershell for downloads --- build_scripts/Windows-msys2/env/env.bat | 1 - .../Windows-msys2/env/tools/prepare-tools.bat | 24 - .../Windows-msys2/tools/download-file.bat | 3 +- .../Windows-msys2/tools/winhttpjs.bat | 584 ------------------ 4 files changed, 1 insertion(+), 611 deletions(-) delete mode 100644 build_scripts/Windows-msys2/tools/winhttpjs.bat diff --git a/build_scripts/Windows-msys2/env/env.bat b/build_scripts/Windows-msys2/env/env.bat index f374f2420..1d2f9c2e4 100644 --- a/build_scripts/Windows-msys2/env/env.bat +++ b/build_scripts/Windows-msys2/env/env.bat @@ -7,7 +7,6 @@ set EnvToolsPath=%EnvRootPath%\tools set EnvTempPath=%EnvRootPath%\tmp set EnvDownloadPath=%EnvRootPath%\download -set EnvWgetExe=%EnvToolsPath%\wget.exe set EnvSevenZipExe=%EnvToolsPath%\7z.exe set EnvCEchoExe=%EnvToolsPath%\cecho.exe set cecho=call "%ToolsPath%\cecho.bat" diff --git a/build_scripts/Windows-msys2/env/tools/prepare-tools.bat b/build_scripts/Windows-msys2/env/tools/prepare-tools.bat index e6f9386cd..c6b14a787 100644 --- a/build_scripts/Windows-msys2/env/tools/prepare-tools.bat +++ b/build_scripts/Windows-msys2/env/tools/prepare-tools.bat @@ -6,20 +6,6 @@ set CEchoUrl=https://github.com/lordmulder/cecho/releases/download/2015-10-10/ce set CEchoInstall=cecho.2015-10-10.zip set SevenZipUrl=https://sourceforge.net/projects/sevenzip/files/7-Zip/18.05/7z1805.msi/download set SevenZipInstall=7z1805.msi -set WgetUrl=https://eternallybored.org/misc/wget/1.19.4/32/wget.exe -set WgetInstall=wget.exe -set SigcheckInstall=Sigcheck.zip -set SigcheckUrl=https://download.sysinternals.com/files/%SigcheckInstall% - -if not exist "%EnvToolsPath%\wget.exe" ( - echo Download Wget installation - - if not exist "%EnvDownloadPath%\%WgetInstall%" call "%ToolsPath%\winhttpjs.bat" %WgetUrl% -saveTo "%EnvDownloadPath%\%WgetInstall%" - if not exist "%EnvDownloadPath%\%WgetInstall%" %cecho% error "Cannot download Wget installation" & goto error - - echo Copy Wget - copy "%EnvDownloadPath%\wget.exe" "%EnvToolsPath%" -) if not exist "%EnvToolsPath%\7z.exe" ( call "%ToolsPath%\remove-dir.bat" "%EnvTempPath%" @@ -54,16 +40,6 @@ if not exist "%EnvToolsPath%\cecho.exe" ( call "%ToolsPath%\remove-dir.bat" "%EnvTempPath%" ) -if not exist "%EnvToolsPath%\sigcheck.exe" ( - %cecho% info "Download Sigcheck installation" - - if not exist "%EnvDownloadPath%\%SigcheckInstall%" call "%ToolsPath%\download-file.bat" "%SigcheckUrl%" "%EnvDownloadPath%\%SigcheckInstall%" - if not exist "%EnvDownloadPath%\%SigcheckInstall%" %cecho% error "Cannot download Sigcheck installation" & goto error - - %cecho% info "Unpack Sigcheck" - "%EnvSevenZipExe%" x -o"%EnvToolsPath%" "%EnvDownloadPath%\%SigcheckInstall%" sigcheck.exe -) - :exit endlocal exit /B 0 diff --git a/build_scripts/Windows-msys2/tools/download-file.bat b/build_scripts/Windows-msys2/tools/download-file.bat index 62720c393..dbcecdcbb 100644 --- a/build_scripts/Windows-msys2/tools/download-file.bat +++ b/build_scripts/Windows-msys2/tools/download-file.bat @@ -7,7 +7,6 @@ if "%~2"=="" ( exit /B 1 ) -::"%EnvCurlExe%" -L -k "%~1" -o "%~2" -"%EnvWgetExe%" --no-check-certificate --continue "%~1" --output-document="%~2" +powershell -NoLogo -NoProfile -Command (New-Object System.Net.WebClient).DownloadFile(\""%~1\"", \""%~2\"") exit /B %ERRORLEVEL% diff --git a/build_scripts/Windows-msys2/tools/winhttpjs.bat b/build_scripts/Windows-msys2/tools/winhttpjs.bat deleted file mode 100644 index cdea152eb..000000000 --- a/build_scripts/Windows-msys2/tools/winhttpjs.bat +++ /dev/null @@ -1,584 +0,0 @@ -@if (@X) == (@Y) @end /* JScript comment - @echo off - - rem :: the first argument is the script name as it will be used for proper help message - cscript //E:JScript //nologo "%~f0" "%~nx0" %* - - exit /b %errorlevel% - -@if (@X)==(@Y) @end JScript comment */ - -// used resources - -// update 12.10.15 -// osvikvi(https://github.com/osvikvi) has nodited that the -password option is not set , so this is fixed - -//https://msdn.microsoft.com/en-us/library/windows/desktop/aa384058(v=vs.85).aspx -//https://msdn.microsoft.com/en-us/library/windows/desktop/aa384055(v=vs.85).aspx -//https://msdn.microsoft.com/en-us/library/windows/desktop/aa384059(v=vs.85).aspx - -// global variables and constants - - -// ---------------------------------- -// -- asynch requests not included -- -// ---------------------------------- - - -//todo - save responceStream instead of responceBody !! -//todo - set all winthttp options ->//https://msdn.microsoft.com/en-us/library/windows/desktop/aa384108(v=vs.85).aspx -//todo - log all options -//todo - improve help message . eventual verbose option - - -var ARGS = WScript.Arguments; -var scriptName = ARGS.Item(0); - -var url = ""; -var saveTo = ""; - -var user = 0; -var pass = 0; - -var proxy = 0; -var bypass = 0; -var proxy_user = 0; -var proxy_pass = 0; - -var certificate = 0; - -var force = true; - -var body = ""; - -//ActiveX objects -var WinHTTPObj = new ActiveXObject("WinHttp.WinHttpRequest.5.1"); -var FileSystemObj = new ActiveXObject("Scripting.FileSystemObject"); -var AdoDBObj = new ActiveXObject("ADODB.Stream"); - -// HttpRequest SetCredentials flags. -var proxy_settings = 0; - -// -HTTPREQUEST_SETCREDENTIALS_FOR_SERVER = 0; -HTTPREQUEST_SETCREDENTIALS_FOR_PROXY = 1; - -//timeouts and their default values -var RESOLVE_TIMEOUT = 0; -var CONNECT_TIMEOUT = 90000; -var SEND_TIMEOUT = 90000; -var RECEIVE_TIMEOUT = 90000; - -//HttpRequestMethod -var http_method = 'GET'; - -//header -var header_file = ""; - -//report -var reportfile = ""; - -//test-this: -var use_stream = false; - -//autologon policy -var autologon_policy = 1; //0,1,2 - - -//headers will be stored as multi-dimensional array -var headers = []; - -//user-agent -var ua = ""; - -//escape URL -var escape = false; - -function printHelp() { - WScript.Echo(scriptName + " - sends HTTP request and saves the request body as a file and/or a report of the sent request"); - WScript.Echo(scriptName + " url [-force yes|no] [-user username -password password] [-proxy proxyserver:port] [-bypass bypass_list]"); - WScript.Echo(" [-proxyuser proxy_username -proxypassword proxy_password] [-certificate certificateString]"); - WScript.Echo(" [-method GET|POST|PATCH|DELETE|HEAD|OPTIONS|CONNECT]"); - WScript.Echo(" [-saveTo file] - to print response to console use con"); - - WScript.Echo(" [-sendTimeout int(milliseconds)]"); - WScript.Echo(" [-resolveTimeout int(milliseconds)]"); - WScript.Echo(" [-connectTimeout int(milliseconds)]"); - WScript.Echo(" [-receiveTimeout int(milliseconds)]"); - - WScript.Echo(" [-autologonPolicy 1|2|3]"); - WScript.Echo(" [-proxySettings 1|2|3] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa384059(v=vs.85).aspx)"); - - //header - WScript.Echo(" [-headers-file header_file]"); - //reportfile - WScript.Echo(" [-reportfile reportfile]"); - WScript.Echo(" [-ua user-agent]"); - WScript.Echo(" [-ua-file user-agent-file]"); - - WScript.Echo(" [-escape yes|no]"); - - WScript.Echo(" [-body body-string]"); - WScript.Echo(" [-body-file body-file]"); - - WScript.Echo("-force - decide to not or to overwrite if the local files exists"); - - WScript.Echo("proxyserver:port - the proxy server"); - WScript.Echo("bypass- bypass list"); - WScript.Echo("proxy_user , proxy_password - credentials for proxy server"); - WScript.Echo("user , password - credentials for the server"); - WScript.Echo("certificate - location of SSL certificate"); - WScript.Echo("method - what HTTP method will be used.Default is GET"); - WScript.Echo("saveTo - save the responce as binary file"); - WScript.Echo(" "); - WScript.Echo("Header file should contain key:value pairs.Lines starting with \"#\" will be ignored."); - WScript.Echo("value should NOT be enclosed with quotes"); - WScript.Echo(" "); - WScript.Echo("Examples:"); - - WScript.Echo(scriptName + " http://somelink.com/somefile.zip -saveTo c:\\somefile.zip -certificate \"LOCAL_MACHINE\\Personal\\My Middle-Tier Certificate\""); - WScript.Echo(scriptName + " http://somelink.com/something.html -method POST -certificate \"LOCAL_MACHINE\\Personal\\My Middle-Tier Certificate\" -header c:\\header_file -reportfile c:\\reportfile.txt"); - WScript.Echo(scriptName + "\"http://somelink\" -method POST -header hdrs.txt -reportfile reportfile2.txt -saveTo responsefile2 -ua \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36\" -body-file some.json"); - -} - -function parseArgs() { - // - if (ARGS.Length < 2) { - WScript.Echo("insufficient arguments"); - printHelp(); - WScript.Quit(43); - } - // !!! - url = ARGS.Item(1); - // !!! - if (ARGS.Length % 2 != 0) { - WScript.Echo("illegal arguments"); - printHelp(); - WScript.Quit(44); - } - - for (var i = 2; i < ARGS.Length - 1; i = i + 2) { - var arg = ARGS.Item(i).toLowerCase(); - var next = ARGS.Item(i + 1); - - - try { - switch (arg) { // the try-catch is set mainly because of the parseInts - case "-force": - if (next == "no") { - force = false; - } - break; - case "-escape": - if (next == "yes") { - escape = true; - } - break; - case "-saveto": - saveTo = next; - break; - case "-user": - case "-u": - user = next; - break; - case "-pass": - case "-password": - case "-p": - pass = next; - break; - case "-proxy": - proxy = next; - break; - case "-bypass": - bypass = next; - break; - case "-proxyuser": - case "-pu": - proxy_user = next; - break; - case "-proxypassword": - case "-pp": - proxy_pass = next; - break; - case "-ua": - ua = next; - break; - case "-ua-file": - ua = readFile(next); - break; - case "-body": - body = next; - break; - case "-usestream": - //WScript.Echo("~~"); - if (next.toLowerCase() === "yes") { - use_stream = true - }; - break; - case "-body-file": - body = readFile(next); - break; - case "-certificate": - certificate = next; - break; - case "-method": - switch (next.toLowerCase()) { - case "post": - http_method = 'POST'; - break; - case "get": - http_method = 'GET'; - break; - case "head": - http_method = 'HEAD'; - break; - case "put": - http_method = 'PUT'; - break; - case "options": - http_method = 'OPTIONS'; - break; - case "connect": - http_method = 'CONNECT'; - break; - case "patch": - http_method = 'PATCH'; - break; - case "delete": - http_method = 'DELETE'; - break; - default: - WScript.Echo("Invalid http method passed " + next); - WScript.Echo("possible values are GET,POST,DELETE,PUT,CONNECT,PATCH,HEAD,OPTIONS"); - WScript.Quit(1326); - break; - } - break; - case "-headers-file": - case "-header": - headers = readPropFile(next); - break; - case "-reportfile": - reportfile = next; - break; - //timeouts - case "-sendtimeout": - SEND_TIMEOUT = parseInt(next); - break; - case "-connecttimeout": - CONNECT_TIMEOUT = parseint(next); - break; - case "-resolvetimeout": - RESOLVE_TIMEOUT = parseInt(next); - break; - case "-receivetimeout": - RECEIVE_TIMEOUT = parseInt(next); - break; - - case "-autologonpolicy": - autologon_policy = parseInt(next); - if (autologon_policy > 2 || autologon_policy < 0) { - WScript.Echo("out of autologon policy range"); - WScript.Quit(87); - }; - break; - case "-proxysettings": - proxy_settings = parseInt(next); - if (proxy_settings > 2 || proxy_settings < 0) { - WScript.Echo("out of proxy settings range"); - WScript.Quit(87); - }; - break; - default: - WScript.Echo("Invalid command line switch: " + arg); - WScript.Quit(1405); - break; - } - } catch (err) { - WScript.Echo(err.message); - WScript.Quit(1348); - } - } -} - -stripTrailingSlash = function(path) { - while (path.substr(path.length - 1, path.length) == '\\') { - path = path.substr(0, path.length - 1); - } - return path; -} - -function existsItem(path) { - return FileSystemObj.FolderExists(path) || FileSystemObj.FileExists(path); -} - -function deleteItem(path) { - if (FileSystemObj.FileExists(path)) { - FileSystemObj.DeleteFile(path); - return true; - } else if (FileSystemObj.FolderExists(path)) { - FileSystemObj.DeleteFolder(stripTrailingSlash(path)); - return true; - } else { - return false; - } -} - -//------------------------------- -//---------------------- -//---------- -//----- -//-- -function request(url) { - - try { - - WinHTTPObj.Open(http_method, url, false); - if (proxy != 0 && bypass != 0) { - WinHTTPObj.SetProxy(proxy_settings, proxy, bypass); - } - - if (proxy != 0) { - WinHTTPObj.SetProxy(proxy_settings, proxy); - } - - if (user != 0 && pass != 0) { - WinHTTPObj.SetCredentials(user, pass, HTTPREQUEST_SETCREDENTIALS_FOR_SERVER); - } - - if (proxy_user != 0 && proxy_pass != 0) { - WinHTTPObj.SetCredentials(proxy_user, proxy_pass, HTTPREQUEST_SETCREDENTIALS_FOR_PROXY); - } - - if (certificate != 0) { - WinHTTPObj.SetClientCertificate(certificate); - } - - //set autologin policy - WinHTTPObj.SetAutoLogonPolicy(autologon_policy); - //set timeouts - WinHTTPObj.SetTimeouts(RESOLVE_TIMEOUT, CONNECT_TIMEOUT, SEND_TIMEOUT, RECEIVE_TIMEOUT); - - if (headers.length !== 0) { - WScript.Echo("Sending with headers:"); - for (var i = 0; i < headers.length; i++) { - WinHTTPObj.SetRequestHeader(headers[i][0], headers[i][1]); - WScript.Echo(headers[i][0] + ":" + headers[i][1]); - } - WScript.Echo(""); - } - - if (ua !== "") { - //user-agent option from: - //WinHttpRequestOption enumeration - // other options can be added like bellow - //https://msdn.microsoft.com/en-us/library/windows/desktop/aa384108(v=vs.85).aspx - WinHTTPObj.Option(0) = ua; - } - if (escape) { - WinHTTPObj.Option(3) = true; - } - if (trim(body) === "") { - WinHTTPObj.Send(); - } else { - WinHTTPObj.Send(body); - } - - var status = WinHTTPObj.Status - } catch (err) { - WScript.Echo(err.message); - WScript.Quit(666); - } - - //////////////////////// - // report // - //////////////////////// - - if (reportfile != "") { - - //var report_string=""; - var n = "\r\n"; - var report_string = "Status:" + n; - report_string = report_string + " " + WinHTTPObj.Status; - report_string = report_string + " " + WinHTTPObj.StatusText + n; - report_string = report_string + " " + n; - report_string = report_string + "Response:" + n; - report_string = report_string + WinHTTPObj.ResponseText + n; - report_string = report_string + " " + n; - report_string = report_string + "Headers:" + n; - report_string = report_string + WinHTTPObj.GetAllResponseHeaders() + n; - - WinHttpRequestOption_UserAgentString = 0; // Name of the user agent - WinHttpRequestOption_URL = 1; // Current URL - WinHttpRequestOption_URLCodePage = 2; // Code page - WinHttpRequestOption_EscapePercentInURL = 3; // Convert percents - // in the URL - // rest of the options can be seen and eventually added using this as reference - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384108(v=vs.85).aspx - - report_string = report_string + "URL:" + n; - report_string = report_string + WinHTTPObj.Option(WinHttpRequestOption_URL) + n; - - report_string = report_string + "URL Code Page:" + n; - report_string = report_string + WinHTTPObj.Option(WinHttpRequestOption_URLCodePage) + n; - - report_string = report_string + "User Agent:" + n; - report_string = report_string + WinHTTPObj.Option(WinHttpRequestOption_UserAgentString) + n; - - report_string = report_string + "Escapped URL:" + n; - report_string = report_string + WinHTTPObj.Option(WinHttpRequestOption_EscapePercentInURL) + n; - - prepareateFile(force, reportfile); - - WScript.Echo("Writing report to " + reportfile); - - writeFile(reportfile, report_string); - - } - - switch (status) { - case 200: - WScript.Echo("Status: 200 OK"); - break; - default: - WScript.Echo("Status: " + status); - WScript.Echo("Status was not OK. More info -> https://en.wikipedia.org/wiki/List_of_HTTP_status_codes"); - } - - //if as binary - if (saveTo.toLowerCase() === "con") { - WScript.Echo(WinHTTPObj.ResponseText); - } - if (saveTo !== "" && saveTo.toLowerCase() !== "con") { - prepareateFile(force, saveTo); - try { - - if (use_stream) { - writeBinFile(saveTo, WinHTTPObj.ResponseStream); - } else { - writeBinFile(saveTo, WinHTTPObj.ResponseBody); - } - - } catch (err) { - WScript.Echo("Failed to save the file as binary.Attempt to save it as text"); - AdoDBObj.Close(); - prepareateFile(true, saveTo); - writeFile(saveTo, WinHTTPObj.ResponseText); - } - } - WScript.Quit(status); -} - -//-- -//----- -//---------- -//---------------------- -//------------------------------- - -function prepareateFile(force, file) { - if (force && existsItem(file)) { - if (!deleteItem(file)) { - WScript.Echo("Unable to delete " + file); - WScript.Quit(8); - } - } else if (existsItem(file)) { - WScript.Echo("Item " + file + " already exist"); - WScript.Quit(9); - } -} - -function writeBinFile(fileName, data) { - AdoDBObj.Type = 1; - AdoDBObj.Open(); - AdoDBObj.Position = 0; - AdoDBObj.Write(data); - AdoDBObj.SaveToFile(fileName, 2); - AdoDBObj.Close(); -} - -function writeFile(fileName, data) { - AdoDBObj.Type = 2; - AdoDBObj.CharSet = "iso-8859-1"; - AdoDBObj.Open(); - AdoDBObj.Position = 0; - AdoDBObj.WriteText(data); - AdoDBObj.SaveToFile(fileName, 2); - AdoDBObj.Close(); -} - - -function readFile(fileName) { - //check existence - try { - if (!FileSystemObj.FileExists(fileName)) { - WScript.Echo("file " + fileName + " does not exist!"); - WScript.Quit(13); - } - if (FileSystemObj.GetFile(fileName).Size === 0) { - return ""; - } - var fileR = FileSystemObj.OpenTextFile(fileName, 1); - var content = fileR.ReadAll(); - fileR.Close(); - return content; - } catch (err) { - WScript.Echo("Error while reading file: " + fileName); - WScript.Echo(err.message); - WScript.Echo("Will return empty string"); - return ""; - } -} - -function readPropFile(fileName) { - //check existence - resultArray = []; - if (!FileSystemObj.FileExists(fileName)) { - WScript.Echo("(headers)file " + fileName + " does not exist!"); - WScript.Quit(15); - } - if (FileSystemObj.GetFile(fileName).Size === 0) { - return resultArray; - } - var fileR = FileSystemObj.OpenTextFile(fileName, 1); - var line = ""; - var k = ""; - var v = ""; - var lineN = 0; - var index = 0; - try { - WScript.Echo("parsing headers form " + fileName + " property file "); - while (!fileR.AtEndOfStream) { - line = fileR.ReadLine(); - lineN++; - index = line.indexOf(":"); - if (line.indexOf("#") === 0 || trim(line) === "") { - continue; - } - if (index === -1 || index === line.length - 1 || index === 0) { - WScript.Echo("Invalid line " + lineN); - WScript.Quit(93); - } - k = trim(line.substring(0, index)); - v = trim(line.substring(index + 1, line.length)); - resultArray.push([k, v]); - } - fileR.Close(); - return resultArray; - } catch (err) { - WScript.Echo("Error while reading headers file: " + fileName); - WScript.Echo(err.message); - WScript.Echo("Will return empty array"); - return resultArray; - } -} - -function trim(str) { - return str.replace(/^\s+/, '').replace(/\s+$/, ''); -} - -function main() { - parseArgs(); - request(url); -} -main(); From a11dc0979082fc3b6f4107f6716a5fbf7128dd43 Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 23 May 2020 22:05:44 +0200 Subject: [PATCH 63/79] Build webui --- .../Windows-msys2/build/build-webui.bat | 37 +++++++++++++++++++ build_scripts/Windows-msys2/build/build.bat | 7 +++- .../Windows-msys2/build/env-base.bat | 7 ++++ build_scripts/Windows-msys2/build/env.bat | 1 + build_scripts/Windows-msys2/tools/webui.bat | 20 ++++++++++ libretroshare/src/libretroshare.pro | 2 +- .../src/gui/settings/rsharesettings.cpp | 2 +- 7 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 build_scripts/Windows-msys2/build/build-webui.bat create mode 100644 build_scripts/Windows-msys2/tools/webui.bat diff --git a/build_scripts/Windows-msys2/build/build-webui.bat b/build_scripts/Windows-msys2/build/build-webui.bat new file mode 100644 index 000000000..d561235c1 --- /dev/null +++ b/build_scripts/Windows-msys2/build/build-webui.bat @@ -0,0 +1,37 @@ +@echo off + +setlocal + +:: Initialize environment +call "%~dp0..\env.bat" +if errorlevel 1 goto error_env +call "%EnvPath%\env.bat" +if errorlevel 1 goto error_env +call "%EnvPath%\env.bat" +if errorlevel 1 goto error_env +call "%EnvPath%\env-msys2.bat" +if errorlevel 1 goto error_env + +:: Initialize base environment +call "%~dp0env-base.bat" %* +if errorlevel 2 exit /B 2 +if errorlevel 1 goto error_env + +:: Initialize environment +call "%~dp0env.bat" %* +if errorlevel 2 exit /B 2 +if errorlevel 1 goto error_env + +call "%~dp0..\tools\webui.bat" + +:error + +title %COMSPEC% + +if errorlevel 1 echo.& echo Webui generation failed& echo. +exit /B %ERRORLEVEL% + +:error_env +echo Failed to initialize environment. +endlocal +exit /B 1 diff --git a/build_scripts/Windows-msys2/build/build.bat b/build_scripts/Windows-msys2/build/build.bat index 84cb0c83c..8ca2f6f1f 100644 --- a/build_scripts/Windows-msys2/build/build.bat +++ b/build_scripts/Windows-msys2/build/build.bat @@ -18,7 +18,7 @@ if errorlevel 2 exit /B 2 if errorlevel 1 goto error_env :: Install needed things -%EnvMSYS2Cmd% "pacman --noconfirm --needed -S make git mingw-w64-%RsMSYS2Architecture%-toolchain mingw-w64-%RsMSYS2Architecture%-qt5 mingw-w64-%RsMSYS2Architecture%-miniupnpc mingw-w64-%RsMSYS2Architecture%-sqlcipher mingw-w64-%RsMSYS2Architecture%-libmicrohttpd mingw-w64-%RsMSYS2Architecture%-xapian-core mingw-w64-%RsMSYS2Architecture%-cmake mingw-w64-%RsMSYS2Architecture%-rapidjson" +%EnvMSYS2Cmd% "pacman --noconfirm --needed -S make git mingw-w64-%RsMSYS2Architecture%-toolchain mingw-w64-%RsMSYS2Architecture%-qt5 mingw-w64-%RsMSYS2Architecture%-miniupnpc mingw-w64-%RsMSYS2Architecture%-sqlcipher mingw-w64-%RsMSYS2Architecture%-xapian-core mingw-w64-%RsMSYS2Architecture%-cmake mingw-w64-%RsMSYS2Architecture%-rapidjson" :: Plugins if "%ParamPlugins%"=="1" %EnvMSYS2Cmd% "pacman --noconfirm --needed -S mingw-w64-%RsMSYS2Architecture%-speex mingw-w64-%RsMSYS2Architecture%-speexdsp mingw-w64-%RsMSYS2Architecture%-curl mingw-w64-%RsMSYS2Architecture%-libxslt mingw-w64-%RsMSYS2Architecture%-opencv mingw-w64-%RsMSYS2Architecture%-ffmpeg" @@ -71,6 +71,11 @@ title Build - %SourceName%-%RsBuildConfig% [make] %EnvMSYS2Cmd% "make -j %NUMBER_OF_PROCESSORS%" +:: Webui +if "%ParamWebui%"=="1" ( + call "%~dp0..\tools\webui.bat" +) + :error popd diff --git a/build_scripts/Windows-msys2/build/env-base.bat b/build_scripts/Windows-msys2/build/env-base.bat index 0140196ec..4f1236fb7 100644 --- a/build_scripts/Windows-msys2/build/env-base.bat +++ b/build_scripts/Windows-msys2/build/env-base.bat @@ -6,6 +6,7 @@ set ParamDebug=0 set ParamAutologin=0 set ParamPlugins=0 set ParamTor=0 +set ParamWebui=0 set RS_QMAKE_CONFIG= :parameter_loop @@ -25,6 +26,8 @@ if "%~1" NEQ "" ( set ParamPlugins=1 ) else if "%%~a"=="tor" ( set ParamTor=1 + ) else if "%%~a"=="webui" ( + set ParamWebui=1 ) else if "%%~a"=="CONFIG+" ( set RS_QMAKE_CONFIG=%RS_QMAKE_CONFIG% %1 ) else ( @@ -75,6 +78,9 @@ if "%ParamTor%"=="1" ( set RsType= ) +if "%ParamWebui%"=="1" ( + set RS_QMAKE_CONFIG=%RS_QMAKE_CONFIG% "CONFIG+=rs_jsonapi" "CONFIG+=rs_webui" +) exit /B 0 @@ -89,6 +95,7 @@ echo. echo Optional parameter (need clean when changed) echo autologin Build with autologin echo plugins Build plugins +echo webui Enable JsonAPI and pack webui files echo. echo Parameter for pack echo tor Pack tor version diff --git a/build_scripts/Windows-msys2/build/env.bat b/build_scripts/Windows-msys2/build/env.bat index d7dcdf130..8443d6218 100644 --- a/build_scripts/Windows-msys2/build/env.bat +++ b/build_scripts/Windows-msys2/build/env.bat @@ -20,6 +20,7 @@ set RsBuildPath=%BuildPath%\Qt-%QtVersion%-%RsArchitecture%-%RsBuildConfig% set RsDeployPath=%DeployPath%\Qt-%QtVersion%%RsType%-%RsArchitecture%-%RsBuildConfig% set RsPackPath=%DeployPath% set RsArchiveAdd= +set RsWebuiPath=%RootPath%\%SourceName%-webui if not exist "%~dp0env-mod.bat" goto no_mod call "%~dp0env-mod.bat" diff --git a/build_scripts/Windows-msys2/tools/webui.bat b/build_scripts/Windows-msys2/tools/webui.bat new file mode 100644 index 000000000..f39da666a --- /dev/null +++ b/build_scripts/Windows-msys2/tools/webui.bat @@ -0,0 +1,20 @@ +setlocal + +echo. +echo === webui +echo. +title Build webui + +if not exist "%RsWebuiPath%" ( + echo Checking out webui source into %RsWebuiPath% + %EnvMSYS2Cmd% "pacman --noconfirm --needed -S git" + git clone https://github.com/RetroShare/RSNewWebUI.git "%RsWebuiPath%" +) else ( + echo Webui source found at %RsWebuiPath% +) + +pushd "%RsWebuiPath%\webui-src\make-src" +%EnvMSYS2Cmd% "sh build.sh" +popd + +endlocal \ No newline at end of file diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index c7b38ce0b..3f9dde680 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -870,7 +870,7 @@ rs_jsonapi { genrestbedheader.name = Generating restbed header. genrestbedheader.input = genrestbedlib.output genrestbedheader.output = $${RESTBED_HEADER_FILE} - genrestbedheader.CONFIG += target_predeps combine no_link + genrestbedheader.CONFIG += target_predeps no_link genrestbedheader.variable_out = HEADERS genrestbedheader.commands = cd $${RESTBED_BUILD_PATH} && $(MAKE) install QMAKE_EXTRA_COMPILERS += genrestbedheader diff --git a/retroshare-gui/src/gui/settings/rsharesettings.cpp b/retroshare-gui/src/gui/settings/rsharesettings.cpp index 2d4a33c7b..ea0bbcb69 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.cpp +++ b/retroshare-gui/src/gui/settings/rsharesettings.cpp @@ -1157,7 +1157,7 @@ void RshareSettings::setWebinterfaceEnabled(bool enabled) QString RshareSettings::getWebinterfaceFilesDirectory() { #ifdef WINDOWS_SYS - return valueFromGroup("Webinterface","directory","data/webui/").toString(); + return valueFromGroup("Webinterface","directory","./webui/").toString(); #else return valueFromGroup("Webinterface","directory","/usr/share/retroshare/webui/").toString(); #endif From e4f94dc99fc7bf3614d07cff2467e08ce1d01c84 Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 23 May 2020 22:17:49 +0200 Subject: [PATCH 64/79] Pack webui --- build_scripts/Windows-msys2/build/env-base.bat | 2 +- build_scripts/Windows-msys2/build/pack.bat | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/build_scripts/Windows-msys2/build/env-base.bat b/build_scripts/Windows-msys2/build/env-base.bat index 4f1236fb7..8f80e8681 100644 --- a/build_scripts/Windows-msys2/build/env-base.bat +++ b/build_scripts/Windows-msys2/build/env-base.bat @@ -86,7 +86,7 @@ exit /B 0 :usage echo. -echo Usage: 32^|64 release^|debug [version autologin plugins] +echo Usage: 32^|64 release^|debug [version autologin plugins webui] echo. echo Mandatory parameter echo 32^|64 32-bit or 64-bit Version diff --git a/build_scripts/Windows-msys2/build/pack.bat b/build_scripts/Windows-msys2/build/pack.bat index b023f5d5b..e759b7980 100644 --- a/build_scripts/Windows-msys2/build/pack.bat +++ b/build_scripts/Windows-msys2/build/pack.bat @@ -166,10 +166,15 @@ copy "%SourcePath%\retroshare-gui\src\changelog.txt" "%RsDeployPath%" %Quite% echo copy buildinfo.txt copy "%RsBuildPath%\buildinfo.txt" "%RsDeployPath%" %Quite% -if exist "%SourcePath%\libresapi\src\webui" ( - echo copy webui - mkdir "%RsDeployPath%\webui" - xcopy /S "%SourcePath%\libresapi\src\webui" "%RsDeployPath%\webui" %Quite% +if "%ParamWebui%"=="1" ( + if exist "%RsWebuiPath%\webui" ( + echo copy webui + mkdir "%RsDeployPath%\webui" + xcopy /S "%RsWebuiPath%\webui" "%RsDeployPath%\webui" %Quite% + ) else ( + %cecho% error "Webui is enabled, but no webui data found at %RsWebuiPath%\webui" + goto error + ) ) if "%ParamTor%"=="1" ( From 735a123a02236d551f95b3f2e641e051a3ba9f10 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sun, 24 May 2020 00:32:24 +0200 Subject: [PATCH 65/79] restore 1.1 factor in ft/fttransfermodule --- libretroshare/src/ft/fttransfermodule.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/ft/fttransfermodule.cc b/libretroshare/src/ft/fttransfermodule.cc index ab9900762..8c6ae1f08 100644 --- a/libretroshare/src/ft/fttransfermodule.cc +++ b/libretroshare/src/ft/fttransfermodule.cc @@ -789,16 +789,16 @@ bool ftTransferModule::locked_tickPeerTransfer(peerInfo &info) std::cerr << std::endl; #endif - // cap next_req to desiredRate in order to respect the bandwidth limit and to avoid clogging our outqueue - if (next_req > info.desiredRate) + if (next_req > info.desiredRate * 1.1) { - next_req = info.desiredRate; + next_req = info.desiredRate * 1.1; #ifdef FT_DEBUG std::cerr << "locked_tickPeerTransfer() Reached MaxRate: next_req: " << next_req; std::cerr << std::endl; #endif } + if (next_req > FT_TM_MAX_PEER_RATE) { next_req = FT_TM_MAX_PEER_RATE; From 178b37a95f6682026747f931b714a6c8307ff979 Mon Sep 17 00:00:00 2001 From: defnax Date: Sun, 24 May 2020 02:28:54 +0200 Subject: [PATCH 66/79] small ui fixes & changes * Update the context menu icons for attachments * Display the File type icon for attachments * on reply load the tags --- retroshare-gui/src/gui/icons.qrc | 1 + .../src/gui/icons/mail/downloadall.png | Bin 0 -> 2986 bytes retroshare-gui/src/gui/msgs/MessageComposer.cpp | 6 ++++++ retroshare-gui/src/gui/msgs/MessageWidget.cpp | 6 ++++-- retroshare-gui/src/gui/msgs/MessagesDialog.cpp | 3 ++- 5 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 retroshare-gui/src/gui/icons/mail/downloadall.png diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 311530b03..6e4bd7569 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -301,6 +301,7 @@ icons/png/arrow-left.png icons/png/next-unread.png icons/mail/compose.png + icons/mail/downloadall.png icons/mail/delete.png icons/mail/tags.png icons/mail/quote.png diff --git a/retroshare-gui/src/gui/icons/mail/downloadall.png b/retroshare-gui/src/gui/icons/mail/downloadall.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d31d3d0a1c6242f3c55cbbe56cb96f0d4ed7a7 GIT binary patch literal 2986 zcmZ`*c{r5q7k)B}EvgTxNFg=ZLyGJfYnHKxN{c;FNHmr#DN9nJS*(!?g-8lX3&}oa z42t5T5(!yGgWvOxx~}h^-*vrnp65B|zR$VOdERSgu3B3f3-E2>0{{q^ni$%^H46Fg zprHNrDU}5mw5Ps>J^*DY{Oscxc;0@}#Kr=Eu$>SW3&0|R{|Z2`G5}+40BGI@Ks12* zjGzSo*NF8YJ3ItnNDMTEj-t|0i0$U0bc1X<*Xof%han7=4lEOW%n!-R) z7=Xk83y~RRXnt4G6Rtf1;9}wV}TU7fe%dH4F`fC z{{a5%(eO?=vs(3INKgqP23jnfWcDCZ0=c!8)s|s$aHAij!^RN|rwU^KL|64Ah2YHL zSP(yw4Q`MJz5{II?`IyvqCv9R<5fcj(-Qm3Bk;q`vO49 z;cg9l(Px8fENy{GT-ozN-%Y3QmB#MbQZai875#Yg&VQfq$?!AldP3{hh77zGeDO*0 z%{I-ZbsEa8LhBU-SS|l7RJIE*cZ#UTZ0w3!L!vWo^oogglew<DSZ#{SlWBWeRBNd&;6G|La;x4$}@}@6mkA?M(RyUT4vT=bWZO5#{9R%*he*04NrMrRu?>= z-nz#0{E2*htT|zBYzVGkwwk~LZ-B|+KmY_^BcC;Ca)M&e$sJ^Bf#?1gBf4>qgd1b- zECASeQ$u~b3w;w5Z#@xv;YNSHq3C*{H2em&Kz(cUOc^e1op(Wbc~|qH@;m`^Ir+}+ z>kjf#X*-HzrTkJ)r^y(;k3OyRexsj^!uxdAz`=owkC!}u)T)O3Jjm8<)BeJ4yXZd( z*8yXbl(2tkytQH6n0el_62e_o$E;V@9?^yHr11`l4_|7w68iB&ebaq*RotRLtc<3(>}G9RW~Y?jB=X|5SJ%QLb@)-85D+gCQ=HaMSWBjJCiv z<iW2dUU#l8c-j7r z^=r&qLFv@+h_wd@CAW#flRm1Vw_i5+7Eg)rYsWp@8}dw$CG6@S7x^j~$FNYVqNF+= zm*ppv;Hz>>s=Bs{O23e)nws`Mc4a8Z?QAWoRxB}ndTO$UAN|hx?Wk*wxO-`IyzYkS zNsr)TS5=(STE~8r%s5C#9Ge64Icv=rrOz@35*OyDh;j3;*52r)W^9yPMrjcZB#1od z-7fEk7Jo|DSF#B@I+7yFF^ylZeP>87V~^@crr~0KHhP~CD_Xz88=)gfr&wdH$Op7B zEGw7KLgl>z(e!R|wU#Z)RbAUR*~(;VbNv#v>{WV6{qg1*2UctiK-D#QF5d{&`C{BR zI%<|-A+9T1 z@oiBI{wgkJG>3W zOd)Jfc1Bmui%nho8xPc~mz-9gf1|Ljz)K))bm;CmQ}V}q-}D`BvDkxo3&VF)t1*}+2_{O=trbG#*>Zf{ghsKS?qm7OfSHRT*mdN;0s3g1Pr$~7FLLur{O6sKeQ|F z<#l)vJ}gcMmz0rf&D`r~k+t@ZM{{c%17^|&oR8Y(JvlZwCT2o6$}8Cs@H>>L7pS!K zpkbx{A??kBJ}(J=Kk%Bc;O0mAD(0M@V)R?^m&^9*TNBBZ?qLZliY;;-DV+%&N1oH? z{5{G2ck(KgOWmX9_?mB6Bl=nJ}GT*$uoH- z;b0#;N}%Xu_mro^R>G6i!6I`Ugc3D!sLr-Oc@gEyrO$vfZ2;~weYxYx95);;AJ8J})$*y>5k z>#X1zp~pKsTiyx7@;@#zKYYJFn@Z24=kSb-C>ar-@_0_^&!Cq!cDiuXtCKFk2}#es;$Cv}cYm`_Xmn60f~NI&n`1 zx1-v7n)(Jv`!5JuEn+>c&nuL-R)$Jhy2PIU_8b*v-lKoYRBp>R8`0bd%y*T5@O7-+ z=UHP?c8qo8wXOxL(}{V-J;Wu_xMCcO z;+j9~sHQj_`*h5Xs7I*F3N(&X>$~NVa^K;X%J`Iu`1UgK5hRH8pt|H}054F=BA zolV=KSw_?aCu(oDvEdA__x>c4_(PL|WexMr^Ha%L>a|^4hs0X1{sjF#=U2$7p zJ~Je?v`xCOf8i;Y>Z9IRbH|wF{#xP@k-EkR!=v{X*C&5$-?c-kgSRDNzXZ|XL3l|q zdu;gCydrI`&1_x2&{S2HQ&!egR!+M48UFSC55dp>l($Fd|0gW99ZrIT%}51Xe~+M$ n7lg9(x75&e7QhsP{fgoUtw={fc;1>Nq<1>$H literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.cpp b/retroshare-gui/src/gui/msgs/MessageComposer.cpp index 6d33e6ca6..92f4de457 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.cpp +++ b/retroshare-gui/src/gui/msgs/MessageComposer.cpp @@ -1206,6 +1206,12 @@ MessageComposer *MessageComposer::replyMsg(const std::string &msgId, bool all) // needed to send system flags with reply msgComposer->msgFlags = (msgInfo.msgflags & RS_MSG_SYSTEM); + MsgTagInfo tagInfo; + rsMail->getMessageTag(msgId, tagInfo); + + msgComposer->m_tagIds = tagInfo.tagIds; + msgComposer->showTagLabels(); + msgComposer->calculateTitle(); /* window will destroy itself! */ diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.cpp b/retroshare-gui/src/gui/msgs/MessageWidget.cpp index 3c085c3c8..bfa94abba 100644 --- a/retroshare-gui/src/gui/msgs/MessageWidget.cpp +++ b/retroshare-gui/src/gui/msgs/MessageWidget.cpp @@ -36,6 +36,7 @@ #include "gui/common/TagDefs.h" #include "gui/common/PeerDefs.h" #include "gui/common/Emoticons.h" +#include "gui/common/FilesDefs.h" #include "gui/settings/rsharesettings.h" #include "MessageComposer.h" #include "MessageWidget.h" @@ -51,8 +52,8 @@ #include /* Images for context menu icons */ -#define IMAGE_DOWNLOAD ":/images/start.png" -#define IMAGE_DOWNLOADALL ":/images/startall.png" +#define IMAGE_DOWNLOAD ":/icons/png/download.png" +#define IMAGE_DOWNLOADALL ":/icons/mail/downloadall.png" #define COLUMN_FILE_NAME 0 #define COLUMN_FILE_SIZE 1 @@ -555,6 +556,7 @@ void MessageWidget::fill(const std::string &msgId) for (it = recList.begin(); it != recList.end(); ++it) { QTreeWidgetItem *item = new QTreeWidgetItem; item->setText(COLUMN_FILE_NAME, QString::fromUtf8(it->fname.c_str())); + item->setIcon(COLUMN_FILE_NAME, FilesDefs::getIconFromFileType(it->fname.c_str())); item->setText(COLUMN_FILE_SIZE, misc::friendlyUnit(it->size)); item->setData(COLUMN_FILE_SIZE, Qt::UserRole, QVariant(qulonglong(it->size)) ); item->setText(COLUMN_FILE_HASH, QString::fromStdString(it->hash.toStdString())); diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 37a6ee319..5d6bc87c5 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -53,6 +53,7 @@ #include /* Images for context menu icons */ +#define IMAGE_MAIL ":/icons/png/message.png" #define IMAGE_MESSAGE ":/icons/mail/compose.png" #define IMAGE_MESSAGEREMOVE ":/icons/mail/delete.png" #define IMAGE_STAR_ON ":/images/star-on-16.png" @@ -766,7 +767,7 @@ void MessagesDialog::openAsTab() return; } - ui.tabWidget->addTab(msgWidget, msgWidget->subject(true)); + ui.tabWidget->addTab(msgWidget,QIcon(IMAGE_MAIL), msgWidget->subject(true)); ui.tabWidget->setCurrentWidget(msgWidget); connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved())); From 301def6018c0913728f1b7721c2bdaefb03ec85a Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 24 May 2020 23:40:26 +0200 Subject: [PATCH 67/79] Revert "bandwidth control improvement" --- libretroshare/src/pqi/pqihandler.cc | 173 +++++++++++++++++----------- 1 file changed, 105 insertions(+), 68 deletions(-) diff --git a/libretroshare/src/pqi/pqihandler.cc b/libretroshare/src/pqi/pqihandler.cc index 72d7dbf9d..1e86fa9d1 100644 --- a/libretroshare/src/pqi/pqihandler.cc +++ b/libretroshare/src/pqi/pqihandler.cc @@ -42,19 +42,39 @@ using std::dec; #include #endif +//#define PQI_HDL_DEBUG_UR 1 + +#ifdef PQI_HDL_DEBUG_UR +static double getCurrentTS() +{ + +#ifndef WINDOWS_SYS + struct timeval cts_tmp; + gettimeofday(&cts_tmp, NULL); + double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0; +#else + struct _timeb timebuf; + _ftime( &timebuf); + double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0; +#endif + return cts; +} +#endif + struct RsLog::logInfo pqihandlerzoneInfo = {RsLog::Default, "pqihandler"}; #define pqihandlerzone &pqihandlerzoneInfo //static const int PQI_HANDLER_NB_PRIORITY_LEVELS = 10 ; //static const float PQI_HANDLER_NB_PRIORITY_RATIO = 2 ; -//#define UPDATE_RATES_DEBUG 1 -// #define DEBUG_TICK 1 -// #define RSITEM_DEBUG 1 +/**** +#define DEBUG_TICK 1 +#define RSITEM_DEBUG 1 +****/ pqihandler::pqihandler() : coreMtx("pqihandler") { - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ // setup minimal total+individual rates. rateIndiv_out = 0.01; @@ -77,7 +97,7 @@ int pqihandler::tick() int moreToTick = 0; { - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ // tick all interfaces... std::map::iterator it; @@ -107,13 +127,9 @@ int pqihandler::tick() if(now > mLastRateCapUpdate + 5) { - std::map rateMap; - std::map::iterator it; - - // every 5 secs, update the max rates for all modules - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ for(std::map::iterator it = mods.begin(); it != mods.end(); ++it) { // This is rather inelegant, but pqihandler has searchModules that are dynamically allocated, so the max rates @@ -133,7 +149,7 @@ int pqihandler::tick() bool pqihandler::queueOutRsItem(RsItem *item) { - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ uint32_t size ; locked_HandleRsItem(item, size); @@ -150,7 +166,7 @@ bool pqihandler::queueOutRsItem(RsItem *item) int pqihandler::status() { std::map::iterator it; - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ { // for output std::string out = "pqihandler::status() Active Modules:\n"; @@ -176,7 +192,7 @@ int pqihandler::status() bool pqihandler::AddSearchModule(SearchModule *mod) { - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ // if peerid used -> error. //std::map::iterator it; if (mod->peerid != mod->pqi->PeerId()) @@ -207,7 +223,7 @@ bool pqihandler::AddSearchModule(SearchModule *mod) bool pqihandler::RemoveSearchModule(SearchModule *mod) { - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) { @@ -297,7 +313,7 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat total.mQueueOut = 0; /* Lock once rates have been retrieved */ - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) @@ -324,6 +340,10 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat // internal fn to send updates int pqihandler::UpdateRates() { +#ifdef PQI_HDL_DEBUG_UR + uint64_t t_now; +#endif + std::map::iterator it; float avail_in = getMaxRate(true); @@ -333,15 +353,18 @@ int pqihandler::UpdateRates() float used_bw_out = 0; /* Lock once rates have been retrieved */ - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ int num_sm = mods.size(); float used_bw_in_table[num_sm]; /* table of in bandwidth currently used by each module */ float used_bw_out_table[num_sm]; /* table of out bandwidth currently used by each module */ - // loop through modules to get the used bandwidth -#ifdef UPDATE_RATES_DEBUG - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Looping through modules" << std::endl; + int effectiveUploadsSm = 0; + int effectiveDownloadsSm = 0; + + // loop through modules to get the used bandwith and the number of modules that are affectively transfering +#ifdef PQI_HDL_DEBUG_UR + std::cerr << "Looping through modules" << std::endl; #endif int index = 0; @@ -349,33 +372,49 @@ int pqihandler::UpdateRates() for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); + float crate_in = mod -> pqi -> getRate(true); traffInSum += mod -> pqi -> getTraffic(true); traffOutSum += mod -> pqi -> getTraffic(false); - float crate_in = mod -> pqi -> getRate(true); +#ifdef PQI_HDL_DEBUG_UR + if(crate_in > 0.0) + std::cerr << " got in rate for peer " << it->first << " : " << crate_in << std::endl; +#endif + + if ((crate_in > 0.01 * avail_in) || (crate_in > 0.1)) + { + ++effectiveDownloadsSm; + } + float crate_out = mod -> pqi -> getRate(false); + if ((crate_out > 0.01 * avail_out) || (crate_out > 0.1)) + { + ++effectiveUploadsSm; + } used_bw_in += crate_in; used_bw_out += crate_out; - /* fill the table of used bandwidths */ + /* fill the table of bandwidth */ used_bw_in_table[index] = crate_in; used_bw_out_table[index] = crate_out; - ++index; } -#ifdef UPDATE_RATES_DEBUG - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; +#ifdef PQI_HDL_DEBUG_UR + t_now = 1000 * getCurrentTS(); + std::cerr << dec << t_now << " pqihandler::UpdateRates(): Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; #endif /* Sort the used bw in/out table in ascending order */ std::sort(used_bw_in_table, used_bw_in_table + num_sm); std::sort(used_bw_out_table, used_bw_out_table + num_sm); -#ifdef UPDATE_RATES_DEBUG - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates used_bw_out " << used_bw_out << std::endl; +#ifdef PQI_HDL_DEBUG_UR + t_now = 1000 * getCurrentTS(); + std::cerr << dec << t_now << " pqihandler::UpdateRates(): Done." << std::endl; + std::cerr << dec << t_now << " pqihandler::UpdateRates(): used_bw_out " << used_bw_out << std::endl; #endif /* Calculate the optimal out_max value, taking into account avail_out and the out bw requested by modules */ @@ -402,8 +441,9 @@ int pqihandler::UpdateRates() } } -#ifdef UPDATE_RATES_DEBUG - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; +#ifdef PQI_HDL_DEBUG_UR + t_now = 1000 * getCurrentTS(); + std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; #endif /* Allocate only half the remaining out bw, if any, to make it smoother */ @@ -433,70 +473,67 @@ int pqihandler::UpdateRates() } } -#ifdef UPDATE_RATES_DEBUG - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; +#ifdef PQI_HDL_DEBUG_UR + t_now = 1000 * getCurrentTS(); + std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; #endif /* Allocate only half the remaining in bw, if any, to make it smoother */ in_max_bw = in_max_bw + in_remaining_bw / 2; - // store current total in and ou used bw + +#ifdef DEBUG_QOS +// std::cerr << "Totals (In) Used B/W " << used_bw_in; +// std::cerr << " Available B/W " << avail_in; +// std::cerr << " Effective transfers " << effectiveDownloadsSm << std::endl; +// std::cerr << "Totals (Out) Used B/W " << used_bw_out; +// std::cerr << " Available B/W " << avail_out; +// std::cerr << " Effective transfers " << effectiveUploadsSm << std::endl; +#endif + locked_StoreCurrentRates(used_bw_in, used_bw_out); -#ifdef UPDATE_RATES_DEBUG - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; + //computing average rates for effective transfers + float max_in_effective = avail_in / num_sm; + if (effectiveDownloadsSm != 0) { + max_in_effective = avail_in / effectiveDownloadsSm; + } + float max_out_effective = avail_out / num_sm; + if (effectiveUploadsSm != 0) { + max_out_effective = avail_out / effectiveUploadsSm; + } + + //modify the in and out limit +#ifdef PQI_HDL_DEBUG_UR + t_now = 1000 * getCurrentTS(); + std::cerr << dec << t_now << " pqihandler::UpdateRates(): setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; #endif - // retrieve down (from peer point of view) bandwidth limits set by peers in their own settings - std::map rateMap; - rsConfig->getAllBandwidthRates(rateMap); - std::map::iterator rateMap_it; - -#ifdef UPDATE_RATES_DEBUG - // Dump RsConfigurationDataRates - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates RsConfigDataRates dump" << std::endl; - for (rateMap_it = rateMap.begin(); rateMap_it != rateMap.end(); rateMap_it++) - RsDbg () << "UPDATE_RATES pqihandler::UpdateRates PeerId " << rateMap_it->first.toStdString() << " mAllowedOut " << rateMap_it->second.mAllowedOut << std::endl; -#endif - - // update max rates taking into account the limits set by peers in their own settings for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - - // for our down bandwidth we set the max to the calculated value without taking into account the max set by peers: they will control their up bw on their side - mod -> pqi -> setMaxRate(true, in_max_bw); - - // for our up bandwidth we limit to the maximum down bw provided by peers via BwCtrl because we don't want to clog our outqueues, the SSL buffers, and our friends inbound queues - if ((rateMap_it = rateMap.find(mod->pqi->PeerId())) != rateMap.end()) - { - if (rateMap_it->second.mAllowedOut > 0) - { - if (out_max_bw > rateMap_it->second.mAllowedOut) - mod -> pqi -> setMaxRate(false, rateMap_it->second.mAllowedOut); - else - mod -> pqi -> setMaxRate(false, out_max_bw); - } - else - mod -> pqi -> setMaxRate(false, out_max_bw); - } + + mod -> pqi -> setMaxRate(true, in_max_bw); + mod -> pqi -> setMaxRate(false, out_max_bw); } -#ifdef UPDATE_RATES_DEBUG - // dump maxRates + + //cap the rates for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - RsDbg() << "UPDATE_RATES pqihandler::UpdateRates PeerID " << (mod ->pqi -> PeerId()).toStdString() << " new bandwidth limits up " << mod -> pqi -> getMaxRate(false) << " down " << mod -> pqi -> getMaxRate(true) << std::endl; + if (mod -> pqi -> getMaxRate(false) < max_out_effective) mod -> pqi -> setMaxRate(false, max_out_effective); + if (mod -> pqi -> getMaxRate(false) > avail_out) mod -> pqi -> setMaxRate(false, avail_out); + if (mod -> pqi -> getMaxRate(true) < max_in_effective) mod -> pqi -> setMaxRate(true, max_in_effective); + if (mod -> pqi -> getMaxRate(true) > avail_in) mod -> pqi -> setMaxRate(true, avail_in); } -#endif return 1; } void pqihandler::getCurrentRates(float &in, float &out) { - RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ + RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ in = rateTotal_in; out = rateTotal_out; From b294a34d11055402ea4166f951cc1609f3688cfa Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 25 May 2020 20:28:50 +0200 Subject: [PATCH 68/79] Revert "Revert "bandwidth control improvement"" --- libretroshare/src/pqi/pqihandler.cc | 173 +++++++++++----------------- 1 file changed, 68 insertions(+), 105 deletions(-) diff --git a/libretroshare/src/pqi/pqihandler.cc b/libretroshare/src/pqi/pqihandler.cc index 1e86fa9d1..72d7dbf9d 100644 --- a/libretroshare/src/pqi/pqihandler.cc +++ b/libretroshare/src/pqi/pqihandler.cc @@ -42,39 +42,19 @@ using std::dec; #include #endif -//#define PQI_HDL_DEBUG_UR 1 - -#ifdef PQI_HDL_DEBUG_UR -static double getCurrentTS() -{ - -#ifndef WINDOWS_SYS - struct timeval cts_tmp; - gettimeofday(&cts_tmp, NULL); - double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0; -#else - struct _timeb timebuf; - _ftime( &timebuf); - double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0; -#endif - return cts; -} -#endif - struct RsLog::logInfo pqihandlerzoneInfo = {RsLog::Default, "pqihandler"}; #define pqihandlerzone &pqihandlerzoneInfo //static const int PQI_HANDLER_NB_PRIORITY_LEVELS = 10 ; //static const float PQI_HANDLER_NB_PRIORITY_RATIO = 2 ; -/**** -#define DEBUG_TICK 1 -#define RSITEM_DEBUG 1 -****/ +//#define UPDATE_RATES_DEBUG 1 +// #define DEBUG_TICK 1 +// #define RSITEM_DEBUG 1 pqihandler::pqihandler() : coreMtx("pqihandler") { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // setup minimal total+individual rates. rateIndiv_out = 0.01; @@ -97,7 +77,7 @@ int pqihandler::tick() int moreToTick = 0; { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // tick all interfaces... std::map::iterator it; @@ -127,9 +107,13 @@ int pqihandler::tick() if(now > mLastRateCapUpdate + 5) { + std::map rateMap; + std::map::iterator it; + + // every 5 secs, update the max rates for all modules - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ for(std::map::iterator it = mods.begin(); it != mods.end(); ++it) { // This is rather inelegant, but pqihandler has searchModules that are dynamically allocated, so the max rates @@ -149,7 +133,7 @@ int pqihandler::tick() bool pqihandler::queueOutRsItem(RsItem *item) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ uint32_t size ; locked_HandleRsItem(item, size); @@ -166,7 +150,7 @@ bool pqihandler::queueOutRsItem(RsItem *item) int pqihandler::status() { std::map::iterator it; - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ { // for output std::string out = "pqihandler::status() Active Modules:\n"; @@ -192,7 +176,7 @@ int pqihandler::status() bool pqihandler::AddSearchModule(SearchModule *mod) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // if peerid used -> error. //std::map::iterator it; if (mod->peerid != mod->pqi->PeerId()) @@ -223,7 +207,7 @@ bool pqihandler::AddSearchModule(SearchModule *mod) bool pqihandler::RemoveSearchModule(SearchModule *mod) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) { @@ -313,7 +297,7 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat total.mQueueOut = 0; /* Lock once rates have been retrieved */ - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) @@ -340,10 +324,6 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat // internal fn to send updates int pqihandler::UpdateRates() { -#ifdef PQI_HDL_DEBUG_UR - uint64_t t_now; -#endif - std::map::iterator it; float avail_in = getMaxRate(true); @@ -353,18 +333,15 @@ int pqihandler::UpdateRates() float used_bw_out = 0; /* Lock once rates have been retrieved */ - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ int num_sm = mods.size(); float used_bw_in_table[num_sm]; /* table of in bandwidth currently used by each module */ float used_bw_out_table[num_sm]; /* table of out bandwidth currently used by each module */ - int effectiveUploadsSm = 0; - int effectiveDownloadsSm = 0; - - // loop through modules to get the used bandwith and the number of modules that are affectively transfering -#ifdef PQI_HDL_DEBUG_UR - std::cerr << "Looping through modules" << std::endl; + // loop through modules to get the used bandwidth +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Looping through modules" << std::endl; #endif int index = 0; @@ -372,49 +349,33 @@ int pqihandler::UpdateRates() for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - float crate_in = mod -> pqi -> getRate(true); traffInSum += mod -> pqi -> getTraffic(true); traffOutSum += mod -> pqi -> getTraffic(false); -#ifdef PQI_HDL_DEBUG_UR - if(crate_in > 0.0) - std::cerr << " got in rate for peer " << it->first << " : " << crate_in << std::endl; -#endif - - if ((crate_in > 0.01 * avail_in) || (crate_in > 0.1)) - { - ++effectiveDownloadsSm; - } - + float crate_in = mod -> pqi -> getRate(true); float crate_out = mod -> pqi -> getRate(false); - if ((crate_out > 0.01 * avail_out) || (crate_out > 0.1)) - { - ++effectiveUploadsSm; - } used_bw_in += crate_in; used_bw_out += crate_out; - /* fill the table of bandwidth */ + /* fill the table of used bandwidths */ used_bw_in_table[index] = crate_in; used_bw_out_table[index] = crate_out; + ++index; } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; #endif /* Sort the used bw in/out table in ascending order */ std::sort(used_bw_in_table, used_bw_in_table + num_sm); std::sort(used_bw_out_table, used_bw_out_table + num_sm); -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): Done." << std::endl; - std::cerr << dec << t_now << " pqihandler::UpdateRates(): used_bw_out " << used_bw_out << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates used_bw_out " << used_bw_out << std::endl; #endif /* Calculate the optimal out_max value, taking into account avail_out and the out bw requested by modules */ @@ -441,9 +402,8 @@ int pqihandler::UpdateRates() } } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; #endif /* Allocate only half the remaining out bw, if any, to make it smoother */ @@ -473,67 +433,70 @@ int pqihandler::UpdateRates() } } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; #endif /* Allocate only half the remaining in bw, if any, to make it smoother */ in_max_bw = in_max_bw + in_remaining_bw / 2; - -#ifdef DEBUG_QOS -// std::cerr << "Totals (In) Used B/W " << used_bw_in; -// std::cerr << " Available B/W " << avail_in; -// std::cerr << " Effective transfers " << effectiveDownloadsSm << std::endl; -// std::cerr << "Totals (Out) Used B/W " << used_bw_out; -// std::cerr << " Available B/W " << avail_out; -// std::cerr << " Effective transfers " << effectiveUploadsSm << std::endl; -#endif - + // store current total in and ou used bw locked_StoreCurrentRates(used_bw_in, used_bw_out); - //computing average rates for effective transfers - float max_in_effective = avail_in / num_sm; - if (effectiveDownloadsSm != 0) { - max_in_effective = avail_in / effectiveDownloadsSm; - } - float max_out_effective = avail_out / num_sm; - if (effectiveUploadsSm != 0) { - max_out_effective = avail_out / effectiveUploadsSm; - } - - //modify the in and out limit -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; #endif + // retrieve down (from peer point of view) bandwidth limits set by peers in their own settings + std::map rateMap; + rsConfig->getAllBandwidthRates(rateMap); + std::map::iterator rateMap_it; + +#ifdef UPDATE_RATES_DEBUG + // Dump RsConfigurationDataRates + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates RsConfigDataRates dump" << std::endl; + for (rateMap_it = rateMap.begin(); rateMap_it != rateMap.end(); rateMap_it++) + RsDbg () << "UPDATE_RATES pqihandler::UpdateRates PeerId " << rateMap_it->first.toStdString() << " mAllowedOut " << rateMap_it->second.mAllowedOut << std::endl; +#endif + + // update max rates taking into account the limits set by peers in their own settings for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - - mod -> pqi -> setMaxRate(true, in_max_bw); - mod -> pqi -> setMaxRate(false, out_max_bw); + + // for our down bandwidth we set the max to the calculated value without taking into account the max set by peers: they will control their up bw on their side + mod -> pqi -> setMaxRate(true, in_max_bw); + + // for our up bandwidth we limit to the maximum down bw provided by peers via BwCtrl because we don't want to clog our outqueues, the SSL buffers, and our friends inbound queues + if ((rateMap_it = rateMap.find(mod->pqi->PeerId())) != rateMap.end()) + { + if (rateMap_it->second.mAllowedOut > 0) + { + if (out_max_bw > rateMap_it->second.mAllowedOut) + mod -> pqi -> setMaxRate(false, rateMap_it->second.mAllowedOut); + else + mod -> pqi -> setMaxRate(false, out_max_bw); + } + else + mod -> pqi -> setMaxRate(false, out_max_bw); + } } - - //cap the rates +#ifdef UPDATE_RATES_DEBUG + // dump maxRates for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - if (mod -> pqi -> getMaxRate(false) < max_out_effective) mod -> pqi -> setMaxRate(false, max_out_effective); - if (mod -> pqi -> getMaxRate(false) > avail_out) mod -> pqi -> setMaxRate(false, avail_out); - if (mod -> pqi -> getMaxRate(true) < max_in_effective) mod -> pqi -> setMaxRate(true, max_in_effective); - if (mod -> pqi -> getMaxRate(true) > avail_in) mod -> pqi -> setMaxRate(true, avail_in); + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates PeerID " << (mod ->pqi -> PeerId()).toStdString() << " new bandwidth limits up " << mod -> pqi -> getMaxRate(false) << " down " << mod -> pqi -> getMaxRate(true) << std::endl; } +#endif return 1; } void pqihandler::getCurrentRates(float &in, float &out) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ in = rateTotal_in; out = rateTotal_out; From 3332c32a840f5652a77c12d41a9fcd4c0afed49c Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 21 May 2020 18:17:49 +0200 Subject: [PATCH 69/79] RsBase64 handle correcly 0 lenght buffer encoding --- libretroshare/src/util/rsbase64.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libretroshare/src/util/rsbase64.cc b/libretroshare/src/util/rsbase64.cc index 6b856888e..72ea119e8 100644 --- a/libretroshare/src/util/rsbase64.cc +++ b/libretroshare/src/util/rsbase64.cc @@ -40,6 +40,12 @@ rs_view_ptr data, size_t len, std::string& outString, bool padding, bool urlSafe ) { + if(!data || !len) + { + outString.clear(); + return; + } + const char* sDict = urlSafe ? uDict : bDict; // Workaround if input and output are the same buffer. @@ -137,6 +143,7 @@ /*static*/ size_t RsBase64::encodedSize(size_t decodedSize, bool padding) { + if(!decodedSize) return 0; if(padding) return 4 * (decodedSize + 2) / 3; return static_cast( std::ceil(4L * static_cast(decodedSize) / 3L) ); From d76f397358cbf805aebdf23afcc694bdccccbf4d Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 28 May 2020 17:57:42 +0200 Subject: [PATCH 70/79] RsBase64 calculate size properly and avoid FP math --- libretroshare/src/util/rsbase64.cc | 9 ++++----- libretroshare/src/util/rsbase64.h | 4 ++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/util/rsbase64.cc b/libretroshare/src/util/rsbase64.cc index 72ea119e8..f62c40cef 100644 --- a/libretroshare/src/util/rsbase64.cc +++ b/libretroshare/src/util/rsbase64.cc @@ -21,8 +21,6 @@ * * *******************************************************************************/ -#include - #include "util/rsbase64.h" #include "util/rsdebug.h" @@ -144,9 +142,10 @@ /*static*/ size_t RsBase64::encodedSize(size_t decodedSize, bool padding) { if(!decodedSize) return 0; - if(padding) return 4 * (decodedSize + 2) / 3; - return static_cast( - std::ceil(4L * static_cast(decodedSize) / 3L) ); + + // Thanks https://stackoverflow.com/a/45401395 + if(padding) return ceilDivision(decodedSize, 3) * 4; + return ceilDivision(decodedSize * 8, 6); } /*static*/ std::tuple RsBase64::decodedSize( diff --git a/libretroshare/src/util/rsbase64.h b/libretroshare/src/util/rsbase64.h index 0715b15ae..819870089 100644 --- a/libretroshare/src/util/rsbase64.h +++ b/libretroshare/src/util/rsbase64.h @@ -137,4 +137,8 @@ private: */ static inline bool isBase64Char(char c) { return rDict[static_cast(c)] >= 0; } + + /** Perform ceil division without floating point operations */ + static inline size_t ceilDivision(size_t dividend, size_t divisor) + { return (dividend + divisor - 1) / divisor; } }; From c1c303218cff1d12639cb2d3840e4298a05785a3 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 28 May 2020 23:01:04 +0200 Subject: [PATCH 71/79] Change raw memory JSON representation Fix bug reported by b1rdG The new way permits to add more formats in the future without breaking retro-compatibility again. Add support for RsJson in rsdebug for Android --- .../src/serialiser/rstypeserializer.cc | 89 +++++++++---------- .../src/serialiser/rstypeserializer.h | 17 ++-- libretroshare/src/util/rsdebug.h | 8 +- libretroshare/src/util/rsjson.h | 2 +- 4 files changed, 63 insertions(+), 53 deletions(-) diff --git a/libretroshare/src/serialiser/rstypeserializer.cc b/libretroshare/src/serialiser/rstypeserializer.cc index 1ea3add9a..7cf799d0f 100644 --- a/libretroshare/src/serialiser/rstypeserializer.cc +++ b/libretroshare/src/serialiser/rstypeserializer.cc @@ -503,8 +503,16 @@ bool RsTypeSerializer::from_JSON( const std::string& /*memberName*/, // Binary blocks // //============================================================================// +#if __cplusplus < 201703L +/* Solve weird undefined reference error with C++ < 17 see: + * https://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char + */ +/*static*/ decltype(RsTypeSerializer::RawMemoryWrapper::base64_key) constexpr +RsTypeSerializer::RawMemoryWrapper::base64_key; + /*static*/ /* without this Android compilation breaks */ constexpr uint32_t RsTypeSerializer::RawMemoryWrapper::MAX_SERIALIZED_CHUNK_SIZE; +#endif /*static*/ void RsTypeSerializer::RawMemoryWrapper::serial_process( @@ -542,18 +550,7 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( ctx.mOffset += second; break; case RsGenericSerializer::DESERIALIZE: - if(first || second) - { - /* Items are created anew before deserialization so buffer pointer - * must be null and size 0 at this point */ - - RsWarn() << __PRETTY_FUNCTION__ << " DESERIALIZE got uninitialized " - << " or pre-allocated buffer! Buffer pointer: " << first - << " must be null and size: " << second << " must be 0 at " - << "this point. Does your item costructor initialize them " - << "properly?" << std::endl; - print_stacktrace(); - } + freshMemCheck(); RS_SERIAL_PROCESS(second); if(!ctx.mOk) break; @@ -597,44 +594,33 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( if(!ctx.mOk) break; std::string encodedValue; RsBase64::encode(first, second, encodedValue, true, false); - ctx.mJson.SetString( - encodedValue.data(), - static_cast(encodedValue.length()), - ctx.mJson.GetAllocator()); + ctx.mOk = ctx.mOk && + RsTypeSerializer::to_JSON(base64_key, encodedValue, ctx.mJson); break; } case RsGenericSerializer::FROM_JSON: { - const bool yelding = !!( - RsSerializationFlags::YIELDING & ctx.mFlags ); - if(!(ctx.mOk || yelding)) - { - clear(); - break; - } - if(!ctx.mJson.IsString()) - { - RsErr() << __PRETTY_FUNCTION__ << " " - << std::errc::invalid_argument << std::endl; - print_stacktrace(); + freshMemCheck(); - ctx.mOk = false; - clear(); - break; - } - if( ctx.mJson.GetStringLength() > + const auto failure = [&]() -> void { ctx.mOk = false; clear(); }; + const bool yielding = !!( + RsSerializationFlags::YIELDING & ctx.mFlags ); + if(!(ctx.mOk || yielding)) return failure(); + + std::string encodedValue; + if(!RsTypeSerializer::from_JSON( + base64_key, encodedValue, ctx.mJson )) return failure(); + + if( encodedValue.length() > RsBase64::encodedSize(MAX_SERIALIZED_CHUNK_SIZE, true) ) { RsErr() << __PRETTY_FUNCTION__ << " " << std::errc::message_size << std::endl; print_stacktrace(); - ctx.mOk = false; - clear(); - break; + return failure(); } - std::string encodedValue = ctx.mJson.GetString(); std::vector decoded; auto ec = RsBase64::decode(encodedValue, decoded); if(ec) @@ -642,9 +628,7 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( RsErr() << __PRETTY_FUNCTION__ << " " << ec << std::endl; print_stacktrace(); - ctx.mOk = false; - clear(); - break; + return failure(); } const auto decodedSize = decoded.size(); @@ -655,11 +639,8 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( break; } - if(decodedSize != second) - { - first = reinterpret_cast(realloc(first, decodedSize)); - second = static_cast(decodedSize); - } + first = reinterpret_cast(malloc(decodedSize)); + second = static_cast(decodedSize); memcpy(first, decoded.data(), second); break; @@ -675,6 +656,24 @@ void RsTypeSerializer::RawMemoryWrapper::clear() second = 0; } +bool RsTypeSerializer::RawMemoryWrapper::freshMemCheck() +{ + if(first || second) + { + /* Items are created anew before deserialization so buffer pointer + * must be null and size 0 at this point */ + + RsWarn() << __PRETTY_FUNCTION__ << " got uninitialized " + << " or pre-allocated buffer! Buffer pointer: " << first + << " must be null and size: " << second << " must be 0 at " + << "this point. Does your item costructor initialize them " + << "properly?" << std::endl; + print_stacktrace(); + return false; + } + return true; +} + //============================================================================// // std::error_condition // //============================================================================// diff --git a/libretroshare/src/serialiser/rstypeserializer.h b/libretroshare/src/serialiser/rstypeserializer.h index d72280bb3..3c8af510e 100644 --- a/libretroshare/src/serialiser/rstypeserializer.h +++ b/libretroshare/src/serialiser/rstypeserializer.h @@ -59,12 +59,17 @@ struct RsTypeSerializer /// Maximum supported size 10MB static constexpr uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024; + /** Key used for JSON serialization. + * @note Changing this value breaks JSON API retro-compatibility */ + static constexpr char base64_key[] = "base64"; + /// @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx ) override; private: void clear(); + bool freshMemCheck(); }; /// Most types are not valid sequence containers @@ -777,9 +782,9 @@ struct RsTypeSerializer { if(!yielding) { - std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName - << "\" not found in JSON:" << std::endl - << jDoc << std::endl << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName + << "\" not found in JSON:" << std::endl + << jDoc << std::endl << std::endl; print_stacktrace(); } ctx.mOk = false; @@ -790,9 +795,9 @@ struct RsTypeSerializer if(!v.IsObject()) { - std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName - << "\" has wrong type in JSON, object expected, got:" - << std::endl << jDoc << std::endl << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName + << "\" has wrong type in JSON, object expected, got:" + << std::endl << jDoc << std::endl << std::endl; print_stacktrace(); ctx.mOk = false; break; diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index c333bd255..01a8b94df 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -32,6 +32,8 @@ std::ostream &operator<<(std::ostream& out, const std::error_condition& err); # include # include +# include "util/rsjson.h" + enum class RsLoggerCategories { DEBUG = ANDROID_LOG_DEBUG, @@ -55,6 +57,10 @@ struct t_RsLogger inline stream_type& operator<<(const T& val) { ostr << val; return *this; } + template + inline stream_type& operator<<(const RsJson& val) + { ostr << val; return *this; } + /// needed for manipulators and things like std::endl stream_type& operator<<(std::ostream& (*pf)(std::ostream&)) { @@ -111,7 +117,7 @@ struct t_RsLogger const auto now = system_clock::now(); const auto sec = time_point_cast(now); const auto msec = duration_cast(now - sec); - std::stringstream tstream; + std::ostringstream tstream; tstream << static_cast(CATEGORY) << " " << sec.time_since_epoch().count() << "." << std::setfill('0') << std::setw(3) << msec.count() diff --git a/libretroshare/src/util/rsjson.h b/libretroshare/src/util/rsjson.h index db864a73f..13073f3b2 100644 --- a/libretroshare/src/util/rsjson.h +++ b/libretroshare/src/util/rsjson.h @@ -29,7 +29,7 @@ typedef rapidjson::Document RsJson; /** - * Print out RsJson to a stream, use std::stringstream to get the string + * Print out RsJson to a stream, use std::ostringstream to get the string * @param[out] out output stream * @param[in] jDoc JSON document to print * @return same output stream passed as out parameter From 2ae21ca800b8622ef86fb29d3988f7a3a61d630a Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 29 May 2020 01:09:10 +0200 Subject: [PATCH 72/79] rsdebug supports variadic style for atomic log --- libretroshare/src/util/rsdebug.h | 73 +++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index c333bd255..f242e05cf 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -46,6 +46,18 @@ struct t_RsLogger { inline t_RsLogger() = default; + /** Offer variadic style too, as a benefit this has better atomicity then + * << style, but doesn't supports manipulators and things like std::endl + * @see https://stackoverflow.com/a/27375675 */ + template + inline t_RsLogger(Arg&& arg, Args&&... args) + { + ostr << std::forward(arg); + using expander = int[]; + (void)expander{0, (void(ostr << std::forward(args)), 0)...}; + mFlush(); + } + /** On other platforms expose the type of underlying stream. * On Android it cannot work like that so return the class type itself * just for code compatibility with other platforms */ @@ -60,12 +72,7 @@ struct t_RsLogger { if(pf == static_cast( &std::endl< char, std::char_traits > )) - { - __android_log_write( - static_cast(CATEGORY), - "RetroShare", ostr.str().c_str() ); - ostr.str() = ""; - } + mFlush(); else ostr << pf; return *this; @@ -78,6 +85,14 @@ struct t_RsLogger private: std::ostringstream ostr; + + void mFlush() + { + __android_log_write( + static_cast(CATEGORY), + "RetroShare", ostr.str().c_str() ); + ostr.str() = ""; + } }; #else // def __ANDROID__ @@ -99,38 +114,56 @@ enum class RsLoggerCategories template struct t_RsLogger { - inline t_RsLogger() = default; - /// Expose the type of underlying stream using stream_type = decltype(std::cerr); + /// Return underlying stream to write avoiding additional prefixes + static inline stream_type& uStream() { return std::cerr; } + + inline t_RsLogger() = default; + + /** Offer variadic style too, as a benefit this has better atomicity then + * << style, but doesn't supports manipulators and things like std::endl + * @see https://stackoverflow.com/a/27375675 */ + template + inline t_RsLogger(Arg&& arg, Args&&... args) + { + std::ostringstream ostr; + ostr << getPrefix() << std::forward(arg); + using expander = int[]; + (void)expander{0, (void(ostr << std::forward(args)), 0)...}; + ostr << std::endl; + uStream() << ostr.str(); + } + template inline stream_type& operator<<(const T& val) + { return uStream() << getPrefix() << val; } + + /// needed for manipulators and things like std::endl + stream_type& operator<<(std::ostream& (*pf)(std::ostream&)) + { return uStream() << pf; } + +private: + std::string getPrefix() { using namespace std::chrono; const auto now = system_clock::now(); const auto sec = time_point_cast(now); const auto msec = duration_cast(now - sec); - std::stringstream tstream; + std::ostringstream tstream; tstream << static_cast(CATEGORY) << " " << sec.time_since_epoch().count() << "." << std::setfill('0') << std::setw(3) << msec.count() - << " " << val; - return std::cerr << tstream.str(); + << " "; + return tstream.str(); } - - /// needed for manipulators and things like std::endl - stream_type& operator<<(std::ostream& (*pf)(std::ostream&)) - { return std::cerr << pf; } - - /// Return underlying stream to write avoiding additional prefixes - inline stream_type& uStream() const { return std::cerr; } }; #endif // def __ANDROID__ /** - * Comfortable debug message loggin, supports chaining like std::cerr but can + * Comfortable debug message logging, supports chaining like std::cerr but can * be easly and selectively disabled at compile time to reduce generated binary * size and performance impact without too many \#ifdef around. * @@ -190,6 +223,8 @@ struct RsNoDbg { inline RsNoDbg() = default; + template inline RsNoDbg(T, Args...) {} + /** Defined as the type itself just for code compatibility with other * logging classes */ using stream_type = RsNoDbg; From 43f7b6c0ba930f5a1b03d94ad999af4a1481746f Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 29 May 2020 11:03:57 +0200 Subject: [PATCH 73/79] RsFiles::alreadyHaveFile look into extra list too --- libretroshare/src/file_sharing/p3filelists.cc | 10 ++++++++-- libretroshare/src/ft/ftserver.cc | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/file_sharing/p3filelists.cc b/libretroshare/src/file_sharing/p3filelists.cc index c7db78b0f..55a28dec6 100644 --- a/libretroshare/src/file_sharing/p3filelists.cc +++ b/libretroshare/src/file_sharing/p3filelists.cc @@ -1424,9 +1424,15 @@ int p3FileDatabase::SearchBoolExp(RsRegularExpression::Expression *exp, std::lis return !results.empty() ; } -bool p3FileDatabase::search(const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info) const + +bool p3FileDatabase::search( + const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info) const { - RS_STACK_MUTEX(mFLSMtx) ; + RS_STACK_MUTEX(mFLSMtx); + + if( (hintflags & RS_FILE_HINTS_EXTRA) && + mExtraFiles->search(hash, hintflags, info) ) + return true; if(hintflags & RS_FILE_HINTS_LOCAL) { diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 3ae1af491..08e294d2b 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -293,7 +293,8 @@ bool ftServer::getFileData(const RsFileHash& hash, uint64_t offset, uint32_t& re bool ftServer::alreadyHaveFile(const RsFileHash& hash, FileInfo &info) { - return mFileDatabase->search(hash, RS_FILE_HINTS_LOCAL, info); + return mFileDatabase->search( + hash, RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL, info ); } bool ftServer::FileRequest( From 22618de00c0a878a0b98d9fa69442ae2cc958589 Mon Sep 17 00:00:00 2001 From: defnax Date: Fri, 29 May 2020 18:16:59 +0200 Subject: [PATCH 74/79] * Added missed facepalming emoji & stylesheet fixes * Added missed facepalming emoji * Added default stylesheets for Messages selection & hover * Added default selection color for the Main Window ListView --- retroshare-gui/src/gui/emojione.qrc | 2 ++ retroshare-gui/src/gui/emojione/emotes.acs | 2 ++ .../src/gui/emojione/man-facepalming.png | Bin 0 -> 2166 bytes .../src/gui/emojione/woman-facepalming.png | Bin 0 -> 2212 bytes .../src/gui/qss/stylesheet/Standard.qss | 19 ++++++++++++++++++ 5 files changed, 23 insertions(+) create mode 100644 retroshare-gui/src/gui/emojione/man-facepalming.png create mode 100644 retroshare-gui/src/gui/emojione/woman-facepalming.png diff --git a/retroshare-gui/src/gui/emojione.qrc b/retroshare-gui/src/gui/emojione.qrc index fdbfc58aa..b636f7b09 100644 --- a/retroshare-gui/src/gui/emojione.qrc +++ b/retroshare-gui/src/gui/emojione.qrc @@ -937,5 +937,7 @@ emojione/1F1FF-1F1FC.png emojione/flags.png emojione/flags2.png + emojione/man-facepalming.png + emojione/woman-facepalming.png diff --git a/retroshare-gui/src/gui/emojione/emotes.acs b/retroshare-gui/src/gui/emojione/emotes.acs index 6e9007948..26af35787 100644 --- a/retroshare-gui/src/gui/emojione/emotes.acs +++ b/retroshare-gui/src/gui/emojione/emotes.acs @@ -113,6 +113,8 @@ "emojione/people2.png"|":man_with_gua_pi_mao:":"emojione/1F472.png"; "emojione/people2.png"|":levitate:|:man_in_business_suit_levitating:":"emojione/1F574.png"; "emojione/people2.png"|":dancer:":"emojione/1F483.png"; +"emojione/people2.png"|":man_facepalming:":"emojione/man-facepalming.png"; +"emojione/people2.png"|":woman_facepalming:":"emojione/woman-facepalming.png"; "emojione/people2.png"|":bust_in_silhouette:":"emojione/1F464.png"; "emojione/people2.png"|":busts_in_silhouette:":"emojione/1F465.png"; "emojione/people2.png"|":family:":"emojione/1F46A.png"; diff --git a/retroshare-gui/src/gui/emojione/man-facepalming.png b/retroshare-gui/src/gui/emojione/man-facepalming.png new file mode 100644 index 0000000000000000000000000000000000000000..d0594eefdd610a67acaa7fee4425af8ede29e7b1 GIT binary patch literal 2166 zcmZ{lX*AT27skKVG$i{L85uN|jG2^B%nX?!`x@DYLCM&olzlC`knB69RE(`bV=XCr z6H;V}(NMND!*6=|fAK%}Joh>0x#x54xvy@LnTf$MkOT+-fMZyUo(0pv|HQ?~?1ACo zTTEleBaM*&(3r+ecjfpubjMg213UnaBm{ z+XdlVgFH0d13Z`pz+rHh3JjqFgImGjn(7*w>SvW;FijXNG&Df^e*j-UoVRD#{|7h~ z-39xaXGFVitY29(!vK~X}r zs1nww3JXPR5W{?*&o~bGR4EQ+WS-61M1`1~+u3iVQNm`v%~1T^Zin7jp1$~q@>gTG zeL0v0YVqePN243t7FLSNPIn;PhlaiE8I^&{RF|G(E@SL{z~=jIU*bUW*0HPEyoxWz z6_U$_|7!R7G^{ypY43=*Q^%bTwHW;Bh%ZF`bNViG4UX7eVo~baDiL0r%|B%|kjaJg zGTDvj+SVRd=H~7-Z2a=PC@!uz)zs9XJ2Ds?_W?s)r%g?WnFM)Sqf3AB zX+w0S59Hs$1>ze<))E&lyl!>Kbt)`!niDu7AVz(soq?4j;pKTqt3FvHlMLOxwO{SW z)kOsJXmcZW_f?HWlWFng({4GWrca%L%OSF781?lC-^@;#(S}yapR5nps>mu`ov*xf zBXyu6gr?_qPbMhqex@c)T%65OVwa{-nH2Z$gse_gCDIO#KFI1#dbT3_4IG-6IWNU~ zR}Y-oMSevBgN_Fjt13A|AISY!cJ!`mPpf*Q^Xr;#)C7U# z9G~90$)93}d!vV}9M}20Sxf~^Z?GdX??`^e%QnD!*tx|k0irotz5sZvIFA)Zzt;c0 ze=SHXc;!V*>@Y06i#Iwe+9v+=$k&}jUQ{3M=EhtnMsHecG%1c- zJsPlcNlgfEWG8k+j?SR?MA`H(wgubBZ2CY@8U)I zk&r0qx!a2fMtW8&7@sxEa@8JzrOg{PvgL{0xxrP09xh}W);Q)4WK6T@Vj$v6cp9(F(#Ic`)nJJKj}Ct* z`kL0KZPkOkKDYbq-oIvT@j73x%_p*8rV4ecs)no9ds z`;n_9y?VQTLOv>ephI>6w;iHwOJU13L==-(gA?MV6w>H&R@1CSav2-_VAW%Ts(BGh zQ@5-aYR2N{bZ8|?9~6sa9Nk$Ar*sM6gSkNP% z$==0xKG=;8<4+9ghM!r>^AdVGHWacqDA-aqiTPTdFVpc7mS}-jr9)JPiEp?$C!&uA zixw$TBi37u_VAWQXV1L?`X?4vMyxkqx%ORBFnkZS%#G-{Fcm|)p~X7cB#TUzzQ+{U6T}F@=>-L-7E$ImQdFie~aq z>F`~ly2PF;E`1=oS3r@3fsBM=Dj7@{3L<6Kt&P3ExWyg`elRsOU z+-x_;;qI=+GcZe_U+mc)6T%Tke>SJtOYbl~>rAK(!iMzyG~!IU!%^+SESdfK-vYDBq_p8Jup{+s+Y%_< z%d4fU!wvP!R_$XRc_K6R-rw1lJc^09Zoc89vm9u4qJH~tx={Q^@9l&5sbRClw$zF2 z;(JvEB4H<_@{w)MaSzsI(nAU3lzcj}xi?bz zJkXjCv_W^rEg|=((Y1P$_6B>#Eu0)SifA>16swv8E&7U+*28@s(16ec2oa_rxmZhh z4NM)Clt##;INyAfA@6Hbvk`evS8B-aL+2}NZbHp<#VI}zT>MLjc2n*NW(^uCZMRIa zTZR(OsSbUR%^9*(TpFC(nwI^xejOrabn2+}tzYVgPN8C*B*xwQrB*NvSPqWc>*R_J%4@SQA1;8^H_>ZAxkUd5Ro3-C literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/emojione/woman-facepalming.png b/retroshare-gui/src/gui/emojione/woman-facepalming.png new file mode 100644 index 0000000000000000000000000000000000000000..10346185ef0aad7b3871caa5298379e788259345 GIT binary patch literal 2212 zcmZ{lXEfW57sr2yEfi7fF&k6Q=1U8QG1W52x=F#V$|NNHDWYoRZ+W-)k<5` zXsOzzMbVn&(U<=h|8vjxe$V;b^F8<6S2xkb=nj~Uiw*z)u&$1#>811k6%Ey8$A*L) zTpGwt%}@;hn$qac94P+|opekM0U$&e0HR_6;N%iTZ2$lc1^}D(007Se0CvBk4kY4o zKP!FSJj!9L?}SZ zD!|zxzyMYm_HvSF`WJ$I`7D7-pgDEx%bFGy((+Pz1B-NxV{CiY739Gc_7Cz}fVs0GW zCvSzAyh zAVfo+yKn!I>BxmSVIt=TI(X~LME1#>XH631hu?P=Fk+)va2w7}F1yux3?v#~J6TPw z9z{)tC@n`38%^K7e3N%H{`w--md}`}>!{*Od5!3rSrjqp3m+NSUd*eamx`MzX z5LUC_ZE5#7{e4hByHlC=G+2Sr9X%D9ZzLS3Ux~0$fcU>aLFXlfP+a$N|J{0!r(5|U zi3Jf#s2gMC8?-kgpEwOXEQ~vEEZ-`>n_EwxIJ_mpEGQt6Gwtpz3K4rS+FT#=MC~?* zL?>AxOO#-V&P309lr+_0fXU{LhCr-RrZT!|8z5*xuI+)XjZ~Vzos;?pYXD> zvWSqbWGnK{=2_t>ROI7E3F~#Q#~$`aznjuv3MSelBlhr9R7GZ15h^GARS|^zniCf% zk0F112?<9$3-t6I$MZ^DlLPf%l@q$R5kdPh2OW$F1*;sN;GnHy1vV2V)|3SveGR6h z^zEN$L|}UytKI!{15Jh%O)Y8gP~t7Q96%`JAao;ChJh)3VJOWAwYy=@oRR|fPjMwo zj;{2gsmYuOYar0ZRgv{(I%3*yUvM}DwBjY zpUJ<`rAKQ4=e8lv(xTSb%Q)c+9h1>PL}+8nqvb`O8#Y=r8WWDQgQ30CqA#{Yr{~A} z{s3n3XsfokFfTganuNG8?8ZH%Pc#G2h7~jWNwS@7CVNg4C5rahvB-LCKfX4E8x)W> zQK7nUw~B_{z?FlTItCNdac+SPds?qA@yp+l4slQQjIh!OtWwbAQlF3!6z@2T~=Q!Gho)Hm)3yx*%f`y=akA5JN-v z9za&-OJigjVoC5}WMyT2qEs3l3;)_J zCfZr&#haq|&4?_fcBE?XpHq{8LQEKI&+(Kfnp;UvcUF&9XPt6t@Ok>xR@^yf!@co= z>X2H+@#8OVCC;CBpV$nBMDct1sc(Cm8xQP|wpBeIF5S>jGsR_a#!K zQookod`dyhFmRb~E`&=>@DA!UL7N1HafXm?P(y3o=0FdpL^D~Fu1J$oah=*kkE^&6 zR;`IIYz@Eof;S%fNB0Q-s=Z|gXKJ9hH14#r$@p^9Q*7!Gv=lr)E(Yb}Qm?2m<*LAb&WXDbw!k0n z?!&Y6OEg}s)Nm#j^HTX_ZZ-B%FggCtgtSZqnqF9l&1N)tb9V?Z{d1G!nH^D%HJ@?? z>y#(Tk=He=PYYMQib*C^)pYFa#b++DhR+`@JVGK`)?!@1tEbWvzIB@_8P-q5KckhY z;*e_D^Qz^6^le!A57zKAVyX6fKSH7ZoEf37XFXvq-0i(0dkWD={p8=6y#T>VoMulm7tv(8l zENqdGwjidAn$@Q(@W)~&J2|iG#||_wg7SQ~ZKF+6Rr4hBtbTciaxg_+7|A4T??zw^ kp6YjzJ+i4q{3g4geliN7@!7 Date: Sat, 30 May 2020 12:28:02 +0200 Subject: [PATCH 75/79] Fix qss StyleSheet dark theme item color for gtk users gtk users can't set Qt system theme. --- retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp | 8 ++++---- retroshare-gui/src/qss/blacknight.qss | 10 ++++++++++ retroshare-gui/src/qss/qdarkstyle-v2.qss | 5 ++++- retroshare-gui/src/qss/qdarkstyle.qss | 5 ++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp b/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp index 89a2ebe8a..3fa95f898 100644 --- a/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp +++ b/retroshare-gui/src/gui/common/RSElidedItemDelegate.cpp @@ -39,19 +39,19 @@ //#define DEBUG_EID_PAINT 1 /* To test it you can make an empty.qss file with: -QTreeView::item, QTreeWidget::item{ +QTreeView::item, QTreeWidget::item, QListWidget::item{ color: #AB0000; background-color: #00DC00; } -QTreeView::item:selected, QTreeWidget::item:selected{ +QTreeView::item:selected, QTreeWidget::item:selected, QListWidget::item:selected{ color: #00CD00; background-color: #0000BA; } -QTreeView::item:hover, QTreeWidget::item:hover{ +QTreeView::item:hover, QTreeWidget::item:hover, QListWidget::item:hover{ color: #0000EF; background-color: #FEDCBA; } -QQTreeView::item:selected:hover, TreeWidget::item:selected:hover{ +QQTreeView::item:selected:hover, TreeWidget::item:selected:hover, QListWidget::item:selected:hover{ color: #ABCDEF; background-color: #FE0000; } diff --git a/retroshare-gui/src/qss/blacknight.qss b/retroshare-gui/src/qss/blacknight.qss index 3f08e0aa8..62adfe013 100644 --- a/retroshare-gui/src/qss/blacknight.qss +++ b/retroshare-gui/src/qss/blacknight.qss @@ -51,6 +51,10 @@ background: black; color: lightgray; border-color: transparent; } +QTreeView::item, QTreeWidget::item, QListWidget::item{ + color: lightgray; +} + QDialog, QMainWindow{ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgb(25, 25, 25), stop:0.05 rgb(0, 0, 0), stop:0.95 rgb(0, 0, 0), stop:1 rgb(25, 25, 25)); } @@ -255,6 +259,12 @@ QTextEdit { color: white; } +RSTextBrowser, MimeTextEdit +{ + /*qproperty-textColorQuote: rgb(125, 125, 255);*/ + qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970); +} + /* OpModeStatus need to be at end to overload other values*/ OpModeStatus { qproperty-opMode_Full_Color: #007000; diff --git a/retroshare-gui/src/qss/qdarkstyle-v2.qss b/retroshare-gui/src/qss/qdarkstyle-v2.qss index 97a331ac9..cb573d765 100644 --- a/retroshare-gui/src/qss/qdarkstyle-v2.qss +++ b/retroshare-gui/src/qss/qdarkstyle-v2.qss @@ -51,6 +51,9 @@ QWidget { selection-background-color: #1464A0; selection-color: #F0F0F0; } +QTreeView::item, QTreeWidget::item, QListWidget::item{ + color: #F0F0F0; +} QWidget:disabled { background-color: #19232D; @@ -2152,5 +2155,5 @@ GxsChannelDialog GroupTreeWidget QTreeWidget#treeWidget::item{ RSTextBrowser, MimeTextEdit { /*qproperty-textColorQuote: rgb(125, 125, 255);*/ - qproperty-textColorQuotes: ColorList(#0000ff #00ff00 #00ffff #ff0000 #ff00ff #ffff00 #ffffff); + qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970); } diff --git a/retroshare-gui/src/qss/qdarkstyle.qss b/retroshare-gui/src/qss/qdarkstyle.qss index 059c87f9d..b50eb9aa1 100644 --- a/retroshare-gui/src/qss/qdarkstyle.qss +++ b/retroshare-gui/src/qss/qdarkstyle.qss @@ -60,6 +60,9 @@ QWidget border-image: none; outline: 0; } +QTreeView::item, QTreeWidget::item, QListWidget::item{ + color: silver; +} QWidget:item:hover { @@ -1299,7 +1302,7 @@ WireGroupItem QFrame#frame{ RSTextBrowser, MimeTextEdit { /*qproperty-textColorQuote: rgb(125, 125, 255);*/ - qproperty-textColorQuotes: ColorList(#0000ff #00ff00 #00ffff #ff0000 #ff00ff #ffff00 #ffffff); + qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970); } ChatWidget QFrame#pluginTitleFrame From d256595aa71f46c32d57b15b2b9fe03c76e17d84 Mon Sep 17 00:00:00 2001 From: Phenom Date: Sat, 30 May 2020 18:19:43 +0200 Subject: [PATCH 76/79] Fix Message Sent keeps Tags --- libretroshare/src/services/p3msgservice.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 01a825bb3..83c1c8e88 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -1187,11 +1187,15 @@ bool p3MsgService::MessageSend(MessageInfo &info) /* use processMsg to get the new msgId */ msg->recvTime = time(NULL); msg->msgId = getNewUniqueMsgId(); - + msg->msgFlags |= RS_MSG_OUTGOING; imsg[msg->msgId] = msg; + // Update info for caller + info.msgId = std::to_string(msg->msgId); + info .msgflags = msg->msgFlags; + RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_ADD); } From df12c72ab88d69ca85618dc6a3ef01a6c482b721 Mon Sep 17 00:00:00 2001 From: Phenom Date: Sat, 30 May 2020 19:38:37 +0200 Subject: [PATCH 77/79] Fix Message Delete Last to clear widget. --- retroshare-gui/src/gui/msgs/MessagesDialog.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 5d6bc87c5..40b61739a 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -1105,7 +1105,10 @@ void MessagesDialog::removemessage() void MessagesDialog::messageRemoved() { - ui.messageTreeWidget->setCurrentIndex(lastSelectedIndex); + if (lastSelectedIndex.isValid()) + ui.messageTreeWidget->setCurrentIndex(lastSelectedIndex); + else + insertMsgTxtAndFiles(QModelIndex()); } void MessagesDialog::undeletemessage() From e7cc74751f18910642ae0bb2260fa674758522e3 Mon Sep 17 00:00:00 2001 From: defnax Date: Sun, 31 May 2020 00:21:19 +0200 Subject: [PATCH 78/79] Removed stylesheet it gets issues on other style --- retroshare-gui/src/gui/qss/stylesheet/Standard.qss | 9 --------- 1 file changed, 9 deletions(-) diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss index 53ac80a44..00569eef2 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss @@ -917,12 +917,3 @@ MessagesDialog QWidget#messageTreeWidget::item:hover { GxsForumThreadWidget QWidget#threadTreeWidget::item { padding: 2px; } - -MainWindow QListView#listWidget::item:selected { - background-color: #cde8ff; - color: black; -} - -MainWindow QListView#listWidget::item:hover { - background-color: #e5f3ff; -} From 295ecf368ee841392d40191176ac830758369882 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sun, 31 May 2020 15:19:00 +0200 Subject: [PATCH 79/79] ExtraFileHash check for integer overflow When passing large periods 2038 problems was silently triggered due to time being stored as int in FileInfo::age, thus causing erratic behaviour in extra files timeout. Now period is checked and if too large an error is reported. Deprecate FileDetails which is confusing dummy wrapper of FileInfo Remove ftExtraList::cleanupEntry deadcode --- libretroshare/src/ft/ftextralist.cc | 65 +++++++++++--------------- libretroshare/src/ft/ftextralist.h | 9 ++-- libretroshare/src/ft/ftserver.cc | 10 ++++ libretroshare/src/retroshare/rsfiles.h | 3 +- 4 files changed, 46 insertions(+), 41 deletions(-) diff --git a/libretroshare/src/ft/ftextralist.cc b/libretroshare/src/ft/ftextralist.cc index ccefe810d..a4a1245e0 100644 --- a/libretroshare/src/ft/ftextralist.cc +++ b/libretroshare/src/ft/ftextralist.cc @@ -4,7 +4,7 @@ * libretroshare: retroshare core library * * * * Copyright (C) 2008 Robert Fernie * - * Copyright (C) 2018-2019 Gioacchino Mazzurco * + * Copyright (C) 2018-2020 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -21,6 +21,9 @@ * * *******************************************************************************/ +#include +#include + #ifdef WINDOWS_SYS #include "util/rswin.h" #endif @@ -245,12 +248,8 @@ bool ftExtraList::cleanupOldFiles() /* remove items */ for(std::list::iterator rit = toRemove.begin(); rit != toRemove.end(); ++rit) { - if (mFiles.end() != (it = mFiles.find(*rit))) - { - cleanupEntry(it->second.info.path, it->second.info.transfer_info_flags); - mFiles.erase(it); - } - mHashOfHash.erase(makeEncryptedHash(*rit)) ; + if (mFiles.end() != (it = mFiles.find(*rit))) mFiles.erase(it); + mHashOfHash.erase(makeEncryptedHash(*rit)); } IndicateConfigChanged(); @@ -258,46 +257,39 @@ bool ftExtraList::cleanupOldFiles() return true; } - -bool ftExtraList::cleanupEntry(std::string /*path*/, TransferRequestFlags /*flags*/) -{ -// if (flags & RS_FILE_CONFIG_CLEANUP_DELETE) -// { -// /* Delete the file? - not yet! */ -// } - return true; -} - - /*** - * Hash file, and add to the files, - * file is removed after period. - **/ - bool ftExtraList::hashExtraFile( std::string path, uint32_t period, TransferRequestFlags flags ) { -#ifdef DEBUG_ELIST - std::cerr << "ftExtraList::hashExtraFile() path: " << path; - std::cerr << " period: " << period; - std::cerr << " flags: " << flags; + constexpr rstime_t max_int = std::numeric_limits::max(); + const rstime_t now = time(nullptr); + const rstime_t timeOut = now + period; - std::cerr << std::endl; -#endif - - auto failure = [](std::string errMsg) + if(timeOut > max_int) { - RsErr() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + /* Under the hood period is stored as int FileInfo::age so we do this + * check here to detect 2038 year problem + * https://en.wikipedia.org/wiki/Year_2038_problem */ + RsErr() << __PRETTY_FUNCTION__ << " period: " << period << " > " + << max_int - now << std::errc::value_too_large << std::endl; return false; - }; + } if(!RsDirUtil::fileExists(path)) - return failure("file: " + path + "not found"); + { + RsErr() << __PRETTY_FUNCTION__ << " path: " << path + << std::errc::no_such_file_or_directory << std::endl; + return false; + } if(RsDirUtil::checkDirectory(path)) - return failure("Cannot add a directory: " + path + "as extra file"); + { + RsErr() << __PRETTY_FUNCTION__ << " path: " << path + << std::errc::is_a_directory << std::endl; + return false; + } FileDetails details(path, period, flags); - details.info.age = static_cast(time(nullptr) + period); + details.info.age = static_cast(timeOut); { RS_STACK_MUTEX(extMutex); @@ -492,8 +484,7 @@ bool ftExtraList::loadList(std::list& load) if (ts > (rstime_t)fi->file.age) { - /* to old */ - cleanupEntry(fi->file.path, TransferRequestFlags(fi->flags)); + /* too old */ delete (*it); continue ; } diff --git a/libretroshare/src/ft/ftextralist.h b/libretroshare/src/ft/ftextralist.h index 52bc87c98..229c0fe3c 100644 --- a/libretroshare/src/ft/ftextralist.h +++ b/libretroshare/src/ft/ftextralist.h @@ -60,7 +60,7 @@ #include "pqi/p3cfgmgr.h" #include "util/rstime.h" -class FileDetails +class RS_DEPRECATED_FOR(FileInfo) FileDetails { public: FileDetails() @@ -130,7 +130,11 @@ public: * file is removed after period. **/ - bool hashExtraFile(std::string path, uint32_t period, TransferRequestFlags flags); + /** + * Hash file, and add to the files, file is removed after period. + */ + bool hashExtraFile( + std::string path, uint32_t period, TransferRequestFlags flags ); bool hashExtraFileDone(std::string path, FileInfo &info); /*** @@ -165,7 +169,6 @@ private: /* Worker Functions */ void hashAFile(); bool cleanupOldFiles(); - bool cleanupEntry(std::string path, TransferRequestFlags flags); mutable RsMutex extMutex; diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 08e294d2b..0f42b8437 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -22,6 +22,8 @@ #include #include +#include +#include #include "crypto/chacha20.h" //const int ftserverzone = 29539; @@ -820,6 +822,14 @@ bool ftServer::ExtraFileRemove(const RsFileHash& hash) bool ftServer::ExtraFileHash( std::string localpath, rstime_t period, TransferRequestFlags flags ) { + constexpr rstime_t uintmax = std::numeric_limits::max(); + if(period > uintmax) + { + RsErr() << __PRETTY_FUNCTION__ << " period: " << period << " > " + << uintmax << std::errc::value_too_large << std::endl; + return false; + } + return mFtExtra->hashExtraFile( localpath, static_cast(period), flags ); } diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index 64563f621..92c017cef 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -658,7 +658,8 @@ public: * @brief Get file details * @jsonapi{development} * @param[in] hash file identifier - * @param[in] hintflags filtering hint (RS_FILE_HINTS_EXTRA|...|RS_FILE_HINTS_LOCAL) + * @param[in] hintflags filtering hint ( RS_FILE_HINTS_UPLOAD|...| + * RS_FILE_HINTS_EXTRA|RS_FILE_HINTS_LOCAL ) * @param[out] info storage for file information * @return true if file found, false otherwise */