Merge pull request #143 from csoler/v0.6-Reputations

V0.6 reputations
This commit is contained in:
Cyril Soler 2015-10-12 15:06:12 -04:00
commit 0120234f92
23 changed files with 2157 additions and 1562 deletions

View File

@ -34,6 +34,7 @@
#include "pqi/p3historymgr.h"
#include "retroshare/rspeers.h"
#include "retroshare/rsiface.h"
#include "retroshare/rsreputations.h"
#include "retroshare/rsidentity.h"
#include "rsserver/p3face.h"
#include "gxs/rsgixs.h"
@ -175,6 +176,12 @@ bool DistributedChatService::handleRecvChatLobbyMsgItem(RsChatMsgItem *ci)
return false ;
}
}
if(rsReputations->isIdentityBanned(cli->signature.keyId))
{
std::cerr << "(WW) Received lobby msg/item from banned identity " << cli->signature.keyId << ". Dropping it." << std::endl;
return false ;
}
if(!bounceLobbyObject(cli,cli->PeerId())) // forwards the message to friends, keeps track of subscribers, etc.
return false;
@ -672,6 +679,11 @@ void DistributedChatService::handleRecvChatLobbyEventItem(RsChatLobbyEventItem *
return ;
}
}
if(rsReputations->isIdentityBanned(item->signature.keyId))
{
std::cerr << "(WW) Received lobby msg/item from banned identity " << item->signature.keyId << ". Dropping it." << std::endl;
return ;
}
addTimeShiftStatistics((int)now - (int)item->sendTime) ;
if(now+100 > (time_t) item->sendTime + MAX_KEEP_MSG_RECORD) // the message is older than the max cache keep minus 100 seconds ! It's too old, and is going to make an echo!

View File

@ -30,6 +30,7 @@
#include "rsgxsnetservice.h"
#include "retroshare/rsconfig.h"
#include "retroshare/rsreputations.h"
#include "retroshare/rsgxsflags.h"
#include "retroshare/rsgxscircles.h"
#include "pgp/pgpauxutils.h"
@ -1997,6 +1998,12 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
continue;
}
if(rsReputations->isIdentityBanned(syncItem->authorId))
{
std::cerr << ", Identity " << syncItem->authorId << " is banned. Not requesting message!" << std::endl;
continue ;
}
if(mReputations->haveReputation(syncItem->authorId) || noAuthor)
{
GixsReputation rep;
@ -2009,7 +2016,7 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
// if author is required for this message, it will simply get dropped
// at genexchange side of things
if(rep.score > (int)grpMeta->mReputationCutOff || noAuthor)
if(rep.score >= (int)grpMeta->mReputationCutOff || noAuthor)
{
#ifdef NXS_NET_DEBUG
std::cerr << ", passed! Adding message to req list." << std::endl;
@ -2211,6 +2218,12 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr)
latestVersion = grpSyncItem->publishTs > metaIter->second->mPublishTs;
}
if(!grpSyncItem->authorId.isNull() && rsReputations->isIdentityBanned(grpSyncItem->authorId))
{
std::cerr << " Identity " << grpSyncItem->authorId << " is banned. Not syncing group." << std::endl;
continue ;
}
if( (mGrpAutoSync && !haveItem) || latestVersion)
{
// determine if you need to check reputation

View File

@ -99,7 +99,7 @@ bool MsgRespPending::accepted()
GixsReputation rep;
if(getAuthorRep(rep, entry.mAuthorId, mPeerId))
{
if(rep.score > mCutOff)
if(rep.score >= mCutOff)
{
entry.mPassedVetting = true;
count++;
@ -134,7 +134,7 @@ bool GrpRespPending::accepted()
if(getAuthorRep(rep, entry.mAuthorId, mPeerId))
{
if(rep.score > mCutOff)
if(rep.score >= mCutOff)
{
entry.mPassedVetting = true;
count++;

View File

@ -675,6 +675,7 @@ SOURCES += zeroconf/p3zcnatassist.cc \
# new gxs cache system
# this should be disabled for releases until further notice.
DEFINES *= SQLITE_HAS_CODEC
DEFINES *= GXS_ENABLE_SYNC_MSGS

View File

@ -32,6 +32,7 @@
#include "retroshare/rstokenservice.h"
#include "retroshare/rsgxsifacehelper.h"
#include "retroshare/rsreputations.h"
#include "retroshare/rsids.h"
#include "serialiser/rstlvimage.h"
#include "retroshare/rsgxscommon.h"
@ -158,8 +159,7 @@ class RsIdentityDetails
{
public:
RsIdentityDetails()
:mIsOwnId(false), mPgpLinked(false), mPgpKnown(false),
mReputation(), mLastUsageTS(0) { return; }
:mIsOwnId(false), mPgpLinked(false), mPgpKnown(false), mLastUsageTS(0) { return; }
RsGxsId mId;
@ -175,8 +175,12 @@ public:
// Recogn details.
std::list<RsRecognTag> mRecognTags;
// reputation details.
GxsReputation mReputation;
// Cyril: Reputation details. At some point we might want to merge information
// between the two into a single global score. Since the old reputation system
// is not finished yet, I leave this in place. We should decide what to do with it.
GxsReputation mReputation_oldSystem; // this is the old "mReputation" field, which apparently is not used.
RsReputations::ReputationInfo mReputation;
// avatar
RsGxsImage mAvatar ;

View File

@ -40,6 +40,7 @@ extern RsPluginHandler *rsPlugins ;
class p3Service ;
class RsServiceControl ;
class RsReputations ;
class RsTurtle ;
class RsDht ;
class RsDisc ;
@ -116,6 +117,7 @@ public:
RsUtil::inited_ptr<PgpAuxUtils> mPgpAuxUtils;
RsUtil::inited_ptr<RsGxsForums> mGxsForums;
RsUtil::inited_ptr<RsGxsChannels> mGxsChannels;
RsUtil::inited_ptr<RsReputations> mReputations;
};
class RsPlugin

View File

@ -0,0 +1,58 @@
/*
* libretroshare/src/services: rsreputation.h
*
* Services for RetroShare.
*
* Copyright 2015 by Cyril Soler
*
* 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 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 "csoler@users.sourceforge.net".
*
*/
#pragma once
#include "retroshare/rsids.h"
#include "retroshare/rsgxsifacetypes.h"
class RsReputations
{
public:
// This is the interface file for the reputation system
//
enum Opinion { OPINION_NEGATIVE = 0, OPINION_NEUTRAL = 1, OPINION_POSITIVE = 2 } ;
enum Assessment { ASSESSMENT_BAD = 0, ASSESSMENT_OK = 1 } ;
struct ReputationInfo
{
RsReputations::Opinion mOwnOpinion ;
float mOverallReputationScore ;
float mFriendAverage ;
RsReputations::Assessment mAssessment; // this should help clients in taking decisions
};
virtual bool setOwnOpinion(const RsGxsId& key_id, const Opinion& op) =0;
virtual bool getReputationInfo(const RsGxsId& id,ReputationInfo& info) =0 ;
// This one is a proxy designed to allow fast checking of a GXS id.
// it basically returns true if assessment is not ASSESSMENT_OK
virtual bool isIdentityBanned(const RsGxsId& id) =0;
};
// To access reputations from anywhere
//
extern RsReputations *rsReputations ;

View File

@ -819,6 +819,7 @@ bool RsInit::SetHiddenLocation(const std::string& hiddenaddress, uint16_t port)
RsFiles *rsFiles = NULL;
RsTurtle *rsTurtle = NULL ;
RsReputations *rsReputations = NULL ;
#ifdef ENABLE_GROUTER
RsGRouter *rsGRouter = NULL ;
#endif
@ -847,6 +848,7 @@ RsGRouter *rsGRouter = NULL ;
#endif
#endif
#include "services/p3gxsreputation.h"
#include "services/p3serviceinfo.h"
#include "services/p3heartbeat.h"
#include "services/p3discovery2.h"
@ -1357,6 +1359,11 @@ int RsServer::StartupRetroShare()
mPosted->setNetworkExchangeService(posted_ns) ;
/**** Reputation system ****/
p3GxsReputation *mReputations = new p3GxsReputation(mLinkMgr) ;
rsReputations = mReputations ;
/**** Wiki GXS service ****/
@ -1492,8 +1499,8 @@ int RsServer::StartupRetroShare()
pqih -> addService(mDisc,true);
pqih -> addService(msgSrv,true);
pqih -> addService(chatSrv,true);
pqih -> addService(mStatusSrv,true);
pqih -> addService(mStatusSrv,true);
pqih -> addService(mReputations,true);
// set interfaces for plugins
//
@ -1514,6 +1521,8 @@ int RsServer::StartupRetroShare()
interfaces.mPgpAuxUtils = pgpAuxUtils;
interfaces.mGxsForums = mGxsForums;
interfaces.mGxsChannels = mGxsChannels;
interfaces.mReputations = mReputations;
mPluginsManager->setInterfaces(interfaces);
// now add plugin objects inside the loop:
@ -1601,12 +1610,13 @@ int RsServer::StartupRetroShare()
mConfigMgr->addConfiguration("peers.cfg", mPeerMgr);
mConfigMgr->addConfiguration("general.cfg", mGeneralConfig);
mConfigMgr->addConfiguration("msgs.cfg", msgSrv);
mConfigMgr->addConfiguration("chat.cfg", chatSrv);
mConfigMgr->addConfiguration("p3History.cfg", mHistoryMgr);
mConfigMgr->addConfiguration("p3Status.cfg", mStatusSrv);
mConfigMgr->addConfiguration("turtle.cfg", tr);
mConfigMgr->addConfiguration("banlist.cfg", mBanList);
mConfigMgr->addConfiguration("servicecontrol.cfg", serviceCtrl);
mConfigMgr->addConfiguration("chat.cfg", chatSrv);
mConfigMgr->addConfiguration("p3History.cfg", mHistoryMgr);
mConfigMgr->addConfiguration("p3Status.cfg", mStatusSrv);
mConfigMgr->addConfiguration("turtle.cfg", tr);
mConfigMgr->addConfiguration("banlist.cfg", mBanList);
mConfigMgr->addConfiguration("servicecontrol.cfg", serviceCtrl);
mConfigMgr->addConfiguration("reputations.cfg", mReputations);
#ifdef ENABLE_GROUTER
mConfigMgr->addConfiguration("grouter.cfg", gr);
#endif

View File

@ -23,9 +23,9 @@
*
*/
#include <stdio.h>
#include "serialiser/rsbaseserial.h"
#include "serialiser/rsbanlistitems.h"
#include "serialiser/rstlvbanlist.h"
#include "serialiser/rsgxsreputationitems.h"
/***
#define RSSERIAL_DEBUG 1
@ -35,170 +35,395 @@
/*************************************************************************/
#ifdef SUSPENDED
RsBanListItem::~RsBanListItem()
bool RsReputationItem::serialise_header(void *data,uint32_t& pktsize,uint32_t& tlvsize, uint32_t& offset) const
{
return;
}
tlvsize = serial_size() ;
offset = 0;
void RsBanListItem::clear()
{
peerList.TlvClear();
}
std::ostream &RsBanListItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsBanListItem", indent);
uint16_t int_Indent = indent + 2;
peerList.print(out, int_Indent);
printRsItemEnd(out, "RsBanListItem", indent);
return out;
}
uint32_t RsBanListSerialiser::sizeList(RsBanListItem *item)
{
uint32_t s = 8; /* header */
s += item->peerList.TlvSize();
return s;
}
/* serialise the data to the buffer */
bool RsBanListSerialiser::serialiseList(RsBanListItem *item, void *data, uint32_t *pktsize)
{
uint32_t tlvsize = sizeList(item);
uint32_t offset = 0;
if (*pktsize < tlvsize)
if (pktsize < tlvsize)
return false; /* not enough space */
*pktsize = tlvsize;
bool ok = true;
ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize);
pktsize = tlvsize;
if(!setRsItemHeader(data, tlvsize, PacketId(), tlvsize))
{
std::cerr << "RsReputationItem::serialise_header(): ERROR. Not enough size!" << std::endl;
return false ;
}
#ifdef RSSERIAL_DEBUG
std::cerr << "RsDsdvSerialiser::serialiseRoute() Header: " << ok << std::endl;
std::cerr << "RsDsdvSerialiser::serialiseRoute() Size: " << tlvsize << std::endl;
std::cerr << "RsReputationItem::serialise() Header: " << ok << std::endl;
#endif
/* skip the header */
offset += 8;
/* add mandatory parts first */
ok &= item->peerList.SetTlv(data, tlvsize, &offset);
if (offset != tlvsize)
{
ok = false;
#ifdef RSSERIAL_DEBUG
std::cerr << "RsDsdvSerialiser::serialiseRoute() Size Error! " << std::endl;
#endif
}
return ok;
}
RsBanListItem *RsBanListSerialiser::deserialiseList(void *data, uint32_t *pktsize)
{
/* get the type and size */
uint32_t rstype = getRsItemId(data);
uint32_t tlvsize = getRsItemSize(data);
uint32_t offset = 0;
if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) ||
(RS_SERVICE_TYPE_BANLIST != getRsItemService(rstype)) ||
(RS_PKT_SUBTYPE_BANLIST_ITEM != getRsItemSubType(rstype)))
{
return NULL; /* wrong type */
}
if (*pktsize < tlvsize) /* check size */
return NULL; /* not enough data */
/* set the packet length */
*pktsize = tlvsize;
bool ok = true;
/* ready to load */
RsBanListItem *item = new RsBanListItem();
item->clear();
/* skip the header */
offset += 8;
/* add mandatory parts first */
ok &= item->peerList.GetTlv(data, tlvsize, &offset);
if (offset != tlvsize)
{
/* error */
delete item;
return NULL;
}
if (!ok)
{
delete item;
return NULL;
}
return item;
return true ;
}
/*************************************************************************/
uint32_t RsBanListSerialiser::size(RsItem *i)
void RsGxsReputationSetItem::clear()
{
RsBanListItem *dri;
if (NULL != (dri = dynamic_cast<RsBanListItem *>(i)))
{
return sizeList(dri);
}
return 0;
mOpinions.clear() ;
}
bool RsBanListSerialiser::serialise(RsItem *i, void *data, uint32_t *pktsize)
void RsGxsReputationUpdateItem::clear()
{
RsBanListItem *dri;
if (NULL != (dri = dynamic_cast<RsBanListItem *>(i)))
{
return serialiseList(dri, data, pktsize);
}
return false;
mOpinions.clear() ;
}
RsItem *RsBanListSerialiser::deserialise(void *data, uint32_t *pktsize)
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
std::ostream& RsGxsReputationConfigItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsReputationConfigItem", indent);
uint16_t int_Indent = indent + 2;
out << "mPeerId: " << mPeerId << std::endl;
out << "last update: " << time(NULL) - mLatestUpdate << " secs ago." << std::endl;
out << "last query : " << time(NULL) - mLastQuery << " secs ago." << std::endl;
printRsItemEnd(out, "RsReputationConfigItem", indent);
return out;
}
std::ostream& RsGxsReputationSetItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsReputationSetItem", indent);
uint16_t int_Indent = indent + 2;
out << "GxsId: " << mGxsId << std::endl;
out << "mOwnOpinion: " << mOwnOpinion << std::endl;
out << "mOwnOpinionTS : " << time(NULL) - mOwnOpinionTS << " secs ago." << std::endl;
out << "Opinions from neighbors: " << std::endl;
for(std::map<RsPeerId,uint32_t>::const_iterator it(mOpinions.begin());it!=mOpinions.end();++it)
out << " " << it->first << ": " << it->second << std::endl;
printRsItemEnd(out, "RsReputationSetItem", indent);
return out;
}
std::ostream& RsGxsReputationUpdateItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsReputationUpdateItem", indent);
uint16_t int_Indent = indent + 2;
out << "from: " << PeerId() << std::endl;
out << "last update: " << time(NULL) - mLatestUpdate << " secs ago." << std::endl;
for(std::map<RsGxsId,uint32_t>::const_iterator it(mOpinions.begin());it!=mOpinions.end();++it)
out << " " << it->first << ": " << it->second << std::endl;
printRsItemEnd(out, "RsReputationUpdateItem", indent);
return out;
}
std::ostream& RsGxsReputationRequestItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsReputationRequestItem", indent);
uint16_t int_Indent = indent + 2;
out << "last update: " << time(NULL) - mLastUpdate << " secs ago." << std::endl;
printRsItemEnd(out, "RsReputationRequestItem", indent);
return out;
}
/*************************************************************************/
uint32_t RsGxsReputationConfigItem::serial_size() const
{
uint32_t s = 8; /* header */
s += mPeerId.serial_size() ; // PeerId
s += 4 ; // mLatestUpdate
s += 4 ; // mLastQuery
return s ;
}
uint32_t RsGxsReputationSetItem::serial_size() const
{
uint32_t s = 8; /* header */
s += mGxsId.serial_size() ;
s += 4 ; // mOwnOpinion
s += 4 ; // mOwnOpinionTS
s += 4 ; // mOpinions.size()
s += (4+RsPeerId::serial_size()) * mOpinions.size() ;
return s ;
}
uint32_t RsGxsReputationUpdateItem::serial_size() const
{
uint32_t s = 8; /* header */
s += 4 ; // mLatestUpdate
s += 4 ; // mOpinions.size();
s += (RsGxsId::serial_size() + 4) * mOpinions.size() ;
return s ;
}
uint32_t RsGxsReputationRequestItem::serial_size() const
{
uint32_t s = 8; /* header */
s += 4 ; // mLastUpdate
return s;
}
/*************************************************************************/
bool RsGxsReputationConfigItem::serialise(void *data, uint32_t& pktsize) const
{
uint32_t tlvsize ;
uint32_t offset=0;
if(!serialise_header(data,pktsize,tlvsize,offset))
return false ;
bool ok = true;
ok &= mPeerId.serialise(data,tlvsize,offset) ;
ok &= setRawUInt32(data, tlvsize, &offset, mLatestUpdate);
ok &= setRawUInt32(data, tlvsize, &offset, mLastQuery);
if (offset != tlvsize)
{
ok = false;
std::cerr << "RsGxsReputationConfigItem::serialisedata() size error! " << std::endl;
}
return ok;
}
bool RsGxsReputationSetItem::serialise(void *data, uint32_t& pktsize) const
{
uint32_t tlvsize ;
uint32_t offset=0;
if(!serialise_header(data,pktsize,tlvsize,offset))
return false ;
bool ok = true;
ok &= mGxsId.serialise(data,tlvsize,offset) ;
ok &= setRawUInt32(data, tlvsize, &offset, mOwnOpinion);
ok &= setRawUInt32(data, tlvsize, &offset, mOwnOpinionTS);
ok &= setRawUInt32(data, tlvsize, &offset, mOpinions.size());
for(std::map<RsPeerId,uint32_t>::const_iterator it(mOpinions.begin());it!=mOpinions.end();++it)
{
ok &= it->first.serialise(data,tlvsize,offset) ;
ok &= setRawUInt32(data, tlvsize, &offset, it->second) ;
}
if (offset != tlvsize)
{
ok = false;
std::cerr << "RsGxsReputationSetItem::serialisedata() size error! " << std::endl;
}
return ok;
}
bool RsGxsReputationUpdateItem::serialise(void *data, uint32_t& pktsize) const
{
uint32_t tlvsize ;
uint32_t offset=0;
if(!serialise_header(data,pktsize,tlvsize,offset))
return false ;
bool ok = true;
ok &= setRawUInt32(data, tlvsize, &offset, mLatestUpdate);
ok &= setRawUInt32(data, tlvsize, &offset, mOpinions.size());
for(std::map<RsGxsId,uint32_t>::const_iterator it(mOpinions.begin());ok && it!=mOpinions.end();++it)
{
ok &= it->first.serialise(data, tlvsize, offset) ;
ok &= setRawUInt32(data, tlvsize, &offset, it->second) ;
}
if (offset != tlvsize)
{
ok = false;
std::cerr << "RsGxsReputationUpdateItem::serialisedata() size error! " << std::endl;
}
return ok;
}
/* serialise the data to the buffer */
bool RsGxsReputationRequestItem::serialise(void *data, uint32_t& pktsize) const
{
uint32_t tlvsize ;
uint32_t offset=0;
if(!serialise_header(data,pktsize,tlvsize,offset))
return false ;
bool ok = true;
ok &= setRawUInt32(data, tlvsize, &offset, mLastUpdate);
if (offset != tlvsize)
{
ok = false;
std::cerr << "RsGxsReputationRequestItem::serialisedata() size error! " << std::endl;
}
return ok;
}
/*************************************************************************/
RsGxsReputationConfigItem *RsGxsReputationSerialiser::deserialiseReputationConfigItem(void *data,uint32_t size)
{
uint32_t offset = 8; // skip the header
uint32_t rssize = getRsItemSize(data);
bool ok = true ;
RsGxsReputationConfigItem *item = new RsGxsReputationConfigItem() ;
/* add mandatory parts first */
ok &= item->mPeerId.deserialise(data, size, offset) ;
ok &= getRawUInt32(data, size, &offset, &item->mLatestUpdate);
ok &= getRawUInt32(data, size, &offset, &item->mLastQuery);
if (offset != rssize || !ok)
{
std::cerr << __PRETTY_FUNCTION__ << ": error while deserialising! Item will be dropped." << std::endl;
delete item;
return NULL ;
}
return item;
}
RsGxsReputationSetItem *RsGxsReputationSerialiser::deserialiseReputationSetItem(void *data,uint32_t tlvsize)
{
uint32_t offset = 8; // skip the header
uint32_t rssize = getRsItemSize(data);
bool ok = true ;
RsGxsReputationSetItem *item = new RsGxsReputationSetItem() ;
/* add mandatory parts first */
ok &= item->mGxsId.deserialise(data, tlvsize, offset) ;
ok &= getRawUInt32(data, tlvsize, &offset, &item->mOwnOpinion);
ok &= getRawUInt32(data, tlvsize, &offset, &item->mOwnOpinionTS);
uint32_t S ;
ok &= getRawUInt32(data, tlvsize, &offset, &S);
for(int i=0;ok && i<S;++i)
{
RsPeerId pid ;
uint32_t op ;
ok &= pid.deserialise(data, tlvsize, offset) ;
ok &= getRawUInt32(data, tlvsize, &offset, &op);
if(ok)
item->mOpinions[pid] = op ;
}
if (offset != rssize || !ok)
{
std::cerr << __PRETTY_FUNCTION__ << ": error while deserialising! Item will be dropped." << std::endl;
delete item;
return NULL ;
}
return item;
}
RsGxsReputationUpdateItem *RsGxsReputationSerialiser::deserialiseReputationUpdateItem(void *data,uint32_t tlvsize)
{
uint32_t offset = 8; // skip the header
uint32_t rssize = getRsItemSize(data);
bool ok = true ;
RsGxsReputationUpdateItem *item = new RsGxsReputationUpdateItem() ;
/* add mandatory parts first */
ok &= getRawUInt32(data, tlvsize, &offset, &item->mLatestUpdate);
uint32_t S ;
ok &= getRawUInt32(data, tlvsize, &offset, &S) ;
for(uint32_t i=0;ok && i<S;++i)
{
RsGxsId gid ;
uint32_t op ;
ok &= gid.deserialise(data, tlvsize, offset) ;
ok &= getRawUInt32(data, tlvsize, &offset, &op);
if(ok)
item->mOpinions[gid] = op ;
}
if (offset != rssize || !ok)
{
std::cerr << __PRETTY_FUNCTION__ << ": error while deserialising! Item will be dropped." << std::endl;
delete item;
return NULL ;
}
return item;
}
RsGxsReputationRequestItem *RsGxsReputationSerialiser::deserialiseReputationRequestItem(void *data,uint32_t tlvsize)
{
uint32_t offset = 8; // skip the header
uint32_t rssize = getRsItemSize(data);
bool ok = true ;
RsGxsReputationRequestItem *item = new RsGxsReputationRequestItem() ;
/* add mandatory parts first */
ok &= getRawUInt32(data, tlvsize, &offset, &item->mLastUpdate);
if (offset != rssize || !ok)
{
std::cerr << __PRETTY_FUNCTION__ << ": error while deserialising! Item will be dropped." << std::endl;
delete item;
return NULL ;
}
return item;
}
/*************************************************************************/
RsItem *RsGxsReputationSerialiser::deserialise(void *data, uint32_t *pktsize)
{
/* get the type and size */
uint32_t rstype = getRsItemId(data);
if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) ||
(RS_SERVICE_TYPE_BANLIST != getRsItemService(rstype)))
{
return NULL; /* wrong type */
}
if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (RS_SERVICE_GXS_TYPE_REPUTATION != getRsItemService(rstype)))
{
std::cerr << "RsReputationSerialiser::deserialise(): wrong item type " << std::hex << rstype << std::dec << std::endl;
return NULL; /* wrong type */
}
switch(getRsItemSubType(rstype))
{
case RS_PKT_SUBTYPE_BANLIST_ITEM:
return deserialiseList(data, pktsize);
break;
case RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM : return deserialiseReputationSetItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_UPDATE_ITEM : return deserialiseReputationUpdateItem (data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM: return deserialiseReputationRequestItem(data, *pktsize);
case RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM : return deserialiseReputationConfigItem (data, *pktsize);
default:
std::cerr << "RsGxsReputationSerialiser::deserialise(): unknown item subtype " << std::hex<< rstype << std::dec << std::endl;
return NULL;
break;
}
}
#endif
/*************************************************************************/

View File

@ -32,88 +32,94 @@
#include "serialiser/rsserial.h"
#include "retroshare/rsgxsifacetypes.h"
#define RS_PKT_SUBTYPE_GXSREPUTATION_CONFIG_ITEM 0x01
#define RS_PKT_SUBTYPE_GXSREPUTATION_SET_ITEM 0x02
#define RS_PKT_SUBTYPE_GXSREPUTATION_UPDATE_ITEM 0x03
#define RS_PKT_SUBTYPE_GXSREPUTATION_REQUEST_ITEM 0x04
#define RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM 0x01
#define RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM 0x02
#define RS_PKT_SUBTYPE_GXS_REPUTATION_UPDATE_ITEM 0x03
#define RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM 0x04
/**************************************************************************/
class RsGxsReputationConfigItem: public RsItem
class RsReputationItem: public RsItem
{
public:
RsGxsReputationConfigItem()
:RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_GXS_TYPE_REPUTATION,
RS_PKT_SUBTYPE_GXSREPUTATION_CONFIG_ITEM)
{
setPriorityLevel(QOS_PRIORITY_RS_GXSREPUTATION_ITEM);
return;
}
RsReputationItem(uint8_t reputation_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_GXS_TYPE_REPUTATION,reputation_subtype)
{
setPriorityLevel(QOS_PRIORITY_RS_GXSREPUTATION_ITEM);
}
virtual ~RsGxsReputationConfigItem();
virtual void clear();
std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual ~RsReputationItem() {}
std::string mPeerId;
virtual bool serialise(void *data,uint32_t& size) const = 0 ;
virtual uint32_t serial_size() const = 0 ;
virtual void clear() = 0 ;
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0) = 0;
protected:
bool serialise_header(void *data, uint32_t& pktsize, uint32_t& tlvsize, uint32_t& offset) const;
};
class RsGxsReputationConfigItem: public RsReputationItem
{
public:
RsGxsReputationConfigItem() :RsReputationItem(RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM) {}
virtual ~RsGxsReputationConfigItem() {}
virtual void clear() {}
std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual bool serialise(void *data,uint32_t& size) const ;
virtual uint32_t serial_size() const ;
RsPeerId mPeerId;
uint32_t mLatestUpdate; // timestamp they returned.
uint32_t mLastQuery; // when we sent out.
};
class RsGxsReputationSetItem: public RsItem
class RsGxsReputationSetItem: public RsReputationItem
{
public:
RsGxsReputationSetItem()
:RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_GXS_TYPE_REPUTATION,
RS_PKT_SUBTYPE_GXSREPUTATION_SET_ITEM)
{
setPriorityLevel(QOS_PRIORITY_RS_GXSREPUTATION_ITEM);
return;
}
public:
RsGxsReputationSetItem() :RsReputationItem(RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM) {}
virtual ~RsGxsReputationSetItem();
virtual void clear();
std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual ~RsGxsReputationSetItem() {}
virtual void clear();
std::ostream &print(std::ostream &out, uint16_t indent = 0);
std::string mGxsId;
virtual bool serialise(void *data,uint32_t& size) const ;
virtual uint32_t serial_size() const ;
RsGxsId mGxsId;
uint32_t mOwnOpinion;
uint32_t mOwnOpinionTs;
uint32_t mReputation;
std::map<std::string, uint32_t> mOpinions; // RsPeerId -> Opinion.
uint32_t mOwnOpinionTS;
std::map<RsPeerId, uint32_t> mOpinions; // RsPeerId -> Opinion.
};
class RsGxsReputationUpdateItem: public RsItem
class RsGxsReputationUpdateItem: public RsReputationItem
{
public:
RsGxsReputationUpdateItem()
:RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_GXS_TYPE_REPUTATION,
RS_PKT_SUBTYPE_GXSREPUTATION_UPDATE_ITEM)
{
setPriorityLevel(QOS_PRIORITY_RS_GXSREPUTATION_ITEM);
return;
}
public:
RsGxsReputationUpdateItem() :RsReputationItem(RS_PKT_SUBTYPE_GXS_REPUTATION_UPDATE_ITEM) {}
virtual ~RsGxsReputationUpdateItem();
virtual void clear();
std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual ~RsGxsReputationUpdateItem() {}
virtual void clear();
std::ostream &print(std::ostream &out, uint16_t indent = 0);
std::map<RsGxsId, uint32_t> mOpinions; // GxsId -> Opinion.
uint32_t mLatestUpdate;
virtual bool serialise(void *data,uint32_t& size) const ;
virtual uint32_t serial_size() const ;
uint32_t mLatestUpdate;
std::map<RsGxsId, uint32_t> mOpinions; // GxsId -> Opinion.
};
class RsGxsReputationRequestItem: public RsItem
class RsGxsReputationRequestItem: public RsReputationItem
{
public:
RsGxsReputationRequestItem()
:RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_GXS_TYPE_REPUTATION,
RS_PKT_SUBTYPE_GXSREPUTATION_REQUEST_ITEM)
{
setPriorityLevel(QOS_PRIORITY_RS_GXSREPUTATION_ITEM);
return;
}
public:
RsGxsReputationRequestItem() :RsReputationItem(RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM) {}
virtual ~RsGxsReputationRequestItem();
virtual void clear();
std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual ~RsGxsReputationRequestItem() {}
virtual void clear() {}
std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual bool serialise(void *data,uint32_t& size) const ;
virtual uint32_t serial_size() const ;
uint32_t mLastUpdate;
};
@ -121,39 +127,26 @@ std::ostream &print(std::ostream &out, uint16_t indent = 0);
class RsGxsReputationSerialiser: public RsSerialType
{
public:
RsGxsReputationSerialiser()
:RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_GXS_TYPE_REPUTATION)
{ return; }
virtual ~RsGxsReputationSerialiser()
{ return; }
public:
RsGxsReputationSerialiser() :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_GXS_TYPE_REPUTATION){}
virtual uint32_t size(RsItem *);
virtual bool serialise (RsItem *item, void *data, uint32_t *size);
virtual RsItem * deserialise(void *data, uint32_t *size);
private:
virtual uint32_t sizeConfig(RsGxsReputationConfigItem *);
virtual bool serialiseConfig(RsGxsReputationConfigItem *item, void *data, uint32_t *size);
virtual RsGxsReputationConfigItem *deserialiseConfig(void *data, uint32_t *size);
virtual uint32_t sizeSet(RsGxsReputationSetItem *);
virtual bool serialiseSet(RsGxsReputationSetItem *item, void *data, uint32_t *size);
virtual RsGxsReputationSetItem *deserialiseSet(void *data, uint32_t *size);
virtual uint32_t sizeUpdate(RsGxsReputationUpdateItem *);
virtual bool serialiseUpdate(RsGxsReputationUpdateItem *item, void *data, uint32_t *size);
virtual RsGxsReputationUpdateItem *deserialiseUpdate(void *data, uint32_t *size);
virtual uint32_t sizeRequest(RsGxsReputationRequestItem *);
virtual bool serialiseRequest(RsGxsReputationRequestItem *item, void *data, uint32_t *size);
virtual RsGxsReputationRequestItem *deserialiseRequest(void *data, uint32_t *size);
virtual ~RsGxsReputationSerialiser(){}
virtual uint32_t size(RsItem *item)
{
return dynamic_cast<RsReputationItem*>(item)->serial_size() ;
}
virtual bool serialise (RsItem *item, void *data, uint32_t *size)
{
return dynamic_cast<RsReputationItem*>(item)->serialise(data,*size) ;
}
virtual RsItem * deserialise(void *data, uint32_t *size);
private:
static RsGxsReputationConfigItem *deserialiseReputationConfigItem (void *data, uint32_t size);
static RsGxsReputationSetItem *deserialiseReputationSetItem (void *data, uint32_t size);
static RsGxsReputationUpdateItem *deserialiseReputationUpdateItem (void *data, uint32_t size);
static RsGxsReputationRequestItem *deserialiseReputationRequestItem(void *data, uint32_t size);
};
/**************************************************************************/

View File

@ -38,13 +38,6 @@
* #define DEBUG_REPUTATION 1
****/
/* DEFINE INTERFACE POINTER! */
//RsGxsReputation *rsGxsReputation = NULL;
const int kMaximumPeerAge = 180; // half a year.
const int kMaximumSetSize = 100;
/************ IMPLEMENTATION NOTES *********************************
*
* p3GxsReputation shares opinions / reputations with peers.
@ -61,8 +54,12 @@ const int kMaximumSetSize = 100;
* last update ----------->
* <----------- modified opinions.
*
* This service will have to store a huge amount of data.
* need to workout how to reduce it.
* If not clever enough, this service will have to store a huge amount of data.
* To make things tractable we do this:
* - do not store reputations when no data is present, or when all friends are neutral
* - only send a neutral opinion when they are a true change over someone's opinion
* - only send a neutral opinion when it is a true change over someone's opinion
* - auto-clean reputations for default values
*
* std::map<RsGxsId, Reputation> mReputations.
* std::multimap<time_t, RsGxsId> mUpdated.
@ -70,55 +67,72 @@ const int kMaximumSetSize = 100;
* std::map<RsPeerId, ReputationConfig> mConfig;
*
* Updates from p3GxsReputation -> p3IdService.
*
*
* Updates from p3IdService -> p3GxsReputation.
*
* Each peer locally stores reputations for all GXS ids. If not stored, a default value
* is used, corresponding to a neutral opinion. Peers also share their reputation level
* with their neighbor nodes.
*
* The calculation method is the following:
*
* Local values:
* Good: 2
* Neutral: 1
* Bad: 0
*
* Overall reputation score:
*
* if(own_opinion == 0) // means we dont' care
* r = average_of_friends_opinions
* else
* r = own_opinion
*
* Decisions based on reputation score:
*
* 0 x1 1 x2 2
* | <-----------------------------------------------------------------------> |
* ---------+
* Lobbies | Msgs dropped
* Forums | Msgs dropped
* Messages | Msgs dropped
* ---------+----------------------------------------------------------------------------
*
* We select x1=0.5
*
* => to kill an identity, either you, or at least 50% of your friends need to flag it
* as bad.
* Rules:
* * a single peer cannot drastically change the behavior of a given GXS id
* * it should be easy for many peers to globally kill a GXS id
*
* Typical examples:
*
* Friends | Friend average | Own | alpha | Score
* -----------+---------------------+----------+------------+--------------
* 10 | 0.5 | 1 | 0.25 | 0.375
* 10 | 1.0 | 1 | 0.25 | 1.0
* 10 | 1.0 | 0 | 0.25 | 1.0
*
* To check:
* [ ] Opinions are saved/loaded accross restart
* [ ] Opinions are transmitted to friends
* [ ] Opinions are transmitted to friends when updated
*
* To do:
* [ ] Add debug info
* [ ] Test the whole thing
* [X] Implement a system to allow not storing info when we don't have it
*/
const int32_t REPUTATION_OFFSET = 100000;
const int32_t LOWER_LIMIT = -100;
const int32_t UPPER_LIMIT = 100;
int32_t ConvertFromSerialised(uint32_t value, bool limit)
{
int32_t converted = ((int32_t) value) - REPUTATION_OFFSET ;
if (limit)
{
if (converted < LOWER_LIMIT)
{
converted = LOWER_LIMIT;
}
if (converted > UPPER_LIMIT)
{
converted = UPPER_LIMIT;
}
}
return converted;
}
uint32_t ConvertToSerialised(int32_t value, bool limit)
{
if (limit)
{
if (value < LOWER_LIMIT)
{
value = LOWER_LIMIT;
}
if (value > UPPER_LIMIT)
{
value = UPPER_LIMIT;
}
}
value += REPUTATION_OFFSET;
if (value < 0)
{
value = 0;
}
return (uint32_t) value;
}
static const uint32_t LOWER_LIMIT = 0; // used to filter valid Opinion values from serialized data
static const uint32_t UPPER_LIMIT = 2; // used to filter valid Opinion values from serialized data
static const float REPUTATION_ASSESSMENT_THRESHOLD_X1 = 0.5f ; // reputation under which the peer gets killed
static const int kMaximumPeerAge = 180; // half a year.
static const int kMaximumSetSize = 100; // max set of updates to send at once.
static const int ACTIVE_FRIENDS_UPDATE_PERIOD = 600 ; // 10 minutes
static const int ACTIVE_FRIENDS_ONLINE_DELAY = 86400*7 ; // 1 week.
static const int kReputationRequestPeriod = 600; // 10 mins
static const int kReputationStoreWait = 180; // 3 minutes.
@ -126,14 +140,15 @@ p3GxsReputation::p3GxsReputation(p3LinkMgr *lm)
:p3Service(), p3Config(),
mReputationMtx("p3GxsReputation"), mLinkMgr(lm)
{
addSerialType(new RsGxsReputationSerialiser());
addSerialType(new RsGxsReputationSerialiser());
mRequestTime = 0;
mStoreTime = 0;
mReputationsUpdated = false;
mRequestTime = 0;
mStoreTime = 0;
mReputationsUpdated = false;
mLastActiveFriendsUpdate = 0 ;
mAverageActiveFriends = 0 ;
}
const std::string GXS_REPUTATION_APP_NAME = "gxsreputation";
const uint16_t GXS_REPUTATION_APP_MAJOR_VERSION = 1;
const uint16_t GXS_REPUTATION_APP_MINOR_VERSION = 0;
@ -150,13 +165,30 @@ RsServiceInfo p3GxsReputation::getServiceInfo()
GXS_REPUTATION_MIN_MINOR_VERSION);
}
int p3GxsReputation::tick()
{
processIncoming();
sendPackets();
time_t now = time(NULL);
if(mLastActiveFriendsUpdate + ACTIVE_FRIENDS_UPDATE_PERIOD < now)
{
updateActiveFriends() ;
cleanup() ;
mLastActiveFriendsUpdate = now ;
}
#ifdef DEBUG_REPUTATION
static time_t last_debug_print = time(NULL) ;
if(now > 10+last_debug_print)
{
last_debug_print = now ;
debug_print() ;
}
#endif
return 0;
}
@ -165,7 +197,53 @@ int p3GxsReputation::status()
return 1;
}
void p3GxsReputation::cleanup()
{
// remove opinions from friends that havn't been seen online for more than the specified delay
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::cleanup() " << std::endl;
#endif
std::cerr << __PRETTY_FUNCTION__ << ": not implemented. TODO!" << std::endl;
}
void p3GxsReputation::updateActiveFriends()
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
// keep track of who is recently connected. That will give a value to average friend
// for this, we count all friends that have been online in the last week.
time_t now = time(NULL) ;
std::list<RsPeerId> idList ;
mLinkMgr->getFriendList(idList) ;
mAverageActiveFriends = 0 ;
#ifdef DEBUG_REPUTATION
std::cerr << " counting recently online peers." << std::endl;
#endif
for(std::list<RsPeerId>::const_iterator it(idList.begin());it!=idList.end();++it)
{
RsPeerDetails details ;
#ifdef DEBUG_REPUTATION
std::cerr << " " << *it << ": last seen " << now - details.lastConnect << " secs ago" << std::endl;
#endif
if(rsPeers->getPeerDetails(*it, details) && now < details.lastConnect + ACTIVE_FRIENDS_ONLINE_DELAY)
++mAverageActiveFriends ;
}
#ifdef DEBUG_REPUTATION
std::cerr << " new count: " << mAverageActiveFriends << std::endl;
#endif
}
static RsReputations::Opinion safe_convert_uint32t_to_opinion(uint32_t op)
{
return RsReputations::Opinion(std::min((uint32_t)op,UPPER_LIMIT)) ;
}
/***** Implementation ******/
bool p3GxsReputation::processIncoming()
@ -184,40 +262,31 @@ bool p3GxsReputation::processIncoming()
switch(item->PacketSubType())
{
default:
case RS_PKT_SUBTYPE_GXSREPUTATION_CONFIG_ITEM:
case RS_PKT_SUBTYPE_GXSREPUTATION_SET_ITEM:
case RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM:
case RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM:
std::cerr << "p3GxsReputation::processingIncoming() Unknown Item";
std::cerr << std::endl;
itemOk = false;
break;
case RS_PKT_SUBTYPE_GXSREPUTATION_REQUEST_ITEM:
case RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM:
{
RsGxsReputationRequestItem *requestItem =
dynamic_cast<RsGxsReputationRequestItem *>(item);
RsGxsReputationRequestItem *requestItem = dynamic_cast<RsGxsReputationRequestItem *>(item);
if (requestItem)
{
SendReputations(requestItem);
}
else
{
itemOk = false;
}
}
break;
case RS_PKT_SUBTYPE_GXSREPUTATION_UPDATE_ITEM:
case RS_PKT_SUBTYPE_GXS_REPUTATION_UPDATE_ITEM:
{
RsGxsReputationUpdateItem *updateItem =
dynamic_cast<RsGxsReputationUpdateItem *>(item);
RsGxsReputationUpdateItem *updateItem = dynamic_cast<RsGxsReputationUpdateItem *>(item);
if (updateItem)
{
RecvReputations(updateItem);
}
else
{
itemOk = false;
}
}
break;
}
@ -237,8 +306,9 @@ bool p3GxsReputation::processIncoming()
bool p3GxsReputation::SendReputations(RsGxsReputationRequestItem *request)
{
std::cerr << "p3GxsReputation::SendReputations()";
std::cerr << std::endl;
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::SendReputations()" << std::endl;
#endif
RsPeerId peerId = request->PeerId();
time_t last_update = request->mLastUpdate;
@ -252,12 +322,13 @@ bool p3GxsReputation::SendReputations(RsGxsReputationRequestItem *request)
int count = 0;
int totalcount = 0;
RsGxsReputationUpdateItem *pkt = new RsGxsReputationUpdateItem();
pkt->PeerId(peerId);
for(;tit != mUpdated.end(); ++tit)
{
/* find */
std::map<RsGxsId, Reputation>::iterator rit;
rit = mReputations.find(tit->second);
std::map<RsGxsId, Reputation>::iterator rit = mReputations.find(tit->second);
if (rit == mReputations.end())
{
std::cerr << "p3GxsReputation::SendReputations() ERROR Missing Reputation";
@ -275,8 +346,9 @@ bool p3GxsReputation::SendReputations(RsGxsReputationRequestItem *request)
}
RsGxsId gxsId = rit->first;
pkt->mOpinions[gxsId] = ConvertToSerialised(rit->second.mOwnOpinion, true);
pkt->mOpinions[gxsId] = rit->second.mOwnOpinion;
pkt->mLatestUpdate = rit->second.mOwnOpinionTs;
if (pkt->mLatestUpdate == (uint32_t) now)
{
// if we could possibly get another Update at this point (same second).
@ -289,10 +361,13 @@ bool p3GxsReputation::SendReputations(RsGxsReputationRequestItem *request)
if (count > kMaximumSetSize)
{
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::SendReputations() Sending Full Packet";
std::cerr << std::endl;
#endif
sendItem(pkt);
pkt = new RsGxsReputationUpdateItem();
pkt->PeerId(peerId);
count = 0;
@ -301,8 +376,10 @@ bool p3GxsReputation::SendReputations(RsGxsReputationRequestItem *request)
if (!pkt->mOpinions.empty())
{
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::SendReputations() Sending Final Packet";
std::cerr << std::endl;
#endif
sendItem(pkt);
}
@ -311,52 +388,125 @@ bool p3GxsReputation::SendReputations(RsGxsReputationRequestItem *request)
delete pkt;
}
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::SendReputations() Total Count: " << totalcount;
std::cerr << std::endl;
#endif
return true;
}
void p3GxsReputation::locked_updateOpinion(const RsPeerId& from,const RsGxsId& about,RsReputations::Opinion op)
{
/* find matching Reputation */
std::map<RsGxsId, Reputation>::iterator rit = mReputations.find(about);
RsReputations::Opinion new_opinion = safe_convert_uint32t_to_opinion(op);
RsReputations::Opinion old_opinion = RsReputations::OPINION_NEUTRAL ; // default if not set
bool updated = false ;
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::update opinion of " << about << " from " << from << " to " << op << std::endl;
#endif
// now 4 cases;
// Opinion already stored
// New opinion is same: nothing to do
// New opinion is different: if neutral, remove entry
// Nothing stored
// New opinion is neutral: nothing to do
// New opinion is != 1: create entry and store
if (rit == mReputations.end())
{
#ifdef DEBUG_REPUTATION
std::cerr << " no preview record"<< std::endl;
#endif
if(new_opinion != RsReputations::OPINION_NEUTRAL)
{
mReputations[about] = Reputation(about);
rit = mReputations.find(about);
}
else
{
#ifdef DEBUG_REPUTATION
std::cerr << " no changes!"<< std::endl;
#endif
return ; // nothing to do
}
}
Reputation& reputation = rit->second;
std::map<RsPeerId,RsReputations::Opinion>::iterator it2 = reputation.mOpinions.find(from) ;
if(it2 == reputation.mOpinions.end())
{
if(new_opinion != RsReputations::OPINION_NEUTRAL)
{
reputation.mOpinions[from] = new_opinion; // filters potentially tweaked reputation score sent by friend
updated = true ;
}
}
else
{
old_opinion = it2->second ;
if(new_opinion == RsReputations::OPINION_NEUTRAL)
{
reputation.mOpinions.erase(it2) ; // don't store when the opinion is neutral
updated = true ;
}
else if(new_opinion != old_opinion)
{
it2->second = new_opinion ;
updated = true ;
}
}
if(reputation.mOpinions.empty() && reputation.mOwnOpinion == RsReputations::OPINION_NEUTRAL)
{
mReputations.erase(rit) ;
#ifdef DEBUG_REPUTATION
std::cerr << " own is neutral and no opinions from friends => remove entry" << std::endl;
#endif
updated = true ;
}
else if(updated)
{
#ifdef DEBUG_REPUTATION
std::cerr << " reputation changed. re-calculating." << std::endl;
#endif
reputation.updateReputation(mAverageActiveFriends) ;
}
if(updated)
IndicateConfigChanged() ;
}
bool p3GxsReputation::RecvReputations(RsGxsReputationUpdateItem *item)
{
std::cerr << "p3GxsReputation::RecvReputations()";
std::cerr << std::endl;
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::RecvReputations() from " << item->PeerId() << std::endl;
#endif
RsPeerId peerid = item->PeerId();
std::map<RsGxsId, uint32_t>::iterator it;
for(it = item->mOpinions.begin(); it != item->mOpinions.end(); ++it)
for( std::map<RsGxsId, uint32_t>::iterator it = item->mOpinions.begin(); it != item->mOpinions.end(); ++it)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
/* find matching Reputation */
std::map<RsGxsId, Reputation>::iterator rit;
RsGxsId gxsId(it->first);
rit = mReputations.find(gxsId);
if (rit == mReputations.end())
{
mReputations[gxsId] = Reputation(gxsId);
rit = mReputations.find(gxsId);
}
Reputation &reputation = rit->second;
reputation.mOpinions[peerid] = ConvertFromSerialised(it->second, true);
int previous = reputation.mReputation;
if (previous != reputation.CalculateReputation())
{
// updated from the network.
mUpdatedReputations.insert(gxsId);
}
locked_updateOpinion(peerid,it->first,safe_convert_uint32t_to_opinion(it->second));
}
updateLatestUpdate(peerid, item->mLatestUpdate);
updateLatestUpdate(peerid,item->mLatestUpdate);
return true;
}
bool p3GxsReputation::updateLatestUpdate(RsPeerId peerid, time_t ts)
bool p3GxsReputation::updateLatestUpdate(RsPeerId peerid,time_t latest_update)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
@ -367,11 +517,12 @@ bool p3GxsReputation::updateLatestUpdate(RsPeerId peerid, time_t ts)
mConfig[peerid] = ReputationConfig(peerid);
it = mConfig.find(peerid) ;
}
it->second.mLatestUpdate = ts;
it->second.mLatestUpdate = latest_update ;
mReputationsUpdated = true;
// Switched to periodic save due to scale of data.
//IndicateConfigChanged();
IndicateConfigChanged();
return true;
}
@ -380,14 +531,75 @@ bool p3GxsReputation::updateLatestUpdate(RsPeerId peerid, time_t ts)
* Opinion
****/
bool p3GxsReputation::updateOpinion(const RsGxsId& gxsid, int opinion)
bool p3GxsReputation::getReputationInfo(const RsGxsId& gxsid, RsReputations::ReputationInfo& info)
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
#ifdef DEBUG_REPUTATION
std::cerr << "getReputationInfo() for " << gxsid << std::endl;
#endif
std::map<RsGxsId,Reputation>::const_iterator it = mReputations.find(gxsid);
if (it == mReputations.end())
{
info.mOwnOpinion = RsReputations::OPINION_NEUTRAL ;
info.mFriendAverage = RsReputations::OPINION_NEUTRAL ;
info.mOverallReputationScore = float(RsReputations::OPINION_NEUTRAL) ;
info.mAssessment = RsReputations::ASSESSMENT_OK ;
#ifdef DEBUG_REPUTATION
std::cerr << " no information present. Returning default. OwnOp = " << info.mOwnOpinion << ", overall score=" << info.mAssessment << std::endl;
#endif
}
else
{
info.mOwnOpinion = RsReputations::Opinion(it->second.mOwnOpinion) ;
info.mOverallReputationScore = it->second.mReputation ;
info.mFriendAverage = it->second.mFriendAverage ;
if(info.mOverallReputationScore > REPUTATION_ASSESSMENT_THRESHOLD_X1)
info.mAssessment = RsReputations::ASSESSMENT_OK ;
else
info.mAssessment = RsReputations::ASSESSMENT_BAD ;
#ifdef DEBUG_REPUTATION
std::cerr << " information present. OwnOp = " << info.mOwnOpinion << ", overall score=" << info.mAssessment << std::endl;
#endif
}
return true ;
}
bool p3GxsReputation::isIdentityBanned(const RsGxsId &id)
{
RsReputations::ReputationInfo info ;
getReputationInfo(id,info) ;
#ifdef DEBUG_REPUTATION
std::cerr << "isIdentityBanned(): returning " << (info.mAssessment == RsReputations::ASSESSMENT_BAD) << " for GXS id " << id << std::endl;
#endif
return info.mAssessment == RsReputations::ASSESSMENT_BAD ;
}
bool p3GxsReputation::setOwnOpinion(const RsGxsId& gxsid, const RsReputations::Opinion& opinion)
{
#ifdef DEBUG_REPUTATION
std::cerr << "setOwnOpinion(): for GXS id " << gxsid << " to " << opinion << std::endl;
#endif
if(gxsid.isNull())
{
std::cerr << " ID " << gxsid << " is rejected. Look for a bug in calling method." << std::endl;
return false ;
}
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
std::map<RsGxsId, Reputation>::iterator rit;
/* find matching Reputation */
rit = mReputations.find(gxsid);
if (rit == mReputations.end())
{
mReputations[gxsid] = Reputation(gxsid);
@ -420,14 +632,15 @@ bool p3GxsReputation::updateOpinion(const RsGxsId& gxsid, int opinion)
time_t now = time(NULL);
reputation.mOwnOpinion = opinion;
reputation.mOwnOpinionTs = now;
reputation.CalculateReputation();
reputation.updateReputation(mAverageActiveFriends);
mUpdated.insert(std::make_pair(now, gxsid));
mUpdatedReputations.insert(gxsid);
mReputationsUpdated = true;
// Switched to periodic save due to scale of data.
//IndicateConfigChanged();
IndicateConfigChanged();
return true;
}
@ -448,6 +661,9 @@ bool p3GxsReputation::saveList(bool& cleanup, std::list<RsItem*> &savelist)
cleanup = true;
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::saveList()" << std::endl;
#endif
/* save */
std::map<RsPeerId, ReputationConfig>::iterator it;
for(it = mConfig.begin(); it != mConfig.end(); ++it)
@ -459,7 +675,7 @@ bool p3GxsReputation::saveList(bool& cleanup, std::list<RsItem*> &savelist)
}
RsGxsReputationConfigItem *item = new RsGxsReputationConfigItem();
item->mPeerId = it->first.toStdString();
item->mPeerId = it->first;
item->mLatestUpdate = it->second.mLatestUpdate;
item->mLastQuery = it->second.mLastQuery;
savelist.push_back(item);
@ -470,16 +686,15 @@ bool p3GxsReputation::saveList(bool& cleanup, std::list<RsItem*> &savelist)
for(rit = mReputations.begin(); rit != mReputations.end(); ++rit, count++)
{
RsGxsReputationSetItem *item = new RsGxsReputationSetItem();
item->mGxsId = rit->first.toStdString();
item->mOwnOpinion = ConvertToSerialised(rit->second.mOwnOpinion, false);
item->mOwnOpinionTs = rit->second.mOwnOpinionTs;
item->mReputation = ConvertToSerialised(rit->second.mReputation, false);
item->mGxsId = rit->first;
item->mOwnOpinion = rit->second.mOwnOpinion;
item->mOwnOpinionTS = rit->second.mOwnOpinionTs;
std::map<RsPeerId, int32_t>::iterator oit;
std::map<RsPeerId, RsReputations::Opinion>::iterator oit;
for(oit = rit->second.mOpinions.begin(); oit != rit->second.mOpinions.end(); ++oit)
{
// should be already limited.
item->mOpinions[oit->first.toStdString()] = ConvertToSerialised(oit->second, false);
item->mOpinions[oit->first] = (uint32_t)oit->second;
}
savelist.push_back(item);
@ -495,6 +710,9 @@ void p3GxsReputation::saveDone()
bool p3GxsReputation::loadList(std::list<RsItem *>& loadList)
{
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::saveList()" << std::endl;
#endif
std::list<RsItem *>::iterator it;
std::set<RsPeerId> peerSet;
@ -515,9 +733,8 @@ bool p3GxsReputation::loadList(std::list<RsItem *>& loadList)
}
RsGxsReputationSetItem *set = dynamic_cast<RsGxsReputationSetItem *>(*it);
if (set)
{
loadReputationSet(set, peerSet);
}
delete (*it);
}
@ -530,6 +747,9 @@ bool p3GxsReputation::loadReputationSet(RsGxsReputationSetItem *item, const std:
std::map<RsGxsId, Reputation>::iterator rit;
if(item->mGxsId.isNull()) // just a protection against potential errors having put 00000 into ids.
return false ;
/* find matching Reputation */
RsGxsId gxsId(item->mGxsId);
rit = mReputations.find(gxsId);
@ -542,26 +762,24 @@ bool p3GxsReputation::loadReputationSet(RsGxsReputationSetItem *item, const std:
Reputation &reputation = mReputations[gxsId];
// install opinions.
std::map<std::string, uint32_t>::const_iterator oit;
std::map<RsPeerId, uint32_t>::const_iterator oit;
for(oit = item->mOpinions.begin(); oit != item->mOpinions.end(); ++oit)
{
// expensive ... but necessary.
RsPeerId peerId(oit->first);
if (peerSet.end() != peerSet.find(peerId))
{
reputation.mOpinions[peerId] = ConvertFromSerialised(oit->second, true);
}
reputation.mOpinions[peerId] = safe_convert_uint32t_to_opinion(oit->second);
}
reputation.mOwnOpinion = ConvertFromSerialised(item->mOwnOpinion, false);
reputation.mOwnOpinionTs = item->mOwnOpinionTs;
reputation.mOwnOpinion = item->mOwnOpinion;
reputation.mOwnOpinionTs = item->mOwnOpinionTS;
// if dropping entries has changed the score -> must update.
int previous = ConvertFromSerialised(item->mReputation, false);
if (previous != reputation.CalculateReputation())
{
mUpdatedReputations.insert(gxsId);
}
float old_reputation = reputation.mReputation ;
if(old_reputation != reputation.updateReputation(mAverageActiveFriends))
mUpdatedReputations.insert(gxsId) ;
mUpdated.insert(std::make_pair(reputation.mOwnOpinionTs, gxsId));
return true;
@ -572,9 +790,6 @@ bool p3GxsReputation::loadReputationSet(RsGxsReputationSetItem *item, const std:
* Send Requests.
****/
const int kReputationRequestPeriod = 3600;
const int kReputationStoreWait = 180; // 3 minutes.
int p3GxsReputation::sendPackets()
{
time_t now = time(NULL);
@ -585,7 +800,7 @@ int p3GxsReputation::sendPackets()
storeTime = mStoreTime;
}
if (now - requestTime > kReputationRequestPeriod)
if (now > requestTime + kReputationRequestPeriod)
{
sendReputationRequests();
@ -629,48 +844,41 @@ void p3GxsReputation::sendReputationRequests()
mLinkMgr->getOnlineList(idList);
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::sendReputationRequests()";
std::cerr << std::endl;
#endif
/* prepare packets */
std::list<RsPeerId>::iterator it;
for(it = idList.begin(); it != idList.end(); ++it)
{
#ifdef DEBUG_REPUTATION
std::cerr << "p3GxsReputation::sendReputationRequest() To: " << *it;
std::cerr << std::endl;
#endif
sendReputationRequest(*it);
}
}
int p3GxsReputation::sendReputationRequest(RsPeerId peerid)
{
std::cerr << "p3GxsReputation::sendReputationRequest(" << peerid << ")";
std::cerr << std::endl;
#ifdef DEBUG_REPUTATION
std::cerr << " p3GxsReputation::sendReputationRequest(" << peerid << ") " ;
#endif
time_t now = time(NULL) ;
/* */
RsGxsReputationRequestItem *requestItem =
new RsGxsReputationRequestItem();
RsGxsReputationRequestItem *requestItem = new RsGxsReputationRequestItem();
requestItem->PeerId(peerid);
{
RsStackMutex stack(mReputationMtx); /****** LOCKED MUTEX *******/
/* find the last timestamp we have */
std::map<RsPeerId, ReputationConfig>::iterator it;
it = mConfig.find(peerid);
std::map<RsPeerId, ReputationConfig>::iterator it = mConfig.find(peerid);
if (it != mConfig.end())
{
#ifdef DEBUG_REPUTATION
std::cerr << " lastUpdate = " << now - it->second.mLatestUpdate << " secs ago. Requesting only more recent." << std::endl;
#endif
requestItem->mLastUpdate = it->second.mLatestUpdate;
}
else
{
#ifdef DEBUG_REPUTATION
std::cerr << " lastUpdate = never. Requesting all!" << std::endl;
#endif
// get whole list.
requestItem->mLastUpdate = 0;
}
@ -680,4 +888,44 @@ int p3GxsReputation::sendReputationRequest(RsPeerId peerid)
return 1;
}
float Reputation::updateReputation(uint32_t average_active_friends)
{
// the calculation of reputation makes the whole thing
int friend_total = 0;
// accounts for all friends. Neutral opinions count for 1-1=0
for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it(mOpinions.begin());it!=mOpinions.end();++it)
friend_total += it->second - 1;
if(mOpinions.empty()) // includes the case of no friends!
mFriendAverage = 1.0f ;
else
mFriendAverage = 1.0+friend_total / float(std::max(average_active_friends,(uint32_t)mOpinions.size()));
if(mOwnOpinion == RsReputations::OPINION_NEUTRAL)
mReputation = mFriendAverage ;
else
mReputation = (float)mOwnOpinion ;
return float(mOwnOpinion) ;
}
void p3GxsReputation::debug_print()
{
std::cerr << "Reputations database: " << std::endl;
std::cerr << " Average number of peers: " << mAverageActiveFriends << std::endl;
time_t now = time(NULL) ;
for(std::map<RsGxsId,Reputation>::const_iterator it(mReputations.begin());it!=mReputations.end();++it)
{
std::cerr << " ID=" << it->first << ", own: " << it->second.mOwnOpinion << ", Friend average: " << it->second.mFriendAverage << ", global_score: " << it->second.mReputation
<< ", last own update: " << now - it->second.mOwnOpinionTs << " secs ago." << std::endl;
for(std::map<RsPeerId,RsReputations::Opinion>::const_iterator it2(it->second.mOpinions.begin());it2!=it->second.mOpinions.end();++it2)
std::cerr << " " << it2->first << ": " << it2->second << std::endl;
}
}

View File

@ -35,6 +35,7 @@
#include "serialiser/rsgxsreputationitems.h"
#include "retroshare/rsidentity.h"
#include "retroshare/rsreputations.h"
#include "services/p3service.h"
@ -58,19 +59,19 @@ class Reputation
{
public:
Reputation()
:mOwnOpinion(0), mOwnOpinionTs(0), mReputation(0) { return; }
:mOwnOpinion(RsReputations::OPINION_NEUTRAL), mOwnOpinionTs(0), mReputation(RsReputations::OPINION_NEUTRAL) { }
Reputation(const RsGxsId& about)
:mGxsId(about), mOwnOpinion(0), mOwnOpinionTs(0), mReputation(0) { return; }
:mOwnOpinion(RsReputations::OPINION_NEUTRAL), mOwnOpinionTs(0), mReputation(RsReputations::OPINION_NEUTRAL) { }
int32_t CalculateReputation();
float updateReputation(uint32_t average_active_friends);
RsGxsId mGxsId;
std::map<RsPeerId, int32_t> mOpinions;
std::map<RsPeerId, RsReputations::Opinion> mOpinions;
int32_t mOwnOpinion;
time_t mOwnOpinionTs;
int32_t mReputation;
float mFriendAverage ;
float mReputation;
};
@ -80,37 +81,25 @@ int32_t CalculateReputation();
*
*/
class p3GxsReputation: public p3Service, public p3Config /* , public pqiMonitor */
class p3GxsReputation: public p3Service, public p3Config, public RsReputations /* , public pqiMonitor */
{
public:
p3GxsReputation(p3LinkMgr *lm);
virtual RsServiceInfo getServiceInfo();
/***** Interface for p3idservice *****/
virtual bool updateOpinion(const RsGxsId& gxsid, int opinion);
/***** Interface for RsReputations *****/
virtual bool setOwnOpinion(const RsGxsId& key_id, const Opinion& op) ;
virtual bool getReputationInfo(const RsGxsId& id,ReputationInfo& info) ;
virtual bool isIdentityBanned(const RsGxsId& id) ;
/***** overloaded from p3Service *****/
/*!
* This retrieves all chat msg items and also (important!)
* processes chat-status items that are in service item queue. chat msg item requests are also processed and not returned
* (important! also) notifications sent to notify base on receipt avatar, immediate status and custom status
* : notifyCustomState, notifyChatStatus, notifyPeerHasNewAvatar
* @see NotifyBase
*/
virtual int tick();
virtual int status();
/*!
* Interface stuff.
*/
/*************** pqiMonitor callback ***********************/
//virtual void statusChange(const std::list<pqipeer> &plist);
/************* from p3Config *******************/
virtual RsSerialiser *setupSerialiser() ;
virtual bool saveList(bool& cleanup, std::list<RsItem*>&) ;
@ -123,22 +112,27 @@ class p3GxsReputation: public p3Service, public p3Config /* , public pqiMonitor
bool SendReputations(RsGxsReputationRequestItem *request);
bool RecvReputations(RsGxsReputationUpdateItem *item);
bool updateLatestUpdate(RsPeerId peerid, time_t ts);
bool updateLatestUpdate(RsPeerId peerid, time_t latest_update);
void updateActiveFriends() ;
bool loadReputationSet(RsGxsReputationSetItem *item,
const std::set<RsPeerId> &peerSet);
// internal update of data. Takes care of cleaning empty boxes.
void locked_updateOpinion(const RsPeerId &from, const RsGxsId &about, RsReputations::Opinion op);
bool loadReputationSet(RsGxsReputationSetItem *item, const std::set<RsPeerId> &peerSet);
int sendPackets();
int sendPackets();
void cleanup();
void sendReputationRequests();
int sendReputationRequest(RsPeerId peerid);
int sendReputationRequest(RsPeerId peerid);
void debug_print() ;
private:
RsMutex mReputationMtx;
time_t mLastActiveFriendsUpdate;
time_t mRequestTime;
time_t mStoreTime;
bool mReputationsUpdated;
uint32_t mAverageActiveFriends ;
p3LinkMgr *mLinkMgr;
@ -148,7 +142,7 @@ class p3GxsReputation: public p3Service, public p3Config /* , public pqiMonitor
std::multimap<time_t, RsGxsId> mUpdated;
// set of Reputations to send to p3IdService.
std::set<RsGxsId> mUpdatedReputations;
std::set<RsGxsId> mUpdatedReputations;
};
#endif //SERVICE_RSGXSREPUTATION_HEADER

View File

@ -413,6 +413,8 @@ bool p3IdService:: getIdDetails(const RsGxsId &id, RsIdentityDetails &details)
if(details.mNickname.length() > RSID_MAXIMUM_NICKNAME_SIZE*4)
details.mNickname = "[too long a name]" ;
rsReputations->getReputationInfo(id,details.mReputation) ;
return true;
}
@ -421,6 +423,9 @@ bool p3IdService:: getIdDetails(const RsGxsId &id, RsIdentityDetails &details)
{
details = data.details;
details.mLastUsageTS = locked_getLastUsageTS(id) ;
rsReputations->getReputationInfo(id,details.mReputation) ;
return true;
}
}
@ -831,7 +836,7 @@ bool p3IdService::getReputation(const RsGxsId &id, GixsReputation &rep)
if (mPublicKeyCache.fetch(id, data))
{
rep.id = id;
rep.score = data.details.mReputation.mOverallScore;
rep.score = 0;//data.details.mReputation.mOverallScore;
#ifdef DEBUG_IDS
std::cerr << "p3IdService::getReputation() id: ";
std::cerr << id.toStdString() << " score: " <<
@ -1669,14 +1674,14 @@ void RsGxsIdCache::updateServiceString(std::string serviceString)
}
// copy over Reputation scores.
details.mReputation = ssdata.score.rep;
//details.mReputation = ssdata.score.rep;
}
else
{
details.mPgpKnown = false;
details.mPgpId.clear();
details.mReputation.updateIdScore(false, false);
details.mReputation.update();
//details.mReputation.updateIdScore(false, false);
//details.mReputation.update();
}
}

View File

@ -34,6 +34,7 @@
#include "gui/msgs/MessageComposer.h"
#include <retroshare/rspeers.h>
#include <retroshare/rsreputations.h>
#include "retroshare/rsgxsflags.h"
#include "retroshare/rsmsgs.h"
#include <iostream>
@ -91,19 +92,10 @@ IdDialog::IdDialog(QWidget *parent) :
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_GpgId);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_GpgName);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_Type);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_LastUsed);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->toolButton_Reputation);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->line_RatingOverall);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->line_RatingImplicit);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->line_RatingOwn);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->line_RatingPeers);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->repModButton);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->repMod_Accept);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->repMod_Ban);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->repMod_Negative);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->repMod_Positive);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->repMod_Custom);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->repMod_spinBox);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_LastUsed);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->ownOpinion_CB);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->overallOpinion_TF);
mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->neighborNodesOpinion_TF);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->lineEdit_Nickname);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->lineEdit_GpgName);
@ -112,23 +104,16 @@ IdDialog::IdDialog(QWidget *parent) :
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->lineEdit_GpgId);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->lineEdit_Type);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->lineEdit_GpgName);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->lineEdit_LastUsed);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->line_RatingOverall);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->line_RatingImplicit);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->line_RatingOwn);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->line_RatingPeers);
mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->lineEdit_LastUsed);
//mStateHelper->addLoadPlaceholder(IDDIALOG_IDDETAILS, ui->line_RatingOverall);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_Nickname);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_KeyId);
// mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_GpgHash);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_GpgId);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_Type);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_GpgName);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_LastUsed);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->line_RatingOverall);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->line_RatingImplicit);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->line_RatingOwn);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->line_RatingPeers);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_GpgName);
mStateHelper->addClear(IDDIALOG_IDDETAILS, ui->lineEdit_LastUsed);
//mStateHelper->addWidget(IDDIALOG_REPLIST, ui->treeWidget_RepList);
//mStateHelper->addLoadPlaceholder(IDDIALOG_REPLIST, ui->treeWidget_RepList);
@ -147,7 +132,7 @@ IdDialog::IdDialog(QWidget *parent) :
connect(ui->filterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterComboBoxChanged()));
connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
connect(ui->repModButton, SIGNAL(clicked()), this, SLOT(modifyReputation()));
connect(ui->ownOpinion_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(modifyReputation()));
connect(ui->messageButton, SIGNAL(clicked()), this, SLOT(sendMsg()));
@ -197,7 +182,7 @@ IdDialog::IdDialog(QWidget *parent) :
// Hiding RepList until that part is finished.
//ui->treeWidget_RepList->setVisible(false);
ui->toolButton_Reputation->setVisible(false);
#ifndef UNFINISHED
ui->todoPushButton->hide() ;
#endif
@ -225,8 +210,8 @@ IdDialog::IdDialog(QWidget *parent) :
processSettings(true);
// hide reputation sice it's currently unused
ui->reputationGroupBox->hide();
ui->tweakGroupBox->hide();
//ui->reputationGroupBox->hide();
//ui->tweakGroupBox->hide();
}
IdDialog::~IdDialog()
@ -652,36 +637,9 @@ void IdDialog::insertIdDetails(uint32_t token)
else
ui->lineEdit_Type->setText(tr("Anonymous identity")) ;
// if (isOwnId)
// {
// ui->radioButton_IdYourself->setChecked(true);
// }
// else if (data.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID)
// {
// if (data.mPgpKnown)
// {
// if (rsPeers->isGPGAccepted(data.mPgpId))
// {
// ui->radioButton_IdFriend->setChecked(true);
// }
// else
// {
// ui->radioButton_IdFOF->setChecked(true);
// }
// }
// else
// {
// ui->radioButton_IdOther->setChecked(true);
// }
// }
// else
// {
// ui->radioButton_IdPseudo->setChecked(true);
// }
if (isOwnId)
{
mStateHelper->setWidgetEnabled(ui->toolButton_Reputation, false);
mStateHelper->setWidgetEnabled(ui->ownOpinion_CB, false);
ui->editIdentity->setEnabled(true);
ui->removeIdentity->setEnabled(true);
ui->chatIdentity->setEnabled(false);
@ -690,7 +648,7 @@ void IdDialog::insertIdDetails(uint32_t token)
else
{
// No Reputation yet!
mStateHelper->setWidgetEnabled(ui->toolButton_Reputation, /*true*/ false);
mStateHelper->setWidgetEnabled(ui->ownOpinion_CB, true);
ui->editIdentity->setEnabled(false);
ui->removeIdentity->setEnabled(false);
ui->chatIdentity->setEnabled(true);
@ -698,9 +656,8 @@ void IdDialog::insertIdDetails(uint32_t token)
}
/* now fill in the reputation information */
ui->line_RatingOverall->setText("Overall Rating TODO");
ui->line_RatingOwn->setText("Own Rating TODO");
#ifdef SUSPENDED
if (data.mPgpKnown)
{
ui->line_RatingImplicit->setText(tr("+50 Known PGP"));
@ -713,25 +670,28 @@ void IdDialog::insertIdDetails(uint32_t token)
{
ui->line_RatingImplicit->setText(tr("+5 Anon Id"));
}
{
QString rating = QString::number(data.mReputation.mOverallScore);
ui->line_RatingOverall->setText(rating);
}
{
QString rating = QString::number(data.mReputation.mIdScore);
ui->line_RatingImplicit->setText(rating);
}
{
QString rating = QString::number(data.mReputation.mOwnOpinion);
ui->line_RatingOwn->setText(rating);
}
#endif
RsReputations::ReputationInfo info ;
rsReputations->getReputationInfo(RsGxsId(data.mMeta.mGroupId),info) ;
ui->neighborNodesOpinion_TF->setText(QString::number(info.mOverallReputationScore-1.0f));
ui->overallOpinion_TF->setText(QString::number(info.mOverallReputationScore-1.0f) +" ("+
((info.mAssessment == RsReputations::ASSESSMENT_OK)? tr("OK") : tr("Banned")) +")" ) ;
switch(info.mOwnOpinion)
{
QString rating = QString::number(data.mReputation.mPeerOpinion);
ui->line_RatingPeers->setText(rating);
case RsReputations::OPINION_NEGATIVE: ui->ownOpinion_CB->setCurrentIndex(0); break ;
case RsReputations::OPINION_NEUTRAL : ui->ownOpinion_CB->setCurrentIndex(1); break ;
case RsReputations::OPINION_POSITIVE: ui->ownOpinion_CB->setCurrentIndex(2); break ;
default:
std::cerr << "Unexpected value in own opinion: " << info.mOwnOpinion << std::endl;
}
}
@ -744,46 +704,37 @@ void IdDialog::modifyReputation()
RsGxsId id(ui->lineEdit_KeyId->text().toStdString());
int mod = 0;
if (ui->repMod_Accept->isChecked())
{
mod += 100;
}
else if (ui->repMod_Positive->isChecked())
{
mod += 10;
}
else if (ui->repMod_Negative->isChecked())
{
mod += -10;
}
else if (ui->repMod_Ban->isChecked())
{
mod += -100;
}
else if (ui->repMod_Custom->isChecked())
{
mod += ui->repMod_spinBox->value();
}
else
{
// invalid
return;
}
RsReputations::Opinion op ;
switch(ui->ownOpinion_CB->currentIndex())
{
case 0: op = RsReputations::OPINION_NEGATIVE ; break ;
case 1: op = RsReputations::OPINION_NEUTRAL ; break ;
case 2: op = RsReputations::OPINION_POSITIVE ; break ;
default:
std::cerr << "Wrong value from opinion combobox. Bug??" << std::endl;
}
rsReputations->setOwnOpinion(id,op) ;
#ifdef ID_DEBUG
std::cerr << "IdDialog::modifyReputation() ID: " << id << " Mod: " << mod;
std::cerr << std::endl;
#endif
#ifdef SUSPENDED
// Cyril: apparently the old reputation system was in used here. It's based on GXS data exchange, and probably not
// very efficient because of this.
uint32_t token;
if (!rsIdentity->submitOpinion(token, id, false, mod))
if (!rsIdentity->submitOpinion(token, id, false, op))
{
#ifdef ID_DEBUG
std::cerr << "IdDialog::modifyReputation() Error submitting Opinion";
std::cerr << std::endl;
#endif
}
#endif
#ifdef ID_DEBUG
std::cerr << "IdDialog::modifyReputation() queuingRequest(), token: " << token;
@ -792,7 +743,7 @@ void IdDialog::modifyReputation()
// trigger refresh when finished.
// basic / anstype are not needed.
mIdQueue->queueRequest(token, 0, 0, IDDIALOG_REFRESH);
requestIdDetails();
return;
}

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>826</width>
<height>752</height>
<height>757</height>
</rect>
</property>
<property name="sizePolicy">
@ -483,7 +483,90 @@
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<item row="2" column="1">
<widget class="QLineEdit" name="neighborNodesOpinion_TF">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Average opinion of neighbor nodes about this identity. Negative is bad,&lt;/p&gt;&lt;p&gt;positive is good. Zero is neutral.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Your opinion:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Neighbor nodes:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="ownOpinion_CB">
<property name="toolTip">
<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:'Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Your own opinion about an identity rules the visibility of that identity for yourself,&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;and is shared among friends. A final score is calculated according to a formula that accounts your own opinion and your friends' opinions about someone:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; S = own_opinion * a + friends_opinion * (1-a)&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The factor 'a' depends on the type of ID. &lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;- anonymous IDs: &lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;- PGP-signed IDs by unknown PGP keys: a=&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The overall score is used in chat lobbies, forums and channels to decide on the actions to take for each specific identity:&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;S &amp;lt; -0.5: Posts are not stored, nor forwarded &lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;S &amp;lt; 0.2: Posts are hidden, but still transmitted&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;S &amp;lt; 0.0: &lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The overall rating is computed in such a way that it is not possible for a single person to deterministically change someone's status at neighbor nodes.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Negative</string>
</property>
<property name="icon">
<iconset>
<normaloff>../icons/yellow_biohazard64.png</normaloff>../icons/yellow_biohazard64.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>Neutral</string>
</property>
</item>
<item>
<property name="text">
<string>Positive</string>
</property>
</item>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="overallOpinion_TF">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Overall reputation score, accounting for yours and your friends'.&lt;/p&gt;&lt;p&gt;Negative is bad, positive is good. Zero is neutral. If the score is too low,&lt;/p&gt;&lt;p&gt;the identity is flagged as bad, and will be filtered out in forums, chat lobbies,&lt;/p&gt;&lt;p&gt;channels, etc.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="font">
<font>
@ -492,158 +575,12 @@
</font>
</property>
<property name="text">
<string>Overall</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="line_RatingOverall">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Implicit</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="line_RatingImplicit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Opinion</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="line_RatingOwn">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Peers</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="line_RatingPeers">
<property name="readOnly">
<bool>true</bool>
<string>Overall:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QToolButton" name="toolButton_Reputation">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Edit reputation</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/edit_24.png</normaloff>:/images/edit_24.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="tweakGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Tweak Opinion</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="repMod_Accept">
<property name="text">
<string>Accept (+100)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="repMod_Positive">
<property name="text">
<string>Positive (+10)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="repMod_Negative">
<property name="text">
<string>Negative (-10)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="repMod_Ban">
<property name="text">
<string>Ban (-100)</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="repMod_Custom">
<property name="text">
<string>Custom</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="repMod_spinBox">
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="repModButton">
<property name="text">
<string>Modify</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -730,9 +667,6 @@
<tabstop>lineEdit_KeyId</tabstop>
<tabstop>lineEdit_GpgId</tabstop>
<tabstop>lineEdit_GpgName</tabstop>
<tabstop>line_RatingOverall</tabstop>
<tabstop>line_RatingImplicit</tabstop>
<tabstop>line_RatingOwn</tabstop>
</tabstops>
<resources>
<include location="../images.qrc"/>

View File

@ -42,6 +42,8 @@
#define TYPE_UNKNOWN_ID 3
#define TYPE_CREATE_ID 4
#define BANNED_ICON ":/icons/yellow_biohazard64.png"
#define IDCHOOSER_REFRESH 1
//#define IDCHOOSER_DEBUG
@ -148,6 +150,10 @@ static void loadPrivateIdsCallback(GxsIdDetailsType type, const RsIdentityDetail
case GXS_ID_DETAILS_TYPE_DONE:
GxsIdDetails::getIcons(details, icons);
break;
case GXS_ID_DETAILS_TYPE_BANNED:
icons.push_back(QIcon(BANNED_ICON)) ;
break;
}
chooser->setItemData(index, QString("%1_%2").arg((type == GXS_ID_DETAILS_TYPE_DONE) ? TYPE_FOUND_ID : TYPE_UNKNOWN_ID).arg(text), ROLE_SORT);

View File

@ -29,6 +29,7 @@
#include <math.h>
#include "GxsIdDetails.h"
#include "retroshare-gui/RsAutoUpdatePage.h"
#include "retroshare/rsreputations.h"
#include <retroshare/rspeers.h>
@ -40,6 +41,7 @@
#define IMAGE_PGPKNOWN ":/images/contact.png"
#define IMAGE_PGPUNKNOWN ":/images/tags/pgp-unknown.png"
#define IMAGE_ANON ":/images/tags/anon.png"
#define IMAGE_BANNED ":/icons/yellow_biohazard64.png"
#define IMAGE_DEV_AMBASSADOR ":/images/tags/dev-ambassador.png"
#define IMAGE_DEV_CONTRIBUTOR ":/images/tags/vote_down.png"
@ -821,6 +823,9 @@ QString GxsIdDetails::getNameForType(GxsIdDetailsType type, const RsIdentityDeta
case GXS_ID_DETAILS_TYPE_DONE:
return getName(details);
case GXS_ID_DETAILS_TYPE_BANNED:
return tr("[Banned]") ;
case GXS_ID_DETAILS_TYPE_FAILED:
return getFailedText(details.mId);
}
@ -873,7 +878,10 @@ bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QLi
QString GxsIdDetails::getName(const RsIdentityDetails &details)
{
QString name = QString::fromUtf8(details.mNickname.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE);
if(rsReputations->isIdentityBanned(details.mId))
return tr("[Banned]") ;
QString name = QString::fromUtf8(details.mNickname.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE);
std::list<RsRecognTag>::const_iterator it;
for (it = details.mRecognTags.begin(); it != details.mRecognTags.end(); ++it)
@ -887,8 +895,17 @@ QString GxsIdDetails::getName(const RsIdentityDetails &details)
QString GxsIdDetails::getComment(const RsIdentityDetails &details)
{
QString comment;
QString nickname ;
bool banned = rsReputations->isIdentityBanned(details.mId) ;
if(details.mNickname.empty())
nickname = tr("[Unknown]") ;
else if(banned)
nickname = tr("[Banned]") ;
else
nickname = QString::fromUtf8(details.mNickname.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE) ;
QString nickname = details.mNickname.empty()?tr("[Unknown]"):QString::fromUtf8(details.mNickname.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE) ;
comment = QString("%1:%2<br/>%3:%4").arg(QApplication::translate("GxsIdDetails", "Identity&nbsp;name"),
nickname,
@ -903,7 +920,8 @@ QString nickname = details.mNickname.empty()?tr("[Unknown]"):QString::fromUtf8(d
{
/* look up real name */
std::string authorName = rsPeers->getGPGName(details.mPgpId);
comment += QString("%1&nbsp;[%2]").arg(QString::fromUtf8(authorName.c_str()), QString::fromStdString(details.mPgpId.toStdString()));
comment += QString("%1&nbsp;[%2]").arg(QString::fromUtf8(authorName.c_str()), QString::fromStdString(details.mPgpId.toStdString()));
}
else
comment += QApplication::translate("GxsIdDetails", "unknown Key");
@ -918,6 +936,13 @@ void GxsIdDetails::getIcons(const RsIdentityDetails &details, QList<QIcon> &icon
{
QPixmap pix ;
if(rsReputations->isIdentityBanned(details.mId))
{
icons.clear() ;
icons.push_back(QIcon(IMAGE_BANNED)) ;
return ;
}
if(icon_types & ICON_TYPE_AVATAR)
{
if(details.mAvatar.mSize == 0 || !pix.loadFromData(details.mAvatar.mData, details.mAvatar.mSize, "PNG"))

View File

@ -39,7 +39,8 @@ enum GxsIdDetailsType
GXS_ID_DETAILS_TYPE_EMPTY,
GXS_ID_DETAILS_TYPE_LOADING,
GXS_ID_DETAILS_TYPE_DONE,
GXS_ID_DETAILS_TYPE_FAILED
GXS_ID_DETAILS_TYPE_FAILED,
GXS_ID_DETAILS_TYPE_BANNED
};
typedef void (*GxsIdDetailsCallbackFunction)(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &data);
@ -49,10 +50,11 @@ class GxsIdDetails : public QObject
Q_OBJECT
public:
static const int ICON_TYPE_AVATAR = 0x0001 ;
static const int ICON_TYPE_PGP = 0x0002 ;
static const int ICON_TYPE_RECOGN = 0x0004 ;
static const int ICON_TYPE_ALL = 0x0007 ;
static const int ICON_TYPE_AVATAR = 0x0001 ;
static const int ICON_TYPE_PGP = 0x0002 ;
static const int ICON_TYPE_RECOGN = 0x0004 ;
static const int ICON_TYPE_ALL = 0x0007 ;
static const int ICON_TYPE_REDACTED= 0x0008 ;
GxsIdDetails();
virtual ~GxsIdDetails();

View File

@ -25,6 +25,9 @@
#include "GxsIdTreeWidgetItem.h"
#include "GxsIdDetails.h"
#include "util/HandleRichText.h"
#include "retroshare/rsreputations.h"
#define BANNED_IMAGE ":/icons/yellow_biohazard64.png"
/** Constructor */
GxsIdRSTreeWidgetItem::GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask,QTreeWidget *parent)
@ -71,6 +74,10 @@ static void fillGxsIdRSTreeWidgetItemCallback(GxsIdDetailsType type, const RsIde
GxsIdDetails::getIcons(details, icons, item->iconTypeMask());
item->processResult(true);
break;
case GXS_ID_DETAILS_TYPE_BANNED:
icons.push_back(QIcon("BANNED_IMAGE")) ;
break ;
}
int column = item->idColumn();
@ -139,28 +146,30 @@ void GxsIdRSTreeWidgetItem::setAvatar(const RsGxsImage &avatar)
QVariant GxsIdRSTreeWidgetItem::data(int column, int role) const
{
if (column == idColumn()) {
switch (role) {
case Qt::ToolTipRole:
{
QString t = RSTreeWidgetItem::data(column, role).toString();
if (column == idColumn())
{
if (role == Qt::ToolTipRole)
{
QString t = RSTreeWidgetItem::data(column, role).toString();
QImage pix;
QImage pix;
if (mAvatar.mSize == 0 || !pix.loadFromData(mAvatar.mData, mAvatar.mSize, "PNG")) {
pix = GxsIdDetails::makeDefaultIcon(mId);
}
if(mId.isNull())
return RSTreeWidgetItem::data(column, role);
else if(rsReputations->isIdentityBanned(mId))
pix = QImage(BANNED_IMAGE) ;
else if (mAvatar.mSize == 0 || !pix.loadFromData(mAvatar.mData, mAvatar.mSize, "PNG"))
pix = GxsIdDetails::makeDefaultIcon(mId);
int S = QFontMetricsF(font(column)).height();
int S = QFontMetricsF(font(column)).height();
QString embeddedImage;
if (RsHtml::makeEmbeddedImage(pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation), embeddedImage, 8*S * 8*S)) {
t = "<table><tr><td>" + embeddedImage + "</td><td>" + t + "</td></table>";
}
QString embeddedImage;
if (RsHtml::makeEmbeddedImage(pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation), embeddedImage, 8*S * 8*S)) {
t = "<table><tr><td>" + embeddedImage + "</td><td>" + t + "</td></table>";
}
return t;
}
}
}
return t;
}
}
return RSTreeWidgetItem::data(column, role);
return RSTreeWidgetItem::data(column, role);
}

View File

@ -41,6 +41,7 @@
#include "util/QtVersion.h"
#include <retroshare/rsgxsforums.h>
#include <retroshare/rsreputations.h>
#include <retroshare/rspeers.h>
// These should be in retroshare/ folder.
#include "retroshare/rsgxsflags.h"
@ -57,6 +58,7 @@
#define IMAGE_DOWNLOAD ":/images/start.png"
#define IMAGE_DOWNLOADALL ":/images/startall.png"
#define IMAGE_COPYLINK ":/images/copyrslink.png"
#define IMAGE_BIOHAZARD ":/icons/yellow_biohazard64.png"
#define VIEW_LAST_POST 0
#define VIEW_THREADED 1
@ -406,6 +408,10 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
QAction *replyauthorAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply with private message"), &contextMnu);
connect(replyauthorAct, SIGNAL(triggered()), this, SLOT(replytomessage()));
QAction *flagasbadAct = new QAction(QIcon(IMAGE_BIOHAZARD), tr("Ban this author"), &contextMnu);
flagasbadAct->setToolTip(tr("This will block/hide messages from this person, and notify neighbor nodes.")) ;
connect(flagasbadAct, SIGNAL(triggered()), this, SLOT(flagpersonasbad()));
QAction *newthreadAct = new QAction(QIcon(IMAGE_MESSAGE), tr("Start New Thread"), &contextMnu);
newthreadAct->setEnabled (IS_GROUP_SUBSCRIBED(mSubscribeFlags));
connect(newthreadAct , SIGNAL(triggered()), this, SLOT(createthread()));
@ -484,6 +490,8 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
contextMnu.addAction(expandAll);
contextMnu.addAction(collapseAll);
contextMnu.addSeparator();
contextMnu.addAction(flagasbadAct);
contextMnu.addSeparator();
contextMnu.addAction(replyauthorAct);
@ -725,6 +733,9 @@ void GxsForumThreadWidget::insertGroupData()
case GXS_ID_DETAILS_TYPE_LOADING:
author = GxsIdDetails::getLoadingText(details.mId);
break;
case GXS_ID_DETAILS_TYPE_BANNED:
author = tr("[Banned]") ;
break ;
case GXS_ID_DETAILS_TYPE_DONE:
author = GxsIdDetails::getName(details);
break;
@ -886,12 +897,21 @@ void GxsForumThreadWidget::fillThreadStatus(QString text)
QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForumMsg &msg, bool useChildTS, uint32_t filterColumn)
{
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_ALL);
// Early check for a message that should be hidden because its author
// is flagged with a bad reputation
bool redacted = rsReputations->isIdentityBanned(msg.mMeta.mAuthorId) ;
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_ALL || (redacted?(GxsIdDetails::ICON_TYPE_REDACTED):0));
item->moveToThread(ui->threadTreeWidget->thread());
QString text;
item->setText(COLUMN_THREAD_TITLE, QString::fromUtf8(msg.mMeta.mMsgName.c_str()));
if(redacted)
item->setText(COLUMN_THREAD_TITLE, tr("[ ... Redacted message ... ]"));
else
item->setText(COLUMN_THREAD_TITLE, QString::fromUtf8(msg.mMeta.mMsgName.c_str()));
QDateTime qtime;
QString sort;
@ -961,7 +981,6 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum
}
#endif
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, msg.mMeta.mMsgStatus);
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING, false);
return item;
@ -970,10 +989,13 @@ QTreeWidgetItem *GxsForumThreadWidget::convertMsgToThreadWidget(const RsGxsForum
QTreeWidgetItem *GxsForumThreadWidget::generateMissingItem(const RsGxsMessageId &msgId)
{
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(mThreadCompareRole,GxsIdDetails::ICON_TYPE_ALL);
item->setText(COLUMN_THREAD_TITLE, tr("[ ... Missing Message ... ]"));
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID, QString::fromStdString(msgId.toStdString()));
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING, true);
item->setId(RsGxsId(), COLUMN_THREAD_AUTHOR, false); // fixed up columnId()
return item;
}
@ -1301,6 +1323,8 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg)
return;
}
bool redacted = rsReputations->isIdentityBanned(msg.mMeta.mAuthorId) ;
mStateHelper->setActive(mTokenTypeMessageData, true);
QTreeWidgetItem *item = ui->threadTreeWidget->currentItem();
@ -1334,9 +1358,20 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg)
ui->by_text_label->show() ;
ui->by_label->show() ;
QString extraTxt = RsHtml().formatText(ui->postText->document(), QString::fromUtf8(msg.mMsg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS);
if(redacted)
{
QString extraTxt = tr("<p><font color=\"#ff0000\"><b>The author of this message (with ID %1) is banned.</b>").arg(QString::fromStdString(msg.mMeta.mAuthorId.toStdString())) ;
extraTxt += tr("<UL><li><b><font color=\"#ff0000\">Messages from this author are not forwarded. </font></b></li>") ;
extraTxt += tr("<li><b><font color=\"#ff0000\">Messages from this author are replaced by this text. </font></b></li></ul>") ;
extraTxt += tr("<p><b><font color=\"#ff0000\">You can force the visibility and forwarding of messages by setting a different opinion for that Id in People's tab.</font></b></p>") ;
ui->postText->setHtml(extraTxt);
}
else
{
QString extraTxt = RsHtml().formatText(ui->postText->document(), QString::fromUtf8(msg.mMsg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS);
ui->postText->setHtml(extraTxt);
}
//ui->threadTitle->setText(QString::fromUtf8(msg.mMeta.mMsgName.c_str()));
}
@ -1685,6 +1720,34 @@ static QString buildReplyHeader(const RsMsgMetaData &meta)
return header;
}
void GxsForumThreadWidget::flagpersonasbad()
{
// no need to use the token system for that, since we just need to find out the author's name, which is in the item.
if (groupId().isNull() || mThreadId.isNull()) {
QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message"));
return;
}
// Get Message ... then complete replyMessageData().
RsGxsGrpMsgIdPair postId = std::make_pair(groupId(), mThreadId);
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumThreadWidget::requestMsgData_BanAuthor(" << postId.first << "," << postId.second << ")";
std::cerr << std::endl;
#endif
GxsMsgReq msgIds;
std::vector<RsGxsMessageId> &vect = msgIds[postId.first];
vect.push_back(postId.second);
uint32_t token;
mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeBanAuthor);
}
void GxsForumThreadWidget::replytomessage()
{
if (groupId().isNull() || mThreadId.isNull()) {
@ -1966,6 +2029,37 @@ void GxsForumThreadWidget::loadMsgData_ReplyMessage(const uint32_t &token)
}
}
void GxsForumThreadWidget::loadMsgData_BanAuthor(const uint32_t &token)
{
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumThreadWidget::loadMsgData_BanAuthor()";
std::cerr << std::endl;
#endif
std::vector<RsGxsForumMsg> msgs;
if (rsGxsForums->getMsgData(token, msgs))
{
if (msgs.size() != 1)
{
std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Wrong number of answers";
std::cerr << std::endl;
return;
}
std::cerr << " banning author id " << msgs[0].mMeta.mAuthorId << std::endl;
rsReputations->setOwnOpinion(msgs[0].mMeta.mAuthorId,RsReputations::OPINION_NEGATIVE) ;
}
else
{
std::cerr << "GxsForumThreadWidget::loadMsgData_ReplyMessage() ERROR Missing Message Data...";
std::cerr << std::endl;
}
updateDisplay(true) ;
// we should also update the icons so that they changed to the icon for banned peers.
std::cerr << __PRETTY_FUNCTION__ << ": need to implement the update of GxsTreeWidgetItems icons too." << std::endl;
}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
@ -1993,6 +2087,11 @@ void GxsForumThreadWidget::loadRequest(const TokenQueue *queue, const TokenReque
loadMsgData_ReplyMessage(req.mToken);
return;
}
if (req.mUserType == mTokenTypeBanAuthor) {
loadMsgData_BanAuthor(req.mToken);
return;
}
}
GxsMessageFrameWidget::loadRequest(queue, req);

View File

@ -101,6 +101,7 @@ private slots:
void downloadAllFiles();
void changedViewBox();
void flagpersonasbad();
void filterColumnChanged(int column);
void filterItems(const QString &text);
@ -140,6 +141,7 @@ private:
void loadMessageData(const uint32_t &token);
void requestMsgData_ReplyMessage(const RsGxsGrpMsgIdPair &msgId);
void loadMsgData_ReplyMessage(const uint32_t &token);
void loadMsgData_BanAuthor(const uint32_t &token);
private:
RsGxsGroupId mLastForumID;
@ -159,6 +161,7 @@ private:
uint32_t mTokenTypeInsertThreads;
uint32_t mTokenTypeMessageData;
uint32_t mTokenTypeReplyMessage;
uint32_t mTokenTypeBanAuthor;
/* Color definitions (for standard see qss.default) */
QColor mTextColorRead;
@ -170,7 +173,7 @@ private:
RsGxsMessageId mNavigatePendingMsgId;
QList<RsGxsMessageId> mIgnoredMsgId;
Ui::GxsForumThreadWidget *ui;
Ui::GxsForumThreadWidget *ui;
};
#endif // GXSFORUMTHREADWIDGET_H

View File

@ -60,5 +60,6 @@
<file>icons/user-busy_64.png</file>
<file>icons/user-offline_64.png</file>
<file>icons/user-online_64.png</file>
<file>icons/yellow_biohazard64.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB