Fixed resource exhaustion due to message/group notification not being handled

Added message/group size limit
Added message validation (identity and publish key)
Added code for message/grp fragmentation/defragmentation (not integrated yet) 
Added crude id picker to photoshare


git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6106 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
chrisparker126 2013-02-07 23:04:16 +00:00
parent 635f915f46
commit 7867063734
21 changed files with 735 additions and 264 deletions

View File

@ -130,6 +130,10 @@ bool GxsSecurity::validateNxsMsg(RsNxsMsg& msg, RsTlvKeySignature& sign, RsTlvSe
RsTlvKeySignatureSet signSet = msgMeta.signSet;
msgMeta.signSet.TlvClear();
RsGxsMessageId msgId = msgMeta.mMsgId, origMsgId = msgMeta.mOrigMsgId;
msgMeta.mOrigMsgId.clear();
msgMeta.mMsgId.clear();
uint32_t metaDataLen = msgMeta.serial_size();
uint32_t allMsgDataLen = metaDataLen + msg.msg.bin_len;
char* metaData = new char[metaDataLen];
@ -156,6 +160,9 @@ bool GxsSecurity::validateNxsMsg(RsNxsMsg& msg, RsTlvKeySignature& sign, RsTlvSe
EVP_PKEY_free(signKey);
EVP_MD_CTX_destroy(mdctx);
msgMeta.mOrigMsgId = origMsgId;
msgMeta.mMsgId = msgId;
msgMeta.signSet = signSet;
if (signOk == 1)
{

View File

@ -134,6 +134,7 @@ const std::string RsGeneralDataService::GRP_META_SUBSCRIBE_FLAG = KEY_GRP_SUBCR_
const std::string RsGeneralDataService::MSG_META_SERV_STRING = KEY_NXS_SERV_STRING;
const std::string RsGeneralDataService::MSG_META_STATUS = KEY_MSG_STATUS;
const uint32_t RsGeneralDataService::GXS_MAX_ITEM_SIZE = 1572864; // 1.5 Mbytes
RsDataService::RsDataService(const std::string &serviceDir, const std::string &dbName, uint16_t serviceType,
RsGxsSearchModule *mod)
@ -453,6 +454,9 @@ int RsDataService::storeMessage(std::map<RsNxsMsg *, RsGxsMsgMetaData *> &msg)
RsNxsMsg* msgPtr = mit->first;
RsGxsMsgMetaData* msgMetaPtr = mit->second;
// skip msg item if size if greater than
if(!validSize(msgPtr)) continue;
// create or access file in binary
std::string msgFile = mServiceDir + "/" + msgPtr->grpId + "-msgs";
std::fstream ostrm(msgFile.c_str(), std::ios::binary | std::ios::app | std::ios::out);
@ -519,6 +523,13 @@ int RsDataService::storeMessage(std::map<RsNxsMsg *, RsGxsMsgMetaData *> &msg)
return ret;
}
bool RsDataService::validSize(RsNxsMsg* msg) const
{
if((msg->msg.TlvSize() + msg->meta.TlvSize()) <= GXS_MAX_ITEM_SIZE) return true;
return false;
}
int RsDataService::storeGroup(std::map<RsNxsGrp *, RsGxsGrpMetaData *> &grp)
{
@ -536,6 +547,9 @@ int RsDataService::storeGroup(std::map<RsNxsGrp *, RsGxsGrpMetaData *> &grp)
RsNxsGrp* grpPtr = sit->first;
RsGxsGrpMetaData* grpMetaPtr = sit->second;
// if data is larger than max item size do not add
if(!validSize(grpPtr)) continue;
std::string grpFile = mServiceDir + "/" + grpPtr->grpId;
std::fstream ostrm(grpFile.c_str(), std::ios::binary | std::ios::app | std::ios::out);
ostrm.seekg(0, std::ios::end); // go to end to append
@ -607,6 +621,12 @@ int RsDataService::storeGroup(std::map<RsNxsGrp *, RsGxsGrpMetaData *> &grp)
return ret;
}
bool RsDataService::validSize(RsNxsGrp* grp) const
{
if((grp->grp.TlvSize() + grp->meta.TlvSize()) <= GXS_MAX_ITEM_SIZE) return true;
return false;
}
int RsDataService::retrieveNxsGrps(std::map<std::string, RsNxsGrp *> &grp, bool withMeta, bool cache){
if(grp.empty()){
@ -969,6 +989,7 @@ int RsDataService::resetDataStore()
std::string msgFile = file + "-msgs";
remove(file.c_str()); // remove group file
remove(msgFile.c_str()); // and remove messages file
delete mit->second;
}
{
RsStackMutex stack(mDbMutex);

View File

@ -132,6 +132,11 @@ public:
*/
int resetDataStore();
bool validSize(RsNxsMsg* msg) const;
bool validSize(RsNxsGrp* grp) const;
private:
/*!

View File

@ -105,6 +105,8 @@ class RsGeneralDataService
public:
static const uint32_t GXS_MAX_ITEM_SIZE;
static const std::string MSG_META_SERV_STRING;
static const std::string MSG_META_STATUS;
@ -210,6 +212,22 @@ public:
*/
virtual int resetDataStore() = 0;
/*!
* Use to determine if message isn't over the storage
* limit for a single message item
* @param msg the message to check size validity
* @return whether the size of of msg is valid
*/
virtual bool validSize(RsNxsMsg* msg) const = 0 ;
/*!
* Use to determine if group isn't over the storage limit
* for a single group item
* @param grp the group to check size validity
* @return whether the size of grp is valid for storage
*/
virtual bool validSize(RsNxsGrp* grp) const = 0 ;
};

View File

@ -160,7 +160,8 @@ bool RsGenExchange::acknowledgeTokenGrp(const uint32_t& token,
return true;
}
void RsGenExchange::generateGroupKeys(RsTlvSecurityKeySet& keySet, bool genPublishKeys)
void RsGenExchange::generateGroupKeys(RsTlvSecurityKeySet& privatekeySet,
RsTlvSecurityKeySet& publickeySet, bool genPublishKeys)
{
/* create Keys */
@ -174,8 +175,10 @@ void RsGenExchange::generateGroupKeys(RsTlvSecurityKeySet& keySet, bool genPubli
GxsSecurity::setRSAPublicKey(adminKey, rsa_admin_pub);
GxsSecurity::setRSAPrivateKey(privAdminKey, rsa_admin);
adminKey.keyId = adminKey.keyId + "_public";
adminKey.startTS = time(NULL);
adminKey.endTS = 0; /* no end */
adminKey.endTS = adminKey.startTS + 60 * 60 * 24 * 365 * 5; /* approx 5 years */
privAdminKey.startTS = adminKey.startTS;
privAdminKey.endTS = 0; /* no end */
@ -184,8 +187,8 @@ void RsGenExchange::generateGroupKeys(RsTlvSecurityKeySet& keySet, bool genPubli
adminKey.keyFlags = RSTLV_KEY_DISTRIB_ADMIN | RSTLV_KEY_TYPE_PUBLIC_ONLY;
privAdminKey.keyFlags = RSTLV_KEY_DISTRIB_ADMIN | RSTLV_KEY_TYPE_FULL;
keySet.keys[adminKey.keyId] = adminKey;
keySet.keys[privAdminKey.keyId] = privAdminKey;
publickeySet.keys[adminKey.keyId] = adminKey;
privatekeySet.keys[privAdminKey.keyId] = privAdminKey;
// clean up
RSA_free(rsa_admin);
@ -204,6 +207,7 @@ void RsGenExchange::generateGroupKeys(RsTlvSecurityKeySet& keySet, bool genPubli
GxsSecurity::setRSAPrivateKey(privPubKey, rsa_publish);
pubKey.startTS = adminKey.startTS;
pubKey.keyId = pubKey.keyId + "_public";
pubKey.endTS = pubKey.startTS + 60 * 60 * 24 * 365 * 5; /* approx 5 years */
privPubKey.startTS = adminKey.startTS;
@ -213,16 +217,15 @@ void RsGenExchange::generateGroupKeys(RsTlvSecurityKeySet& keySet, bool genPubli
pubKey.keyFlags = RSTLV_KEY_DISTRIB_PUBLIC | RSTLV_KEY_TYPE_PUBLIC_ONLY;
privPubKey.keyFlags = RSTLV_KEY_DISTRIB_PRIVATE | RSTLV_KEY_TYPE_FULL;
keySet.keys[pubKey.keyId] = pubKey;
keySet.keys[privPubKey.keyId] = privPubKey;
publickeySet.keys[pubKey.keyId] = pubKey;
privatekeySet.keys[privPubKey.keyId] = privPubKey;
RSA_free(rsa_publish);
RSA_free(rsa_publish_pub);
}
}
bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& keySet)
bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& privateKeySet, RsTlvSecurityKeySet& publicKeySet)
{
std::cerr << "RsGenExchange::createGroup()";
std::cerr << std::endl;
@ -233,22 +236,14 @@ bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& keySet)
// find private admin key
RsTlvSecurityKey privAdminKey;
std::map<std::string, RsTlvSecurityKey>::iterator mit = keySet.keys.begin();
std::map<std::string, RsTlvSecurityKey>::iterator mit = privateKeySet.keys.begin();
bool privKeyFound = false;
for(; mit != keySet.keys.end(); mit++)
bool privKeyFound = false; // private admin key
for(; mit != privateKeySet.keys.end(); mit++)
{
RsTlvSecurityKey& key = mit->second;
// add public admin key
if(key.keyFlags & (RSTLV_KEY_DISTRIB_ADMIN | RSTLV_KEY_TYPE_PUBLIC_ONLY))
meta->keys.keys.insert(std::make_pair(key.keyId, key));
// add public publish key
if(key.keyFlags & (RSTLV_KEY_DISTRIB_PUBLIC | RSTLV_KEY_TYPE_PUBLIC_ONLY))
meta->keys.keys.insert(std::make_pair(key.keyId, key));
if(key.keyFlags & (RSTLV_KEY_DISTRIB_ADMIN | RSTLV_KEY_TYPE_FULL))
if((key.keyFlags & RSTLV_KEY_DISTRIB_ADMIN) && (key.keyFlags & RSTLV_KEY_TYPE_FULL))
{
privAdminKey = key;
privKeyFound = true;
@ -263,6 +258,8 @@ bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& keySet)
return false;
}
meta->keys = publicKeySet; // only public keys are included to be transported
// group is self signing
// for the creation of group signature
// only public admin and publish keys are present in meta
@ -288,9 +285,9 @@ bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& keySet)
grp->meta.setBinData(metaData, metaDataLen);
// but meta that is stored locally
// has all keys
// has private keys
// nxs net transports only bin data
meta->keys = keySet;
meta->keys = privateKeySet;
// clean up
delete[] allGrpData;
@ -432,7 +429,7 @@ bool RsGenExchange::createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBina
// poll immediately but, don't spend more than a second polling
while( (mGixs->getPrivateKey(msgMeta.mAuthorId, authorKey) == -1) &&
((now + 1) >> time(NULL))
((now + 5) > time(NULL))
)
{
#ifndef WINDOWS_SYS
@ -606,16 +603,30 @@ bool RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, RsTlvSec
{
RsTlvKeySignature sign = metaData.signSet.keySignSet[GXS_SERV::FLAG_AUTHEN_PUBLISH];
if(grpKeySet.keys.find(sign.keyId) != grpKeySet.keys.end())
std::map<std::string, RsTlvSecurityKey>& keys = grpKeySet.keys;
std::map<std::string, RsTlvSecurityKey>::iterator mit = keys.begin();
std::string keyId;
for(; mit != keys.end() ; mit++)
{
RsTlvSecurityKey publishKey = grpKeySet.keys[sign.keyId];
valid &= GxsSecurity::validateNxsMsg(*msg, sign, publishKey);
RsTlvSecurityKey& key = mit->second;
if((key.keyFlags & RSTLV_KEY_DISTRIB_PUBLIC) &&
(key.keyFlags & RSTLV_KEY_TYPE_PUBLIC_ONLY))
{
keyId = key.keyId;
}
}
if(!keyId.empty())
{
RsTlvSecurityKey& key = keys[keyId];
valid &= GxsSecurity::validateNxsMsg(*msg, sign, key);
}
else
{
valid = false;
}
}
@ -647,7 +658,7 @@ bool RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, RsTlvSec
#endif
}
RsTlvKeySignature sign = metaData.signSet.keySignSet[GXS_SERV::FLAG_AUTHEN_PUBLISH];
RsTlvKeySignature sign = metaData.signSet.keySignSet[GXS_SERV::FLAG_AUTHEN_IDENTITY];
valid &= GxsSecurity::validateNxsMsg(*msg, sign, authorKey);
}else
{
@ -809,13 +820,13 @@ bool RsGenExchange::getGroupData(const uint32_t &token, std::vector<RsGxsGrpItem
RsGxsGrpItem* gItem = dynamic_cast<RsGxsGrpItem*>(item);
gItem->meta = *((*lit)->metaData);
grpItem.push_back(gItem);
delete *lit;
}
else
{
std::cerr << "RsGenExchange::getGroupData() ERROR deserialising item";
std::cerr << std::endl;
}
delete *lit;
}
}
return ok;
@ -935,6 +946,8 @@ bool RsGenExchange::setAuthenPolicyFlag(const uint8_t &msgFlag, uint32_t& authen
void RsGenExchange::notifyNewGroups(std::vector<RsNxsGrp *> &groups)
{
RsStackMutex stack(mGenMtx);
std::vector<RsNxsGrp*>::iterator vit = groups.begin();
// store these for tick() to pick them up
@ -945,6 +958,8 @@ void RsGenExchange::notifyNewGroups(std::vector<RsNxsGrp *> &groups)
void RsGenExchange::notifyNewMessages(std::vector<RsNxsMsg *>& messages)
{
RsStackMutex stack(mGenMtx);
std::vector<RsNxsMsg*>::iterator vit = messages.begin();
// store these for tick() to pick them up
@ -1225,7 +1240,7 @@ void RsGenExchange::publishMsgs()
RsGxsMessageId msgId;
RsGxsGroupId grpId = msgItem->meta.mGroupId;
bool msgDoesnExist = false;
bool msgDoesnExist = false, validSize = false;
if(createOk)
{
@ -1247,6 +1262,11 @@ void RsGenExchange::publishMsgs()
}
if(createOk && msgDoesnExist)
{
validSize = mDataStore->validSize(msg);
}
if(createOk && msgDoesnExist && validSize)
{
// empty orig msg id means this is the original
// msg
@ -1334,16 +1354,16 @@ void RsGenExchange::publishGrps()
RsNxsGrp* grp = new RsNxsGrp(mServType);
RsGxsGrpItem* grpItem = mit->second;
RsTlvSecurityKeySet keySet;
generateGroupKeys(keySet,
RsTlvSecurityKeySet privatekeySet, publicKeySet, tempKeySet;
generateGroupKeys(privatekeySet, publicKeySet,
!(grpItem->meta.mGroupFlags & GXS_SERV::FLAG_PRIVACY_PUBLIC));
// find private admin key
RsTlvSecurityKey privAdminKey;
std::map<std::string, RsTlvSecurityKey>::iterator mit_keys = keySet.keys.begin();
std::map<std::string, RsTlvSecurityKey>::iterator mit_keys = privatekeySet.keys.begin();
bool privKeyFound = false;
for(; mit_keys != keySet.keys.end(); mit_keys++)
for(; mit_keys != privatekeySet.keys.end(); mit_keys++)
{
RsTlvSecurityKey& key = mit_keys->second;
@ -1366,8 +1386,14 @@ void RsGenExchange::publishGrps()
ok = false;
}
//tempKeySet = privatekeySet;
privatekeySet.keys.insert(publicKeySet.keys.begin(),
publicKeySet.keys.end());
service_CreateGroup(grpItem, privatekeySet);
//privatekeySet = tempKeySet;
service_CreateGroup(grpItem, keySet);
uint32_t size = mSerialiser->size(grpItem);
char gData[size];
@ -1387,13 +1413,18 @@ void RsGenExchange::publishGrps()
*(grp->metaData) = grpItem->meta;
grp->metaData->mSubscribeFlags = GXS_SERV::GROUP_SUBSCRIBE_ADMIN;
ok &= createGroup(grp, keySet);
if (!ok)
if (!createGroup(grp, privatekeySet, publicKeySet))
{
std::cerr << "RsGenExchange::publishGrps() !ok ERROR After createGroup" << std::endl;
}
else
{
// ensure group size is not too large
ok &= mDataStore->validSize(grp);
if(ok)
{
RsGxsGroupId grpId = grp->grpId;
mDataAccess->addGroupData(grp);
@ -1403,6 +1434,8 @@ void RsGenExchange::publishGrps()
mGrpNotify.insert(std::make_pair(mit->first, grpId));
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE);
}
}
}
if(!ok)
{
@ -1485,16 +1518,16 @@ void RsGenExchange::createDummyGroup(RsGxsGrpItem *grpItem)
bool ok = mSerialiser->serialise(grpItem, gData, &size);
grp->grp.setBinData(gData, size);
RsTlvSecurityKeySet keySet;
generateGroupKeys(keySet,
RsTlvSecurityKeySet privateKeySet, publicKeySet;
generateGroupKeys(privateKeySet, publicKeySet,
!(grpItem->meta.mGroupFlags & GXS_SERV::FLAG_PRIVACY_PUBLIC));
// find private admin key
RsTlvSecurityKey privAdminKey;
std::map<std::string, RsTlvSecurityKey>::iterator mit_keys = keySet.keys.begin();
std::map<std::string, RsTlvSecurityKey>::iterator mit_keys = privateKeySet.keys.begin();
bool privKeyFound = false;
for(; mit_keys != keySet.keys.end(); mit_keys++)
for(; mit_keys != privateKeySet.keys.end(); mit_keys++)
{
RsTlvSecurityKey& key = mit_keys->second;
@ -1516,7 +1549,7 @@ void RsGenExchange::createDummyGroup(RsGxsGrpItem *grpItem)
ok = false;
}
service_CreateGroup(grpItem, keySet);
service_CreateGroup(grpItem, privateKeySet);
if(ok)
{
@ -1524,7 +1557,7 @@ void RsGenExchange::createDummyGroup(RsGxsGrpItem *grpItem)
grpItem->meta.mPublishTs = time(NULL);
*(grp->metaData) = grpItem->meta;
grp->metaData->mSubscribeFlags = GXS_SERV::GROUP_SUBSCRIBE_ADMIN;
createGroup(grp, keySet);
createGroup(grp, privateKeySet, publicKeySet);
mDataAccess->addGroupData(grp);
}
@ -1584,9 +1617,9 @@ void RsGenExchange::processRecvdMessages()
if(mit != grpMetas.end()){
RsGxsGrpMetaData* grpMeta = mit->second;
ok = true;
// msg->metaData = meta;
// ok &= validateMsg(msg, grpMeta->mGroupFlags, grpMeta->keys);
// msg->metaData = NULL;
msg->metaData = meta;
ok &= validateMsg(msg, grpMeta->mGroupFlags, grpMeta->keys);
msg->metaData = NULL;
}
else
ok = false;

View File

@ -254,7 +254,8 @@ protected:
&msg->msg.bin_len);
GxsMsgType* mItem = dynamic_cast<GxsMsgType*>(item);
if(mItem == NULL){
if(mItem == NULL)
{
delete msg;
continue;
}
@ -474,7 +475,7 @@ private:
* Meta is serialised and stored in group at this point also
* @param grp Nxs group to create
*/
bool createGroup(RsNxsGrp* grp, RsTlvSecurityKeySet& keySet);
bool createGroup(RsNxsGrp* grp, RsTlvSecurityKeySet& privateKeySet, RsTlvSecurityKeySet& publicKeySet);
/*!
* This completes the creation of an instance on RsNxsMsg
@ -503,10 +504,11 @@ private:
/*!
* Generate a set of keys that can define a GXS group
* @param keySet this is set generated keys
* @param genPublicKeys should public keys also be generated
* @param privatekeySet contains private generated keys
* @param privatekeySet contains public generated keys (counterpart of private)
* @param genPublicKeys should publish key pair also be generated
*/
void generateGroupKeys(RsTlvSecurityKeySet& keySet, bool genPublishKeys);
void generateGroupKeys(RsTlvSecurityKeySet& privatekeySet, RsTlvSecurityKeySet& publickeySet, bool genPublishKeys);
/*!
* Attempts to validate msg

View File

@ -142,9 +142,17 @@ bool RsGxsGrpMetaData::deserialise(void *data, uint32_t &pktsize)
return ok;
}
int RsGxsMsgMetaData::refcount = 0;
RsGxsMsgMetaData::RsGxsMsgMetaData(){
//std::cout << "\nrefcount++ : " << ++refcount << std::endl;
return;
}
RsGxsMsgMetaData::~RsGxsMsgMetaData(){
//std::cout << "\nrefcount-- : " << --refcount << std::endl;
return;
}
uint32_t RsGxsMsgMetaData::serial_size()

View File

@ -87,7 +87,8 @@ class RsGxsMsgMetaData
{
public:
RsGxsMsgMetaData();
explicit RsGxsMsgMetaData();
~RsGxsMsgMetaData();
bool deserialise(void *data, uint32_t *size);
bool serialise(void* data, uint32_t *size);
uint32_t serial_size();
@ -96,7 +97,7 @@ public:
RsGxsGroupId mGroupId;
RsGxsMessageId mMsgId;
static int refcount;
RsGxsMessageId mThreadId;
RsGxsMessageId mParentId;
RsGxsMessageId mOrigMsgId;

View File

@ -52,11 +52,26 @@ void RsGxsIfaceImpl::groupsChanged(std::list<RsGxsGroupId> &grpIds)
}
}
bool RsGxsIfaceImpl::updated()
bool RsGxsIfaceImpl::updated(bool willCallGrpChanged, bool willCallMsgChanged)
{
bool changed = false;
{
RsStackMutex stack(mGxsIfaceMutex);
bool changed = (!mGroupChange.empty() || !mMsgChange.empty());
changed = (!mGroupChange.empty() || !mMsgChange.empty());
}
if(!willCallGrpChanged)
{
std::list<RsGxsGroupId> grpIds;
groupsChanged(grpIds);
}
if(!willCallMsgChanged)
{
std::map<RsGxsGroupId, std::vector<RsGxsMessageId> > msgs;
msgsChanged(msgs);
}
return changed;
}

View File

@ -46,6 +46,7 @@ public:
*/
RsGxsIfaceImpl(RsGenExchange* gxs);
protected:
/*!
* Gxs services should call this for automatic handling of
* changes, send
@ -53,14 +54,20 @@ public:
*/
void receiveChanges(std::vector<RsGxsNotify*>& changes);
public:
/*!
* Checks to see if a change has been received for
* for a message or group
* @param willCallGrpChanged if this is set to true, group changed function will return list
* groups that have changed, if false, the group changed list is cleared
* @param willCallMsgChanged if this is set to true, msgChanged function will return map
* messages that have changed, if false, the message changed map is cleared
* @return true if a change has occured for msg or group
* @see groupsChanged
* @see msgsChanged
*/
virtual bool updated();
public:
virtual bool updated(bool willCallGrpChanged = false, bool willCallMsgChanged = false);
/*!
* The groups changed. \n
@ -68,7 +75,8 @@ public:
* the group actually set for ui notification.
* If receivedChanges is not passed RsGxsNotify changes
* this function does nothing
* @param grpIds
* @param grpIds returns list of grpIds that have changed
* @see updated
*/
virtual void groupsChanged(std::list<RsGxsGroupId>& grpIds);
@ -78,7 +86,8 @@ public:
* the msg actually set for ui notification.
* If receivedChanges is not passed RsGxsNotify changes
* this function does nothing
* @param msgs
* @param msgs returns map of message ids that have changed
* @see updated
*/
virtual void msgsChanged(std::map<RsGxsGroupId,
std::vector<RsGxsMessageId> >& msgs);

View File

@ -25,6 +25,7 @@
*/
#include <unistd.h>
#include <math.h>
#include "rsgxsnetservice.h"
#include "rsgxsflags.h"
@ -34,6 +35,7 @@
#define SYNC_PERIOD 12 // in microseconds every 10 seconds (1 second for testing)
#define TRANSAC_TIMEOUT 5 // 5 seconds
const uint32_t RsGxsNetService::FRAGMENT_SIZE = 150000;
RsGxsNetService::RsGxsNetService(uint16_t servType, RsGeneralDataService *gds,
RsNxsNetMgr *netMgr, RsNxsObserver *nxsObs)
@ -88,7 +90,6 @@ void RsGxsNetService::syncWithPeers()
sendItem(grp);
}
#ifdef GXS_ENABLE_SYNC_MSGS
std::map<RsGxsGroupId, RsGxsGrpMetaData* > grpMeta;
mDataStore->retrieveGxsGrpMetaData(grpMeta);
@ -130,6 +131,236 @@ void RsGxsNetService::syncWithPeers()
#endif
}
bool RsGxsNetService::fragmentMsg(RsNxsMsg& msg, MsgFragments& msgFragments) const
{
// first determine how many fragments
uint32_t msgSize = msg.msg.TlvSize();
uint32_t dataLeft = msgSize;
uint8_t nFragments = ceil(float(msgSize)/FRAGMENT_SIZE);
char buffer[FRAGMENT_SIZE];
int currPos = 0;
for(uint8_t i=0; i < nFragments; i++)
{
RsNxsMsg* msgFrag = new RsNxsMsg(mServType);
msgFrag->grpId = msg.grpId;
msgFrag->msgId = msg.msgId;
msgFrag->meta = msg.meta;
msgFrag->pos = i;
msgFrag->count = nFragments;
uint32_t fragSize = std::min(dataLeft, FRAGMENT_SIZE);
memcpy(buffer, ((char*)msg.msg.bin_data) + currPos, fragSize);
currPos += fragSize;
dataLeft -= fragSize;
msgFragments.push_back(msgFrag);
}
return true;
}
bool RsGxsNetService::fragmentGrp(RsNxsGrp& grp, GrpFragments& grpFragments) const
{
// first determine how many fragments
uint32_t grpSize = grp.grp.TlvSize();
uint32_t dataLeft = grpSize;
uint8_t nFragments = ceil(float(grpSize)/FRAGMENT_SIZE);
char buffer[FRAGMENT_SIZE];
int currPos = 0;
for(uint8_t i=0; i < nFragments; i++)
{
RsNxsGrp* grpFrag = new RsNxsGrp(mServType);
grpFrag->grpId = grp.grpId;
grpFrag->meta = grp.meta;
grpFrag->pos = i;
grpFrag->count = nFragments;
uint32_t fragSize = std::min(dataLeft, FRAGMENT_SIZE);
memcpy(buffer, ((char*)grp.grp.bin_data) + currPos, fragSize);
currPos += fragSize;
dataLeft -= fragSize;
grpFragments.push_back(grpFrag);
}
return true;
}
RsNxsMsg* RsGxsNetService::deFragmentMsg(MsgFragments& msgFragments) const
{
if(msgFragments.empty()) return NULL;
// first determine total size for binary data
MsgFragments::iterator mit = msgFragments.begin();
uint32_t datSize = 0;
for(; mit != msgFragments.end(); mit++)
datSize += (*mit)->msg.bin_len;
char* data = new char[datSize];
uint32_t currPos = 0;
for(mit = msgFragments.begin(); mit != msgFragments.end(); mit++)
{
RsNxsMsg* msg = *mit;
memcpy(data + (currPos), msg->msg.bin_data, msg->msg.bin_len);
currPos += msg->msg.bin_len;
}
RsNxsMsg* msg = new RsNxsMsg(mServType);
const RsNxsMsg& m = *(*(msgFragments.begin()));
msg->msg.setBinData(data, datSize);
msg->msgId = m.msgId;
msg->grpId = m.grpId;
msg->transactionNumber = m.transactionNumber;
msg->meta = m.meta;
delete[] data;
return msg;
}
RsNxsGrp* RsGxsNetService::deFragmentGrp(GrpFragments& grpFragments) const
{
if(grpFragments.empty()) return NULL;
// first determine total size for binary data
GrpFragments::iterator mit = grpFragments.begin();
uint32_t datSize = 0;
for(; mit != grpFragments.end(); mit++)
datSize += (*mit)->grp.bin_len;
char* data = new char[datSize];
uint32_t currPos = 0;
for(mit = grpFragments.begin(); mit != grpFragments.end(); mit++)
{
RsNxsGrp* grp = *mit;
memcpy(data + (currPos), grp->grp.bin_data, grp->grp.bin_len);
currPos += grp->grp.bin_len;
}
RsNxsGrp* grp = new RsNxsGrp(mServType);
const RsNxsGrp& g = *(*(grpFragments.begin()));
grp->grp.setBinData(data, datSize);
grp->grpId = g.grpId;
grp->transactionNumber = g.transactionNumber;
grp->meta = g.meta;
delete[] data;
return grp;
}
struct GrpFragCollate
{
RsGxsGroupId mGrpId;
GrpFragCollate(const RsGxsGroupId& grpId) : mGrpId(grpId){ }
bool operator()(RsNxsGrp* grp) { return grp->grpId == mGrpId;}
};
void RsGxsNetService::collateGrpFragments(GrpFragments fragments,
std::map<RsGxsGroupId, GrpFragments>& partFragments) const
{
// get all unique grpIds;
GrpFragments::iterator vit = fragments.begin();
std::set<RsGxsGroupId> grpIds;
for(; vit != fragments.end(); vit++)
grpIds.insert( (*vit)->grpId );
std::set<RsGxsGroupId>::iterator sit = grpIds.begin();
for(; sit != grpIds.end(); sit++)
{
const RsGxsGroupId& grpId = *sit;
GrpFragments::iterator bound = std::partition(
fragments.begin(), fragments.end(),
GrpFragCollate(grpId));
// something will always be found for a group id
for(vit = fragments.begin(); vit != bound; )
{
partFragments[grpId].push_back(*vit);
vit = fragments.erase(vit);
}
GrpFragments& f = partFragments[grpId];
RsNxsGrp* grp = *(f.begin());
// if counts of fragments is incorrect remove
// from coalescion
if(grp->count != f.size())
{
GrpFragments::iterator vit2 = f.begin();
for(; vit2 != f.end(); vit2++)
delete *vit2;
partFragments.erase(grpId);
}
}
fragments.clear();
}
struct MsgFragCollate
{
RsGxsGroupId mMsgId;
MsgFragCollate(const RsGxsMessageId& msgId) : mMsgId(msgId){ }
bool operator()(RsNxsMsg* msg) { return msg->msgId == mMsgId;}
};
void RsGxsNetService::collateMsgFragments(MsgFragments fragments, std::map<RsGxsMessageId, MsgFragments>& partFragments) const
{
// get all unique message Ids;
MsgFragments::iterator vit = fragments.begin();
std::set<RsGxsMessageId> msgIds;
for(; vit != fragments.end(); vit++)
msgIds.insert( (*vit)->msgId );
std::set<RsGxsMessageId>::iterator sit = msgIds.begin();
for(; sit != msgIds.end(); sit++)
{
const RsGxsMessageId& msgId = *sit;
MsgFragments::iterator bound = std::partition(
fragments.begin(), fragments.end(),
MsgFragCollate(msgId));
// something will always be found for a group id
for(vit = fragments.begin(); vit != bound; )
{
partFragments[msgId].push_back(*vit);
vit = fragments.erase(vit);
}
MsgFragments& f = partFragments[msgId];
RsNxsMsg* msg = *(f.begin());
// if counts of fragments is incorrect remove
// from coalescion
if(msg->count != f.size())
{
MsgFragments::iterator vit2 = f.begin();
for(; vit2 != f.end(); vit2++)
delete *vit2;
partFragments.erase(msgId);
}
}
fragments.clear();
}
bool RsGxsNetService::loadList(std::list<RsItem*>& load)
{
return false;
@ -186,7 +417,8 @@ void RsGxsNetService::recvNxsItemQueue(){
}
bool RsGxsNetService::handleTransaction(RsNxsItem* item){
bool RsGxsNetService::handleTransaction(RsNxsItem* item)
{
/*!
* This attempts to handle a transaction
@ -201,9 +433,9 @@ bool RsGxsNetService::handleTransaction(RsNxsItem* item){
RsNxsTransac* transItem = dynamic_cast<RsNxsTransac*>(item);
// if this is a RsNxsTransac item process
if(transItem){
if(transItem)
return locked_processTransac(transItem);
}
// then this must be transaction content to be consumed
// first check peer exist for transaction
@ -221,7 +453,8 @@ bool RsGxsNetService::handleTransaction(RsNxsItem* item){
transExists = transMap.find(transN) != transMap.end();
if(transExists){
if(transExists)
{
#ifdef NXS_NET_DEBUG
std::cerr << "handleTransaction() " << std::endl;
@ -231,14 +464,13 @@ bool RsGxsNetService::handleTransaction(RsNxsItem* item){
tr = transMap[transN];
tr->mItems.push_back(item);
}
}else{
return false;
}
return true;
}
}
return false;
}
bool RsGxsNetService::locked_processTransac(RsNxsTransac* item)
{
@ -368,8 +600,8 @@ void RsGxsNetService::run(){
bool RsGxsNetService::locked_checkTransacTimedOut(NxsTransaction* tr)
{
return tr->mTimeOut < ((uint32_t) time(NULL));
// return false;
//return tr->mTimeOut < ((uint32_t) time(NULL));
return false;
}
void RsGxsNetService::processTransactions(){

View File

@ -133,7 +133,7 @@ class RsGxsNetService : public RsNetworkExchangeService, public p3ThreadedServic
{
public:
static const uint32_t FRAGMENT_SIZE;
/*!
* only one observer is allowed
* @param servType service type
@ -365,6 +365,60 @@ private:
private:
typedef std::vector<RsNxsGrp*> GrpFragments;
typedef std::vector<RsNxsMsg*> MsgFragments;
/*!
* Fragment a message into individual fragments which are at most 150kb
* @param msg message to fragment
* @param msgFragments fragmented message
* @return false if fragmentation fails true otherwise
*/
bool fragmentMsg(RsNxsMsg& msg, MsgFragments& msgFragments) const;
/*!
* Fragment a group into individual fragments which are at most 150kb
* @param grp group to fragment
* @param grpFragments fragmented group
* @return false if fragmentation fails true other wise
*/
bool fragmentGrp(RsNxsGrp& grp, GrpFragments& grpFragments) const;
/*!
* Fragment a message into individual fragments which are at most 150kb
* @param msg message to fragment
* @param msgFragments fragmented message
* @return NULL if not possible to reconstruct message from fragment,
* pointer to defragments nxs message is possible
*/
RsNxsMsg* deFragmentMsg(MsgFragments& msgFragments) const;
/*!
* Fragment a group into individual fragments which are at most 150kb
* @param grp group to fragment
* @param grpFragments fragmented group
* @return NULL if not possible to reconstruct group from fragment,
* pointer to defragments nxs group is possible
*/
RsNxsGrp* deFragmentGrp(GrpFragments& grpFragments) const;
/*!
* Note that if all fragments for a message are not found then its fragments are dropped
* @param fragments message fragments which are not necessarily from the same message
* @param partFragments the partitioned fragments (into message ids)
*/
void collateMsgFragments(MsgFragments fragments, std::map<RsGxsMessageId, MsgFragments>& partFragments) const;
/*!
* Note that if all fragments for a group are not found then its fragments are dropped
* @param fragments group fragments which are not necessarily from the same group
* @param partFragments the partitioned fragments (into message ids)
*/
void collateGrpFragments(GrpFragments fragments, std::map<RsGxsGroupId, GrpFragments>& partFragments) const;
private:
/*** transactions ***/
/// active transactions

View File

@ -58,6 +58,7 @@ class GroupIdReq : public GxsRequest
{
public:
std::list<std::string> mGroupIds;
std::list<std::string> mGroupIdResult;
};

View File

@ -2263,7 +2263,6 @@ int RsServer::StartupRetroShare()
mPluginsManager->registerClientServices(pqih) ;
mPluginsManager->registerCacheServices() ;
#ifdef RS_ENABLE_GXS
// The idea is that if priorGxsDir is non
@ -2331,9 +2330,9 @@ int RsServer::StartupRetroShare()
RsGenExchange::RESTRICTED_GRP_BITS);
// Re-enable later, photo not using gixs yet
// flag = GXS_SERV::MSG_AUTHEN_CHILD_AUTHOR_SIGN;
// RsGenExchange::setAuthenPolicyFlag(flag, photoAuthenPolicy,
// RsGenExchange::RESTRICTED_GRP_BITS);
flag = GXS_SERV::MSG_AUTHEN_ROOT_AUTHOR_SIGN; // should be GXS_SERV::MSG_AUTHEN_CHILD_AUTHOR_SIGN for comments
RsGenExchange::setAuthenPolicyFlag(flag, photoAuthenPolicy,
RsGenExchange::RESTRICTED_GRP_BITS);
flag = GXS_SERV::GRP_OPTION_AUTHEN_AUTHOR_SIGN;
RsGenExchange::setAuthenPolicyFlag(flag, photoAuthenPolicy,

View File

@ -248,6 +248,7 @@ bool RsNxsSerialiser::serialiseNxsMsg(RsNxsMsg *item, void *data, uint32_t *size
offset += 8;
ok &= setRawUInt32(data, *size, &offset, item->transactionNumber);
ok &= setRawUInt8(data, *size, &offset, item->pos);
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_MSGID, item->msgId);
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GROUPID, item->grpId);
ok &= item->msg.SetTlv(data, tlvsize, &offset);
@ -299,6 +300,7 @@ bool RsNxsSerialiser::serialiseNxsGrp(RsNxsGrp *item, void *data, uint32_t *size
// grp id
ok &= setRawUInt32(data, *size, &offset, item->transactionNumber);
ok &= setRawUInt8(data, *size, &offset, item->pos);
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GROUPID, item->grpId);
ok &= item->grp.SetTlv(data, tlvsize, &offset);
ok &= item->meta.SetTlv(data, *size, &offset);
@ -564,6 +566,7 @@ RsNxsGrp* RsNxsSerialiser::deserialNxsGrp(void *data, uint32_t *size){
offset += 8;
ok &= getRawUInt32(data, *size, &offset, &(item->transactionNumber));
ok &= getRawUInt8(data, *size, &offset, &(item->pos));
ok &= GetTlvString(data, *size, &offset, TLV_TYPE_STR_GROUPID, item->grpId);
ok &= item->grp.GetTlv(data, *size, &offset);
ok &= item->meta.GetTlv(data, *size, &offset);
@ -632,6 +635,7 @@ RsNxsMsg* RsNxsSerialiser::deserialNxsMsg(void *data, uint32_t *size){
offset += 8;
ok &= getRawUInt32(data, *size, &offset, &(item->transactionNumber));
ok &= getRawUInt8(data, *size, &offset, &(item->pos));
ok &= GetTlvString(data, *size, &offset, TLV_TYPE_STR_MSGID, item->msgId);
ok &= GetTlvString(data, *size, &offset, TLV_TYPE_STR_GROUPID, item->grpId);
ok &= item->msg.GetTlv(data, *size, &offset);
@ -1015,6 +1019,7 @@ uint32_t RsNxsSerialiser::sizeNxsMsg(RsNxsMsg *item)
uint32_t s = 8; //header size
s += 4; // transaction number
s += 1; // pos
s += GetTlvStringSize(item->grpId);
s += GetTlvStringSize(item->msgId);
s += item->msg.TlvSize();
@ -1028,6 +1033,7 @@ uint32_t RsNxsSerialiser::sizeNxsGrp(RsNxsGrp *item)
uint32_t s = 8; // header size
s += 4; // transaction number
s += 1; // pos
s += GetTlvStringSize(item->grpId);
s += item->grp.TlvSize();
s += item->meta.TlvSize();
@ -1106,9 +1112,9 @@ uint32_t RsNxsSerialiser::sizeNxsExtended(RsNxsExtended *item){
return 0;
}
int RsNxsGrp::refcount = 0;
/** print and clear functions **/
int RsNxsMsg::refcount = 0;
void RsNxsMsg::clear()
{
@ -1253,6 +1259,8 @@ std::ostream& RsNxsGrp::print(std::ostream &out, uint16_t indent){
out << "grpId: " << grpId << std::endl;
printIndent(out , int_Indent);
out << "grp: " << std::endl;
printIndent(out , int_Indent);
out << "pos: " << pos << std::endl;
grp.print(out, int_Indent);
out << "meta: " << std::endl;
meta.print(out, int_Indent);
@ -1269,6 +1277,8 @@ std::ostream& RsNxsMsg::print(std::ostream &out, uint16_t indent){
out << "msgId: " << msgId << std::endl;
printIndent(out , int_Indent);
out << "grpId: " << grpId << std::endl;
printIndent(out , int_Indent);
out << "pos: " << pos << std::endl;
printIndent(out , int_Indent);
out << "msg: " << std::endl;
msg.print(out, indent);

View File

@ -73,6 +73,7 @@ public:
setPriorityLevel(QOS_PRIORITY_RS_VOIP_PING);
return;
}
virtual ~RsNxsItem(){ return; }
virtual void clear() = 0;
virtual std::ostream &print(std::ostream &out, uint16_t indent = 0) = 0;
@ -188,15 +189,21 @@ class RsNxsGrp : public RsNxsItem
public:
RsNxsGrp(uint16_t servtype) : RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_GRP), grp(servtype), meta(servtype),
metaData(NULL) { clear(); return; }
virtual ~RsNxsGrp() { if(metaData) delete metaData; }
metaData(NULL) { clear();
//std::cout << "\nGrp refcount++ : " << ++refcount << std::endl;
return; }
virtual ~RsNxsGrp() { if(metaData) delete metaData;
//std::cout << "\nGrp refcount-- : " << --refcount << std::endl;
}
virtual void clear();
virtual std::ostream &print(std::ostream &out, uint16_t indent);
std::string grpId; /// group Id, needed to complete version Id (ncvi)
static int refcount;
RsTlvBinaryData grp; /// actual group data
uint8_t pos; /// used for splitting up grp
uint8_t count; /// number of split up messages
/*!
* This should contains all data
@ -263,15 +270,27 @@ class RsNxsMsg : public RsNxsItem
public:
RsNxsMsg(uint16_t servtype) : RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_MSG), meta(servtype), msg(servtype),
metaData(NULL) { clear(); return; }
~RsNxsMsg() { if(metaData) delete metaData; }
metaData(NULL) {
// std::cout << "\nrefcount++ : " << ++refcount << std::endl;
clear(); return;
}
virtual ~RsNxsMsg()
{
//std::cout << "\nrefcount-- : " << --refcount << std::endl;
if(metaData){
//std::cout << "\ndeleted\n";
delete metaData;
}
}
virtual void clear();
virtual std::ostream &print(std::ostream &out, uint16_t indent);
uint8_t pos; /// used for splitting up msg
uint8_t count; /// number of split up messages
std::string grpId; /// group id, forms part of version id
std::string msgId; /// msg id
static int refcount;
/*!
* This should contains all the data
* which is not specific to the Gxs service data

View File

@ -691,23 +691,26 @@ bool p3IdService::cache_store(const RsGxsIdGroupItem *item)
for (kit = keySet.keys.begin(); kit != keySet.keys.end(); kit++)
{
if (kit->second.keyFlags | RSTLV_KEY_DISTRIB_ADMIN)
if (kit->second.keyFlags & RSTLV_KEY_DISTRIB_ADMIN)
{
std::cerr << "p3IdService::cache_store() Found Admin Key";
std::cerr << std::endl;
/* save full key - if we have it */
if (kit->second.keyFlags | RSTLV_KEY_TYPE_FULL)
if (kit->second.keyFlags & RSTLV_KEY_TYPE_FULL)
{
fullkey = kit->second;
full_key_ok = true;
}
if (kit->second.keyFlags & RSTLV_KEY_TYPE_PUBLIC_ONLY)
{
/* cache public key always */
pubkey = kit->second;
pub_key_ok = true;
}
}
}
if (!pub_key_ok)
{

View File

@ -68,18 +68,18 @@ void p3Posted::service_tick()
generatePosts();
generateVotesAndComments();
time_t now = time(NULL);
if((now > (time_t) (VOTE_UPDATE_PERIOD + mLastUpdate)) &&
(mUpdatePhase == UPDATE_PHASE_GRP_REQUEST))
{
mPostUpdate = true;
mLastUpdate = time(NULL);
}
updateVotes();
processRankings();
// time_t now = time(NULL);
//
// if((now > (time_t) (VOTE_UPDATE_PERIOD + mLastUpdate)) &&
// (mUpdatePhase == UPDATE_PHASE_GRP_REQUEST))
// {
// mPostUpdate = true;
// mLastUpdate = time(NULL);
// }
//
// updateVotes();
//
// processRankings();
}
void p3Posted::generateVotesAndComments()
@ -505,7 +505,6 @@ bool p3Posted::requestPostRankings(uint32_t &token, const RankType &rType, const
gp->pubToken = token;
gp->rankingResult.rType = gp->rType;
gp->rankingResult.grpId = gp->grpId;
gp->grpId = gp->grpId;
mPendingPostRanks.push_back(gp);
@ -768,6 +767,7 @@ bool p3Posted::completePostedPostCalc(GxsPostedPostRanking *gpp)
break;
default:
std::cerr << "Unknown ranking tpye: " << gpp->rType << std::endl;
break;
}
return true;
}else

View File

@ -24,6 +24,8 @@ PhotoItem::PhotoItem(PhotoShareItemHolder *holder, const RsPhotoPhoto &photo, QW
ui->lineEdit_PhotoGrapher->setVisible(false);
setUp();
ui->idChooser->setVisible(false);
}
PhotoItem::PhotoItem(PhotoShareItemHolder *holder, const QString& path, QWidget *parent) :
@ -43,6 +45,8 @@ PhotoItem::PhotoItem(PhotoShareItemHolder *holder, const QString& path, QWidget
connect(ui->lineEdit_Title, SIGNAL(editingFinished()), this, SLOT(setTitle()));
connect(ui->lineEdit_PhotoGrapher, SIGNAL(editingFinished()), this, SLOT(setPhotoGrapher()));
ui->idChooser->loadIds(0, "");
}
void PhotoItem::setSelected(bool selected)
@ -101,6 +105,15 @@ void PhotoItem::setPhotoGrapher()
const RsPhotoPhoto& PhotoItem::getPhotoDetails()
{
if(ui->idChooser->isVisible())
{
RsGxsId id;
ui->idChooser->getChosenId(id);
mPhotoDetails.mMeta.mAuthorId = id;
}
return mPhotoDetails;
}

View File

@ -28,7 +28,7 @@ border-radius: 10px}</string>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_Thumbnail">
<property name="text">
@ -67,6 +67,17 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="identity">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt; font-weight:600;&quot;&gt;Author :&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -81,6 +92,9 @@ p, li { white-space: pre-wrap; }
<item>
<widget class="QLineEdit" name="lineEdit_PhotoGrapher"/>
</item>
<item>
<widget class="GxsIdChooser" name="idChooser"/>
</item>
</layout>
</item>
</layout>
@ -105,6 +119,13 @@ p, li { white-space: pre-wrap; }
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>GxsIdChooser</class>
<extends>QComboBox</extends>
<header>gui/gxs/GxsIdChooser.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -223,7 +223,7 @@ void PostedListDialog::updateDisplay()
std::map<RsGxsGroupId, std::vector<RsGxsMessageId> > msgs;
if (rsPosted->updated())
if (rsPosted->updated(true, true))
{
/* update Forums List */