Merge remote-tracking branch g1o/qml_app_identity_avatar into qml_app_chat_aesthetic

This commit is contained in:
Angela Mazzurco 2017-06-21 14:56:31 +02:00
commit ca3a0bd2d1
37 changed files with 1822 additions and 321 deletions

View File

@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <QStringList>
#include "ApiServerLocal.h" #include "ApiServerLocal.h"
#include "JsonStream.h" #include "JsonStream.h"

View File

@ -22,6 +22,7 @@
#include <retroshare/rsidentity.h> #include <retroshare/rsidentity.h>
#include <retroshare/rspeers.h> #include <retroshare/rspeers.h>
#include <util/radix64.h>
#include <time.h> #include <time.h>
#include "Operators.h" #include "Operators.h"
@ -500,6 +501,11 @@ void IdentityHandler::handleGetIdentityDetails(Request& req, Response& resp)
RsIdentityDetails details; RsIdentityDetails details;
mRsIdentity->getIdDetails(RsGxsId(data.mMeta.mGroupId), details); mRsIdentity->getIdDetails(RsGxsId(data.mMeta.mGroupId), details);
std::string base64Avatar;
Radix64::encode(details.mAvatar.mData, details.mAvatar.mSize, base64Avatar);
resp.mDataStream << makeKeyValue("avatar", base64Avatar);
StreamBase& usagesStream = resp.mDataStream.getStreamToMember("usages"); StreamBase& usagesStream = resp.mDataStream.getStreamToMember("usages");
usagesStream.getStreamToMember(); usagesStream.getStreamToMember();

View File

@ -169,6 +169,12 @@ class p3ChatService::AvatarInfo
void toUnsignedChar(unsigned char *& data,uint32_t& size) const void toUnsignedChar(unsigned char *& data,uint32_t& size) const
{ {
if(_image_size == 0)
{
size = 0 ;
data = NULL ;
return ;
}
data = (unsigned char *)rs_malloc(_image_size) ; data = (unsigned char *)rs_malloc(_image_size) ;
size = _image_size ; size = _image_size ;
memcpy(data,_image_data,size*sizeof(unsigned char)) ; memcpy(data,_image_data,size*sizeof(unsigned char)) ;

View File

@ -190,18 +190,29 @@ void RsGenExchange::tick()
now = time(NULL); now = time(NULL);
if(mChecking || (mLastCheck + INTEGRITY_CHECK_PERIOD < now)) if(mChecking || (mLastCheck + INTEGRITY_CHECK_PERIOD < now))
{ {
if(mIntegrityCheck) mLastCheck = time(NULL);
{ {
RS_STACK_MUTEX(mGenMtx) ;
if(!mIntegrityCheck)
{
mIntegrityCheck = new RsGxsIntegrityCheck(mDataStore,this,mGixs);
mIntegrityCheck->start("gxs integrity");
mChecking = true;
}
}
if(mIntegrityCheck->isDone()) if(mIntegrityCheck->isDone())
{ {
RS_STACK_MUTEX(mGenMtx) ;
std::list<RsGxsGroupId> grpIds; std::list<RsGxsGroupId> grpIds;
std::map<RsGxsGroupId, std::vector<RsGxsMessageId> > msgIds; std::map<RsGxsGroupId, std::vector<RsGxsMessageId> > msgIds;
mIntegrityCheck->getDeletedIds(grpIds, msgIds); mIntegrityCheck->getDeletedIds(grpIds, msgIds);
if (!grpIds.empty()) if (!grpIds.empty())
{ {
RS_STACK_MUTEX(mGenMtx) ;
RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PROCESSED, false); RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PROCESSED, false);
gc->mGrpIdList = grpIds; gc->mGrpIdList = grpIds;
#ifdef GEN_EXCH_DEBUG #ifdef GEN_EXCH_DEBUG
@ -217,9 +228,8 @@ void RsGenExchange::tick()
mNetService->removeGroups(grpIds) ; mNetService->removeGroups(grpIds) ;
} }
if (!msgIds.empty()) { if (!msgIds.empty())
RS_STACK_MUTEX(mGenMtx) ; {
RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, false); RsGxsMsgChange* c = new RsGxsMsgChange(RsGxsNotify::TYPE_PROCESSED, false);
c->msgChangeMap = msgIds; c->msgChangeMap = msgIds;
mNotifications.push_back(c); mNotifications.push_back(c);
@ -227,17 +237,9 @@ void RsGenExchange::tick()
delete mIntegrityCheck; delete mIntegrityCheck;
mIntegrityCheck = NULL; mIntegrityCheck = NULL;
mLastCheck = time(NULL);
mChecking = false; mChecking = false;
} }
} }
else
{
mIntegrityCheck = new RsGxsIntegrityCheck(mDataStore,this,mGixs);
mIntegrityCheck->start("gxs integrity");
mChecking = true;
}
}
} }
bool RsGenExchange::messagePublicationTest(const RsGxsMsgMetaData& meta) bool RsGenExchange::messagePublicationTest(const RsGxsMsgMetaData& meta)
@ -1752,8 +1754,18 @@ void RsGenExchange::deleteGroup(uint32_t& token, const RsGxsGroupId& grpId)
} }
void RsGenExchange::deleteMsgs(uint32_t& token, const GxsMsgReq& msgs) void RsGenExchange::deleteMsgs(uint32_t& token, const GxsMsgReq& msgs)
{ {
RS_STACK_MUTEX(mGenMtx) ;
token = mDataAccess->generatePublicToken(); token = mDataAccess->generatePublicToken();
mMsgDeletePublish.push_back(MsgDeletePublish(msgs, token)); mMsgDeletePublish.push_back(MsgDeletePublish(msgs, token));
// This code below will suspend any requests of the deleted messages for 24 hrs. This of course only works
// if all friend nodes consistently delete the messages in the mean time.
if(mNetService != NULL)
for(GxsMsgReq::const_iterator it(msgs.begin());it!=msgs.end();++it)
for(uint32_t i=0;i<it->second.size();++i)
mNetService->rejectMessage(it->second[i]) ;
} }
void RsGenExchange::publishMsg(uint32_t& token, RsGxsMsgItem *msgItem) void RsGenExchange::publishMsg(uint32_t& token, RsGxsMsgItem *msgItem)
@ -2900,8 +2912,12 @@ void RsGenExchange::processRecvdMessages()
std::cerr << " deserialised info: grp id=" << meta->mGroupId << ", msg id=" << meta->mMsgId ; std::cerr << " deserialised info: grp id=" << meta->mGroupId << ", msg id=" << meta->mMsgId ;
#endif #endif
uint8_t validateReturn = VALIDATE_FAIL; uint8_t validateReturn = VALIDATE_FAIL;
bool accept_new_msg = acceptNewMessage(meta,msg->msg.bin_len);
if(ok) if(!accept_new_msg && mNetService != NULL)
mNetService->rejectMessage(meta->mMsgId) ; // This prevents reloading the message again at next sync.
if(ok && accept_new_msg)
{ {
std::map<RsGxsGroupId, RsGxsGrpMetaData*>::iterator mit = grpMetas.find(msg->grpId); std::map<RsGxsGroupId, RsGxsGrpMetaData*>::iterator mit = grpMetas.find(msg->grpId);
@ -3042,8 +3058,8 @@ void RsGenExchange::processRecvdMessages()
mNetService->rejectMessage(*it) ; mNetService->rejectMessage(*it) ;
} }
bool RsGenExchange::acceptNewGroup(const RsGxsGrpMetaData* /*grpMeta*/ ) bool RsGenExchange::acceptNewGroup(const RsGxsGrpMetaData* /*grpMeta*/ ) { return true; }
{ return true; } bool RsGenExchange::acceptNewMessage(const RsGxsMsgMetaData* /*grpMeta*/,uint32_t size ) { return true; }
void RsGenExchange::processRecvdGroups() void RsGenExchange::processRecvdGroups()
{ {

View File

@ -260,6 +260,17 @@ public:
*/ */
virtual bool acceptNewGroup(const RsGxsGrpMetaData *grpMeta) ; virtual bool acceptNewGroup(const RsGxsGrpMetaData *grpMeta) ;
/*!
* \brief acceptNewMessage
* Early checks if the message can be accepted. This is mainly used to check wether the group is for instance overloaded and the service wants
* to put limitations to it.
* Returns true unless derived in GXS services.
*
* \param grpMeta Group metadata to check
* \return
*/
virtual bool acceptNewMessage(const RsGxsMsgMetaData *msgMeta, uint32_t size) ;
bool subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, bool subscribe); bool subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, bool subscribe);
/*! /*!

View File

@ -268,7 +268,7 @@ static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_GXS_KEY_MISSING = 0x05 ;
static const RsPeerId peer_to_print = RsPeerId(std::string("")) ; 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 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 = 0x215 ; // use this to allow to this service id only, or 0 for all services static const uint32_t service_to_print = RS_SERVICE_TYPE_GXS_TRANS ; // 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) // warning. Numbers should be SERVICE IDS (see serialiser/rsserviceids.h. E.g. 0x0215 for forums)
class nullstream: public std::ostream {}; class nullstream: public std::ostream {};
@ -447,6 +447,9 @@ void RsGxsNetService::rejectMessage(const RsGxsMessageId& msg_id)
{ {
RS_STACK_MUTEX(mNxsMutex) ; RS_STACK_MUTEX(mNxsMutex) ;
#ifdef NXS_NET_DEBUG_0
GXSNETDEBUG___ << "adding message " << msg_id << " to rejection list for 24hrs." << std::endl;
#endif
mRejectedMessages[msg_id] = time(NULL) ; mRejectedMessages[msg_id] = time(NULL) ;
} }
void RsGxsNetService::cleanRejectedMessages() void RsGxsNetService::cleanRejectedMessages()
@ -595,9 +598,9 @@ void RsGxsNetService::syncWithPeers()
#ifdef NXS_NET_DEBUG_0 #ifdef NXS_NET_DEBUG_0
GXSNETDEBUG_PG(peerId,grpId) << " peer can send messages for group " << grpId ; GXSNETDEBUG_PG(peerId,grpId) << " peer can send messages for group " << grpId ;
if(!encrypt_to_this_circle_id.isNull()) if(!encrypt_to_this_circle_id.isNull())
std::cerr << " request should be encrypted for circle ID " << encrypt_to_this_circle_id << std::endl; GXSNETDEBUG_PG(peerId,grpId) << " request should be encrypted for circle ID " << encrypt_to_this_circle_id << std::endl;
else else
std::cerr << " request should be sent in clear." << std::endl; GXSNETDEBUG_PG(peerId,grpId) << " request should be sent in clear." << std::endl;
#endif #endif
// On default, the info has never been received so the TS is 0, meaning the peer has sent that it had no information. // On default, the info has never been received so the TS is 0, meaning the peer has sent that it had no information.
@ -1839,7 +1842,7 @@ void RsGxsNetService::debugDump()
GXSNETDEBUG_PG(it->first,it2->first) << " group " << it2->first << " - last updated at peer (secs ago): " << nice_time_stamp(time(NULL),it2->second.time_stamp) << ". Message count=" << it2->second.message_count << std::endl; GXSNETDEBUG_PG(it->first,it2->first) << " group " << it2->first << " - last updated at peer (secs ago): " << nice_time_stamp(time(NULL),it2->second.time_stamp) << ". Message count=" << it2->second.message_count << std::endl;
} }
GXSNETDEBUG___<< " List of rejected message ids: " << mRejectedMessages.size() << std::endl; GXSNETDEBUG___<< " List of rejected message ids: " << std::dec << mRejectedMessages.size() << std::endl;
#endif #endif
} }

View File

@ -136,6 +136,9 @@ RsGxsIntegrityCheck::RsGxsIntegrityCheck(RsGeneralDataService* const dataService
void RsGxsIntegrityCheck::run() void RsGxsIntegrityCheck::run()
{ {
check(); check();
RsStackMutex stack(mIntegrityMutex);
mDone = true;
} }
bool RsGxsIntegrityCheck::check() bool RsGxsIntegrityCheck::check()
@ -286,8 +289,8 @@ bool RsGxsIntegrityCheck::check()
mDs->removeMsgs(msgsToDel); mDs->removeMsgs(msgsToDel);
{
RsStackMutex stack(mIntegrityMutex); RsStackMutex stack(mIntegrityMutex);
mDone = true;
std::vector<RsGxsGroupId>::iterator grpIt; std::vector<RsGxsGroupId>::iterator grpIt;
for(grpIt = grpsToDel.begin(); grpIt != grpsToDel.end(); ++grpIt) for(grpIt = grpsToDel.begin(); grpIt != grpsToDel.end(); ++grpIt)
@ -351,6 +354,7 @@ bool RsGxsIntegrityCheck::check()
#ifdef DEBUG_GXSUTIL #ifdef DEBUG_GXSUTIL
GXSUTIL_DEBUG() << " total actual cache requests: "<< nb_requested_not_in_cache << std::endl; GXSUTIL_DEBUG() << " total actual cache requests: "<< nb_requested_not_in_cache << std::endl;
#endif #endif
}
return true; return true;
} }

View File

@ -20,17 +20,20 @@
#include "gxstrans/p3gxstrans.h" #include "gxstrans/p3gxstrans.h"
#include "util/stacktrace.h" #include "util/stacktrace.h"
#define DEBUG_GXSTRANS 1
typedef unsigned int uint; typedef unsigned int uint;
RsGxsTrans *rsGxsTrans = NULL ; RsGxsTrans *rsGxsTrans = NULL ;
const uint32_t p3GxsTrans::MAX_DELAY_BETWEEN_CLEANUPS = 900; // every 15 mins. Could be less.
p3GxsTrans::~p3GxsTrans() p3GxsTrans::~p3GxsTrans()
{ {
p3Config::saveConfiguration(); p3Config::saveConfiguration();
{ {
RS_STACK_MUTEX(mIngoingMutex); RS_STACK_MUTEX(mIngoingMutex);
for ( auto& kv : mIngoingQueue ) delete kv.second; for ( auto& kv : mIncomingQueue) delete kv.second;
} }
} }
@ -48,8 +51,8 @@ bool p3GxsTrans::getStatistics(GxsTransStatistics& stats)
RsGxsTransOutgoingRecord rec ; RsGxsTransOutgoingRecord rec ;
rec.status = pr.status ; rec.status = pr.status ;
rec.send_TS = pr.mailItem.meta.mPublishTs ; rec.send_TS = pr.sent_ts ;
rec.group_id = pr.mailItem.meta.mGroupId ; rec.group_id = pr.group_id ;
rec.trans_id = pr.mailItem.mailId ; rec.trans_id = pr.mailItem.mailId ;
rec.recipient = pr.recipient ; rec.recipient = pr.recipient ;
rec.data_size = pr.mailData.size(); rec.data_size = pr.mailData.size();
@ -69,7 +72,9 @@ bool p3GxsTrans::sendData( RsGxsTransId& mailId,
const uint8_t* data, uint32_t size, const uint8_t* data, uint32_t size,
RsGxsTransEncryptionMode cm ) RsGxsTransEncryptionMode cm )
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::sendEmail(...)" << std::endl; std::cout << "p3GxsTrans::sendEmail(...)" << std::endl;
#endif
if(!mIdService.isOwnId(own_gxsid)) if(!mIdService.isOwnId(own_gxsid))
{ {
@ -89,8 +94,7 @@ bool p3GxsTrans::sendData( RsGxsTransId& mailId,
OutgoingRecord pr( recipient, service, data, size ); OutgoingRecord pr( recipient, service, data, size );
pr.mailItem.clear(); pr.mailItem.clear();
pr.mailItem.meta.mAuthorId = own_gxsid; pr.author = own_gxsid; //pr.mailItem.meta.mAuthorId = own_gxsid;
pr.mailItem.meta.mMsgId.clear();
pr.mailItem.cryptoType = cm; pr.mailItem.cryptoType = cm;
pr.mailItem.mailId = RSRandom::random_u64(); pr.mailItem.mailId = RSRandom::random_u64();
@ -100,6 +104,8 @@ bool p3GxsTrans::sendData( RsGxsTransId& mailId,
} }
mailId = pr.mailItem.mailId; mailId = pr.mailItem.mailId;
IndicateConfigChanged(); // This causes the saving of the message after all data has been filled in.
return true; return true;
} }
@ -124,8 +130,11 @@ void p3GxsTrans::registerGxsTransClient(
void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type) void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
{ {
std::cout << "p3GxsTrans::handleResponse(" << token << ", " << req_type #ifdef DEBUG_GXSTRANS
<< ")" << std::endl; std::cout << "p3GxsTrans::handleResponse(" << token << ", " << req_type << ")" << std::endl;
#endif
bool changed = false ;
switch (req_type) switch (req_type)
{ {
case GROUPS_LIST: case GROUPS_LIST:
@ -186,8 +195,10 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
* avoid to create yet another never used mail distribution group. * avoid to create yet another never used mail distribution group.
*/ */
#ifdef DEBUG_GXSTRANS
std::cerr << "p3GxsTrans::handleResponse(...) preferredGroupId.isNu" std::cerr << "p3GxsTrans::handleResponse(...) preferredGroupId.isNu"
<< "ll() let's create a new group." << std::endl; << "ll() let's create a new group." << std::endl;
#endif
uint32_t token; uint32_t token;
publishGroup(token, new RsGxsTransGroupItem()); publishGroup(token, new RsGxsTransGroupItem());
queueRequest(token, GROUP_CREATE); queueRequest(token, GROUP_CREATE);
@ -197,7 +208,9 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
} }
case GROUP_CREATE: case GROUP_CREATE:
{ {
#ifdef DEBUG_GXSTRANS
std::cerr << "p3GxsTrans::handleResponse(...) GROUP_CREATE" << std::endl; std::cerr << "p3GxsTrans::handleResponse(...) GROUP_CREATE" << std::endl;
#endif
RsGxsGroupId grpId; RsGxsGroupId grpId;
acknowledgeTokenGrp(token, grpId); acknowledgeTokenGrp(token, grpId);
supersedePreferredGroup(grpId); supersedePreferredGroup(grpId);
@ -205,7 +218,9 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
} }
case MAILS_UPDATE: case MAILS_UPDATE:
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::handleResponse(...) MAILS_UPDATE" << std::endl; std::cout << "p3GxsTrans::handleResponse(...) MAILS_UPDATE" << std::endl;
#endif
typedef std::map<RsGxsGroupId, std::vector<RsGxsMsgItem*> > GxsMsgDataMap; typedef std::map<RsGxsGroupId, std::vector<RsGxsMsgItem*> > GxsMsgDataMap;
GxsMsgDataMap gpMsgMap; GxsMsgDataMap gpMsgMap;
getMsgData(token, gpMsgMap); getMsgData(token, gpMsgMap);
@ -222,12 +237,14 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL:
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT:
{ {
RsGxsTransBaseItem* mb = RsGxsTransBaseMsgItem* mb = dynamic_cast<RsGxsTransBaseMsgItem*>(*mIt);
dynamic_cast<RsGxsTransBaseItem*>(*mIt);
if(mb) if(mb)
{ {
RS_STACK_MUTEX(mIngoingMutex); RS_STACK_MUTEX(mIngoingMutex);
mIngoingQueue.insert(inMap::value_type(mb->mailId, mb)); mIncomingQueue.insert(inMap::value_type(mb->mailId,mb));
changed = true ;
} }
else else
std::cerr << "p3GxsTrans::handleResponse(...) " std::cerr << "p3GxsTrans::handleResponse(...) "
@ -253,6 +270,15 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
<< req_type << std::endl; << req_type << std::endl;
break; break;
} }
if(changed)
IndicateConfigChanged();
}
void p3GxsTrans::GxsTransIntegrityCleanupThread::getPerUserStatistics(std::map<RsGxsId,MsgSizeCount>& m)
{
RS_STACK_MUTEX(mMtx) ;
m = total_message_size_and_count ;
} }
void p3GxsTrans::GxsTransIntegrityCleanupThread::getMessagesToDelete(GxsMsgReq& m) void p3GxsTrans::GxsTransIntegrityCleanupThread::getMessagesToDelete(GxsMsgReq& m)
@ -263,13 +289,33 @@ void p3GxsTrans::GxsTransIntegrityCleanupThread::getMessagesToDelete(GxsMsgReq&
mMsgToDel.clear(); mMsgToDel.clear();
} }
// This method does two things:
// 1 - cleaning up old messages and messages for which an ACK has been received.
// 2 - building per user statistics across groups. This is important because it allows to mitigate the excess of
// messages, which might be due to spam.
//
// Note: the anti-spam system is disabled the level of GXS, because we want to allow to send anonymous messages
// between identities that might not have a reputation yet. Still, messages from identities with a bad reputation
// are still deleted by GXS.
//
// The group limits are enforced according to the following rules:
// * a temporal sliding window is computed for each identity and the number of messages signed by this identity is counted
// *
//
//
// Deleted messages are notified to the RsGxsNetService part which keeps a list of delete messages so as not to request them again
// during the same session. This allows to safely delete messages while avoiding re-synchronisation from friend nodes.
void p3GxsTrans::GxsTransIntegrityCleanupThread::run() void p3GxsTrans::GxsTransIntegrityCleanupThread::run()
{ {
// first take out all the groups // first take out all the groups
std::map<RsGxsGroupId, RsNxsGrp*> grp; std::map<RsGxsGroupId, RsNxsGrp*> grp;
mDs->retrieveNxsGrps(grp, true, true); mDs->retrieveNxsGrps(grp, true, true);
#ifdef DEBUG_GXSTRANS
std::cerr << "GxsTransIntegrityCleanupThread::run()" << std::endl; std::cerr << "GxsTransIntegrityCleanupThread::run()" << std::endl;
#endif
// compute hash and compare to stored value, if it fails then simply add it // compute hash and compare to stored value, if it fails then simply add it
// to list // to list
@ -287,6 +333,8 @@ void p3GxsTrans::GxsTransIntegrityCleanupThread::run()
// now messages // now messages
std::map<RsGxsId,MsgSizeCount> totalMessageSizeAndCount;
std::map<RsGxsTransId,std::pair<RsGxsGroupId,RsGxsMessageId> > stored_msgs ; std::map<RsGxsTransId,std::pair<RsGxsGroupId,RsGxsMessageId> > stored_msgs ;
std::list<RsGxsTransId> received_msgs ; std::list<RsGxsTransId> received_msgs ;
@ -312,27 +360,41 @@ void p3GxsTrans::GxsTransIntegrityCleanupThread::run()
std::cerr << " Unrecocognised item type!" << std::endl; std::cerr << " Unrecocognised item type!" << std::endl;
else if(NULL != (mitem = dynamic_cast<RsGxsTransMailItem*>(item))) else if(NULL != (mitem = dynamic_cast<RsGxsTransMailItem*>(item)))
{ {
#ifdef DEBUG_GXSTRANS
std::cerr << " " << msg->metaData->mMsgId << ": Mail data with ID " << std::hex << std::setfill('0') << std::setw(16) << mitem->mailId << std::dec << " from " << msg->metaData->mAuthorId << " size: " << msg->msg.bin_len << std::endl; std::cerr << " " << msg->metaData->mMsgId << ": Mail data with ID " << std::hex << std::setfill('0') << std::setw(16) << mitem->mailId << std::dec << " from " << msg->metaData->mAuthorId << " size: " << msg->msg.bin_len << std::endl;
#endif
stored_msgs[mitem->mailId] = std::make_pair(msg->metaData->mGroupId,msg->metaData->mMsgId) ; stored_msgs[mitem->mailId] = std::make_pair(msg->metaData->mGroupId,msg->metaData->mMsgId) ;
} }
else if(NULL != (pitem = dynamic_cast<RsGxsTransPresignedReceipt*>(item))) else if(NULL != (pitem = dynamic_cast<RsGxsTransPresignedReceipt*>(item)))
{ {
#ifdef DEBUG_GXSTRANS
std::cerr << " " << msg->metaData->mMsgId << ": Signed rcpt of ID " << std::hex << pitem->mailId << std::dec << " from " << msg->metaData->mAuthorId << " size: " << msg->msg.bin_len << std::endl; std::cerr << " " << msg->metaData->mMsgId << ": Signed rcpt of ID " << std::hex << pitem->mailId << std::dec << " from " << msg->metaData->mAuthorId << " size: " << msg->msg.bin_len << std::endl;
#endif
received_msgs.push_back(pitem->mailId) ; received_msgs.push_back(pitem->mailId) ;
} }
else else
std::cerr << " Unknown item type!" << std::endl; std::cerr << " Unknown item type!" << std::endl;
totalMessageSizeAndCount[msg->metaData->mAuthorId].size += msg->msg.bin_len ;
totalMessageSizeAndCount[msg->metaData->mAuthorId].count++;
delete msg; delete msg;
} }
} }
// From the collected information, build a list of group messages to delete.
GxsMsgReq msgsToDel ; GxsMsgReq msgsToDel ;
#ifdef DEBUG_GXSTRANS
std::cerr << "Msg removal report:" << std::endl; std::cerr << "Msg removal report:" << std::endl;
std::cerr << " Per user size and count: " << std::endl;
for(std::map<RsGxsId,MsgSizeCount>::const_iterator it(totalMessageSizeAndCount.begin());it!=totalMessageSizeAndCount.end();++it)
std::cerr << " " << it->first << ": " << it->second.count << " messages, for a total size of " << it->second.size << " bytes." << std::endl;
#endif
for(std::list<RsGxsTransId>::const_iterator it(received_msgs.begin());it!=received_msgs.end();++it) for(std::list<RsGxsTransId>::const_iterator it(received_msgs.begin());it!=received_msgs.end();++it)
{ {
std::map<RsGxsTransId,std::pair<RsGxsGroupId,RsGxsMessageId> >::const_iterator it2 = stored_msgs.find(*it) ; std::map<RsGxsTransId,std::pair<RsGxsGroupId,RsGxsMessageId> >::const_iterator it2 = stored_msgs.find(*it) ;
@ -341,22 +403,33 @@ void p3GxsTrans::GxsTransIntegrityCleanupThread::run()
{ {
msgsToDel[it2->second.first].push_back(it2->second.second); msgsToDel[it2->second.first].push_back(it2->second.second);
#ifdef DEBUG_GXSTRANS
std::cerr << " scheduling msg " << std::hex << it2->second.first << "," << it2->second.second << " for deletion." << std::endl; std::cerr << " scheduling msg " << std::hex << it2->second.first << "," << it2->second.second << " for deletion." << std::endl;
#endif
} }
} }
RS_STACK_MUTEX(mMtx) ; RS_STACK_MUTEX(mMtx) ;
mMsgToDel = msgsToDel ; mMsgToDel = msgsToDel ;
total_message_size_and_count = totalMessageSizeAndCount;
mDone = true;
} }
bool p3GxsTrans::GxsTransIntegrityCleanupThread::isDone()
{
RS_STACK_MUTEX(mMtx) ;
return mDone ;
}
void p3GxsTrans::service_tick() void p3GxsTrans::service_tick()
{ {
GxsTokenQueue::checkRequests(); GxsTokenQueue::checkRequests();
time_t now = time(NULL); time_t now = time(NULL);
bool changed = false ;
if(mLastMsgCleanup + MAX_DELAY_BETWEEN_CLEANUPS < now) if(mLastMsgCleanup + MAX_DELAY_BETWEEN_CLEANUPS < now)
{ {
RS_STACK_MUTEX(mPerUserStatsMutex);
if(!mCleanupThread) if(!mCleanupThread)
mCleanupThread = new GxsTransIntegrityCleanupThread(getDataStore()); mCleanupThread = new GxsTransIntegrityCleanupThread(getDataStore());
@ -364,7 +437,9 @@ void p3GxsTrans::service_tick()
std::cerr << "Cleanup thread is already running. Not running it again!" << std::endl; std::cerr << "Cleanup thread is already running. Not running it again!" << std::endl;
else else
{ {
#ifdef DEBUG_GXSTRANS
std::cerr << "Starting GxsIntegrity cleanup thread." << std::endl; std::cerr << "Starting GxsIntegrity cleanup thread." << std::endl;
#endif
mCleanupThread->start() ; mCleanupThread->start() ;
mLastMsgCleanup = now ; mLastMsgCleanup = now ;
@ -373,17 +448,32 @@ void p3GxsTrans::service_tick()
// now grab collected messages to delete // now grab collected messages to delete
if(mCleanupThread != NULL && !mCleanupThread->isRunning()) if(mCleanupThread != NULL && mCleanupThread->isDone())
{ {
RS_STACK_MUTEX(mPerUserStatsMutex);
GxsMsgReq msgToDel ; GxsMsgReq msgToDel ;
mCleanupThread->getMessagesToDelete(msgToDel) ; mCleanupThread->getMessagesToDelete(msgToDel) ;
if(!msgToDel.empty()) if(!msgToDel.empty())
{ {
#ifdef DEBUG_GXSTRANS
std::cerr << "p3GxsTrans::service_tick(): deleting messages." << std::endl; std::cerr << "p3GxsTrans::service_tick(): deleting messages." << std::endl;
getDataStore()->removeMsgs(msgToDel); #endif
uint32_t token ;
deleteMsgs(token,msgToDel);
} }
mCleanupThread->getPerUserStatistics(per_user_statistics) ;
#ifdef DEBUG_GXSTRANS
std::cerr << "p3GxsTrans: Got new set of per user statistics:"<< std::endl;
for(std::map<RsGxsId,MsgSizeCount>::const_iterator it(per_user_statistics.begin());it!=per_user_statistics.end();++it)
std::cerr << " " << it->first << ": " << it->second.count << " " << it->second.size << std::endl;
#endif
delete mCleanupThread;
mCleanupThread=NULL ;
} }
{ {
@ -392,10 +482,15 @@ void p3GxsTrans::service_tick()
{ {
OutgoingRecord& pr(it->second); OutgoingRecord& pr(it->second);
GxsTransSendStatus oldStatus = pr.status; GxsTransSendStatus oldStatus = pr.status;
processOutgoingRecord(pr);
locked_processOutgoingRecord(pr);
if (oldStatus != pr.status) notifyClientService(pr); if (oldStatus != pr.status) notifyClientService(pr);
if( pr.status >= GxsTransSendStatus::RECEIPT_RECEIVED ) if( pr.status >= GxsTransSendStatus::RECEIPT_RECEIVED )
{
it = mOutgoingQueue.erase(it); it = mOutgoingQueue.erase(it);
changed = true ;
}
else ++it; else ++it;
} }
} }
@ -403,15 +498,14 @@ void p3GxsTrans::service_tick()
{ {
RS_STACK_MUTEX(mIngoingMutex); RS_STACK_MUTEX(mIngoingMutex);
for( auto it = mIngoingQueue.begin(); it != mIngoingQueue.end(); ) for( auto it = mIncomingQueue.begin(); it != mIncomingQueue.end(); )
{ {
switch(static_cast<GxsTransItemsSubtypes>( switch(static_cast<GxsTransItemsSubtypes>( it->second->PacketSubType()))
it->second->PacketSubType()))
{ {
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL:
{ {
RsGxsTransMailItem* msg = RsGxsTransMailItem* msg = dynamic_cast<RsGxsTransMailItem*>(it->second);
dynamic_cast<RsGxsTransMailItem*>(it->second);
if(!msg) if(!msg)
{ {
std::cerr << "p3GxsTrans::service_tick() (EE) " std::cerr << "p3GxsTrans::service_tick() (EE) "
@ -421,6 +515,7 @@ void p3GxsTrans::service_tick()
} }
else else
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::service_tick() " std::cout << "p3GxsTrans::service_tick() "
<< "GXS_MAIL_SUBTYPE_MAIL handling: " << "GXS_MAIL_SUBTYPE_MAIL handling: "
<< msg->meta.mMsgId << msg->meta.mMsgId
@ -430,14 +525,15 @@ void p3GxsTrans::service_tick()
<< " mailId: "<< msg->mailId << " mailId: "<< msg->mailId
<< " payload.size(): " << msg->payload.size() << " payload.size(): " << msg->payload.size()
<< std::endl; << std::endl;
#endif
handleEncryptedMail(msg); handleEncryptedMail(msg);
} }
break; break;
} }
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT:
{ {
RsGxsTransPresignedReceipt* rcpt = RsGxsTransPresignedReceipt* rcpt = dynamic_cast<RsGxsTransPresignedReceipt*>(it->second);
dynamic_cast<RsGxsTransPresignedReceipt*>(it->second);
if(!rcpt) if(!rcpt)
{ {
std::cerr << "p3GxsTrans::service_tick() (EE) " std::cerr << "p3GxsTrans::service_tick() (EE) "
@ -467,22 +563,31 @@ void p3GxsTrans::service_tick()
break; break;
} }
delete it->second; it = mIngoingQueue.erase(it); delete it->second ;
it = mIncomingQueue.erase(it);
changed = true ;
} }
} }
if(changed)
IndicateConfigChanged();
} }
RsGenExchange::ServiceCreate_Return p3GxsTrans::service_CreateGroup( RsGenExchange::ServiceCreate_Return p3GxsTrans::service_CreateGroup(
RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/ ) RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/ )
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::service_CreateGroup(...) " std::cout << "p3GxsTrans::service_CreateGroup(...) "
<< grpItem->meta.mGroupId << std::endl; << grpItem->meta.mGroupId << std::endl;
#endif
return SERVICE_CREATE_SUCCESS; return SERVICE_CREATE_SUCCESS;
} }
void p3GxsTrans::notifyChanges(std::vector<RsGxsNotify*>& changes) void p3GxsTrans::notifyChanges(std::vector<RsGxsNotify*>& changes)
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::notifyChanges(...)" << std::endl; std::cout << "p3GxsTrans::notifyChanges(...)" << std::endl;
#endif
for( std::vector<RsGxsNotify*>::const_iterator it = changes.begin(); for( std::vector<RsGxsNotify*>::const_iterator it = changes.begin();
it != changes.end(); ++it ) it != changes.end(); ++it )
{ {
@ -491,12 +596,16 @@ void p3GxsTrans::notifyChanges(std::vector<RsGxsNotify*>& changes)
if (grpChange) if (grpChange)
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::notifyChanges(...) grpChange" << std::endl; std::cout << "p3GxsTrans::notifyChanges(...) grpChange" << std::endl;
#endif
requestGroupsData(&(grpChange->mGrpIdList)); requestGroupsData(&(grpChange->mGrpIdList));
} }
else if(msgChange) else if(msgChange)
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::notifyChanges(...) msgChange" << std::endl; std::cout << "p3GxsTrans::notifyChanges(...) msgChange" << std::endl;
#endif
uint32_t token; uint32_t token;
RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
RsGenExchange::getTokenService()->requestMsgInfo( token, 0xcaca, RsGenExchange::getTokenService()->requestMsgInfo( token, 0xcaca,
@ -512,13 +621,16 @@ void p3GxsTrans::notifyChanges(std::vector<RsGxsNotify*>& changes)
for(itT vit = msgsIds.begin(); vit != msgsIds.end(); ++vit) for(itT vit = msgsIds.begin(); vit != msgsIds.end(); ++vit)
{ {
const RsGxsMessageId& msgId = *vit; const RsGxsMessageId& msgId = *vit;
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::notifyChanges(...) got " std::cout << "p3GxsTrans::notifyChanges(...) got "
<< "notification for message " << msgId << "notification for message " << msgId
<< " in group " << grpId << std::endl; << " in group " << grpId << std::endl;
#endif
} }
} }
} }
} }
RsGxsIfaceHelper::receiveChanges(changes);
} }
uint32_t p3GxsTrans::AuthenPolicy() uint32_t p3GxsTrans::AuthenPolicy()
@ -563,7 +675,9 @@ bool p3GxsTrans::requestGroupsData(const std::list<RsGxsGroupId>* groupIds)
bool p3GxsTrans::handleEncryptedMail(const RsGxsTransMailItem* mail) bool p3GxsTrans::handleEncryptedMail(const RsGxsTransMailItem* mail)
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::handleEcryptedMail(...)" << std::endl; std::cout << "p3GxsTrans::handleEcryptedMail(...)" << std::endl;
#endif
std::set<RsGxsId> decryptIds; std::set<RsGxsId> decryptIds;
std::list<RsGxsId> ownIds; std::list<RsGxsId> ownIds;
@ -586,8 +700,11 @@ bool p3GxsTrans::handleEncryptedMail(const RsGxsTransMailItem* mail)
uint16_t csri = 0; uint16_t csri = 0;
uint32_t off = 0; uint32_t off = 0;
getRawUInt16(&mail->payload[0], mail->payload.size(), &off, &csri); getRawUInt16(&mail->payload[0], mail->payload.size(), &off, &csri);
#ifdef DEBUG_GXSTRANS
std::cerr << "service: " << csri << " got CLEAR_TEXT mail!" std::cerr << "service: " << csri << " got CLEAR_TEXT mail!"
<< std::endl; << std::endl;
#endif
/* As we cannot verify recipient without encryption, just pass the hint /* As we cannot verify recipient without encryption, just pass the hint
* as recipient */ * as recipient */
return dispatchDecryptedMail( mail->meta.mAuthorId, mail->recipientHint, return dispatchDecryptedMail( mail->meta.mAuthorId, mail->recipientHint,
@ -626,8 +743,10 @@ bool p3GxsTrans::dispatchDecryptedMail( const RsGxsId& authorId,
const uint8_t* decrypted_data, const uint8_t* decrypted_data,
uint32_t decrypted_data_size ) uint32_t decrypted_data_size )
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::dispatchDecryptedMail(, , " << decrypted_data_size std::cout << "p3GxsTrans::dispatchDecryptedMail(, , " << decrypted_data_size
<< ")" << std::endl; << ")" << std::endl;
#endif
uint16_t csri = 0; uint16_t csri = 0;
uint32_t offset = 0; uint32_t offset = 0;
@ -653,8 +772,10 @@ bool p3GxsTrans::dispatchDecryptedMail( const RsGxsId& authorId,
<< " wrong is happening!" << std::endl; << " wrong is happening!" << std::endl;
return false; return false;
} }
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::dispatchDecryptedMail(...) dispatching receipt " std::cout << "p3GxsTrans::dispatchDecryptedMail(...) dispatching receipt "
<< "with: msgId: " << receipt->msgId << std::endl; << "with: msgId: " << receipt->msgId << std::endl;
#endif
std::vector<RsNxsMsg*> rcct; rcct.push_back(receipt); std::vector<RsNxsMsg*> rcct; rcct.push_back(receipt);
RsGenExchange::notifyNewMessages(rcct); RsGenExchange::notifyNewMessages(rcct);
@ -678,7 +799,7 @@ bool p3GxsTrans::dispatchDecryptedMail( const RsGxsId& authorId,
} }
} }
void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr) void p3GxsTrans::locked_processOutgoingRecord(OutgoingRecord& pr)
{ {
//std::cout << "p3GxsTrans::processRecord(...)" << std::endl; //std::cout << "p3GxsTrans::processRecord(...)" << std::endl;
@ -688,7 +809,7 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr)
{ {
pr.mailItem.saltRecipientHint(pr.recipient); pr.mailItem.saltRecipientHint(pr.recipient);
pr.mailItem.saltRecipientHint(RsGxsId::random()); pr.mailItem.saltRecipientHint(RsGxsId::random());
pr.mailItem.meta.mPublishTs = time(NULL); pr.sent_ts = time(NULL) ; //pr.mailItem.meta.mPublishTs = time(NULL);
} }
case GxsTransSendStatus::PENDING_PREFERRED_GROUP: case GxsTransSendStatus::PENDING_PREFERRED_GROUP:
{ {
@ -699,12 +820,16 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr)
break; break;
} }
pr.mailItem.meta.mGroupId = mPreferredGroupId; pr.group_id = mPreferredGroupId ; //pr.mailItem.meta.mGroupId = mPreferredGroupId;
} }
case GxsTransSendStatus::PENDING_RECEIPT_CREATE: case GxsTransSendStatus::PENDING_RECEIPT_CREATE:
{ {
RsGxsTransPresignedReceipt grcpt; RsGxsTransPresignedReceipt grcpt;
grcpt.meta = pr.mailItem.meta; grcpt.meta.mAuthorId = pr.author ; //grcpt.meta = pr.mailItem.meta;
grcpt.meta.mGroupId = pr.group_id ; //grcpt.meta = pr.mailItem.meta;
grcpt.meta.mMsgId.clear() ;
grcpt.meta.mParentId.clear() ;
grcpt.meta.mOrigMsgId.clear() ;
grcpt.meta.mPublishTs = time(NULL); grcpt.meta.mPublishTs = time(NULL);
grcpt.mailId = pr.mailItem.mailId; grcpt.mailId = pr.mailItem.mailId;
uint32_t grsz = RsGxsTransSerializer().size(&grcpt); uint32_t grsz = RsGxsTransSerializer().size(&grcpt);
@ -717,7 +842,7 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr)
*pr.presignedReceipt.metaData = grcpt.meta; *pr.presignedReceipt.metaData = grcpt.meta;
pr.presignedReceipt.msg.setBinData(&grsrz[0], grsz); pr.presignedReceipt.msg.setBinData(&grsrz[0], grsz);
} }
case GxsTransSendStatus::PENDING_RECEIPT_SIGNATURE: case GxsTransSendStatus::PENDING_RECEIPT_SIGNATURE: // (cyril) This step is never actually used.
{ {
switch (RsGenExchange::createMessage(&pr.presignedReceipt)) switch (RsGenExchange::createMessage(&pr.presignedReceipt))
{ {
@ -795,6 +920,7 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr)
} }
case GxsTransSendStatus::PENDING_PUBLISH: case GxsTransSendStatus::PENDING_PUBLISH:
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::sendEmail(...) sending mail to: " std::cout << "p3GxsTrans::sendEmail(...) sending mail to: "
<< pr.recipient << pr.recipient
<< " with cryptoType: " << " with cryptoType: "
@ -803,28 +929,50 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr)
<< " receiptId: " << pr.mailItem.mailId << " receiptId: " << pr.mailItem.mailId
<< " payload size: " << pr.mailItem.payload.size() << " payload size: " << pr.mailItem.payload.size()
<< std::endl; << std::endl;
#endif
RsGxsTransMailItem *mail_item = new RsGxsTransMailItem(pr.mailItem);
// pr.mailItem.meta is *not* serialised. So it is important to not rely on what's in it!
mail_item->meta.mGroupId = pr.group_id ;
mail_item->meta.mAuthorId = pr.author ;
mail_item->meta.mMsgId.clear();
mail_item->meta.mParentId.clear();
mail_item->meta.mOrigMsgId.clear();
uint32_t token; uint32_t token;
publishMsg(token, new RsGxsTransMailItem(pr.mailItem)); publishMsg(token, mail_item) ;
pr.status = GxsTransSendStatus::PENDING_RECEIPT_RECEIVE; pr.status = GxsTransSendStatus::PENDING_RECEIPT_RECEIVE;
IndicateConfigChanged(); // This causes the saving of the message after pr.status has changed.
break; break;
} }
//case GxsTransSendStatus::PENDING_TRANSFER: //case GxsTransSendStatus::PENDING_TRANSFER:
case GxsTransSendStatus::PENDING_RECEIPT_RECEIVE: case GxsTransSendStatus::PENDING_RECEIPT_RECEIVE:
{ {
RS_STACK_MUTEX(mIngoingMutex); RS_STACK_MUTEX(mIngoingMutex);
auto range = mIngoingQueue.equal_range(pr.mailItem.mailId); auto range = mIncomingQueue.equal_range(pr.mailItem.mailId);
bool changed = false ;
for( auto it = range.first; it != range.second; ++it) for( auto it = range.first; it != range.second; ++it)
{ {
RsGxsTransPresignedReceipt* rt = RsGxsTransPresignedReceipt* rt = dynamic_cast<RsGxsTransPresignedReceipt*>(it->second);
dynamic_cast<RsGxsTransPresignedReceipt*>(it->second);
if(rt && mIdService.isOwnId(rt->meta.mAuthorId)) if(rt && mIdService.isOwnId(rt->meta.mAuthorId))
{ {
mIngoingQueue.erase(it); delete rt; mIncomingQueue.erase(it); delete rt;
pr.status = GxsTransSendStatus::RECEIPT_RECEIVED; pr.status = GxsTransSendStatus::RECEIPT_RECEIVED;
changed = true ;
break; break;
} }
} }
if(changed)
IndicateConfigChanged();
// TODO: Resend message if older then treshold // TODO: Resend message if older then treshold
break; break;
} }
@ -875,19 +1023,31 @@ RsSerialiser* p3GxsTrans::setupSerialiser()
bool p3GxsTrans::saveList(bool &cleanup, std::list<RsItem *>& saveList) bool p3GxsTrans::saveList(bool &cleanup, std::list<RsItem *>& saveList)
{ {
std::cout << "p3GxsTrans::saveList(...)" << saveList.size() << " " #ifdef DEBUG_GXSTRANS
<< mIngoingQueue.size() << " " << mOutgoingQueue.size() std::cout << "p3GxsTrans::saveList(...)" << saveList.size() << " " << mIncomingQueue.size() << " " << mOutgoingQueue.size() << std::endl;
<< std::endl; #endif
mOutgoingMutex.lock(); mOutgoingMutex.lock();
mIngoingMutex.lock(); mIngoingMutex.lock();
for ( auto& kv : mOutgoingQueue ) saveList.push_back(&kv.second); for ( auto& kv : mOutgoingQueue )
for ( auto& kv : mIngoingQueue ) saveList.push_back(kv.second); {
#ifdef DEBUG_GXSTRANS
std::cerr << "Saving outgoing item, ID " << std::hex << std::setfill('0') << std::setw(16) << kv.first << std::dec << "Group id: " << kv.second.group_id << ", TS=" << kv.second.sent_ts << std::endl;
#endif
saveList.push_back(&kv.second);
}
for ( auto& kv : mIncomingQueue )
{
#ifdef DEBUG_GXSTRANS
std::cerr << "Saving incoming item, ID " << std::hex << std::setfill('0') << std::setw(16) << kv.first << std::endl;
#endif
saveList.push_back(kv.second);
}
std::cout << "p3GxsTrans::saveList(...)" << saveList.size() << " " #ifdef DEBUG_GXSTRANS
<< mIngoingQueue.size() << " " << mOutgoingQueue.size() std::cout << "p3GxsTrans::saveList(...)" << saveList.size() << " " << mIncomingQueue.size() << " " << mOutgoingQueue.size() << std::endl;
<< std::endl; #endif
cleanup = false; cleanup = false;
return true; return true;
@ -901,9 +1061,11 @@ void p3GxsTrans::saveDone()
bool p3GxsTrans::loadList(std::list<RsItem *>&loadList) bool p3GxsTrans::loadList(std::list<RsItem *>&loadList)
{ {
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::loadList(...) " << loadList.size() << " " std::cout << "p3GxsTrans::loadList(...) " << loadList.size() << " "
<< mIngoingQueue.size() << " " << mOutgoingQueue.size() << mIncomingQueue.size() << " " << mOutgoingQueue.size()
<< std::endl; << std::endl;
#endif
for(auto& v : loadList) for(auto& v : loadList)
switch(static_cast<GxsTransItemsSubtypes>(v->PacketSubType())) switch(static_cast<GxsTransItemsSubtypes>(v->PacketSubType()))
@ -911,14 +1073,44 @@ bool p3GxsTrans::loadList(std::list<RsItem *>&loadList)
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL:
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT:
{ {
RsGxsTransBaseItem* mi = dynamic_cast<RsGxsTransBaseItem*>(v); RsGxsTransBaseMsgItem* mi = dynamic_cast<RsGxsTransBaseMsgItem*>(v);
if(mi) if(mi)
{ {
RS_STACK_MUTEX(mIngoingMutex); RS_STACK_MUTEX(mIngoingMutex);
mIngoingQueue.insert(inMap::value_type(mi->mailId, mi)); mIncomingQueue.insert(inMap::value_type(mi->mailId, mi));
} }
break; break;
} }
case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM_deprecated:
{
OutgoingRecord_deprecated* dot = dynamic_cast<OutgoingRecord_deprecated*>(v);
if(dot)
{
std::cerr << "(EE) Read a deprecated GxsTrans outgoing item. Converting to new format..." << std::endl;
OutgoingRecord ot(dot->recipient,dot->clientService,&dot->mailData[0],dot->mailData.size()) ;
ot.status = dot->status ;
ot.author.clear(); // These 3 fields cannot be stored in mailItem.meta, which is not serialised, so they are lost.
ot.group_id.clear() ;
ot.sent_ts = 0;
ot.mailItem = dot->mailItem ;
ot.presignedReceipt = dot->presignedReceipt;
RS_STACK_MUTEX(mOutgoingMutex);
mOutgoingQueue.insert(prMap::value_type(ot.mailItem.mailId, ot));
#ifdef DEBUG_GXSTRANS
std::cerr << "Loaded outgoing item (converted), ID " << std::hex << std::setfill('0') << std::setw(16) << ot.mailItem.mailId<< std::dec << ", Group id: " << ot.group_id << ", TS=" << ot.sent_ts << std::endl;
#endif
}
delete v;
break;
}
case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM:
{ {
OutgoingRecord* ot = dynamic_cast<OutgoingRecord*>(v); OutgoingRecord* ot = dynamic_cast<OutgoingRecord*>(v);
@ -927,6 +1119,10 @@ bool p3GxsTrans::loadList(std::list<RsItem *>&loadList)
RS_STACK_MUTEX(mOutgoingMutex); RS_STACK_MUTEX(mOutgoingMutex);
mOutgoingQueue.insert( mOutgoingQueue.insert(
prMap::value_type(ot->mailItem.mailId, *ot)); prMap::value_type(ot->mailItem.mailId, *ot));
#ifdef DEBUG_GXSTRANS
std::cerr << "Loading outgoing item, ID " << std::hex << std::setfill('0') << std::setw(16) << ot->mailItem.mailId<< std::dec << "Group id: " << ot->group_id << ", TS=" << ot->sent_ts << std::endl;
#endif
} }
delete v; delete v;
break; break;
@ -941,9 +1137,106 @@ bool p3GxsTrans::loadList(std::list<RsItem *>&loadList)
break; break;
} }
#ifdef DEBUG_GXSTRANS
std::cout << "p3GxsTrans::loadList(...) " << loadList.size() << " " std::cout << "p3GxsTrans::loadList(...) " << loadList.size() << " "
<< mIngoingQueue.size() << " " << mOutgoingQueue.size() << mIncomingQueue.size() << " " << mOutgoingQueue.size()
<< std::endl; << std::endl;
#endif
return true; return true;
} }
bool p3GxsTrans::acceptNewMessage(const RsGxsMsgMetaData *msgMeta,uint32_t msg_size)
{
// 1 - check the total size of the msgs for the author of this particular msg.
// 2 - Reject depending on embedded limits.
// Depending on reputation, the messages will be rejected:
//
// Reputation | Maximum msg count | Maximum msg size
// ------------+----------------------+------------------
// Negative | 0 | 0 // This is already handled by the anti-spam
// R-Negative | 10 | 10k
// Neutral | 100 | 20k
// R-Positive | 400 | 1M
// Positive | 1000 | 2M
// Ideally these values should be left as user-defined parameters, with the
// default values below used as backup.
static const uint32_t GXSTRANS_MAX_COUNT_REMOTELY_NEGATIVE_DEFAULT = 10 ;
static const uint32_t GXSTRANS_MAX_COUNT_NEUTRAL_DEFAULT = 40 ;
static const uint32_t GXSTRANS_MAX_COUNT_REMOTELY_POSITIVE_DEFAULT = 400 ;
static const uint32_t GXSTRANS_MAX_COUNT_LOCALLY_POSITIVE_DEFAULT = 1000 ;
static const uint32_t GXSTRANS_MAX_SIZE_REMOTELY_NEGATIVE_DEFAULT = 10 * 1024 ;
static const uint32_t GXSTRANS_MAX_SIZE_NEUTRAL_DEFAULT = 200 * 1024 ;
static const uint32_t GXSTRANS_MAX_SIZE_REMOTELY_POSITIVE_DEFAULT = 1024 * 1024 ;
static const uint32_t GXSTRANS_MAX_SIZE_LOCALLY_POSITIVE_DEFAULT = 2 * 1024 * 1024 ;
uint32_t max_count = 0 ;
uint32_t max_size = 0 ;
uint32_t identity_flags = 0 ;
RsReputations::ReputationLevel rep_lev = rsReputations->overallReputationLevel(msgMeta->mAuthorId,&identity_flags);
switch(rep_lev)
{
case RsReputations::REPUTATION_REMOTELY_NEGATIVE: max_count = GXSTRANS_MAX_COUNT_REMOTELY_NEGATIVE_DEFAULT;
max_size = GXSTRANS_MAX_SIZE_REMOTELY_NEGATIVE_DEFAULT;
break ;
case RsReputations::REPUTATION_NEUTRAL: max_count = GXSTRANS_MAX_COUNT_NEUTRAL_DEFAULT;
max_size = GXSTRANS_MAX_SIZE_NEUTRAL_DEFAULT;
break ;
case RsReputations::REPUTATION_REMOTELY_POSITIVE: max_count = GXSTRANS_MAX_COUNT_REMOTELY_POSITIVE_DEFAULT;
max_size = GXSTRANS_MAX_SIZE_REMOTELY_POSITIVE_DEFAULT;
break ;
case RsReputations::REPUTATION_LOCALLY_POSITIVE: max_count = GXSTRANS_MAX_COUNT_LOCALLY_POSITIVE_DEFAULT;
max_size = GXSTRANS_MAX_SIZE_LOCALLY_POSITIVE_DEFAULT;
break ;
default:
case RsReputations::REPUTATION_LOCALLY_NEGATIVE: max_count = 0 ;
max_size = 0 ;
break ;
}
bool pgp_linked = identity_flags & RS_IDENTITY_FLAGS_PGP_LINKED ;
if(rep_lev <= RsReputations::REPUTATION_NEUTRAL && !pgp_linked)
{
max_count /= 10 ;
max_size /= 10 ;
}
RS_STACK_MUTEX(mPerUserStatsMutex);
MsgSizeCount& s(per_user_statistics[msgMeta->mAuthorId]) ;
#ifdef DEBUG_GXSTRANS
std::cerr << "GxsTrans::acceptMessage(): size=" << msg_size << ", grp=" << msgMeta->mGroupId << ", gxs_id=" << msgMeta->mAuthorId << ", pgp_linked=" << pgp_linked << ", current (size,cnt)=("
<< s.size << "," << s.count << ") reputation=" << rep_lev << ", limits=(" << max_size << "," << max_count << ") " ;
#endif
if(s.size + msg_size > max_size || 1+s.count > max_count)
{
#ifdef DEBUG_GXSTRANS
std::cerr << "=> rejected." << std::endl;
#endif
return false ;
}
else
{
#ifdef DEBUG_GXSTRANS
std::cerr << "=> accepted." << std::endl;
#endif
s.count++ ;
s.size += msg_size ; // update the statistics, so that it's not possible to pass a bunch of msgs at once below the limits.
return true ;
}
}

View File

@ -57,6 +57,14 @@ struct GxsTransClient
GxsTransSendStatus status ) = 0; GxsTransSendStatus status ) = 0;
}; };
struct MsgSizeCount
{
MsgSizeCount() : size(0),count(0) {}
uint32_t size ;
uint32_t count ;
};
/** /**
* @brief p3GxsTrans is a mail delivery service based on GXS. * @brief p3GxsTrans is a mail delivery service based on GXS.
* p3GxsTrans is capable of asynchronous mail delivery and acknowledgement. * p3GxsTrans is capable of asynchronous mail delivery and acknowledgement.
@ -90,9 +98,10 @@ public:
mIdService(identities), mIdService(identities),
mServClientsMutex("p3GxsTrans client services map mutex"), mServClientsMutex("p3GxsTrans client services map mutex"),
mOutgoingMutex("p3GxsTrans outgoing queue map mutex"), mOutgoingMutex("p3GxsTrans outgoing queue map mutex"),
mIngoingMutex("p3GxsTrans ingoing queue map mutex") mIngoingMutex("p3GxsTrans ingoing queue map mutex"),
mPerUserStatsMutex("p3GxsTrans user stats mutex")
{ {
mLastMsgCleanup = time(NULL) - 60; // to be changed into 0 mLastMsgCleanup = time(NULL) - MAX_DELAY_BETWEEN_CLEANUPS + 30; // always check 30 secs after start
mCleanupThread = NULL ; mCleanupThread = NULL ;
} }
@ -159,7 +168,7 @@ private:
* Two weeks seems fair ATM. * Two weeks seems fair ATM.
*/ */
static const uint32_t GXS_STORAGE_PERIOD = 0x127500; static const uint32_t GXS_STORAGE_PERIOD = 0x127500;
static const uint32_t MAX_DELAY_BETWEEN_CLEANUPS = 1203; // every 20 mins. Could be less. static const uint32_t MAX_DELAY_BETWEEN_CLEANUPS ; // every 20 mins. Could be less.
time_t mLastMsgCleanup ; time_t mLastMsgCleanup ;
@ -193,7 +202,7 @@ private:
typedef std::map<RsGxsTransId, OutgoingRecord> prMap; typedef std::map<RsGxsTransId, OutgoingRecord> prMap;
prMap mOutgoingQueue; prMap mOutgoingQueue;
RsMutex mOutgoingMutex; RsMutex mOutgoingMutex;
void processOutgoingRecord(OutgoingRecord& r); void locked_processOutgoingRecord(OutgoingRecord& r);
/** /**
* @brief Ingoing mail and receipt processing queue. * @brief Ingoing mail and receipt processing queue.
@ -204,8 +213,8 @@ private:
* item to not being processed and memleaked multimap is used instead of map * item to not being processed and memleaked multimap is used instead of map
* for incoming queue. * for incoming queue.
*/ */
typedef std::unordered_multimap<RsGxsTransId, RsGxsTransBaseItem*> inMap; typedef std::unordered_multimap<RsGxsTransId, RsGxsTransBaseMsgItem*> inMap;
inMap mIngoingQueue; inMap mIncomingQueue;
RsMutex mIngoingMutex; RsMutex mIngoingMutex;
/// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type) /// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type)
@ -282,7 +291,7 @@ private:
enum CheckState { CheckStart, CheckChecking }; enum CheckState { CheckStart, CheckChecking };
public: public:
GxsTransIntegrityCleanupThread(RsGeneralDataService *const dataService): mDs(dataService),mMtx("GxsTransIntegrityCheck") {} GxsTransIntegrityCleanupThread(RsGeneralDataService *const dataService): mDs(dataService),mMtx("GxsTransIntegrityCheck") { mDone=false;}
bool isDone(); bool isDone();
void run(); void run();
@ -290,14 +299,26 @@ private:
void getDeletedIds(std::list<RsGxsGroupId>& grpIds, std::map<RsGxsGroupId, std::vector<RsGxsMessageId> >& msgIds); void getDeletedIds(std::list<RsGxsGroupId>& grpIds, std::map<RsGxsGroupId, std::vector<RsGxsMessageId> >& msgIds);
void getMessagesToDelete(GxsMsgReq& req) ; void getMessagesToDelete(GxsMsgReq& req) ;
void getPerUserStatistics(std::map<RsGxsId,MsgSizeCount>& m) ;
private: private:
RsGeneralDataService* const mDs; RsGeneralDataService* const mDs;
RsMutex mMtx ; RsMutex mMtx ;
GxsMsgReq mMsgToDel ; GxsMsgReq mMsgToDel ;
std::map<RsGxsId,MsgSizeCount> total_message_size_and_count;
bool mDone ;
}; };
// Overloaded from RsGenExchange.
bool acceptNewMessage(const RsGxsMsgMetaData *msgMeta, uint32_t size) ;
GxsTransIntegrityCleanupThread *mCleanupThread ; GxsTransIntegrityCleanupThread *mCleanupThread ;
// statistics of the load across all groups, per user.
RsMutex mPerUserStatsMutex;
std::map<RsGxsId,MsgSizeCount> per_user_statistics ;
}; };

View File

@ -21,10 +21,11 @@
const RsGxsId RsGxsTransMailItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); const RsGxsId RsGxsTransMailItem::allRecipientsHint("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
OutgoingRecord::OutgoingRecord() : OutgoingRecord_deprecated::OutgoingRecord_deprecated()
RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TRANS, : RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TRANS, static_cast<uint8_t>(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM_deprecated) ) { clear();}
static_cast<uint8_t>(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM) )
{ clear();} OutgoingRecord::OutgoingRecord()
: RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TRANS, static_cast<uint8_t>(GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM) ) { clear();}
OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsTransSubServices cs, OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsTransSubServices cs,
const uint8_t* data, uint32_t size ) : const uint8_t* data, uint32_t size ) :
@ -41,8 +42,7 @@ OutgoingRecord::OutgoingRecord( RsGxsId rec, GxsTransSubServices cs,
RS_REGISTER_ITEM_TYPE(RsGxsTransMailItem) // for mailItem RS_REGISTER_ITEM_TYPE(RsGxsTransMailItem) // for mailItem
RS_REGISTER_ITEM_TYPE(RsNxsTransPresignedReceipt) // for presignedReceipt RS_REGISTER_ITEM_TYPE(RsNxsTransPresignedReceipt) // for presignedReceipt
void OutgoingRecord::serial_process(RsGenericSerializer::SerializeJob j, void OutgoingRecord_deprecated::serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx)
RsGenericSerializer::SerializeContext& ctx)
{ {
RS_REGISTER_SERIAL_MEMBER_TYPED(status, uint8_t); RS_REGISTER_SERIAL_MEMBER_TYPED(status, uint8_t);
RS_REGISTER_SERIAL_MEMBER(recipient); RS_REGISTER_SERIAL_MEMBER(recipient);
@ -51,3 +51,17 @@ void OutgoingRecord::serial_process(RsGenericSerializer::SerializeJob j,
RS_REGISTER_SERIAL_MEMBER_TYPED(clientService, uint16_t); RS_REGISTER_SERIAL_MEMBER_TYPED(clientService, uint16_t);
RS_REGISTER_SERIAL_MEMBER(presignedReceipt); RS_REGISTER_SERIAL_MEMBER(presignedReceipt);
} }
void OutgoingRecord::serial_process(RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx)
{
RS_REGISTER_SERIAL_MEMBER_TYPED(status, uint8_t);
RS_REGISTER_SERIAL_MEMBER(recipient);
RS_REGISTER_SERIAL_MEMBER(author);
RS_REGISTER_SERIAL_MEMBER(group_id);
RS_REGISTER_SERIAL_MEMBER(sent_ts);
RS_REGISTER_SERIAL_MEMBER(mailItem);
RS_REGISTER_SERIAL_MEMBER(mailData);
RS_REGISTER_SERIAL_MEMBER_TYPED(clientService, uint16_t);
RS_REGISTER_SERIAL_MEMBER(presignedReceipt);
}

View File

@ -36,14 +36,14 @@ public:
virtual ~RsNxsTransPresignedReceipt() {} virtual ~RsNxsTransPresignedReceipt() {}
}; };
class RsGxsTransBaseItem : public RsGxsMsgItem class RsGxsTransBaseMsgItem : public RsGxsMsgItem
{ {
public: public:
RsGxsTransBaseItem(GxsTransItemsSubtypes subtype) : RsGxsTransBaseMsgItem(GxsTransItemsSubtypes subtype) :
RsGxsMsgItem( RS_SERVICE_TYPE_GXS_TRANS, RsGxsMsgItem( RS_SERVICE_TYPE_GXS_TRANS,
static_cast<uint8_t>(subtype) ), mailId(0) {} static_cast<uint8_t>(subtype) ), mailId(0) {}
virtual ~RsGxsTransBaseItem() {} virtual ~RsGxsTransBaseMsgItem() {}
RsGxsTransId mailId; RsGxsTransId mailId;
@ -58,10 +58,10 @@ public:
{ RS_REGISTER_SERIAL_MEMBER_TYPED(mailId, uint64_t); } { RS_REGISTER_SERIAL_MEMBER_TYPED(mailId, uint64_t); }
}; };
class RsGxsTransPresignedReceipt : public RsGxsTransBaseItem class RsGxsTransPresignedReceipt : public RsGxsTransBaseMsgItem
{ {
public: public:
RsGxsTransPresignedReceipt() : RsGxsTransBaseItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT) {} RsGxsTransPresignedReceipt() : RsGxsTransBaseMsgItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT) {}
virtual ~RsGxsTransPresignedReceipt() {} virtual ~RsGxsTransPresignedReceipt() {}
}; };
@ -72,11 +72,11 @@ enum class RsGxsTransEncryptionMode : uint8_t
UNDEFINED_ENCRYPTION = 250 UNDEFINED_ENCRYPTION = 250
}; };
class RsGxsTransMailItem : public RsGxsTransBaseItem class RsGxsTransMailItem : public RsGxsTransBaseMsgItem
{ {
public: public:
RsGxsTransMailItem() : RsGxsTransMailItem() :
RsGxsTransBaseItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL), RsGxsTransBaseMsgItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL),
cryptoType(RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION) {} cryptoType(RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION) {}
virtual ~RsGxsTransMailItem() {} virtual ~RsGxsTransMailItem() {}
@ -139,7 +139,7 @@ public:
void serial_process( RsGenericSerializer::SerializeJob j, void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) RsGenericSerializer::SerializeContext& ctx )
{ {
RsGxsTransBaseItem::serial_process(j, ctx); RsGxsTransBaseMsgItem::serial_process(j, ctx);
RS_REGISTER_SERIAL_MEMBER_TYPED(cryptoType, uint8_t); RS_REGISTER_SERIAL_MEMBER_TYPED(cryptoType, uint8_t);
RS_REGISTER_SERIAL_MEMBER(recipientHint); RS_REGISTER_SERIAL_MEMBER(recipientHint);
RS_REGISTER_SERIAL_MEMBER(payload); RS_REGISTER_SERIAL_MEMBER(payload);
@ -147,7 +147,7 @@ public:
void clear() void clear()
{ {
RsGxsTransBaseItem::clear(); RsGxsTransBaseMsgItem::clear();
cryptoType = RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION; cryptoType = RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION;
recipientHint.clear(); recipientHint.clear();
payload.clear(); payload.clear();
@ -183,6 +183,33 @@ public:
class RsGxsTransSerializer; class RsGxsTransSerializer;
class OutgoingRecord_deprecated : public RsItem
{
public:
OutgoingRecord_deprecated( RsGxsId rec, GxsTransSubServices cs, const uint8_t* data, uint32_t size );
virtual ~OutgoingRecord_deprecated() {}
GxsTransSendStatus status;
RsGxsId recipient;
/// Don't use a pointer would be invalid after publish
RsGxsTransMailItem mailItem;
std::vector<uint8_t> mailData;
GxsTransSubServices clientService;
RsNxsTransPresignedReceipt presignedReceipt;
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx );
void clear() {}
private:
friend class RsGxsTransSerializer;
OutgoingRecord_deprecated();
};
class OutgoingRecord : public RsItem class OutgoingRecord : public RsItem
{ {
public: public:
@ -193,10 +220,17 @@ public:
GxsTransSendStatus status; GxsTransSendStatus status;
RsGxsId recipient; RsGxsId recipient;
RsGxsId author; // These 3 fields cannot be stored in mailItem.meta, which is not serialised.
RsGxsGroupId group_id ;
uint32_t sent_ts ;
/// Don't use a pointer would be invalid after publish /// Don't use a pointer would be invalid after publish
RsGxsTransMailItem mailItem; RsGxsTransMailItem mailItem;
std::vector<uint8_t> mailData; std::vector<uint8_t> mailData;
GxsTransSubServices clientService; GxsTransSubServices clientService;
RsNxsTransPresignedReceipt presignedReceipt; RsNxsTransPresignedReceipt presignedReceipt;
void serial_process( RsGenericSerializer::SerializeJob j, void serial_process( RsGenericSerializer::SerializeJob j,
@ -225,6 +259,7 @@ public:
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: return new RsGxsTransMailItem(); case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL: return new RsGxsTransMailItem();
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: return new RsGxsTransPresignedReceipt(); case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT: return new RsGxsTransPresignedReceipt();
case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: return new RsGxsTransGroupItem(); case GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_GROUP: return new RsGxsTransGroupItem();
case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM_deprecated: return new OutgoingRecord_deprecated();
case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: return new OutgoingRecord(); case GxsTransItemsSubtypes::OUTGOING_RECORD_ITEM: return new OutgoingRecord();
default: return NULL; default: return NULL;
} }

View File

@ -142,6 +142,7 @@ public:
/* standard load */ /* standard load */
virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsCircleGroup> &groups) = 0; virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsCircleGroup> &groups) = 0;
virtual bool getMsgData(const uint32_t &token, std::vector<RsGxsCircleMsg> &msgs) = 0;
/* make new group */ /* make new group */
virtual void createGroup(uint32_t& token, RsGxsCircleGroup &group) = 0; virtual void createGroup(uint32_t& token, RsGxsCircleGroup &group) = 0;

View File

@ -19,7 +19,8 @@ enum class GxsTransItemsSubtypes : uint8_t
GXS_TRANS_SUBTYPE_MAIL = 0x01, GXS_TRANS_SUBTYPE_MAIL = 0x01,
GXS_TRANS_SUBTYPE_RECEIPT = 0x02, GXS_TRANS_SUBTYPE_RECEIPT = 0x02,
GXS_TRANS_SUBTYPE_GROUP = 0x03, GXS_TRANS_SUBTYPE_GROUP = 0x03,
OUTGOING_RECORD_ITEM = 0x04 OUTGOING_RECORD_ITEM_deprecated = 0x04,
OUTGOING_RECORD_ITEM = 0x05
}; };
enum class GxsTransSendStatus : uint8_t enum class GxsTransSendStatus : uint8_t

View File

@ -77,6 +77,7 @@ const uint32_t RS_FEED_TYPE_FILES = 0x0400;
const uint32_t RS_FEED_TYPE_SECURITY = 0x0800; const uint32_t RS_FEED_TYPE_SECURITY = 0x0800;
const uint32_t RS_FEED_TYPE_POSTED = 0x1000; const uint32_t RS_FEED_TYPE_POSTED = 0x1000;
const uint32_t RS_FEED_TYPE_SECURITY_IP = 0x2000; const uint32_t RS_FEED_TYPE_SECURITY_IP = 0x2000;
const uint32_t RS_FEED_TYPE_CIRCLE = 0x4000;
const uint32_t RS_FEED_ITEM_PEER_CONNECT = RS_FEED_TYPE_PEER | 0x0001; const uint32_t RS_FEED_ITEM_PEER_CONNECT = RS_FEED_TYPE_PEER | 0x0001;
const uint32_t RS_FEED_ITEM_PEER_DISCONNECT = RS_FEED_TYPE_PEER | 0x0002; const uint32_t RS_FEED_ITEM_PEER_DISCONNECT = RS_FEED_TYPE_PEER | 0x0002;
@ -118,6 +119,9 @@ 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_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_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_MESSAGE_CONNECT_ATTEMPT = 0x0001; const uint32_t RS_MESSAGE_CONNECT_ATTEMPT = 0x0001;
const int NOTIFY_LIST_NEIGHBOURS = 1; const int NOTIFY_LIST_NEIGHBOURS = 1;

View File

@ -55,7 +55,8 @@ void RsGxsCircleSubscriptionRequestItem::clear()
void RsGxsCircleMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) void RsGxsCircleMsgItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{ {
RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_MSG,msg.stuff,"msg.stuff") ; //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 RsGxsCircleSubscriptionRequestItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) void RsGxsCircleSubscriptionRequestItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
@ -74,7 +75,7 @@ void RsGxsCircleGroupItem::serial_process(RsGenericSerializer::SerializeJob j,Rs
void RsGxsCircleMsgItem::clear() void RsGxsCircleMsgItem::clear()
{ {
msg.stuff.clear(); mMsg.stuff.clear();
} }
void RsGxsCircleGroupItem::clear() void RsGxsCircleGroupItem::clear()

View File

@ -78,7 +78,7 @@ public:
virtual void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx); virtual void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx);
RsGxsCircleMsg msg; RsGxsCircleMsg mMsg;
}; };
class RsGxsCircleSubscriptionRequestItem: public RsGxsMsgItem class RsGxsCircleSubscriptionRequestItem: public RsGxsMsgItem

View File

@ -34,7 +34,7 @@ static const int sleepFactorDefault = 10; // 0.5s
static const int sleepFactorFast = 1; // 0.05s static const int sleepFactorFast = 1; // 0.05s
static const int sleepFactorSlow = 20; // 1s static const int sleepFactorSlow = 20; // 1s
static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Debug_All, "p3I2pBob"}; static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Default, "p3I2pBob"};
static const time_t selfCheckPeroid = 30; static const time_t selfCheckPeroid = 30;

View File

@ -35,6 +35,7 @@
#include "pgp/pgpauxutils.h" #include "pgp/pgpauxutils.h"
#include "retroshare/rsgxscircles.h" #include "retroshare/rsgxscircles.h"
#include "retroshare/rspeers.h" #include "retroshare/rspeers.h"
#include "rsserver/p3face.h"
#include <sstream> #include <sstream>
#include <stdio.h> #include <stdio.h>
@ -198,11 +199,13 @@ void p3GxsCircles::notifyChanges(std::vector<RsGxsNotify *> &changes)
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
p3Notify *notify = RsServer::notify();
std::vector<RsGxsNotify *>::iterator it; std::vector<RsGxsNotify *>::iterator it;
for(it = changes.begin(); it != changes.end(); ++it) for(it = changes.begin(); it != changes.end(); ++it)
{ {
RsGxsGroupChange *groupChange = dynamic_cast<RsGxsGroupChange *>(*it); RsGxsGroupChange *groupChange = dynamic_cast<RsGxsGroupChange *>(*it);
RsGxsMsgChange *msgChange = dynamic_cast<RsGxsMsgChange *>(*it); RsGxsMsgChange *msgChange = dynamic_cast<RsGxsMsgChange *>(*it);
RsGxsNotify *c = *it;
if (msgChange && !msgChange->metaChange()) if (msgChange && !msgChange->metaChange())
{ {
@ -214,8 +217,14 @@ void p3GxsCircles::notifyChanges(std::vector<RsGxsNotify *> &changes)
#ifdef DEBUG_CIRCLES #ifdef DEBUG_CIRCLES
std::cerr << " Msgs for Group: " << mit->first << std::endl; std::cerr << " Msgs for Group: " << mit->first << std::endl;
#endif #endif
for(std::map<RsGxsGroupId, std::vector<RsGxsMessageId> >::const_iterator it2(msgChange->msgChangeMap.begin());it2!=msgChange->msgChangeMap.end();++it2) force_cache_reload(RsGxsCircleId(mit->first));
force_cache_reload(RsGxsCircleId(it2->first)) ; if (notify && (c->getType() == RsGxsNotify::TYPE_RECEIVE) )
for (std::vector<RsGxsMessageId>::const_iterator msgIdIt(mit->second.begin()), end(mit->second.end()); msgIdIt != end; ++msgIdIt)
{
const RsGxsMessageId& msgId = *msgIdIt;
notify->AddFeedItem(RS_FEED_ITEM_CIRCLE_MEMB_REQ,RsGxsCircleId(mit->first).toStdString(),msgId.toStdString());
}
} }
} }
@ -252,7 +261,10 @@ void p3GxsCircles::notifyChanges(std::vector<RsGxsNotify *> &changes)
std::cerr << " forcing cache loading for circle " << *git << " in order to trigger subscribe update." << std::endl; std::cerr << " forcing cache loading for circle " << *git << " in order to trigger subscribe update." << std::endl;
#endif #endif
force_cache_reload(RsGxsCircleId(*git)) ; force_cache_reload(RsGxsCircleId(*git)) ;
if (notify && (c->getType() == RsGxsNotify::TYPE_RECEIVE) )
notify->AddFeedItem(RS_FEED_ITEM_CIRCLE_INVIT_REC,RsGxsCircleId(*git).toStdString(),"");
} }
} }
RsGxsIfaceHelper::receiveChanges(changes); // this clear up the vector and delete its elements RsGxsIfaceHelper::receiveChanges(changes); // this clear up the vector and delete its elements
} }
@ -496,6 +508,62 @@ bool p3GxsCircles::getGroupData(const uint32_t &token, std::vector<RsGxsCircleGr
/********************************************************************************/ /********************************************************************************/
/********************************************************************************/ /********************************************************************************/
bool p3GxsCircles::getMsgData(const uint32_t &token, std::vector<RsGxsCircleMsg> &msgs)
{
GxsMsgDataMap msgData;
bool ok = RsGenExchange::getMsgData(token, msgData);
if(ok)
{
GxsMsgDataMap::iterator mit = msgData.begin();
for(; mit != msgData.end(); ++mit)
{
std::vector<RsGxsMsgItem*>& msgItems = mit->second;
std::vector<RsGxsMsgItem*>::iterator vit = msgItems.begin();
for(; vit != msgItems.end(); ++vit)
{
RsGxsCircleMsgItem* item = dynamic_cast<RsGxsCircleMsgItem*>(*vit);
RsGxsCircleSubscriptionRequestItem* rsItem = dynamic_cast<RsGxsCircleSubscriptionRequestItem*>(*vit);
if(item)
{
RsGxsCircleMsg msg = item->mMsg;
msg.mMeta = item->meta;
msgs.push_back(msg);
delete item;
}
else 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;
}
msgs.push_back(msg);
delete rsItem;
}
else
{
std::cerr << "Not a GxsCircleMsgItem, deleting!" << std::endl;
delete *vit;
}
}
}
}
return ok;
}
void p3GxsCircles::createGroup(uint32_t& token, RsGxsCircleGroup &group) void p3GxsCircles::createGroup(uint32_t& token, RsGxsCircleGroup &group)
{ {
#ifdef DEBUG_CIRCLES #ifdef DEBUG_CIRCLES
@ -2065,21 +2133,3 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token)
return true ; return true ;
} }

View File

@ -199,6 +199,7 @@ virtual RsServiceInfo getServiceInfo();
virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsCircleGroup> &groups); virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsCircleGroup> &groups);
virtual bool getMsgData(const uint32_t &token, std::vector<RsGxsCircleMsg> &msgs);
virtual void createGroup(uint32_t& token, RsGxsCircleGroup &group); virtual void createGroup(uint32_t& token, RsGxsCircleGroup &group);
virtual void updateGroup(uint32_t &token, RsGxsCircleGroup &group); virtual void updateGroup(uint32_t &token, RsGxsCircleGroup &group);

View File

@ -179,6 +179,7 @@ void RsThread::start(const std::string &threadName)
THREAD_DEBUG << "pqithreadstreamer::start() initing should_stop=0" << std::endl; THREAD_DEBUG << "pqithreadstreamer::start() initing should_stop=0" << std::endl;
#endif #endif
mShouldStopSemaphore.set(0) ; mShouldStopSemaphore.set(0) ;
mHasStoppedSemaphore.set(0) ;
int err ; int err ;

View File

@ -25,45 +25,43 @@
#include "NewsFeed.h" #include "NewsFeed.h"
#include "ui_NewsFeed.h" #include "ui_NewsFeed.h"
#include <retroshare/rsnotify.h> #include <retroshare/rsbanlist.h>
#include <retroshare/rspeers.h>
#include <retroshare/rsgxschannels.h> #include <retroshare/rsgxschannels.h>
#include <retroshare/rsgxsforums.h> #include <retroshare/rsgxsforums.h>
#include <retroshare/rsposted.h>
#include <retroshare/rsmsgs.h> #include <retroshare/rsmsgs.h>
#include <retroshare/rsnotify.h>
#include <retroshare/rspeers.h>
#include <retroshare/rsplugin.h> #include <retroshare/rsplugin.h>
#include <retroshare/rsbanlist.h> #include <retroshare/rsposted.h>
#include "feeds/GxsChannelGroupItem.h"
#include "feeds/GxsChannelPostItem.h"
#include "feeds/GxsForumGroupItem.h"
#include "feeds/GxsForumMsgItem.h"
#include "feeds/PostedGroupItem.h"
#include "Posted/PostedItem.h"
#include "feeds/GxsForumMsgItem.h"
#include "settings/rsettingswin.h"
#include "feeds/ChatMsgItem.h"
#ifdef BLOGS #ifdef BLOGS
#include "feeds/BlogNewItem.h" #include "feeds/BlogNewItem.h"
#include "feeds/BlogMsgItem.h" #include "feeds/BlogMsgItem.h"
#endif #endif
#include "feeds/GxsCircleItem.h"
#include "feeds/GxsChannelGroupItem.h"
#include "feeds/GxsChannelPostItem.h"
#include "feeds/GxsForumGroupItem.h"
#include "feeds/GxsForumMsgItem.h"
#include "feeds/MsgItem.h" #include "feeds/MsgItem.h"
#include "feeds/NewsFeedUserNotify.h"
#include "feeds/PeerItem.h" #include "feeds/PeerItem.h"
#include "feeds/ChatMsgItem.h" #include "feeds/PostedGroupItem.h"
#include "feeds/SecurityItem.h" #include "feeds/SecurityItem.h"
#include "feeds/SecurityIpItem.h" #include "feeds/SecurityIpItem.h"
#include "feeds/NewsFeedUserNotify.h"
#include "settings/rsettingswin.h"
#include "settings/rsharesettings.h" #include "settings/rsharesettings.h"
#include "chat/ChatDialog.h" #include "chat/ChatDialog.h"
#include "Posted/PostedItem.h"
#include "msgs/MessageComposer.h" #include "msgs/MessageComposer.h"
#include "msgs/MessageInterface.h"
#include "common/FeedNotify.h" #include "common/FeedNotify.h"
#include "notifyqt.h" #include "notifyqt.h"
#include "gui/msgs/MessageInterface.h"
const uint32_t NEWSFEED_PEERLIST = 0x0001; const uint32_t NEWSFEED_PEERLIST = 0x0001;
const uint32_t NEWSFEED_FORUMNEWLIST = 0x0002; const uint32_t NEWSFEED_FORUMNEWLIST = 0x0002;
@ -80,6 +78,7 @@ const uint32_t NEWSFEED_CHATMSGLIST = 0x0009;
const uint32_t NEWSFEED_SECLIST = 0x000a; const uint32_t NEWSFEED_SECLIST = 0x000a;
const uint32_t NEWSFEED_POSTEDNEWLIST = 0x000b; const uint32_t NEWSFEED_POSTEDNEWLIST = 0x000b;
const uint32_t NEWSFEED_POSTEDMSGLIST = 0x000c; const uint32_t NEWSFEED_POSTEDMSGLIST = 0x000c;
const uint32_t NEWSFEED_CIRCLELIST = 0x000d;
#define ROLE_RECEIVED FEED_TREEWIDGET_SORTROLE #define ROLE_RECEIVED FEED_TREEWIDGET_SORTROLE
@ -102,6 +101,7 @@ NewsFeed::NewsFeed(QWidget *parent) :
ui->setupUi(this); ui->setupUi(this);
mTokenQueueChannel = NULL; mTokenQueueChannel = NULL;
mTokenQueueCircle = NULL;
mTokenQueueForum = NULL; mTokenQueueForum = NULL;
mTokenQueuePosted = NULL; mTokenQueuePosted = NULL;
@ -156,6 +156,9 @@ NewsFeed::~NewsFeed()
if (mTokenQueueChannel) { if (mTokenQueueChannel) {
delete(mTokenQueueChannel); delete(mTokenQueueChannel);
} }
if (mTokenQueueCircle) {
delete(mTokenQueueCircle);
}
if (mTokenQueueForum) { if (mTokenQueueForum) {
delete(mTokenQueueForum); delete(mTokenQueueForum);
} }
@ -370,6 +373,52 @@ void NewsFeed::updateDisplay()
if (flags & RS_FEED_TYPE_FILES) if (flags & RS_FEED_TYPE_FILES)
addFeedItemFilesNew(fi); addFeedItemFilesNew(fi);
break; break;
case RS_FEED_ITEM_CIRCLE_MEMB_REQ:
if (flags & RS_FEED_TYPE_CIRCLE)
{
if (!mTokenQueueCircle) {
mTokenQueueCircle = new TokenQueue(rsGxsCircles->getTokenService(), instance);
}
RsGxsGroupId grpId(fi.mId1);
RsGxsMessageId msgId(fi.mId2);
if (!grpId.isNull() && !msgId.isNull()) {
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
GxsMsgReq msgIds;
std::vector<RsGxsMessageId> &vect_msgIds = msgIds[grpId];
vect_msgIds.push_back(msgId);
uint32_t token;
mTokenQueueCircle->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, TOKEN_TYPE_MESSAGE);
}
}
// addFeedItemCircleMembReq(fi);
break;
case RS_FEED_ITEM_CIRCLE_INVIT_REC:
if (flags & RS_FEED_TYPE_CIRCLE)
{
if (!mTokenQueueCircle) {
mTokenQueueCircle = new TokenQueue(rsGxsCircles->getTokenService(), instance);
}
RsGxsGroupId grpId(fi.mId1);
if (!grpId.isNull()) {
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
std::list<RsGxsGroupId> grpIds;
grpIds.push_back(grpId);
uint32_t token;
mTokenQueueCircle->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, grpIds, TOKEN_TYPE_GROUP);
}
}
// addFeedItemCircleInvitRec(fi);
break;
default: default:
std::cerr << "(EE) Unknown type " << std::hex << fi.mType << std::dec << " in news feed." << std::endl; std::cerr << "(EE) Unknown type " << std::hex << fi.mType << std::dec << " in news feed." << std::endl;
break; break;
@ -534,6 +583,24 @@ void NewsFeed::testFeeds(uint notifyFlags)
// not used // not used
// instance->addFeedItemFilesNew(fi); // instance->addFeedItemFilesNew(fi);
break; break;
case RS_FEED_TYPE_CIRCLE:
{
if (!instance->mTokenQueueCircle) {
instance->mTokenQueueCircle = new TokenQueue(rsGxsCircles->getTokenService(), instance);
}
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
uint32_t token;
instance->mTokenQueueCircle->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, TOKEN_TYPE_GROUP);
break;
}
// instance->addFeedItemCircleMembReq(fi);
// instance->addFeedItemCircleInvitRec(fi);
break;
} }
} }
@ -542,6 +609,78 @@ void NewsFeed::testFeeds(uint notifyFlags)
instance->sendNewsFeedChanged(); instance->sendNewsFeedChanged();
} }
void NewsFeed::loadCircleGroup(const uint32_t &token)
{
std::vector<RsGxsCircleGroup> groups;
if (!rsGxsCircles->getGroupData(token, groups)) {
std::cerr << "NewsFeed::loadCircleGroup() ERROR getting data";
std::cerr << std::endl;
return;
}
std::list<RsGxsId> own_identities;
rsIdentity->getOwnIds(own_identities);
std::vector<RsGxsCircleGroup>::const_iterator circleIt;
for (circleIt = groups.begin(); circleIt != groups.end(); ++circleIt) {
RsGxsCircleGroup group = *(circleIt);
RsGxsCircleDetails details;
if(rsGxsCircles->getCircleDetails(group.mMeta.mCircleId,details))
{
for(std::list<RsGxsId>::const_iterator it(own_identities.begin());it!=own_identities.end();++it) {
std::map<RsGxsId,uint32_t>::const_iterator vit = details.mSubscriptionFlags.find(*it);
uint32_t subscribe_flags = (vit == details.mSubscriptionFlags.end())?0:(vit->second);
if( !(subscribe_flags & GXS_EXTERNAL_CIRCLE_FLAGS_SUBSCRIBED)
&& (subscribe_flags & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST) ) {
RsFeedItem fi;
fi.mId1 = group.mMeta.mGroupId.toStdString();
fi.mId2 = it->toStdString();
instance->addFeedItemCircleInvitRec(fi);
}
}
}
}
}
void NewsFeed::loadCircleMessage(const uint32_t &token)
{
std::vector<RsGxsCircleMsg> msgs;
if (!rsGxsCircles->getMsgData(token, msgs)) {
std::cerr << "NewsFeed::loadCircleMessage() ERROR getting data";
std::cerr << std::endl;
return;
}
std::list<RsGxsId> own_identities;
rsIdentity->getOwnIds(own_identities);
std::vector<RsGxsCircleMsg>::iterator msgIt;
for (msgIt = msgs.begin(); msgIt != msgs.end(); ++msgIt) {
RsGxsCircleMsg msg = *(msgIt);
RsGxsCircleDetails details;
if(rsGxsCircles->getCircleDetails(RsGxsCircleId(msg.mMeta.mGroupId),details)) {
//for(std::list<RsGxsId>::const_iterator it(own_identities.begin());it!=own_identities.end();++it) {
// std::map<RsGxsId,uint32_t>::const_iterator vit = details.mSubscriptionFlags.find(*it);
// if (vit != details.mSubscriptionFlags.end()) {
RsFeedItem fi;
fi.mId1 = msgIt->mMeta.mGroupId.toStdString();
fi.mId2 = msgIt->mMeta.mAuthorId.toStdString();
if (msgIt->stuff == "SUBSCRIPTION_REQUEST_UNSUBSCRIBE")
instance->remFeedItemCircleMembReq(fi);
else
instance->addFeedItemCircleMembReq(fi);
//}
//}
}
}
}
void NewsFeed::loadChannelGroup(const uint32_t &token) void NewsFeed::loadChannelGroup(const uint32_t &token)
{ {
std::vector<RsGxsChannelGroup> groups; std::vector<RsGxsChannelGroup> groups;
@ -821,7 +960,24 @@ void NewsFeed::loadRequest(const TokenQueue *queue, const TokenRequest &req)
break; break;
default: default:
std::cerr << "NewsFeed::loadRequest() ERROR: INVALID TYPE"; std::cerr << "NewsFeed::loadRequest() ERROR: INVALID CHANNEL TYPE";
std::cerr << std::endl;
break;
}
}
if (queue == mTokenQueueCircle) {
switch (req.mUserType) {
case TOKEN_TYPE_GROUP:
loadCircleGroup(req.mToken);
break;
case TOKEN_TYPE_MESSAGE:
loadCircleMessage(req.mToken);
break;
default:
std::cerr << "NewsFeed::loadRequest() ERROR: INVALID CIRCLE TYPE";
std::cerr << std::endl; std::cerr << std::endl;
break; break;
} }
@ -842,7 +998,7 @@ void NewsFeed::loadRequest(const TokenQueue *queue, const TokenRequest &req)
break; break;
default: default:
std::cerr << "NewsFeed::loadRequest() ERROR: INVALID TYPE"; std::cerr << "NewsFeed::loadRequest() ERROR: INVALID FORUM TYPE";
std::cerr << std::endl; std::cerr << std::endl;
break; break;
} }
@ -859,7 +1015,7 @@ void NewsFeed::loadRequest(const TokenQueue *queue, const TokenRequest &req)
break; break;
default: default:
std::cerr << "NewsFeed::loadRequest() ERROR: INVALID TYPE"; std::cerr << "NewsFeed::loadRequest() ERROR: INVALID POSTED TYPE";
std::cerr << std::endl; std::cerr << std::endl;
break; break;
} }
@ -908,18 +1064,24 @@ void NewsFeed::addFeedItem(FeedItem *item)
struct AddFeedItemIfUniqueData struct AddFeedItemIfUniqueData
{ {
AddFeedItemIfUniqueData(FeedItem *feedItem, int type, const RsPeerId &sslId, const std::string& ipAddr, const std::string& ipAddrReported) AddFeedItemIfUniqueData(FeedItem *feedItem, int type
: mType(type), mSslId(sslId), mIpAddr(ipAddr), mIpAddrReported(ipAddrReported) , const std::string& id1, const std::string& id2
, const std::string& id3, const std::string& id4)
: mType(type), mId1(id1), mId2(id2), mId3(id3), mId4(id4)
{ {
mGxsCircleItem = dynamic_cast<GxsCircleItem*>(feedItem);
mPeerItem = dynamic_cast<PeerItem*>(feedItem); mPeerItem = dynamic_cast<PeerItem*>(feedItem);
mSecItem = dynamic_cast<SecurityItem*>(feedItem); mSecItem = dynamic_cast<SecurityItem*>(feedItem);
mSecurityIpItem = dynamic_cast<SecurityIpItem*>(feedItem); mSecurityIpItem = dynamic_cast<SecurityIpItem*>(feedItem);
} }
int mType; int mType;
const RsPeerId &mSslId; const std::string& mId1;
const std::string& mIpAddr; const std::string& mId2;
const std::string& mIpAddrReported; const std::string& mId3;
const std::string& mId4;
GxsCircleItem *mGxsCircleItem;
PeerItem *mPeerItem; PeerItem *mPeerItem;
SecurityItem *mSecItem; SecurityItem *mSecItem;
SecurityIpItem *mSecurityIpItem; SecurityIpItem *mSecurityIpItem;
@ -928,13 +1090,21 @@ struct AddFeedItemIfUniqueData
static bool addFeedItemIfUniqueCallback(FeedItem *feedItem, void *data) static bool addFeedItemIfUniqueCallback(FeedItem *feedItem, void *data)
{ {
AddFeedItemIfUniqueData *findData = (AddFeedItemIfUniqueData*) data; AddFeedItemIfUniqueData *findData = (AddFeedItemIfUniqueData*) data;
if (!findData || findData->mSslId.isNull()) { if (!findData || findData->mId1.empty()) {
return false;
}
if (findData->mGxsCircleItem) {
GxsCircleItem *gxsCircleItem = dynamic_cast<GxsCircleItem*>(feedItem);
if (gxsCircleItem && gxsCircleItem->isSame(RsGxsCircleId(findData->mId1), RsGxsId(findData->mId2), findData->mType)) {
return true;
}
return false; return false;
} }
if (findData->mPeerItem) { if (findData->mPeerItem) {
PeerItem *peerItem = dynamic_cast<PeerItem*>(feedItem); PeerItem *peerItem = dynamic_cast<PeerItem*>(feedItem);
if (peerItem && peerItem->isSame(findData->mSslId, findData->mType)) { if (peerItem && peerItem->isSame(RsPeerId(findData->mId1), findData->mType)) {
return true; return true;
} }
return false; return false;
@ -942,7 +1112,7 @@ static bool addFeedItemIfUniqueCallback(FeedItem *feedItem, void *data)
if (findData->mSecItem) { if (findData->mSecItem) {
SecurityItem *secitem = dynamic_cast<SecurityItem*>(feedItem); SecurityItem *secitem = dynamic_cast<SecurityItem*>(feedItem);
if (secitem && secitem->isSame(findData->mSslId, findData->mType)) { if (secitem && secitem->isSame(RsPeerId(findData->mId1), findData->mType)) {
return true; return true;
} }
return false; return false;
@ -950,7 +1120,7 @@ static bool addFeedItemIfUniqueCallback(FeedItem *feedItem, void *data)
if (findData->mSecurityIpItem) { if (findData->mSecurityIpItem) {
SecurityIpItem *securityIpItem = dynamic_cast<SecurityIpItem*>(feedItem); SecurityIpItem *securityIpItem = dynamic_cast<SecurityIpItem*>(feedItem);
if (securityIpItem && securityIpItem->isSame(findData->mIpAddr, findData->mIpAddrReported, findData->mType)) { if (securityIpItem && securityIpItem->isSame(findData->mId1, findData->mId2, findData->mType)) {
return true; return true;
} }
return false; return false;
@ -959,9 +1129,9 @@ static bool addFeedItemIfUniqueCallback(FeedItem *feedItem, void *data)
return false; return false;
} }
void NewsFeed::addFeedItemIfUnique(FeedItem *item, int itemType, const RsPeerId &sslId, const std::string& ipAddr, const std::string& ipAddrReported, bool replace) void NewsFeed::addFeedItemIfUnique(FeedItem *item, int itemType, const std::string& id1, const std::string& id2, const std::string& id3, const std::string& id4, bool replace)
{ {
AddFeedItemIfUniqueData data(item, itemType, sslId, ipAddr, ipAddrReported); AddFeedItemIfUniqueData data(item, itemType, id1, id2, id3, id4);
FeedItem *feedItem = ui->feedWidget->findFeedItem(addFeedItemIfUniqueCallback, &data); FeedItem *feedItem = ui->feedWidget->findFeedItem(addFeedItemIfUniqueCallback, &data);
if (feedItem) { if (feedItem) {
@ -976,6 +1146,18 @@ void NewsFeed::addFeedItemIfUnique(FeedItem *item, int itemType, const RsPeerId
addFeedItem(item); addFeedItem(item);
} }
void NewsFeed::remUniqueFeedItem(FeedItem *item, int itemType, const std::string &id1, const std::string &id2, const std::string &id3, const std::string &id4)
{
AddFeedItemIfUniqueData data(item, itemType, id1, id2, id3, id4);
FeedItem *feedItem = ui->feedWidget->findFeedItem(addFeedItemIfUniqueCallback, &data);
if (feedItem) {
delete item;
ui->feedWidget->removeFeedItem(feedItem);
}
}
void NewsFeed::addFeedItemPeerConnect(const RsFeedItem &fi) void NewsFeed::addFeedItemPeerConnect(const RsFeedItem &fi)
{ {
/* make new widget */ /* make new widget */
@ -1038,7 +1220,7 @@ void NewsFeed::addFeedItemPeerOffset(const RsFeedItem &fi)
PeerItem *pi = new PeerItem(this, NEWSFEED_PEERLIST, RsPeerId(fi.mId1), PEER_TYPE_OFFSET, false); PeerItem *pi = new PeerItem(this, NEWSFEED_PEERLIST, RsPeerId(fi.mId1), PEER_TYPE_OFFSET, false);
/* add to layout */ /* add to layout */
addFeedItemIfUnique(pi, PEER_TYPE_OFFSET, RsPeerId(fi.mId1), "", "", false); addFeedItemIfUnique(pi, PEER_TYPE_OFFSET, fi.mId1, fi.mId2, fi.mId3, fi.mId4, false);
#ifdef NEWS_DEBUG #ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemPeerOffset()"; std::cerr << "NewsFeed::addFeedItemPeerOffset()";
@ -1052,7 +1234,7 @@ void NewsFeed::addFeedItemSecurityConnectAttempt(const RsFeedItem &fi)
SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, fi.mType, false); SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, fi.mType, false);
/* add to layout */ /* add to layout */
addFeedItemIfUnique(pi, fi.mType, RsPeerId(fi.mId2), "", "", false); addFeedItemIfUnique(pi, fi.mType, fi.mId2, "", "", "", false);
#ifdef NEWS_DEBUG #ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemSecurityConnectAttempt()"; std::cerr << "NewsFeed::addFeedItemSecurityConnectAttempt()";
@ -1066,7 +1248,7 @@ void NewsFeed::addFeedItemSecurityAuthDenied(const RsFeedItem &fi)
SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, fi.mType, false); SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, fi.mType, false);
/* add to layout */ /* add to layout */
addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_AUTH_DENIED, RsPeerId(fi.mId2), "", "", false); addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_AUTH_DENIED, fi.mId2, "", "", "", false);
#ifdef NEWS_DEBUG #ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemSecurityAuthDenied()"; std::cerr << "NewsFeed::addFeedItemSecurityAuthDenied()";
@ -1080,7 +1262,7 @@ void NewsFeed::addFeedItemSecurityUnknownIn(const RsFeedItem &fi)
SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, RS_FEED_ITEM_SEC_UNKNOWN_IN, false); SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, RS_FEED_ITEM_SEC_UNKNOWN_IN, false);
/* add to layout */ /* add to layout */
addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_UNKNOWN_IN, RsPeerId(fi.mId2), "", "", false); addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_UNKNOWN_IN, fi.mId2, "", "", "", false);
#ifdef NEWS_DEBUG #ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemSecurityUnknownIn()"; std::cerr << "NewsFeed::addFeedItemSecurityUnknownIn()";
@ -1094,7 +1276,7 @@ void NewsFeed::addFeedItemSecurityUnknownOut(const RsFeedItem &fi)
SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, RS_FEED_ITEM_SEC_UNKNOWN_OUT, false); SecurityItem *pi = new SecurityItem(this, NEWSFEED_SECLIST, RsPgpId(fi.mId1), RsPeerId(fi.mId2), fi.mId3, fi.mId4, RS_FEED_ITEM_SEC_UNKNOWN_OUT, false);
/* add to layout */ /* add to layout */
addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_UNKNOWN_OUT, RsPeerId(fi.mId2), "", "", false); addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_UNKNOWN_OUT, fi.mId2, "", "", "", false);
#ifdef NEWS_DEBUG #ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemSecurityUnknownOut()"; std::cerr << "NewsFeed::addFeedItemSecurityUnknownOut()";
@ -1108,7 +1290,7 @@ void NewsFeed::addFeedItemSecurityIpBlacklisted(const RsFeedItem &fi, bool isTes
SecurityIpItem *pi = new SecurityIpItem(this, RsPeerId(fi.mId1), fi.mId2, fi.mResult1, RS_FEED_ITEM_SEC_IP_BLACKLISTED, isTest); SecurityIpItem *pi = new SecurityIpItem(this, RsPeerId(fi.mId1), fi.mId2, fi.mResult1, RS_FEED_ITEM_SEC_IP_BLACKLISTED, isTest);
/* add to layout */ /* add to layout */
addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_IP_BLACKLISTED, RsPeerId(fi.mId1), fi.mId2, "", false); addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_IP_BLACKLISTED, fi.mId1, fi.mId2, fi.mId3, fi.mId4, false);
#ifdef NEWS_DEBUG #ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemSecurityIpBlacklisted()"; std::cerr << "NewsFeed::addFeedItemSecurityIpBlacklisted()";
@ -1122,7 +1304,7 @@ void NewsFeed::addFeedItemSecurityWrongExternalIpReported(const RsFeedItem &fi,
SecurityIpItem *pi = new SecurityIpItem(this, RsPeerId(fi.mId1), fi.mId2, fi.mId3, RS_FEED_ITEM_SEC_IP_WRONG_EXTERNAL_IP_REPORTED, isTest); SecurityIpItem *pi = new SecurityIpItem(this, RsPeerId(fi.mId1), fi.mId2, fi.mId3, RS_FEED_ITEM_SEC_IP_WRONG_EXTERNAL_IP_REPORTED, isTest);
/* add to layout */ /* add to layout */
addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_IP_WRONG_EXTERNAL_IP_REPORTED, RsPeerId(fi.mId1), fi.mId2, fi.mId3, false); addFeedItemIfUnique(pi, RS_FEED_ITEM_SEC_IP_WRONG_EXTERNAL_IP_REPORTED, fi.mId1, fi.mId2, fi.mId3, fi.mId4, false);
#ifdef NEWS_DEBUG #ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemSecurityWrongExternalIpReported()"; std::cerr << "NewsFeed::addFeedItemSecurityWrongExternalIpReported()";
@ -1375,6 +1557,66 @@ void NewsFeed::addFeedItemFilesNew(const RsFeedItem &/*fi*/)
#endif #endif
} }
void NewsFeed::addFeedItemCircleMembReq(const RsFeedItem &fi)
{
RsGxsCircleId circleId(fi.mId1);
RsGxsId gxsId(fi.mId2);
if (circleId.isNull() || gxsId.isNull()) {
return;
}
/* make new widget */
GxsCircleItem *item = new GxsCircleItem(this, NEWSFEED_CIRCLELIST, circleId, gxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ);
/* add to layout */
addFeedItemIfUnique(item, RS_FEED_ITEM_CIRCLE_MEMB_REQ, fi.mId1, fi.mId2, fi.mId3, fi.mId4, false);
#ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemCircleMembReq()" << std::endl;
#endif
}
void NewsFeed::remFeedItemCircleMembReq(const RsFeedItem &fi)
{
RsGxsCircleId circleId(fi.mId1);
RsGxsId gxsId(fi.mId2);
if (circleId.isNull() || gxsId.isNull()) {
return;
}
/* make new widget */
GxsCircleItem *item = new GxsCircleItem(this, NEWSFEED_CIRCLELIST, circleId, gxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ);
/* add to layout */
remUniqueFeedItem(item, RS_FEED_ITEM_CIRCLE_MEMB_REQ, fi.mId1, fi.mId2, fi.mId3, fi.mId4);
#ifdef NEWS_DEBUG
std::cerr << "NewsFeed::remFeedItemCircleMembReq()" << std::endl;
#endif
}
void NewsFeed::addFeedItemCircleInvitRec(const RsFeedItem &fi)
{
RsGxsCircleId circleId(fi.mId1);
RsGxsId gxsId(fi.mId2);
if (circleId.isNull()) {
return;
}
/* make new widget */
GxsCircleItem *item = new GxsCircleItem(this, NEWSFEED_CIRCLELIST, circleId, gxsId, RS_FEED_ITEM_CIRCLE_INVIT_REC);
/* add to layout */
addFeedItem(item);
#ifdef NEWS_DEBUG
std::cerr << "NewsFeed::addFeedItemCircleInvitRec()" << std::endl;
#endif
}
/* FeedHolder Functions (for FeedItem functionality) */ /* FeedHolder Functions (for FeedItem functionality) */
QScrollArea *NewsFeed::getScrollArea() QScrollArea *NewsFeed::getScrollArea()
{ {
@ -1403,7 +1645,7 @@ void NewsFeed::openChat(const RsPeerId &peerId)
ChatDialog::chatFriend(ChatId(peerId)); ChatDialog::chatFriend(ChatId(peerId));
} }
void NewsFeed::openComments(uint32_t /*type*/, const RsGxsGroupId &/*groupId*/, const QVector<RsGxsMessageId>& versions,const RsGxsMessageId &/*msgId*/, const QString &/*title*/) void NewsFeed::openComments(uint32_t /*type*/, const RsGxsGroupId &/*groupId*/, const QVector<RsGxsMessageId> &/*versions*/,const RsGxsMessageId &/*msgId*/, const QString &/*title*/)
{ {
std::cerr << "NewsFeed::openComments() Not Handled Yet"; std::cerr << "NewsFeed::openComments() Not Handled Yet";
std::cerr << std::endl; std::cerr << std::endl;

View File

@ -83,7 +83,8 @@ private slots:
private: private:
void addFeedItem(FeedItem *item); void addFeedItem(FeedItem *item);
void addFeedItemIfUnique(FeedItem *item, int itemType, const RsPeerId &sslId, const std::string& ipAddr, const std::string& ipAddrReported, bool replace); void addFeedItemIfUnique(FeedItem *item, int itemType, const std::string& id1, const std::string& id2, const std::string& id3, const std::string& id4, bool replace);
void remUniqueFeedItem(FeedItem *item, int itemType, const std::string& id1, const std::string& id2, const std::string& id3, const std::string& id4);
void addFeedItemPeerConnect(const RsFeedItem &fi); void addFeedItemPeerConnect(const RsFeedItem &fi);
void addFeedItemPeerDisconnect(const RsFeedItem &fi); void addFeedItemPeerDisconnect(const RsFeedItem &fi);
@ -119,6 +120,10 @@ private:
void addFeedItemMessage(const RsFeedItem &fi); void addFeedItemMessage(const RsFeedItem &fi);
void addFeedItemFilesNew(const RsFeedItem &fi); void addFeedItemFilesNew(const RsFeedItem &fi);
void addFeedItemCircleMembReq(const RsFeedItem &fi);
void remFeedItemCircleMembReq(const RsFeedItem &fi);
void addFeedItemCircleInvitRec(const RsFeedItem &fi);
virtual void loadChannelGroup(const uint32_t &token); virtual void loadChannelGroup(const uint32_t &token);
virtual void loadChannelPost(const uint32_t &token); virtual void loadChannelPost(const uint32_t &token);
virtual void loadChannelPublishKey(const uint32_t &token); virtual void loadChannelPublishKey(const uint32_t &token);
@ -130,8 +135,12 @@ private:
virtual void loadPostedGroup(const uint32_t &token); virtual void loadPostedGroup(const uint32_t &token);
virtual void loadPostedMessage(const uint32_t &token); virtual void loadPostedMessage(const uint32_t &token);
virtual void loadCircleGroup(const uint32_t &token);
virtual void loadCircleMessage(const uint32_t &token);
private: private:
TokenQueue *mTokenQueueChannel; TokenQueue *mTokenQueueChannel;
TokenQueue *mTokenQueueCircle;
TokenQueue *mTokenQueueForum; TokenQueue *mTokenQueueForum;
TokenQueue *mTokenQueuePosted; TokenQueue *mTokenQueuePosted;

View File

@ -185,8 +185,9 @@ bool GxsChannelPostItem::setGroup(const RsGxsChannelGroup &group, bool doFill)
mGroup = group; mGroup = group;
// if not publisher, hide the edit button. Without the publish key, there's no way to edit a message. // if not publisher, hide the edit button. Without the publish key, there's no way to edit a message.
#ifdef DEBUG_ITEM
std::cerr << "Group subscribe flags = " << std::hex << mGroup.mMeta.mSubscribeFlags << std::dec << std::endl; std::cerr << "Group subscribe flags = " << std::hex << mGroup.mMeta.mSubscribeFlags << std::dec << std::endl;
#endif
if(!IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags)) if(!IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags))
ui->editButton->hide(); ui->editButton->hide();

View File

@ -0,0 +1,284 @@
/*
* Retroshare Gxs Feed Item
*
* Copyright 2014 RetroShare Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2.1 as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
#include "GxsCircleItem.h"
#include "ui_GxsCircleItem.h"
#include "FeedHolder.h"
#include "gui/notifyqt.h"
#include "gui/Circles/CreateCircleDialog.h"
#include "gui/gxs/GxsIdDetails.h"
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <iostream>
/****
* #define DEBUG_ITEM 1
****/
#define COLOR_NORMAL QColor(248, 248, 248)
#define COLOR_NEW QColor(220, 236, 253)
#define CIRCLESDIALOG_GROUPUPDATE 3
GxsCircleItem::GxsCircleItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsCircleId &circleId, const RsGxsId &gxsId, const uint32_t type)
:FeedItem(NULL), mFeedHolder(feedHolder), mFeedId(feedId), mType(type), mCircleId(circleId), mGxsId(gxsId)
{
setup();
}
GxsCircleItem::~GxsCircleItem()
{
delete(ui);
}
void GxsCircleItem::setup()
{
/* Invoke the Qt Designer generated object setup routine */
ui = new Ui::GxsCircleItem;
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
/* general ones */
connect(ui->expandButton, SIGNAL(clicked()), this, SLOT(showCircleDetails()));
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(removeItem()));
/* update gxs information */
RsIdentityDetails idDetails ;
QString idName ;
if(rsIdentity->getIdDetails(mGxsId, idDetails))
idName = tr("for identity ")+QString::fromUtf8(idDetails.mNickname.c_str()) + " (ID=" + QString::fromStdString(mGxsId.toStdString()) + ")" ;
else
idName = tr("for identity ")+QString::fromStdString(mGxsId.toStdString()) ;
/* update circle information */
RsGxsCircleDetails circleDetails;
if (rsGxsCircles->getCircleDetails(mCircleId, circleDetails))
{
if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REQ)
{
ui->titleLabel->setText(tr("You received a membership request for circle:"));
ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str()));
ui->gxsIdLabel->setText(idName);
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 if (mType == RS_FEED_ITEM_CIRCLE_INVIT_REC)
{
ui->titleLabel->setText(tr("You received an invitation for circle:"));
ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str()));
ui->gxsIdLabel->setText(idName);
ui->acceptButton->setToolTip(tr("Accept invitation"));
connect(ui->acceptButton, SIGNAL(clicked()), this, SLOT(acceptCircleSubscription()));
ui->revokeButton->setHidden(true);
}
}
else
{
ui->titleLabel->setText(tr("Received event from unknown Circle:"));
ui->nameLabel->setText(QString::fromStdString(mCircleId.toStdString()));
ui->gxsIdLabel->setText(idName);
}
/* Setup TokenQueue */
mCircleQueue = new TokenQueue(rsGxsCircles->getTokenService(), this);
}
bool GxsCircleItem::isSame(const RsGxsCircleId &circleId, const RsGxsId &gxsId, uint32_t type)
{
if ((mCircleId == circleId) && (mGxsId == gxsId) && (mType == type))
{
return true;
}
return false;
}
void GxsCircleItem::removeItem()
{
#ifdef DEBUG_ITEM
std::cerr << "GxsCircleItem::removeItem()" << std::endl;
#endif
if (mFeedHolder)
{
mFeedHolder->lockLayout(this, true);
hide();
mFeedHolder->lockLayout(this, false);
mFeedHolder->deleteFeedItem(this, mFeedId);
}
}
void GxsCircleItem::loadRequest(const TokenQueue * queue, const TokenRequest &req)
{
#ifdef ID_DEBUG
std::cerr << "GxsCircleItem::loadRequest() UserType: " << req.mUserType;
std::cerr << std::endl;
#endif
if(queue == mCircleQueue)
{
#ifdef ID_DEBUG
std::cerr << "CirclesDialog::loadRequest() UserType: " << req.mUserType;
std::cerr << std::endl;
#endif
/* now switch on req */
switch(req.mUserType)
{
case CIRCLESDIALOG_GROUPUPDATE:
updateCircleGroup(req.mToken);
break;
default:
std::cerr << "GxsCircleItem::loadRequest() ERROR: INVALID TYPE";
std::cerr << std::endl;
break;
}
}
}
/*********** SPECIFIC FUNCTIONS ***********************/
void GxsCircleItem::showCircleDetails()
{
CreateCircleDialog dlg;
dlg.editExistingId(RsGxsGroupId(mCircleId), true, mType != RS_FEED_ITEM_CIRCLE_MEMB_REQ) ;
dlg.exec();
}
void GxsCircleItem::acceptCircleSubscription()
{
if (rsGxsCircles->requestCircleMembership(mGxsId, mCircleId))
removeItem();
}
void GxsCircleItem::grantCircleMembership()
{
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
std::list<RsGxsGroupId> grps ;
grps.push_back(RsGxsGroupId(mCircleId));
uint32_t token;
mCircleQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, grps, CIRCLESDIALOG_GROUPUPDATE);
CircleUpdateOrder c ;
c.token = token ;
c.gxs_id = mGxsId ;
c.action = CircleUpdateOrder::GRANT_MEMBERSHIP ;
mCircleUpdates[token] = c ;
}
void GxsCircleItem::revokeCircleMembership()
{
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
std::list<RsGxsGroupId> grps;
grps.push_back(RsGxsGroupId(mCircleId));
uint32_t token;
mCircleQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, grps, CIRCLESDIALOG_GROUPUPDATE);
CircleUpdateOrder c;
c.token = token;
c.gxs_id = mGxsId;
c.action = CircleUpdateOrder::REVOKE_MEMBERSHIP;
mCircleUpdates[token] = c;
}
void GxsCircleItem::updateCircleGroup(const uint32_t& token)
{
#ifdef ID_DEBUG
std::cerr << "Loading circle info" << std::endl;
#endif
std::vector<RsGxsCircleGroup> circle_grp_v ;
rsGxsCircles->getGroupData(token, circle_grp_v);
if (circle_grp_v.empty())
{
std::cerr << "(EE) unexpected empty result from getGroupData. Cannot process circle now!" << std::endl;
return ;
}
if (circle_grp_v.size() != 1)
{
std::cerr << "(EE) very weird result from getGroupData. Should get exactly one circle" << std::endl;
return ;
}
RsGxsCircleGroup cg = circle_grp_v.front();
/* now mark all the members */
//std::set<RsGxsId> members = cg.mInvitedMembers;
std::map<uint32_t,CircleUpdateOrder>::iterator it = mCircleUpdates.find(token) ;
if(it == mCircleUpdates.end())
{
std::cerr << "(EE) Cannot find token " << token << " to perform group update!" << std::endl;
return ;
}
if(it->second.action == CircleUpdateOrder::GRANT_MEMBERSHIP)
cg.mInvitedMembers.insert(it->second.gxs_id) ;
else if(it->second.action == CircleUpdateOrder::REVOKE_MEMBERSHIP)
cg.mInvitedMembers.erase(it->second.gxs_id) ;
else
{
std::cerr << "(EE) unrecognised membership action to perform: " << it->second.action << "!" << std::endl;
return ;
}
uint32_t token2 ;
rsGxsCircles->updateGroup(token2,cg) ;
mCircleUpdates.erase(it) ;
}

View File

@ -0,0 +1,98 @@
/*
* Retroshare Gxs Feed Item
*
* Copyright 2014 RetroShare Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2.1 as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
#ifndef _GXSCIRCLEITEM_H
#define _GXSCIRCLEITEM_H
#include <retroshare/rsgxscircles.h>
#include "FeedItem.h"
#include "util/TokenQueue.h"
namespace Ui {
class GxsCircleItem;
}
class FeedHolder;
struct CircleUpdateOrder
{
enum { UNKNOWN_ACTION=0x00, GRANT_MEMBERSHIP=0x01, REVOKE_MEMBERSHIP=0x02 };
uint32_t token ;
RsGxsId gxs_id ;
uint32_t action ;
};
class GxsCircleItem : public FeedItem, public TokenResponse
{
Q_OBJECT
public:
/** Default Constructor */
GxsCircleItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsCircleId &circleId, const RsGxsId &gxsId, const uint32_t type);
virtual ~GxsCircleItem();
bool isSame(const RsGxsCircleId &circleId, const RsGxsId &gxsId, uint32_t type);
void loadRequest(const TokenQueue *queue, const TokenRequest &req);
protected:
/* FeedItem */
virtual void doExpand(bool /*open*/) {}
void updateCircleGroup(const uint32_t& token);
private slots:
/* default stuff */
void removeItem();
void showCircleDetails();
void acceptCircleSubscription();
void grantCircleMembership() ;
void revokeCircleMembership();
private:
void setup();
FeedHolder *mFeedHolder;
uint32_t mFeedId;
uint32_t mType;
RsGxsCircleId mCircleId;
RsGxsId mGxsId;
TokenQueue *mCircleQueue;
std::map<uint32_t, CircleUpdateOrder> mCircleUpdates ;
/** Qt Designer generated object */
Ui::GxsCircleItem *ui;
};
#endif

View File

@ -0,0 +1,298 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GxsCircleItem</class>
<widget class="QWidget" name="GxsCircleItem">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>618</width>
<height>96</height>
</rect>
</property>
<layout class="QGridLayout" name="GxsCircleItemGLayout">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>215</red>
<green>215</green>
<blue>215</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>215</red>
<green>215</green>
<blue>215</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>215</red>
<green>215</green>
<blue>215</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>215</red>
<green>215</green>
<blue>215</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>215</red>
<green>215</green>
<blue>215</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>215</red>
<green>215</green>
<blue>215</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="frameGLayout">
<item row="0" column="0">
<layout class="QGridLayout" name="topGLayout">
<item row="0" column="0" rowspan="2">
<widget class="QLabel" name="logoLabel">
<property name="minimumSize">
<size>
<width>70</width>
<height>70</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>70</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../icons.qrc">:/icons/svg/circles.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="nameHLayout">
<item>
<widget class="QLabel" name="titleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">Circle</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="nameLabel">
<property name="text">
<string notr="true">name</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="nameHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="toolbarHLayout">
<item>
<widget class="QLabel" name="gxsIdLabel">
<property name="text">
<string notr="true">name</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="tollbarHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>254</width>
<height>28</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="acceptButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/accepted16.png</normaloff>:/images/accepted16.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="revokeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/cancel.png</normaloff>:/images/cancel.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="expandButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Details</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/edit_add24.png</normaloff>:/images/edit_add24.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Remove Item</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/close_normal.png</normaloff>:/images/close_normal.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../images.qrc"/>
<include location="../icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -162,6 +162,7 @@ NotifyPage::NotifyPage(QWidget * parent, Qt::WindowFlags flags)
connect(ui.message_ConnectAttempt, SIGNAL(toggled(bool)), this, SLOT(updateMessageFlags())) ; connect(ui.message_ConnectAttempt, SIGNAL(toggled(bool)), this, SLOT(updateMessageFlags())) ;
connect(ui.notify_Peers, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags())); connect(ui.notify_Peers, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags()));
connect(ui.notify_Circles, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags()));
connect(ui.notify_Channels, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags())); connect(ui.notify_Channels, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags()));
connect(ui.notify_Forums, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags())); connect(ui.notify_Forums, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags()));
connect(ui.notify_Posted, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags())); connect(ui.notify_Posted, SIGNAL(toggled(bool)), this, SLOT(updateNewsFeedFlags()));
@ -195,6 +196,8 @@ uint NotifyPage::getNewsFlags()
if (ui.notify_Peers->isChecked()) if (ui.notify_Peers->isChecked())
newsFlags |= RS_FEED_TYPE_PEER; newsFlags |= RS_FEED_TYPE_PEER;
if (ui.notify_Circles->isChecked())
newsFlags |= RS_FEED_TYPE_CIRCLE;
if (ui.notify_Channels->isChecked()) if (ui.notify_Channels->isChecked())
newsFlags |= RS_FEED_TYPE_CHANNEL; newsFlags |= RS_FEED_TYPE_CHANNEL;
if (ui.notify_Forums->isChecked()) if (ui.notify_Forums->isChecked())
@ -324,6 +327,7 @@ void NotifyPage::load()
whileBlocking(ui.popup_ConnectAttempt)->setChecked(notifyflags & RS_POPUP_CONNECT_ATTEMPT); whileBlocking(ui.popup_ConnectAttempt)->setChecked(notifyflags & RS_POPUP_CONNECT_ATTEMPT);
whileBlocking(ui.notify_Peers)->setChecked(newsflags & RS_FEED_TYPE_PEER); whileBlocking(ui.notify_Peers)->setChecked(newsflags & RS_FEED_TYPE_PEER);
whileBlocking(ui.notify_Circles)->setChecked(newsflags & RS_FEED_TYPE_CIRCLE);
whileBlocking(ui.notify_Channels)->setChecked(newsflags & RS_FEED_TYPE_CHANNEL); whileBlocking(ui.notify_Channels)->setChecked(newsflags & RS_FEED_TYPE_CHANNEL);
whileBlocking(ui.notify_Forums)->setChecked(newsflags & RS_FEED_TYPE_FORUM); whileBlocking(ui.notify_Forums)->setChecked(newsflags & RS_FEED_TYPE_FORUM);
whileBlocking(ui.notify_Posted)->setChecked(newsflags & RS_FEED_TYPE_POSTED); whileBlocking(ui.notify_Posted)->setChecked(newsflags & RS_FEED_TYPE_POSTED);

View File

@ -51,6 +51,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="notify_Circles">
<property name="text">
<string>Circles</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="notify_Channels"> <widget class="QCheckBox" name="notify_Channels">
<property name="text"> <property name="text">

View File

@ -1635,7 +1635,7 @@ void ServerPage::updateStatusBob()
ui.pbBobStart->setToolTip("BOB is not accessible"); ui.pbBobStart->setToolTip("BOB is not accessible");
ui.pbBobRestart->setEnabled(false); ui.pbBobRestart->setEnabled(false);
ui.pbBobRestart->setToolTip("BOB is not accessible"); ui.pbBobRestart->setToolTip("BOB is not accessible");
ui.pbBobStop->setEnabled(false); // don't disable the stop button! (in case bob is running you are otherwise unable to stop and disable it)
ui.pbBobStop->setToolTip("BOB is not accessible"); ui.pbBobStop->setToolTip("BOB is not accessible");
} else { } else {
ui.pbBobStart->setToolTip(""); ui.pbBobStart->setToolTip("");

View File

@ -73,7 +73,7 @@ static const int GXSTRANS_STATISTICS_DELAY_BETWEEN_GROUP_REQ = 30 ; // never req
#define DEBUG_GXSTRANS_STATS 1 #define DEBUG_GXSTRANS_STATS 1
GxsTransportStatistics::GxsTransportStatistics(QWidget *parent) GxsTransportStatistics::GxsTransportStatistics(QWidget *parent)
: RsAutoUpdatePage(2000,parent) : RsGxsUpdateBroadcastPage(rsGxsTrans,parent)
{ {
setupUi(this) ; setupUi(this) ;
@ -93,6 +93,7 @@ GxsTransportStatistics::GxsTransportStatistics(QWidget *parent)
// load settings // load settings
processSettings(true); processSettings(true);
updateDisplay(true);
} }
GxsTransportStatistics::~GxsTransportStatistics() GxsTransportStatistics::~GxsTransportStatistics()
@ -139,21 +140,16 @@ void GxsTransportStatistics::CustomPopupMenu( QPoint )
contextMnu.exec(QCursor::pos()); contextMnu.exec(QCursor::pos());
} }
void GxsTransportStatistics::updateDisplay() void GxsTransportStatistics::updateDisplay(bool)
{ {
time_t now = time(NULL) ; time_t now = time(NULL) ;
if(mLastGroupReqTS + GXSTRANS_STATISTICS_DELAY_BETWEEN_GROUP_REQ < now) std::cerr << "GxsTransportStatistics::updateDisplay()" << std::endl;
{
requestGroupMeta(); requestGroupMeta();
mLastGroupReqTS = now ; mLastGroupReqTS = now ;
} }
//_tst_CW->updateContent() ;
updateContent();
}
QString GxsTransportStatistics::getPeerName(const RsPeerId &peer_id) QString GxsTransportStatistics::getPeerName(const RsPeerId &peer_id)
{ {
static std::map<RsPeerId, QString> names ; static std::map<RsPeerId, QString> names ;
@ -319,6 +315,8 @@ void GxsTransportStatistics::loadRequest(const TokenQueue *queue, const TokenReq
std::cerr << std::endl; std::cerr << std::endl;
break; break;
} }
updateContent();
} }
void GxsTransportStatistics::requestGroupMeta() void GxsTransportStatistics::requestGroupMeta()

View File

@ -30,6 +30,7 @@
#include "util/TokenQueue.h" #include "util/TokenQueue.h"
#include "RsAutoUpdatePage.h" #include "RsAutoUpdatePage.h"
#include "ui_GxsTransportStatistics.h" #include "ui_GxsTransportStatistics.h"
#include "gui/gxs/RsGxsUpdateBroadcastPage.h"
class GxsTransportStatisticsWidget ; class GxsTransportStatisticsWidget ;
class UIStateHelper; class UIStateHelper;
@ -45,7 +46,7 @@ public:
std::vector<RsMsgMetaData> messages_metas ; std::vector<RsMsgMetaData> messages_metas ;
}; };
class GxsTransportStatistics: public RsAutoUpdatePage, public TokenResponse, public Ui::GxsTransportStatistics class GxsTransportStatistics: public RsGxsUpdateBroadcastPage, public TokenResponse, public Ui::GxsTransportStatistics
{ {
Q_OBJECT Q_OBJECT
@ -66,6 +67,7 @@ private slots:
void personDetails(); void personDetails();
private: private:
void updateDisplay(bool complete) ;
void loadGroupMeta(const uint32_t& token); void loadGroupMeta(const uint32_t& token);
void loadGroupStat(const uint32_t& token); void loadGroupStat(const uint32_t& token);
void loadMsgMeta(const uint32_t& token); void loadMsgMeta(const uint32_t& token);
@ -77,8 +79,6 @@ private:
void processSettings(bool bLoad); void processSettings(bool bLoad);
bool m_bProcessSettings; bool m_bProcessSettings;
virtual void updateDisplay() ;
GxsTransportStatisticsWidget *_tst_CW ; GxsTransportStatisticsWidget *_tst_CW ;
TokenQueue *mTransQueue ; TokenQueue *mTransQueue ;
UIStateHelper *mStateHelper; UIStateHelper *mStateHelper;

View File

@ -13,51 +13,8 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Router Statistics</string> <string>Router Statistics</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Gxs Transport Groups:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTreeWidget" name="groupTreeWidget">
<column>
<property name="text">
<string>Group ID / Author</string>
</property>
</column>
<column>
<property name="text">
<string>Number of messages / Publish TS</string>
</property>
</column>
<column>
<property name="text">
<string>Total size of messages</string>
</property>
</column>
<column>
<property name="text">
<string>Subscribed</string>
</property>
</column>
<column>
<property name="text">
<string>Popularity</string>
</property>
</column>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
<string>GroupBox</string> <string>GroupBox</string>
@ -65,6 +22,12 @@
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTreeWidget" name="treeWidget"> <widget class="QTreeWidget" name="treeWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum> <enum>Qt::CustomContextMenu</enum>
</property> </property>
@ -114,6 +77,49 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Gxs Transport Groups:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTreeWidget" name="groupTreeWidget">
<column>
<property name="text">
<string>Group ID / Author</string>
</property>
</column>
<column>
<property name="text">
<string>Number of messages / Publish TS</string>
</property>
</column>
<column>
<property name="text">
<string>Total size of messages</string>
</property>
</column>
<column>
<property name="text">
<string>Subscribed</string>
</property>
</column>
<column>
<property name="text">
<string>Popularity</string>
</property>
</column>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>

View File

@ -142,7 +142,7 @@ void TurtleRouterDialog::updateTunnelRequests( const std::vector<std::vector<std
num /= 1024.0f,++k; num /= 1024.0f,++k;
sprintf(tmp,"%3.2f %s",num,units[k].c_str()) ; sprintf(tmp,"%3.2f %s",num,units[k].c_str()) ;
QString str = tr("Tunnel id") + ": " + QString::fromUtf8(tunnels_info[i][0].c_str()) + "\t [" + QString::fromUtf8(tunnels_info[i][2].c_str()) + "] --> [" + QString::fromUtf8(tunnels_info[i][1].c_str()) + "]\t\t " + tr("last transfer") + ": " + QString::fromStdString(tunnels_info[i][4]) + " " + "\t " + tr("Speed") + ": " + QString::fromStdString(tmp) ; QString str = tr("Tunnel id") + ": " + QString::fromUtf8(tunnels_info[i][0].c_str()) + "\t" + tr("Speed") + ": " + QString::fromStdString(tmp) + "\t " + tr("last transfer") + ": " + QString::fromStdString(tunnels_info[i][4])+ "\t" + QString::fromUtf8(tunnels_info[i][2].c_str()) + " -> " + QString::fromUtf8(tunnels_info[i][1].c_str());
stl.clear() ; stl.clear() ;
stl.push_back(str) ; stl.push_back(str) ;
QTreeWidgetItem *item = new QTreeWidgetItem(stl); QTreeWidgetItem *item = new QTreeWidgetItem(stl);

View File

@ -551,6 +551,7 @@ HEADERS += rshare.h \
gui/NewsFeed.h \ gui/NewsFeed.h \
gui/feeds/FeedItem.h \ gui/feeds/FeedItem.h \
gui/feeds/FeedHolder.h \ gui/feeds/FeedHolder.h \
gui/feeds/GxsCircleItem.h \
gui/feeds/PeerItem.h \ gui/feeds/PeerItem.h \
gui/feeds/MsgItem.h \ gui/feeds/MsgItem.h \
gui/feeds/ChatMsgItem.h \ gui/feeds/ChatMsgItem.h \
@ -656,6 +657,7 @@ FORMS += gui/StartDialog.ui \
gui/advsearch/AdvancedSearchDialog.ui \ gui/advsearch/AdvancedSearchDialog.ui \
gui/advsearch/expressionwidget.ui \ gui/advsearch/expressionwidget.ui \
gui/NewsFeed.ui \ gui/NewsFeed.ui \
gui/feeds/GxsCircleItem.ui \
gui/feeds/PeerItem.ui \ gui/feeds/PeerItem.ui \
gui/feeds/MsgItem.ui \ gui/feeds/MsgItem.ui \
gui/feeds/ChatMsgItem.ui \ gui/feeds/ChatMsgItem.ui \
@ -685,7 +687,7 @@ FORMS += gui/StartDialog.ui \
gui/statistics/StatisticsWindow.ui \ gui/statistics/StatisticsWindow.ui \
gui/statistics/BwCtrlWindow.ui \ gui/statistics/BwCtrlWindow.ui \
gui/statistics/RttStatistics.ui \ gui/statistics/RttStatistics.ui \
gui/GetStartedDialog.ui \ gui/GetStartedDialog.ui
# gui/ForumsDialog.ui \ # gui/ForumsDialog.ui \
@ -900,6 +902,7 @@ SOURCES += main.cpp \
gui/NewsFeed.cpp \ gui/NewsFeed.cpp \
gui/feeds/FeedItem.cpp \ gui/feeds/FeedItem.cpp \
gui/feeds/FeedHolder.cpp \ gui/feeds/FeedHolder.cpp \
gui/feeds/GxsCircleItem.cpp \
gui/feeds/PeerItem.cpp \ gui/feeds/PeerItem.cpp \
gui/feeds/MsgItem.cpp \ gui/feeds/MsgItem.cpp \
gui/feeds/ChatMsgItem.cpp \ gui/feeds/ChatMsgItem.cpp \

View File

@ -0,0 +1,76 @@
/*
* RetroShare Android QML App
* Copyright (C) 2017 Gioacchino Mazzurco <gio@eigenlab.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.7
Item
{
id: compRoot
property string gxs_id
height: 130
width: height
////////////// The following should be considered privates /////////////////////
property bool has_avatar: false
property int avatarAttemptCnt: 0
function getDetails()
{
++compRoot.avatarAttemptCnt
rsApi.request(
"/identity/get_identity_details",
JSON.stringify({ gxs_id: compRoot.gxs_id }),
function(par)
{
var jData = JSON.parse(par.response).data
setDetails(jData)
if(!compRoot.has_avatar &&
compRoot.avatarAttemptCnt < 3) getDetails()
})
}
function setDetails(data)
{
compRoot.has_avatar = data.avatar.length > 0
if(compRoot.has_avatar)
{
contactAvatar.source =
"data:image/png;base64," + data.avatar
}
}
Component.onCompleted: if(visible && !has_avatar) getDetails()
onVisibleChanged: if(visible && !has_avatar) getDetails()
Image
{
id: contactAvatar
anchors.fill: parent
visible: compRoot.has_avatar
}
ColorHash
{
anchors.fill: parent
visible: !compRoot.has_avatar
hash: compRoot.gxs_id
}
}

View File

@ -28,21 +28,20 @@ Item
property var md property var md
property bool is_contact: cntDt.md.is_contact property bool is_contact: cntDt.md.is_contact
ColorHash AvatarOrColorHash
{ {
id: colorHash id: topFace
gxs_id: cntDt.md.gxs_id
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 6 anchors.topMargin: 6
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
height: 150
hash: cntDt.md.gxs_id
} }
Column Column
{ {
anchors.top: colorHash.bottom anchors.top: topFace.bottom
anchors.topMargin: 6 anchors.topMargin: 6
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -54,6 +53,13 @@ Item
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
spacing: 6 spacing: 6
ColorHash
{
hash: cntDt.md.gxs_id
height: parent.height - 10
anchors.verticalCenter: parent.verticalCenter
}
Text Text
{ {
text: cntDt.md.name text: cntDt.md.name
@ -62,7 +68,6 @@ Item
Image Image
{ {
source: cntDt.is_contact ? source: cntDt.is_contact ?
"qrc:/icons/rating.png" : "qrc:/icons/rating.png" :
"qrc:/icons/rating-unrated.png" "qrc:/icons/rating-unrated.png"

View File

@ -25,6 +25,7 @@
<file>TrustedNodeDetails.qml</file> <file>TrustedNodeDetails.qml</file>
<file>ClipboardWrapper.qml</file> <file>ClipboardWrapper.qml</file>
<file>ContactDetails.qml</file> <file>ContactDetails.qml</file>
<file>ColorHash.qml</file>
<file>icons/rating-unrated.png</file> <file>icons/rating-unrated.png</file>
<file>icons/rating.png</file> <file>icons/rating.png</file>
<file>TimedPopup.qml</file> <file>TimedPopup.qml</file>