diff --git a/libretroshare/src/ft/ftextralist.cc b/libretroshare/src/ft/ftextralist.cc index a4a1245e0..3912cc1b3 100644 --- a/libretroshare/src/ft/ftextralist.cc +++ b/libretroshare/src/ft/ftextralist.cc @@ -129,6 +129,11 @@ void ftExtraList::hashAFile() mHashedList[details.info.path] = details.info.hash; IndicateConfigChanged(); + + auto ev = std::make_shared(); + ev->mEventCode = RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_ADDED; + if(rsEvents) + rsEvents->postEvent(ev); } } @@ -195,6 +200,12 @@ bool ftExtraList::removeExtraFile(const RsFileHash& hash) IndicateConfigChanged(); + if(rsEvents) + { + auto ev = std::make_shared(); + ev->mEventCode = RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_REMOVED; + rsEvents->postEvent(ev); + } return true; } diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 4ef9ae9d7..cf67857f5 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -301,36 +301,23 @@ void RsGenExchange::tick() { RS_STACK_MUTEX(mGenMtx) ; - std::list grpIds; - std::map > msgIds; + std::vector grpIds; + GxsMsgReq msgIds; + mIntegrityCheck->getDeletedIds(grpIds, msgIds); - if (!grpIds.empty()) - { - for(auto& groupId:grpIds) - { - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_GROUP_DELETED,groupId, false); + if(!msgIds.empty()) + { + uint32_t token1=0; + deleteMsgs(token1,msgIds); + } -#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; -#endif - mNotifications.push_back(gc); - } - - // also notify the network exchange service that these groups no longer exist. - - if(mNetService) - mNetService->removeGroups(grpIds) ; - } - - 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); - } + if(!grpIds.empty()) + for(auto& grpId: grpIds) + { + uint32_t token2=0; + deleteGroup(token2,grpId); + } delete mIntegrityCheck; mIntegrityCheck = NULL; diff --git a/libretroshare/src/gxs/rsgxsutil.cc b/libretroshare/src/gxs/rsgxsutil.cc index d2d6fbb05..b32d63392 100644 --- a/libretroshare/src/gxs/rsgxsutil.cc +++ b/libretroshare/src/gxs/rsgxsutil.cc @@ -207,13 +207,16 @@ RsGxsIntegrityCheck::RsGxsIntegrityCheck( void RsGxsIntegrityCheck::run() { - check(); + std::vector grps_to_delete; + GxsMsgReq msgs_to_delete; + + check(mGenExchangeClient->serviceType(),mGixs,mDs,mDeletedGrps,mDeletedMsgs); RS_STACK_MUTEX(mIntegrityMutex); mDone = true; } -bool RsGxsIntegrityCheck::check() +bool RsGxsIntegrityCheck::check(uint16_t service_type, RsGixs *mgixs, RsGeneralDataService *mds, std::vector& grpsToDel, GxsMsgReq& msgsToDel) { #ifdef RS_DEEP_CHANNEL_INDEX bool isGxsChannels = mGenExchangeClient->serviceType() == RS_SERVICE_GXS_TYPE_CHANNELS; @@ -222,8 +225,7 @@ bool RsGxsIntegrityCheck::check() // first take out all the groups std::map grp; - mDs->retrieveNxsGrps(grp, true, true); - std::vector grpsToDel; + mds->retrieveNxsGrps(grp, true, true); GxsMsgReq msgIds; GxsMsgReq grps; @@ -244,7 +246,7 @@ bool RsGxsIntegrityCheck::check() if(currHash == grp->metaData->mHash) { // get all message ids of group - if (mDs->retrieveMsgIds(grp->grpId, msgIds[grp->grpId]) == 1) + if (mds->retrieveMsgIds(grp->grpId, msgIds[grp->grpId]) == 1) { // store the group for retrieveNxsMsgs grps[grp->grpId]; @@ -262,8 +264,7 @@ bool RsGxsIntegrityCheck::check() rsReputations->overallReputationLevel( grp->metaData->mAuthorId ) > RsReputationLevel::LOCALLY_NEGATIVE ) - used_gxs_ids.insert(std::make_pair(grp->metaData->mAuthorId, RsIdentityUsage(RsServiceType(mGenExchangeClient->serviceType()), - RsIdentityUsage::GROUP_AUTHOR_KEEP_ALIVE,grp->grpId))); + used_gxs_ids.insert(std::make_pair(grp->metaData->mAuthorId, RsIdentityUsage(RsServiceType(service_type), RsIdentityUsage::GROUP_AUTHOR_KEEP_ALIVE,grp->grpId))); } } } @@ -317,33 +318,15 @@ bool RsGxsIntegrityCheck::check() #endif // def RS_DEEP_CHANNEL_INDEX } - if( !(grp->metaData->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) && - !(grp->metaData->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) && - !(grp->metaData->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_PUBLISH) ) - { - RsGroupNetworkStats stats; - mGenExchangeClient->getGroupNetworkStats(grp->grpId,stats); - - if( stats.mSuppliers == 0 && stats.mMaxVisibleCount == 0 - && stats.mGrpAutoSync ) - { -#ifdef DEBUG_GXSUTIL - GXSUTIL_DEBUG() << "Scheduling group \"" << grp->metaData->mGroupName << "\" ID=" << grp->grpId << " in service " << std::hex << mGenExchangeClient->serviceType() << std::dec << " for deletion because it has no suppliers not any visible data at friends." << std::endl; -#endif - grpsToDel.push_back(grp->grpId); - } - } - delete grp; } - mDs->removeGroups(grpsToDel); + mds->removeGroups(grpsToDel); // now messages - GxsMsgReq msgsToDel; GxsMsgResult msgs; - mDs->retrieveNxsMsgs(grps, msgs, false, true); + mds->retrieveNxsMsgs(grps, msgs, false, true); // check msg ids and messages GxsMsgReq::iterator msgIdsIt; @@ -455,7 +438,7 @@ bool RsGxsIntegrityCheck::check() rsReputations->overallReputationLevel( msg->metaData->mAuthorId ) > RsReputationLevel::LOCALLY_NEGATIVE ) - used_gxs_ids.insert(std::make_pair(msg->metaData->mAuthorId,RsIdentityUsage(RsServiceType(mGenExchangeClient->serviceType()), + used_gxs_ids.insert(std::make_pair(msg->metaData->mAuthorId,RsIdentityUsage(RsServiceType(service_type), RsIdentityUsage::MESSAGE_AUTHOR_KEEP_ALIVE, msg->metaData->mGroupId, msg->metaData->mMsgId, @@ -468,18 +451,9 @@ bool RsGxsIntegrityCheck::check() } } - mDs->removeMsgs(msgsToDel); + mds->removeMsgs(msgsToDel); { - RS_STACK_MUTEX(mIntegrityMutex); - - std::vector::iterator grpIt; - for(grpIt = grpsToDel.begin(); grpIt != grpsToDel.end(); ++grpIt) - { - mDeletedGrps.push_back(*grpIt); - } - mDeletedMsgs = msgsToDel; - #ifdef DEBUG_GXSUTIL GXSUTIL_DEBUG() << "At end of pass, this is the list used GXS ids: " << std::endl; GXSUTIL_DEBUG() << " requesting them to GXS identity service to enforce loading." << std::endl; @@ -512,9 +486,9 @@ bool RsGxsIntegrityCheck::check() GXSUTIL_DEBUG() << " requesting ID " << gxs_ids[n].first ; #endif - if(!mGixs->haveKey(gxs_ids[n].first)) // checks if we have it already in the cache (conservative way to ensure that we atually have it) + if(!mgixs->haveKey(gxs_ids[n].first)) // checks if we have it already in the cache (conservative way to ensure that we atually have it) { - mGixs->requestKey(gxs_ids[n].first,connected_friends,gxs_ids[n].second); + mgixs->requestKey(gxs_ids[n].first,connected_friends,gxs_ids[n].second); ++nb_requested_not_in_cache ; #ifdef DEBUG_GXSUTIL @@ -527,7 +501,7 @@ bool RsGxsIntegrityCheck::check() GXSUTIL_DEBUG() << " ... already in cache" << std::endl; #endif } - mGixs->timeStampKey(gxs_ids[n].first,gxs_ids[n].second); + mgixs->timeStampKey(gxs_ids[n].first,gxs_ids[n].second); gxs_ids[n] = gxs_ids[gxs_ids.size()-1] ; gxs_ids.pop_back() ; @@ -546,7 +520,7 @@ bool RsGxsIntegrityCheck::isDone() return mDone; } -void RsGxsIntegrityCheck::getDeletedIds(std::list& grpIds, std::map >& msgIds) +void RsGxsIntegrityCheck::getDeletedIds(std::vector& grpIds, GxsMsgReq& msgIds) { RS_STACK_MUTEX(mIntegrityMutex); grpIds = mDeletedGrps; diff --git a/libretroshare/src/gxs/rsgxsutil.h b/libretroshare/src/gxs/rsgxsutil.h index 2b79112d1..ff2a0e20c 100644 --- a/libretroshare/src/gxs/rsgxsutil.h +++ b/libretroshare/src/gxs/rsgxsutil.h @@ -175,12 +175,12 @@ public: RsGenExchange *genex, RsSerialType& gxsSerialiser, RsGixs *gixs); - bool check(); + static bool check(uint16_t service_type, RsGixs *mgixs, RsGeneralDataService *mds, std::vector& grpsToDel, GxsMsgReq& msgsToDel); bool isDone(); void run(); - void getDeletedIds(std::list& grpIds, std::map > &msgIds); + void getDeletedIds(std::vector &grpIds, GxsMsgReq &msgIds); private: @@ -191,8 +191,8 @@ private: #endif bool mDone; RsMutex mIntegrityMutex; - std::list mDeletedGrps; - std::map > mDeletedMsgs; + std::vector mDeletedGrps; + GxsMsgReq mDeletedMsgs; RsGixs* mGixs; }; diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index fa6b37e29..f25d90957 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -184,6 +184,8 @@ enum class RsSharedDirectoriesEventCode: uint8_t { HASHING_FILE = 0x02, // mMessage: full path and hashing speed of the file being hashed DIRECTORY_SWEEP_ENDED = 0x03, // (void) SAVING_FILE_INDEX = 0x04, // (void) + EXTRA_LIST_FILE_ADDED = 0x05, // (void) + EXTRA_LIST_FILE_REMOVED = 0x06, // (void) }; enum class RsFileTransferEventCode: uint8_t { diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 1556380e2..a69ddc8f6 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -342,7 +342,16 @@ void p3GxsChannels::notifyChanges(std::vector &changes) } break; - case RsGxsNotify::TYPE_PUBLISHED: + case RsGxsNotify::TYPE_UPDATED: + { + auto ev = std::make_shared(); + ev->mChannelGroupId = grpChange->mGroupId; + ev->mChannelEventCode = RsChannelEventCode::UPDATED_CHANNEL; + rsEvents->postEvent(ev); + } + break; + + case RsGxsNotify::TYPE_PUBLISHED: case RsGxsNotify::TYPE_RECEIVED_NEW: { /* group received or updated */ diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 32f1394f1..74ae4d2d5 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -196,15 +196,17 @@ void p3MsgService::processIncomingMsg(RsMsgItem *mi) /**** STACK UNLOCKED ***/ } - // If the peer is allowed to push files, then auto-download the recommended files. - if(rsPeers->servicePermissionFlags(mi->PeerId()) & RS_NODE_PERM_ALLOW_PUSH) - { - std::list srcIds; - srcIds.push_back(mi->PeerId()); + // If the peer is allowed to push files, then auto-download the recommended files. - for(std::list::const_iterator it(mi->attachment.items.begin());it!=mi->attachment.items.end();++it) - rsFiles->FileRequest((*it).name,(*it).hash,(*it).filesize,std::string(),RS_FILE_REQ_ANONYMOUS_ROUTING,srcIds) ; - } + RsIdentityDetails id_details; + if(rsIdentity->getIdDetails(RsGxsId(mi->PeerId()),id_details) && !id_details.mPgpId.isNull() && (rsPeers->servicePermissionFlags(id_details.mPgpId) & RS_NODE_PERM_ALLOW_PUSH)) + { + std::list srcIds; + srcIds.push_back(mi->PeerId()); + + for(std::list::const_iterator it(mi->attachment.items.begin());it!=mi->attachment.items.end();++it) + rsFiles->FileRequest((*it).name,(*it).hash,(*it).filesize,std::string(),RS_FILE_REQ_ANONYMOUS_ROUTING,srcIds) ; + } RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_ADD); } diff --git a/libretroshare/src/services/p3postbase.cc b/libretroshare/src/services/p3postbase.cc index f37ddd03c..5585b256d 100644 --- a/libretroshare/src/services/p3postbase.cc +++ b/libretroshare/src/services/p3postbase.cc @@ -208,6 +208,18 @@ void p3PostBase::notifyChanges(std::vector &changes) } 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 + + auto ev = std::make_shared(); + ev->mPostedGroupId = grpChange->mGroupId; + ev->mPostedEventCode = RsPostedEventCode::UPDATED_POSTED_GROUP; + rsEvents->postEvent(ev); + } + break; + + case RsGxsNotify::TYPE_PUBLISHED: case RsGxsNotify::TYPE_RECEIVED_NEW: { diff --git a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp index 1d9dd05b0..10195dd82 100644 --- a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp @@ -564,11 +564,9 @@ void IdEditDialog::createId() { ui->createButton->setEnabled(false); - RsIdentityDetails det; - - if(rsIdentity->getIdDetails(keyId,det)) + if(!keyId.isNull()) { - QMessageBox::information(NULL,tr("Identity creation success"),tr("Your new identity was successfuly created.")); + QMessageBox::information(NULL,tr("Identity creation success"),tr("Your new identity was successfuly created, its ID is %1.").arg(QString::fromStdString(keyId.toStdString()))); close(); } else diff --git a/retroshare-gui/src/gui/RemoteDirModel.cpp b/retroshare-gui/src/gui/RemoteDirModel.cpp index 49d9b2d6e..f989a2ec5 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.cpp +++ b/retroshare-gui/src/gui/RemoteDirModel.cpp @@ -30,6 +30,7 @@ #include "retroshare/rsfiles.h" #include "retroshare/rspeers.h" #include "util/misc.h" +#include "util/qtthreadsutils.h" #include "retroshare/rsexpr.h" #include @@ -63,6 +64,37 @@ RetroshareDirModel::RetroshareDirModel(bool mode, QObject *parent) treeStyle(); mDirDetails.ref = (void*)intptr_t(0xffffffff) ; + + rsEvents->registerEventsHandler( + [this](std::shared_ptr event) + { + RsQThreadUtils::postToObject( [this,event]() { handleEvent_main_thread(event); }); + }, + mEventHandlerId, + RsEventType::SHARED_DIRECTORIES ); +} + +RetroshareDirModel::~RetroshareDirModel() +{ + rsEvents->unregisterEventsHandler(mEventHandlerId); +} +void RetroshareDirModel::handleEvent_main_thread(std::shared_ptr event) +{ + if(event->mType != RsEventType::SHARED_DIRECTORIES) return; + + const RsSharedDirectoriesEvent *fe = dynamic_cast(event.get()); + if(!fe) + return; + + switch (fe->mEventCode) + { + case RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_ADDED: + case RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_REMOVED: + update(); + break; + default: + break; + } } TreeStyle_RDM::TreeStyle_RDM(bool mode) diff --git a/retroshare-gui/src/gui/RemoteDirModel.h b/retroshare-gui/src/gui/RemoteDirModel.h index 115ba5b20..9d94abf32 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.h +++ b/retroshare-gui/src/gui/RemoteDirModel.h @@ -22,6 +22,7 @@ #define REMOTE_DIR_MODEL #include +#include #include #include @@ -63,9 +64,9 @@ class RetroshareDirModel : public QAbstractItemModel enum Roles{ FileNameRole = Qt::UserRole+1, SortRole = Qt::UserRole+2, FilterRole = Qt::UserRole+3 }; RetroshareDirModel(bool mode, QObject *parent = 0); - virtual ~RetroshareDirModel() {} + virtual ~RetroshareDirModel() ; - virtual Qt::ItemFlags flags ( const QModelIndex & index ) const; + virtual Qt::ItemFlags flags ( const QModelIndex & index ) const; /* Callback from Core */ virtual void preMods(); @@ -107,7 +108,9 @@ class RetroshareDirModel : public QAbstractItemModel protected: bool _visible ; - void treeStyle(); + void handleEvent_main_thread(std::shared_ptr event); + + void treeStyle(); void downloadDirectory(const DirDetails & details, int prefixLen); static QString getFlagsString(FileStorageFlags f) ; static QString getGroupsString(FileStorageFlags flags, const std::list &) ; @@ -176,6 +179,8 @@ class RetroshareDirModel : public QAbstractItemModel bool mUpdating ; std::set mFilteredPointers ; + + RsEventsHandlerId_t mEventHandlerId; }; // This class shows the classical hierarchical directory view of shared files diff --git a/retroshare-gui/src/gui/connect/PGPKeyDialog.ui b/retroshare-gui/src/gui/connect/PGPKeyDialog.ui index b178da227..53c59b1ae 100644 --- a/retroshare-gui/src/gui/connect/PGPKeyDialog.ui +++ b/retroshare-gui/src/gui/connect/PGPKeyDialog.ui @@ -27,7 +27,7 @@ - 0 + 2 @@ -385,7 +385,7 @@ p, li { white-space: pre-wrap; } - <html><head/><body><p>This option allows you to automatically download a file that is recommended in an message coming from this node. This can be used for instance to send files between your own nodes. Applied to all locations of the same node.</p></body></html> + <html><head/><body><p>This option allows you to automatically download a file that is recommended in an message coming from this profile (e.g. when the message author is a signed identity that belongs to this profile). This can be used for instance to send files between your own nodes.</p></body></html> Auto-download recommended files from this node diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index b6451e5d6..c8442902e 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -73,6 +73,7 @@ void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr ev updateGroupStatisticsReal(e->mChannelGroupId);// update the list immediately break; + case RsChannelEventCode::UPDATED_CHANNEL: // [[fallthrough]]; case RsChannelEventCode::RECEIVED_PUBLISH_KEY: // [[fallthrough]]; case RsChannelEventCode::NEW_CHANNEL: // [[fallthrough]]; case RsChannelEventCode::DELETED_CHANNEL: // [[fallthrough]]; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index ae869cb5a..b6123864a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -918,7 +918,7 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() navigate(mNavigatePendingMsgId); else if( (mLastSelectedPosts.count(groupId()) > 0) - && !mLastSelectedPosts[groupId()].isNull()) + && !mLastSelectedPosts[groupId()].isNull()) { QModelIndex index = mChannelPostsModel->getIndexOfMessage(mLastSelectedPosts[groupId()]); @@ -938,7 +938,7 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() mChannelFilesModel->setFiles(files); ui->channelFiles_TV->setAutoSelect(true); - ui->channelFiles_TV->sortByColumn(0, Qt::AscendingOrder); + ui->channelFiles_TV->sortByColumn(3, Qt::AscendingOrder); ui->infoPosts->setText(QString::number(mChannelPostsModel->getNumberOfPosts()) + " / " + QString::number(mGroup.mMeta.mVisibleMsgCount)); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index b0fa31729..290e80431 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1243,6 +1243,13 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo recursSetMsgReadStatus(entry,read_status,with_children) ; recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below); + // also emit dataChanged() for parents since they need to re-draw + + for(QModelIndex j = i.parent(); j.isValid(); j=j.parent()) + { + emit dataChanged(j,j); + j = j.parent(); + } } void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children)