Merge branch 'master' into qmlapp_pex_alpha

This commit is contained in:
Gioacchino Mazzurco 2017-05-31 12:11:15 +02:00
commit 59b77da6a2
113 changed files with 6880 additions and 1675 deletions

View File

@ -97,6 +97,7 @@ install:
# Install toolchain
#- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain" #Already installed
# Install other binutils
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-curl mingw-w64-x86_64-curl"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-miniupnpc mingw-w64-x86_64-miniupnpc"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-sqlite3 mingw-w64-x86_64-sqlite3"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-speex mingw-w64-x86_64-speex"

View File

@ -266,7 +266,7 @@ libs/curl-$(CURL_VERSION): $(DOWNLOAD_PATH)/curl-$(CURL_VERSION).tar.gz
sqlcipher: libs/sqlcipher-$(SQLCIPHER_VERSION)
$(DOWNLOAD_PATH)/tcl$(TCL_VERSION)-src.tar.gz:
wget http://prdownloads.sourceforge.net/tcl/tcl$(TCL_VERSION)-src.tar.gz -O $(DOWNLOAD_PATH)/tcl$(TCL_VERSION)-src.tar.gz
wget --no-check-certificate http://downloads.sourceforge.net/project/tcl/Tcl/$(TCL_VERSION)/tcl$(TCL_VERSION)-src.tar.gz -O $(DOWNLOAD_PATH)/tcl$(TCL_VERSION)-src.tar.gz
$(DOWNLOAD_PATH)/sqlcipher-$(SQLCIPHER_VERSION).tar.gz:
wget --no-check-certificate https://github.com/sqlcipher/sqlcipher/archive/v$(SQLCIPHER_VERSION).tar.gz -O $(DOWNLOAD_PATH)/sqlcipher-$(SQLCIPHER_VERSION).tar.gz

View File

@ -443,8 +443,10 @@ void RsControlModule::handleCreateLocation(Request &req, Response &resp)
}
}
if(hidden_port)
RsInit::SetHiddenLocation(hidden_address, hidden_port);
if(hidden_port) {
/// TODO add bob to webui
RsInit::SetHiddenLocation(hidden_address, hidden_port, false);
}
std::string ssl_password = RSRandom::random_alphaNumericString(RsInit::getSslPwdLen()) ;

View File

@ -349,7 +349,7 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg)
uint32_t sz = _serializer->size(ci);
std::vector<uint8_t> data; data.resize(sz);
_serializer->serialise(ci, &data[0], &sz);
mGxsTransport.sendMail(tId, GxsTransSubServices::P3_CHAT_SERVICE,
mGxsTransport.sendData(tId, GxsTransSubServices::P3_CHAT_SERVICE,
de.from, de.to, &data[0], sz);
}
else

View File

@ -44,7 +44,7 @@
//#define DEBUG_CHACHA20
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
#if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER)
#define AEAD_chacha20_poly1305_openssl AEAD_chacha20_poly1305
#else
#define AEAD_chacha20_poly1305_rs AEAD_chacha20_poly1305
@ -386,7 +386,7 @@ void chacha20_encrypt_rs(uint8_t key[32], uint32_t block_counter, uint8_t nonce[
}
}
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
#if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER)
void chacha20_encrypt_openssl(uint8_t key[32], uint32_t block_counter, uint8_t nonce[12], uint8_t *data, uint32_t size)
{
EVP_CIPHER_CTX *ctx;
@ -577,7 +577,7 @@ bool AEAD_chacha20_poly1305_rs(uint8_t key[32], uint8_t nonce[12],uint8_t *data,
}
}
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
#if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER)
#define errorOut {ret = false; goto out;}
bool AEAD_chacha20_poly1305_openssl(uint8_t key[32], uint8_t nonce[12], uint8_t *data, uint32_t data_size, uint8_t *aad, uint32_t aad_size, uint8_t tag[16], bool encrypt_or_decrypt)
@ -667,7 +667,7 @@ bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint3
if(encrypt)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
chacha20_encrypt_rs(key,1,nonce,data,data_size);
#else
chacha20_encrypt_openssl(key, 1, nonce, data, data_size);
@ -676,7 +676,7 @@ bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint3
uint8_t computed_tag[EVP_MAX_MD_SIZE];
unsigned int md_size ;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
HMAC_CTX hmac_ctx ;
HMAC_CTX_init(&hmac_ctx) ;
@ -709,7 +709,7 @@ bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint3
uint8_t computed_tag[EVP_MAX_MD_SIZE];
unsigned int md_size ;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
HMAC_CTX hmac_ctx ;
HMAC_CTX_init(&hmac_ctx) ;
@ -733,7 +733,7 @@ bool AEAD_chacha20_sha256(uint8_t key[32], uint8_t nonce[12],uint8_t *data,uint3
// decrypt
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
chacha20_encrypt_rs(key,1,nonce,data,data_size);
#else
chacha20_encrypt_openssl(key, 1, nonce, data, data_size);
@ -1396,7 +1396,7 @@ bool perform_tests()
std::cerr << " AEAD/poly1305 own encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
}
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
#if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER)
{
RsScopeTimer s("AEAD3") ;
AEAD_chacha20_poly1305_openssl(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;

View File

@ -1624,11 +1624,18 @@ Sha1CheckSum p3GRouter::computeDataItemHash(RsGRouterGenericDataItem *data_item)
RsTemporaryMemory mem(total_size) ;
uint32_t offset = 0 ;
signature_serializer.serialise(data_item,mem,&total_size) ;
offset += signed_data_size ;
uint32_t tmp_size = total_size ;
signature_serializer.serialise(data_item,mem,&tmp_size) ;
if(tmp_size != signed_data_size)
std::cerr << "(EE) Some error occured in p3GRouter::computeDataItemHash(). Mismatched offset/data size" << std::endl;
offset += tmp_size ;
data_item->signature.SetTlv(mem, total_size,&offset) ;
if(offset != total_size)
std::cerr << "(EE) Some error occured in p3GRouter::computeDataItemHash(). Mismatched offset/data size" << std::endl;
return RsDirUtil::sha1sum(mem,total_size) ;
}
@ -1983,7 +1990,7 @@ bool p3GRouter::signDataItem(RsGRouterAbstractMsgItem *item,const RsGxsId& signi
std::cerr << "Created signature for data hash: " << RsDirUtil::sha1sum(data,data_size) << " and key id=" << signing_id << std::endl;
//#endif
// Check signature
RsIdentityUsage::UsageCode info;
RsIdentityUsage::UsageCode info = RsIdentityUsage::GLOBAL_ROUTER_SIGNATURE_CREATION;
uint32_t error;
if(verifySignedDataItem(item,info,error))

View File

@ -41,7 +41,7 @@ static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE = 256 ;
static RsGxsId getRsaKeyFingerprint_old_insecure_method(RSA *pubkey)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
int lenn = BN_num_bytes(pubkey -> n);
RsTemporaryMemory tmp(lenn) ;
@ -65,7 +65,7 @@ static RsGxsId getRsaKeyFingerprint_old_insecure_method(RSA *pubkey)
}
static RsGxsId getRsaKeyFingerprint(RSA *pubkey)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
int lenn = BN_num_bytes(pubkey -> n);
int lene = BN_num_bytes(pubkey -> e);
@ -359,7 +359,7 @@ bool GxsSecurity::getSignature(const char *data, uint32_t data_len, const RsTlvP
ok &= EVP_SignUpdate(mdctx, data, data_len) == 1;
unsigned int siglen = EVP_PKEY_size(key_priv);
unsigned char sigbuf[siglen];
unsigned char sigbuf[siglen] = { 0 };
ok &= EVP_SignFinal(mdctx, sigbuf, &siglen, key_priv) == 1;
// clean up

View File

@ -1576,11 +1576,20 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req)
req->mGroupStatistic.mNumChildMsgsNew = 0;
req->mGroupStatistic.mNumChildMsgsUnread = 0;
std::set<RsGxsMessageId> obsolete_msgs ; // stored message ids that are referred to as older versions of an existing message
for(uint32_t i = 0; i < msgMetaV.size(); ++i)
if(!msgMetaV[i]->mOrigMsgId.isNull() && msgMetaV[i]->mOrigMsgId!=msgMetaV[i]->mMsgId)
obsolete_msgs.insert(msgMetaV[i]->mOrigMsgId);
for(uint32_t i = 0; i < msgMetaV.size(); ++i)
{
RsGxsMsgMetaData* m = msgMetaV[i];
req->mGroupStatistic.mTotalSizeOfMsgs += m->mMsgSize + m->serial_size();
if(obsolete_msgs.find(m->mMsgId) != obsolete_msgs.end()) // skip obsolete messages.
continue;
if (IS_MSG_NEW(m->mMsgStatus))
{
if (m->mParentId.isNull())

View File

@ -16,11 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "util/rsdir.h"
#include "gxstrans/p3gxstrans.h"
#include "util/stacktrace.h"
typedef unsigned int uint;
RsGxsTrans *rsGxsTrans = NULL ;
p3GxsTrans::~p3GxsTrans()
{
p3Config::saveConfiguration();
@ -31,7 +34,36 @@ p3GxsTrans::~p3GxsTrans()
}
}
bool p3GxsTrans::sendMail( RsGxsTransId& mailId,
bool p3GxsTrans::getStatistics(GxsTransStatistics& stats)
{
stats.prefered_group_id = mPreferredGroupId;
stats.outgoing_records.clear();
{
RS_STACK_MUTEX(mOutgoingMutex);
for ( auto it = mOutgoingQueue.begin(); it != mOutgoingQueue.end(); ++it)
{
const OutgoingRecord& pr(it->second);
RsGxsTransOutgoingRecord rec ;
rec.status = pr.status ;
rec.send_TS = pr.mailItem.meta.mPublishTs ;
rec.group_id = pr.mailItem.meta.mGroupId ;
rec.trans_id = pr.mailItem.mailId ;
rec.recipient = pr.recipient ;
rec.data_size = pr.mailData.size();
rec.data_hash = RsDirUtil::sha1sum(pr.mailData.data(),pr.mailData.size());
rec.client_service = pr.clientService ;
stats.outgoing_records.push_back(rec) ;
}
}
return true;
}
bool p3GxsTrans::sendData( RsGxsTransId& mailId,
GxsTransSubServices service,
const RsGxsId& own_gxsid, const RsGxsId& recipient,
const uint8_t* data, uint32_t size,
@ -55,7 +87,10 @@ bool p3GxsTrans::sendMail( RsGxsTransId& mailId,
}
OutgoingRecord pr( recipient, service, data, size );
pr.mailItem.clear();
pr.mailItem.meta.mAuthorId = own_gxsid;
pr.mailItem.meta.mMsgId.clear();
pr.mailItem.cryptoType = cm;
pr.mailItem.mailId = RSRandom::random_u64();
@ -120,9 +155,9 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
&& meta.mGroupId != mPreferredGroupId;
if(shoudlSubscribe)
subscribeToGroup(token, meta.mGroupId, true);
RsGenExchange::subscribeToGroup(token, meta.mGroupId, true);
else if(shoudlUnSubscribe)
subscribeToGroup(token, meta.mGroupId, false);
RsGenExchange::subscribeToGroup(token, meta.mGroupId, false);
#ifdef GXS_MAIL_GRP_DEBUG
char buff[30];
@ -220,10 +255,113 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type)
}
}
void p3GxsTrans::GxsTransIntegrityCleanupThread::run()
{
// first take out all the groups
std::map<RsGxsGroupId, RsNxsGrp*> grp;
mDs->retrieveNxsGrps(grp, true, true);
std::cerr << "GxsTransIntegrityCleanupThread::run()" << std::endl;
// compute hash and compare to stored value, if it fails then simply add it
// to list
GxsMsgReq grps;
for(std::map<RsGxsGroupId, RsNxsGrp*>::iterator git = grp.begin(); git != grp.end(); ++git)
{
RsNxsGrp* grp = git->second;
// store the group for retrieveNxsMsgs
grps[grp->grpId];
delete grp;
}
// now messages
std::map<RsGxsTransId,std::pair<RsGxsGroupId,RsGxsMessageId> > stored_msgs ;
std::list<RsGxsTransId> received_msgs ;
GxsMsgResult msgs;
mDs->retrieveNxsMsgs(grps, msgs, false, true);
for(GxsMsgResult::iterator mit = msgs.begin();mit != msgs.end(); ++mit)
{
std::vector<RsNxsMsg*>& msgV = mit->second;
std::vector<RsNxsMsg*>::iterator vit = msgV.begin();
for(; vit != msgV.end(); ++vit)
{
RsNxsMsg* msg = *vit;
RsGxsTransSerializer s ;
uint32_t size = msg->msg.bin_len;
RsItem *item = s.deserialise(msg->msg.bin_data,&size);
RsGxsTransMailItem *mitem ;
RsGxsTransPresignedReceipt *pitem ;
if(item == NULL)
std::cerr << " Unrecocognised item type!" << std::endl;
else if(NULL != (mitem = dynamic_cast<RsGxsTransMailItem*>(item)))
{
std::cerr << " " << msg->metaData->mMsgId << ": Mail data with ID " << std::hex << mitem->mailId << std::dec << " from " << msg->metaData->mAuthorId << " size: " << msg->msg.bin_len << std::endl;
stored_msgs[mitem->mailId] = std::make_pair(msg->metaData->mGroupId,msg->metaData->mMsgId) ;
}
else if(NULL != (pitem = dynamic_cast<RsGxsTransPresignedReceipt*>(item)))
{
std::cerr << " " << msg->metaData->mMsgId << ": Signed rcpt of ID " << std::hex << pitem->mailId << std::dec << " from " << msg->metaData->mAuthorId << " size: " << msg->msg.bin_len << std::endl;
received_msgs.push_back(pitem->mailId) ;
}
else
std::cerr << " Unknown item type!" << std::endl;
delete msg;
}
}
GxsMsgReq msgsToDel ;
std::cerr << "Msg removal report:" << std::endl;
for(std::list<RsGxsTransId>::const_iterator it(received_msgs.begin());it!=received_msgs.end();++it)
{
std::map<RsGxsTransId,std::pair<RsGxsGroupId,RsGxsMessageId> >::const_iterator it2 = stored_msgs.find(*it) ;
if(stored_msgs.end() != it2)
{
msgsToDel[it2->second.first].push_back(it2->second.second);
std::cerr << " scheduling msg " << std::hex << it2->second.first << "," << it2->second.second << " for deletion." << std::endl;
}
}
mDs->removeMsgs(msgsToDel);
}
void p3GxsTrans::service_tick()
{
GxsTokenQueue::checkRequests();
time_t now = time(NULL);
if(mLastMsgCleanup + MAX_DELAY_BETWEEN_CLEANUPS < now)
{
if(!mCleanupThread)
mCleanupThread = new GxsTransIntegrityCleanupThread(getDataStore());
if(mCleanupThread->isRunning())
std::cerr << "Cleanup thread is already running. Not running it again!" << std::endl;
else
{
std::cerr << "Starting GxsIntegrity cleanup thread." << std::endl;
mCleanupThread->start() ;
mLastMsgCleanup = now ;
}
}
{
RS_STACK_MUTEX(mOutgoingMutex);
for ( auto it = mOutgoingQueue.begin(); it != mOutgoingQueue.end(); )
@ -337,7 +475,7 @@ void p3GxsTrans::notifyChanges(std::vector<RsGxsNotify*>& changes)
std::cout << "p3GxsTrans::notifyChanges(...) msgChange" << std::endl;
uint32_t token;
RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
getTokenService()->requestMsgInfo( token, 0xcaca,
RsGenExchange::getTokenService()->requestMsgInfo( token, 0xcaca,
opts, msgChange->msgChangeMap );
GxsTokenQueue::queueRequest(token, MAILS_UPDATE);
@ -393,8 +531,8 @@ bool p3GxsTrans::requestGroupsData(const std::list<RsGxsGroupId>* groupIds)
// std::cout << "p3GxsTrans::requestGroupsList()" << std::endl;
uint32_t token;
RsTokReqOptions opts; opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
if(!groupIds) getTokenService()->requestGroupInfo(token, 0xcaca, opts);
else getTokenService()->requestGroupInfo(token, 0xcaca, opts, *groupIds);
if(!groupIds) RsGenExchange::getTokenService()->requestGroupInfo(token, 0xcaca, opts);
else RsGenExchange::getTokenService()->requestGroupInfo(token, 0xcaca, opts, *groupIds);
GxsTokenQueue::queueRequest(token, GROUPS_LIST);
return true;
}
@ -526,6 +664,7 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr)
{
pr.mailItem.saltRecipientHint(pr.recipient);
pr.mailItem.saltRecipientHint(RsGxsId::random());
pr.mailItem.meta.mPublishTs = time(NULL);
}
case GxsTransSendStatus::PENDING_PREFERRED_GROUP:
{
@ -608,8 +747,7 @@ void p3GxsTrans::processOutgoingRecord(OutgoingRecord& pr)
pr.recipient, encryptError, true ) )
{
pr.mailItem.payload.resize(encryptedSize);
memcpy( &pr.mailItem.payload[0], encryptedData,
encryptedSize );
memcpy( &pr.mailItem.payload[0], encryptedData, encryptedSize );
free(encryptedData);
break;
}

View File

@ -26,6 +26,7 @@
#include "gxstrans/p3gxstransitems.h"
#include "services/p3idservice.h" // For p3IdService
#include "util/rsthreads.h"
#include "retroshare/rsgxstrans.h"
struct p3GxsTrans;
@ -76,18 +77,36 @@ struct GxsTransClient
* @see GxsTransClient::receiveGxsTransMail(...),
* @see GxsTransClient::notifyGxsTransSendStatus(...).
*/
struct p3GxsTrans : RsGenExchange, GxsTokenQueue, p3Config
class p3GxsTrans : public RsGenExchange, public GxsTokenQueue, public p3Config, public RsGxsTrans
{
public:
p3GxsTrans( RsGeneralDataService* gds, RsNetworkExchangeService* nes,
p3IdService& identities ) :
RsGenExchange( gds, nes, new RsGxsTransSerializer(),
RS_SERVICE_TYPE_GXS_TRANS, &identities,
AuthenPolicy(), GXS_STORAGE_PERIOD ),
GxsTokenQueue(this), mIdService(identities),
GxsTokenQueue(this),
RsGxsTrans(this),
mIdService(identities),
mServClientsMutex("p3GxsTrans client services map mutex"),
mOutgoingMutex("p3GxsTrans outgoing queue map mutex"),
mIngoingMutex("p3GxsTrans ingoing queue map mutex") {}
~p3GxsTrans();
mIngoingMutex("p3GxsTrans ingoing queue map mutex")
{
mLastMsgCleanup = time(NULL) - 60; // to be changed into 0
mCleanupThread = NULL ;
}
virtual ~p3GxsTrans();
/*!
* \brief getStatistics
* Gathers all sorts of statistics about the internals of p3GxsTrans, in order to display info about the running status,
* message transport, etc.
* \param stats This structure contains all statistics information.
* \return true is the call succeeds.
*/
virtual bool getStatistics(GxsTransStatistics& stats);
/**
* Send an email to recipient, in the process author of the email is
@ -97,7 +116,7 @@ struct p3GxsTrans : RsGenExchange, GxsTokenQueue, p3Config
* This method is part of the public interface of this service.
* @return true if the mail will be sent, false if not
*/
bool sendMail( RsGxsTransId& mailId,
bool sendData( RsGxsTransId& mailId,
GxsTransSubServices service,
const RsGxsId& own_gxsid, const RsGxsId& recipient,
const uint8_t* data, uint32_t size,
@ -139,7 +158,10 @@ private:
* signed acknowledged is received for each of them.
* Two weeks seems fair ATM.
*/
const static uint32_t GXS_STORAGE_PERIOD = 0x127500;
static const uint32_t GXS_STORAGE_PERIOD = 0x127500;
static const uint32_t MAX_DELAY_BETWEEN_CLEANUPS = 1203; // every 20 mins. Could be less.
time_t mLastMsgCleanup ;
/// Define how the backend should handle authentication based on signatures
static uint32_t AuthenPolicy();
@ -251,5 +273,27 @@ private:
uint32_t decrypted_data_size );
void notifyClientService(const OutgoingRecord& pr);
/*!
* Checks the integrity message and groups
*/
class GxsTransIntegrityCleanupThread : public RsSingleJobThread
{
enum CheckState { CheckStart, CheckChecking };
public:
GxsTransIntegrityCleanupThread(RsGeneralDataService *const dataService): mDs(dataService) {}
bool isDone();
void run();
void getDeletedIds(std::list<RsGxsGroupId>& grpIds, std::map<RsGxsGroupId, std::vector<RsGxsMessageId> >& msgIds);
private:
RsGeneralDataService* const mDs;
};
GxsTransIntegrityCleanupThread *mCleanupThread ;
};

View File

@ -23,41 +23,28 @@
#include "serialiser/rsbaseserial.h"
#include "serialiser/rstlvidset.h"
#include "retroshare/rsgxsflags.h"
#include "retroshare/rsgxstrans.h"
#include "retroshare/rsgxscircles.h" // For: GXS_CIRCLE_TYPE_PUBLIC
#include "services/p3idservice.h"
#include "serialiser/rstypeserializer.h"
/// Subservices identifiers (like port for TCP)
enum class GxsTransSubServices : uint16_t
{
UNKNOWN = 0,
TEST_SERVICE = 1,
P3_MSG_SERVICE = 2,
P3_CHAT_SERVICE = 3
};
/// Values must fit into uint8_t
enum class GxsTransItemsSubtypes : uint8_t
{
GXS_TRANS_SUBTYPE_MAIL = 1,
GXS_TRANS_SUBTYPE_RECEIPT = 2,
GXS_TRANS_SUBTYPE_GROUP = 3,
OUTGOING_RECORD_ITEM = 4
};
typedef uint64_t RsGxsTransId;
struct RsNxsTransPresignedReceipt : RsNxsMsg
class RsNxsTransPresignedReceipt : public RsNxsMsg
{
public:
RsNxsTransPresignedReceipt() : RsNxsMsg(RS_SERVICE_TYPE_GXS_TRANS) {}
virtual ~RsNxsTransPresignedReceipt() {}
};
struct RsGxsTransBaseItem : RsGxsMsgItem
class RsGxsTransBaseItem : public RsGxsMsgItem
{
public:
RsGxsTransBaseItem(GxsTransItemsSubtypes subtype) :
RsGxsMsgItem( RS_SERVICE_TYPE_GXS_TRANS,
static_cast<uint8_t>(subtype) ), mailId(0) {}
virtual ~RsGxsTransBaseItem() {}
RsGxsTransId mailId;
void inline clear()
@ -71,10 +58,11 @@ struct RsGxsTransBaseItem : RsGxsMsgItem
{ RS_REGISTER_SERIAL_MEMBER_TYPED(mailId, uint64_t); }
};
struct RsGxsTransPresignedReceipt : RsGxsTransBaseItem
class RsGxsTransPresignedReceipt : public RsGxsTransBaseItem
{
RsGxsTransPresignedReceipt() :
RsGxsTransBaseItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT) {}
public:
RsGxsTransPresignedReceipt() : RsGxsTransBaseItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_RECEIPT) {}
virtual ~RsGxsTransPresignedReceipt() {}
};
enum class RsGxsTransEncryptionMode : uint8_t
@ -84,12 +72,15 @@ enum class RsGxsTransEncryptionMode : uint8_t
UNDEFINED_ENCRYPTION = 250
};
struct RsGxsTransMailItem : RsGxsTransBaseItem
class RsGxsTransMailItem : public RsGxsTransBaseItem
{
public:
RsGxsTransMailItem() :
RsGxsTransBaseItem(GxsTransItemsSubtypes::GXS_TRANS_SUBTYPE_MAIL),
cryptoType(RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION) {}
virtual ~RsGxsTransMailItem() {}
RsGxsTransEncryptionMode cryptoType;
/**
@ -166,8 +157,9 @@ struct RsGxsTransMailItem : RsGxsTransBaseItem
const static uint32_t MAX_SIZE = 10*8*1024*1024;
};
struct RsGxsTransGroupItem : RsGxsGrpItem
class RsGxsTransGroupItem : public RsGxsGrpItem
{
public:
RsGxsTransGroupItem() :
RsGxsGrpItem( RS_SERVICE_TYPE_GXS_TRANS,
static_cast<uint8_t>(
@ -177,6 +169,7 @@ struct RsGxsTransGroupItem : RsGxsGrpItem
meta.mGroupName = "Mail";
meta.mCircleType = GXS_CIRCLE_TYPE_PUBLIC;
}
virtual ~RsGxsTransGroupItem() {}
// TODO: Talk with Cyril why there is no RsGxsGrpItem::serial_process
virtual void serial_process(RsGenericSerializer::SerializeJob /*j*/,
@ -188,33 +181,16 @@ struct RsGxsTransGroupItem : RsGxsGrpItem
{ return out; }
};
enum class GxsTransSendStatus : uint8_t
{
UNKNOWN = 0,
PENDING_PROCESSING,
PENDING_PREFERRED_GROUP,
PENDING_RECEIPT_CREATE,
PENDING_RECEIPT_SIGNATURE,
PENDING_SERIALIZATION,
PENDING_PAYLOAD_CREATE,
PENDING_PAYLOAD_ENCRYPT,
PENDING_PUBLISH,
/** This will be useful so the user can know if the mail reached at least
* some friend node, in case of internet connection interruption */
//PENDING_TRANSFER,
PENDING_RECEIPT_RECEIVE,
/// Records with status >= RECEIPT_RECEIVED get deleted
RECEIPT_RECEIVED,
FAILED_RECEIPT_SIGNATURE = 240,
FAILED_ENCRYPTION
};
class RsGxsTransSerializer;
struct OutgoingRecord : RsItem
class OutgoingRecord : public RsItem
{
public:
OutgoingRecord( RsGxsId rec, GxsTransSubServices cs,
const uint8_t* data, uint32_t size );
virtual ~OutgoingRecord() {}
GxsTransSendStatus status;
RsGxsId recipient;
/// Don't use a pointer would be invalid after publish
@ -234,10 +210,11 @@ private:
};
struct RsGxsTransSerializer : public RsServiceSerializer
class RsGxsTransSerializer : public RsServiceSerializer
{
public:
RsGxsTransSerializer() : RsServiceSerializer(RS_SERVICE_TYPE_GXS_TRANS) {}
~RsGxsTransSerializer() {}
virtual ~RsGxsTransSerializer() {}
RsItem* create_item(uint16_t service_id, uint8_t item_sub_id) const
{

View File

@ -1056,7 +1056,7 @@ bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_
}
RsGxsTunnelDHPublicKeyItem *dhitem = new RsGxsTunnelDHPublicKeyItem ;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
dhitem->public_key = BN_dup(dh->pub_key) ;
#else
const BIGNUM *pub_key=NULL ;
@ -1140,7 +1140,7 @@ bool p3GxsTunnelService::locked_initDHSessionKey(DH *& dh)
return false ;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
BN_hex2bn(&dh->p,dh_prime_2048_hex.c_str()) ;
BN_hex2bn(&dh->g,"5") ;
#else

View File

@ -140,7 +140,6 @@ PUBLIC_HEADERS = retroshare/rsdisc.h \
retroshare/rsversion.h \
retroshare/rsservicecontrol.h \
HEADERS += plugins/pluginmanager.h \
plugins/dlfcn_win32.h \
rsitems/rspluginitems.h \
@ -429,6 +428,7 @@ HEADERS += pqi/authssl.h \
pqi/pqissl.h \
pqi/pqissllistener.h \
pqi/pqisslpersongrp.h \
pqi/pqissli2pbob.h \
pqi/pqissludp.h \
pqi/pqisslproxy.h \
pqi/pqistore.h \
@ -493,7 +493,9 @@ HEADERS += rsitems/rsitem.h \
rsitems/rsgxsupdateitems.h \
rsitems/rsserviceinfoitems.h \
HEADERS += services/p3msgservice.h \
HEADERS += services/autoproxy/p3i2pbob.h \
services/autoproxy/rsautoproxymonitor.h \
services/p3msgservice.h \
services/p3service.h \
services/p3statusservice.h \
services/p3banlist.h \
@ -518,6 +520,9 @@ HEADERS += util/folderiterator.h \
util/rsnet.h \
util/extaddrfinder.h \
util/dnsresolver.h \
util/radix32.h \
util/radix64.h \
util/rsinitedptr.h \
util/rsprint.h \
util/rsstring.h \
util/rsstd.h \
@ -525,7 +530,6 @@ HEADERS += util/folderiterator.h \
util/rsversioninfo.h \
util/rswin.h \
util/rsrandom.h \
util/radix64.h \
util/pugiconfig.h \
util/rsmemcache.h \
util/rstickevent.h \
@ -580,6 +584,7 @@ SOURCES += pqi/authgpg.cc \
pqi/pqissl.cc \
pqi/pqissllistener.cc \
pqi/pqisslpersongrp.cc \
pqi/pqissli2pbob.cpp \
pqi/pqissludp.cc \
pqi/pqisslproxy.cc \
pqi/pqistore.cc \
@ -638,7 +643,9 @@ SOURCES += serialiser/rsbaseserial.cc \
rsitems/rsgxsupdateitems.cc \
rsitems/rsserviceinfoitems.cc \
SOURCES += services/p3msgservice.cc \
SOURCES += services/autoproxy/rsautoproxymonitor.cc \
services/autoproxy/p3i2pbob.cc \
services/p3msgservice.cc \
services/p3service.cc \
services/p3statusservice.cc \
services/p3banlist.cc \

View File

@ -245,7 +245,7 @@ sslcert::sslcert(X509 *x509, const RsPeerId& pid)
{
certificate = x509;
id = pid;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
name = getX509CNString(x509->cert_info->subject);
org = getX509OrgString(x509->cert_info->subject);
location = getX509LocString(x509->cert_info->subject);
@ -377,7 +377,7 @@ static int initLib = 0;
if (dh)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
BN_hex2bn(&dh->p,dh_prime_4096_hex.c_str()) ;
BN_hex2bn(&dh->g,"5") ;
#else
@ -599,7 +599,7 @@ bool AuthSSLimpl::SignData(const void *data, const uint32_t len, std::string &si
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
unsigned int signlen = EVP_PKEY_size(mOwnPrivateKey);
unsigned char signature[signlen];
unsigned char signature[signlen] = { 0 };
if (0 == EVP_SignInit(mdctx, EVP_sha1()))
{
@ -795,7 +795,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
// The code has been copied in order to use the PGP signing instead of supplying the
// private EVP_KEY to ASN1_sign(), which would be another alternative.
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
int (*i2d)(X509_CINF*, unsigned char**) = i2d_X509_CINF;
X509_ALGOR *algor1 = x509->cert_info->signature;
X509_ALGOR *algor2 = x509->sig_alg;
@ -824,7 +824,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
/* FIX ALGORITHMS */
a = const_cast<X509_ALGOR*>(algor1);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
ASN1_TYPE_free(a->parameter);
a->parameter=ASN1_TYPE_new();
a->parameter->type=V_ASN1_NULL;
@ -836,7 +836,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
#endif
a = const_cast<X509_ALGOR*>(algor2);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
ASN1_TYPE_free(a->parameter);
a->parameter=ASN1_TYPE_new();
a->parameter->type=V_ASN1_NULL;
@ -851,7 +851,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
std::cerr << "Algorithms Fixed" << std::endl;
/* input buffer */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
inl=i2d(data,NULL);
buf_in=(unsigned char *)OPENSSL_malloc((unsigned int)inl);
unsigned char *p=NULL;
@ -874,7 +874,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
}
std::cerr << "Buffers Allocated" << std::endl;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
p=buf_in;
i2d(data,&p);
#endif
@ -960,7 +960,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
}
/* extract CN for peer Id */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
RsPgpId issuer(std::string(getX509CNString(x509->cert_info->issuer)));
#else
RsPgpId issuer(std::string(getX509CNString(X509_get_issuer_name(x509))));
@ -979,7 +979,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
/*** NOW The Manual signing bit (HACKED FROM asn1/a_sign.c) ***/
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
int (*i2d)(X509_CINF*, unsigned char**) = i2d_X509_CINF;
ASN1_BIT_STRING *signature = x509->signature;
X509_CINF *data = x509->cert_info;
@ -1000,7 +1000,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
int sigoutl=0;
/* input buffer */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
inl=i2d(data,NULL);
buf_in=(unsigned char *)OPENSSL_malloc((unsigned int)inl);
unsigned char *p=NULL;
@ -1033,7 +1033,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic)
std::cerr << "Buffers Allocated" << std::endl;
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
p=buf_in;
i2d(data,&p);
#endif
@ -1157,7 +1157,7 @@ static int verify_x509_callback(int preverify_ok, X509_STORE_CTX *ctx)
if(x509 != NULL)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
RsPgpId gpgid (std::string(getX509CNString(x509->cert_info->issuer)));
#else
RsPgpId gpgid (std::string(getX509CNString(X509_get_issuer_name(x509))));
@ -1165,7 +1165,7 @@ static int verify_x509_callback(int preverify_ok, X509_STORE_CTX *ctx)
if(gpgid.isNull())
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
std::cerr << "verify_x509_callback(): wrong PGP id \"" << std::string(getX509CNString(x509->cert_info->issuer)) << "\"" << std::endl;
#else
std::cerr << "verify_x509_callback(): wrong PGP id \"" << std::string(getX509CNString(X509_get_issuer_name(x509))) << "\"" << std::endl;
@ -1173,7 +1173,7 @@ static int verify_x509_callback(int preverify_ok, X509_STORE_CTX *ctx)
return false ;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
std::string sslcn = getX509CNString(x509->cert_info->subject);
#else
std::string sslcn = getX509CNString(X509_get_subject_name(x509));
@ -1262,7 +1262,7 @@ int AuthSSLimpl::VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx)
std::cerr << "(WW) Certificate was rejected because authentication failed. Diagnostic = " << auth_diagnostic << std::endl;
return false;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
RsPgpId pgpid(std::string(getX509CNString(X509_STORE_CTX_get_current_cert(ctx)->cert_info->issuer)));
#else
RsPgpId pgpid(std::string(getX509CNString(X509_get_issuer_name(X509_STORE_CTX_get_current_cert(ctx)))));
@ -1339,7 +1339,7 @@ bool AuthSSLimpl::encrypt(void *&out, int &outlen, const void *in, int inlen,
#endif
return false;
} else {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
public_key = mCerts[peerId]->certificate->cert_info->key->pkey;
#else
public_key = X509_get0_pubkey(mCerts[peerId]->certificate) ;
@ -1586,20 +1586,26 @@ bool AuthSSLimpl::FailedCertificate(X509 *x509, const RsPgpId& gpgid,
switch(auth_diagnostic)
{
case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_MISSING: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_MISSING_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_NOT_VALID: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_BAD_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_UNKNOWN_IN , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_INTERNAL_ERROR , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_WRONG_SIGNATURE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_OK:
case RS_SSL_HANDSHAKE_DIAGNOSTIC_UNKNOWN:
default:
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_CONNECT_ATTEMPT, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_MISSING:
RsServer::notify()->notifyConnectionWithoutCert();
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_MISSING_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_NOT_VALID:
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_BAD_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN:
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_UNKNOWN_IN , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR:
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_INTERNAL_ERROR , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE:
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_WRONG_SIGNATURE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
break ;
case RS_SSL_HANDSHAKE_DIAGNOSTIC_OK:
case RS_SSL_HANDSHAKE_DIAGNOSTIC_UNKNOWN:
default:
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_CONNECT_ATTEMPT, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address);
}
#ifdef AUTHSSL_DEBUG

View File

@ -237,6 +237,7 @@ void p3Notify::notifyOwnStatusMessageChanged()
void p3Notify::notifyDiskFull (uint32_t location , uint32_t size_limit_in_MB ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyDiskFull (location,size_limit_in_MB) ; }
void p3Notify::notifyPeerStatusChanged (const std::string& peer_id , uint32_t status ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerStatusChanged (peer_id,status) ; }
void p3Notify::notifyGxsChange (const RsGxsChanges& changes) {FOR_ALL_NOTIFY_CLIENTS (*it)->notifyGxsChange(changes) ;}
void p3Notify::notifyConnectionWithoutCert () { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyConnectionWithoutCert(); }
void p3Notify::notifyPeerStatusChangedSummary () { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerStatusChangedSummary() ; }
void p3Notify::notifyDiscInfoChanged () { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyDiscInfoChanged () ; }

View File

@ -112,6 +112,7 @@ class p3Notify: public RsNotify
void notifyDiskFull (uint32_t /* location */, uint32_t /* size limit in MB */) ;
void notifyPeerStatusChanged (const std::string& /* peer_id */, uint32_t /* status */) ;
void notifyGxsChange (const RsGxsChanges& /* changes */);
void notifyConnectionWithoutCert ();
void notifyPeerStatusChangedSummary () ;
void notifyDiscInfoChanged () ;

View File

@ -521,12 +521,14 @@ int pqiperson::connect(uint32_t type, const sockaddr_storage &raddr,
return 0;
}
pqiconnect *pqi = it->second;
#ifdef PERSON_DEBUG
std::cerr << "pqiperson::connect() resetting for new connection attempt" << std::endl;
#endif
/* set the parameters */
(it->second)->reset();
pqi->reset();
#ifdef PERSON_DEBUG
std::cerr << "pqiperson::connect() clearing rate cap" << std::endl;
@ -538,22 +540,22 @@ int pqiperson::connect(uint32_t type, const sockaddr_storage &raddr,
#endif
// These two are universal.
(it->second)->connect_parameter(NET_PARAM_CONNECT_DELAY, delay);
(it->second)->connect_parameter(NET_PARAM_CONNECT_TIMEOUT, timeout);
pqi->connect_parameter(NET_PARAM_CONNECT_DELAY, delay);
pqi->connect_parameter(NET_PARAM_CONNECT_TIMEOUT, timeout);
// these 5 are only used by UDP connections.
(it->second)->connect_parameter(NET_PARAM_CONNECT_PERIOD, period);
(it->second)->connect_parameter(NET_PARAM_CONNECT_FLAGS, flags);
(it->second)->connect_parameter(NET_PARAM_CONNECT_BANDWIDTH, bandwidth);
pqi->connect_parameter(NET_PARAM_CONNECT_PERIOD, period);
pqi->connect_parameter(NET_PARAM_CONNECT_FLAGS, flags);
pqi->connect_parameter(NET_PARAM_CONNECT_BANDWIDTH, bandwidth);
(it->second)->connect_additional_address(NET_PARAM_CONNECT_PROXY, proxyaddr);
(it->second)->connect_additional_address(NET_PARAM_CONNECT_SOURCE, srcaddr);
pqi->connect_additional_address(NET_PARAM_CONNECT_PROXY, proxyaddr);
pqi->connect_additional_address(NET_PARAM_CONNECT_SOURCE, srcaddr);
// These are used by Proxy/Hidden
(it->second)->connect_parameter(NET_PARAM_CONNECT_DOMAIN_ADDRESS, domain_addr);
(it->second)->connect_parameter(NET_PARAM_CONNECT_REMOTE_PORT, domain_port);
pqi->connect_parameter(NET_PARAM_CONNECT_DOMAIN_ADDRESS, domain_addr);
pqi->connect_parameter(NET_PARAM_CONNECT_REMOTE_PORT, domain_port);
(it->second)->connect(raddr);
pqi->connect(raddr);
// flag if we started a new connectionAttempt.
inConnectAttempt = true;

View File

@ -361,7 +361,7 @@ void pqissl::getCryptoParams(RsPeerCryptoParams& params)
bool pqissl::actAsServer()
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
return (bool)ssl_connection->server;
#else
return (bool)SSL_is_server(ssl_connection);
@ -1230,7 +1230,7 @@ int pqissl::Extract_Failed_SSL_Certificate()
RsPeerId sslid ;
getX509id(peercert, sslid) ;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
RsPgpId gpgid(getX509CNString(peercert->cert_info->issuer));
std::string sslcn = getX509CNString(peercert->cert_info->subject);
#else

View File

@ -0,0 +1,31 @@
#include "pqissli2pbob.h"
bool pqissli2pbob::connect_parameter(uint32_t type, const std::string &value)
{
if (type == NET_PARAM_CONNECT_DOMAIN_ADDRESS)
{
RS_STACK_MUTEX(mSslMtx);
// a new line must be appended!
mI2pAddr = value + '\n';
return true;
}
return pqissl::connect_parameter(type, value);
}
int pqissli2pbob::Basic_Connection_Complete()
{
int ret;
if ((ret = pqissl::Basic_Connection_Complete()) != 1)
{
// basic connection not complete.
return ret;
}
// send addr. (new line is already appended)
ret = send(sockfd, mI2pAddr.c_str(), mI2pAddr.length(), 0);
if (ret != (int)mI2pAddr.length())
return -1;
return 1;
}

View File

@ -0,0 +1,31 @@
#ifndef PQISSLI2PBOB_H
#define PQISSLI2PBOB_H
#include "pqi/pqissl.h"
/*
* This class is a minimal varied version of pqissl to work with I2P BOB tunnels.
* The only difference is that the [.b32].i2p addresses must be sent first.
*
* Everything else is untouched.
*/
class pqissli2pbob : public pqissl
{
public:
pqissli2pbob(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm)
: pqissl(l, parent, lm) {}
// NetInterface interface
public:
bool connect_parameter(uint32_t type, const std::string &value);
// pqissl interface
protected:
int Basic_Connection_Complete();
private:
std::string mI2pAddr;
};
#endif // PQISSLI2PBOB_H

View File

@ -493,7 +493,7 @@ int pqissllistenbase::continueSSL(IncomingSSLInfo& incoming_connexion_info, bool
#endif
if(x509 != NULL)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
incoming_connexion_info.gpgid = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer)));
incoming_connexion_info.sslcn = getX509CNString(x509->cert_info->subject);
#else
@ -892,7 +892,7 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info)
AuthSSL::getAuthSSL()->CheckCertificate(newPeerId, peercert);
/* now need to get GPG id too */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
RsPgpId pgpid(std::string(getX509CNString(peercert->cert_info->issuer)));
#else
RsPgpId pgpid(std::string(getX509CNString(X509_get_issuer_name(peercert))));

View File

@ -24,6 +24,7 @@
*/
#include "serialiser/rsserializer.h"
#include "services/autoproxy/rsautoproxymonitor.h"
#include "util/rsdebug.h"
#include "pqi/pqisslpersongrp.h"
@ -49,6 +50,7 @@ static struct RsLog::logInfo pqipersongrpzoneInfo = {RsLog::Default, "pqipersong
#endif
#include "pqi/pqisslproxy.h"
#include "pqi/pqissli2pbob.h"
pqilistener * pqisslpersongrp::locked_createListener(const struct sockaddr_storage &laddr)
{
@ -76,29 +78,34 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener
std::cerr << std::endl;
#endif
pqisslproxy *pqis = new pqisslproxy((pqissllistener *) listener, pqip, mLinkMgr);
/* construct the serialiser ....
* Needs:
* * FileItem
* * FileData
* * ServiceGeneric
*/
// Use pqicI2PBOB for I2P
pqiconnect *pqicSOCKSProxy, *pqicI2PBOB;
{
pqisslproxy *pqis = new pqisslproxy((pqissllistener *) listener, pqip, mLinkMgr);
RsSerialiser *rss = new RsSerialiser();
rss->addSerialType(new RsRawSerialiser());
pqicSOCKSProxy = new pqiconnect(pqip, rss, pqis);
}
if (rsAutoProxyMonitor::instance()->isEnabled(autoProxyType::I2PBOB))
{
pqissli2pbob *pqis = new pqissli2pbob((pqissllistener *) listener, pqip, mLinkMgr);
RsSerialiser *rss = new RsSerialiser();
rss->addSerialType(new RsRawSerialiser());
pqicI2PBOB = new pqiconnect(pqip, rss, pqis);
} else {
pqicI2PBOB = pqicSOCKSProxy;
}
RsSerialiser *rss = new RsSerialiser();
rss->addSerialType(new RsRawSerialiser());
pqiconnect *pqisc = new pqiconnect(pqip, rss, pqis);
/* first select type based on peer */
uint32_t typePeer = mPeerMgr->getHiddenType(id);
switch (typePeer) {
case RS_HIDDEN_TYPE_TOR:
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqisc);
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqicSOCKSProxy);
break;
case RS_HIDDEN_TYPE_I2P:
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqisc);
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2PBOB);
break;
default:
/* peer is not a hidden one but we are */
@ -106,7 +113,7 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener
uint32_t typeOwn = mPeerMgr->getHiddenType(AuthSSL::getAuthSSL()->OwnId());
switch (typeOwn) {
case RS_HIDDEN_TYPE_I2P:
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqisc);
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2PBOB);
break;
default:
/* this case shouldn't happen! */
@ -117,7 +124,7 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener
std::cerr << " - hidden types: peer=" << typePeer << " own=" << typeOwn << std::endl;
std::cerr << " --> falling back to Tor" << std::endl;
case RS_HIDDEN_TYPE_TOR:
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqisc);
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqicSOCKSProxy);
break;
}
}

View File

@ -81,7 +81,7 @@ private:
uint32_t mProxyState;
std::string mDomainAddress;
uint16_t mRemotePort;
uint16_t mRemotePort;
};
#endif // MRK_PQI_SSL_PROXY_HEADER

View File

@ -602,7 +602,7 @@ bool getX509id(X509 *x509, RsPeerId& xid)
}
// get the signature from the cert, and copy to the array.
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
ASN1_BIT_STRING *signature = x509->signature;
#else
const ASN1_BIT_STRING *signature = NULL ;
@ -700,7 +700,7 @@ int LoadCheckX509(const char *cert_file, RsPgpId& issuerName, std::string &locat
if (valid)
{
// extract the name.
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
issuerName = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer)));
location = getX509LocString(x509->cert_info->subject);
#else

View File

@ -60,6 +60,8 @@ public:
public:
RsMsgMetaData mMeta;
std::set<RsGxsMessageId> mOlderVersions ;
std::string mMsg; // UTF8 encoded.
std::list<RsGxsFile> mFiles;

View File

@ -0,0 +1,103 @@
#pragma once
#include "retroshare/rstokenservice.h"
#include "retroshare/rsgxsifacehelper.h"
#include "retroshare/rsgxscommon.h"
/// Subservices identifiers (like port for TCP)
enum class GxsTransSubServices : uint16_t
{
UNKNOWN = 0x00,
TEST_SERVICE = 0x01,
P3_MSG_SERVICE = 0x02,
P3_CHAT_SERVICE = 0x03
};
/// Values must fit into uint8_t
enum class GxsTransItemsSubtypes : uint8_t
{
GXS_TRANS_SUBTYPE_MAIL = 0x01,
GXS_TRANS_SUBTYPE_RECEIPT = 0x02,
GXS_TRANS_SUBTYPE_GROUP = 0x03,
OUTGOING_RECORD_ITEM = 0x04
};
enum class GxsTransSendStatus : uint8_t
{
UNKNOWN = 0x00,
PENDING_PROCESSING = 0x01,
PENDING_PREFERRED_GROUP = 0x02,
PENDING_RECEIPT_CREATE = 0x03,
PENDING_RECEIPT_SIGNATURE = 0x04,
PENDING_SERIALIZATION = 0x05,
PENDING_PAYLOAD_CREATE = 0x06,
PENDING_PAYLOAD_ENCRYPT = 0x07,
PENDING_PUBLISH = 0x08,
/** This will be useful so the user can know if the mail reached at least
* some friend node, in case of internet connection interruption */
//PENDING_TRANSFER,
PENDING_RECEIPT_RECEIVE = 0x09,
/// Records with status >= RECEIPT_RECEIVED get deleted
RECEIPT_RECEIVED = 0x0a,
FAILED_RECEIPT_SIGNATURE = 0xf0,
FAILED_ENCRYPTION = 0xf1
};
typedef uint64_t RsGxsTransId;
class RsGxsTransGroup
{
public:
RsGroupMetaData mMeta;
};
class RsGxsTransMsg
{
public:
RsGxsTransMsg() : size(0),data(NULL) {}
virtual ~RsGxsTransMsg() { free(data) ; }
public:
RsMsgMetaData mMeta;
uint32_t size ;
uint8_t *data ;
};
struct RsGxsTransOutgoingRecord
{
GxsTransSendStatus status;
RsGxsId recipient;
RsGxsTransId trans_id;
GxsTransSubServices client_service;
uint32_t data_size ;
Sha1CheckSum data_hash ;
uint32_t send_TS ;
RsGxsGroupId group_id ;
};
class RsGxsTrans: public RsGxsIfaceHelper
{
public:
class GxsTransStatistics
{
public:
GxsTransStatistics() {}
RsGxsGroupId prefered_group_id ;
std::vector<RsGxsTransOutgoingRecord> outgoing_records;
};
RsGxsTrans(RsGxsIface *gxs) : RsGxsIfaceHelper(gxs) {}
virtual ~RsGxsTrans() {}
virtual bool getStatistics(GxsTransStatistics& stats)=0;
// virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsTransGroup> &groups) = 0;
// virtual bool getPostData(const uint32_t &token, std::vector<RsGxsTransMsg> &posts) = 0;
};
extern RsGxsTrans *rsGxsTrans ;

View File

@ -78,7 +78,7 @@ class RsInit
/*!
* Setup Hidden Location;
*/
static bool SetHiddenLocation(const std::string& hiddenaddress, uint16_t port);
static void SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob);
static bool LoadPassword(const std::string& passwd) ;

View File

@ -228,6 +228,7 @@ class NotifyClient
virtual void notifyDiskFull (uint32_t /* location */, uint32_t /* size limit in MB */) {}
virtual void notifyPeerStatusChanged (const std::string& /* peer_id */, uint32_t /* status */) {}
virtual void notifyGxsChange (const RsGxsChanges& /* changes */) {}
virtual void notifyConnectionWithoutCert () {}
/* one or more peers has changed the states */
virtual void notifyPeerStatusChangedSummary () {}

View File

@ -45,6 +45,8 @@ const int p3facemsgzone = 11453;
// TO SHUTDOWN THREADS.
#ifdef RS_ENABLE_GXS
#include "services/autoproxy/rsautoproxymonitor.h"
#include "services/p3idservice.h"
#include "services/p3gxscircles.h"
#include "services/p3wiki.h"
@ -89,6 +91,8 @@ void RsServer::rsGlobalShutDown()
mNetMgr->shutdown(); /* Handles UPnP */
rsAutoProxyMonitor::instance()->stopAllRSShutdown();
fullstop() ;
// kill all registered service threads

View File

@ -46,6 +46,7 @@
class p3heartbeat;
class p3discovery2;
class p3I2pBob;
/* GXS Classes - just declare the classes.
so we don't have to totally recompile to switch */
@ -129,7 +130,7 @@ class RsServer: public RsControl, public RsTickingThread
* This function is responsible for ensuring Retroshare exits in a legal state:
* i.e. releases all held resources and saves current configuration
*/
virtual void rsGlobalShutDown( );
virtual void rsGlobalShutDown( );
/****************************************/
@ -164,6 +165,7 @@ class RsServer: public RsControl, public RsTickingThread
p3ChatService *chatSrv;
p3StatusService *mStatusSrv;
p3GxsTunnelService *mGxsTunnels;
p3I2pBob *mI2pBob;
// This list contains all threaded services. It will be used to shut them down properly.

View File

@ -125,6 +125,8 @@ class RsInitConfig
std::string hiddenNodeAddress;
uint16_t hiddenNodePort;
bool hiddenNodeI2PBOB;
/* Logging */
bool haveLogFile;
bool outStderr;
@ -794,13 +796,13 @@ void RsInit::setAutoLogin(bool autoLogin){
}
/* Setup Hidden Location; */
bool RsInit::SetHiddenLocation(const std::string& hiddenaddress, uint16_t port)
void RsInit::SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob)
{
/* parse the bugger (todo) */
rsInitConfig->hiddenNodeSet = true;
rsInitConfig->hiddenNodeAddress = hiddenaddress;
rsInitConfig->hiddenNodePort = port;
return true;
rsInitConfig->hiddenNodeI2PBOB = useBob;
}
@ -854,7 +856,10 @@ RsGRouter *rsGRouter = NULL ;
#include "upnp/upnphandler_miniupnp.h"
#endif
#endif
#include "services/autoproxy/p3i2pbob.h"
#include "services/autoproxy/rsautoproxymonitor.h"
#include "services/p3gxsreputation.h"
#include "services/p3serviceinfo.h"
#include "services/p3heartbeat.h"
@ -1046,8 +1051,11 @@ int RsServer::StartupRetroShare()
mPeerMgr->setManagers(mLinkMgr, mNetMgr);
mNetMgr->setManagers(mPeerMgr, mLinkMgr);
rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance();
mI2pBob = new p3I2pBob(mPeerMgr);
autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob);
//load all the SSL certs as friends
// std::list<std::string> sslIds;
// AuthSSL::getAuthSSL()->getAuthenticatedList(sslIds);
@ -1261,12 +1269,6 @@ int RsServer::StartupRetroShare()
rsFiles = ftserver;
/* create Cache Services */
std::string config_dir = rsAccounts->PathAccountDirectory();
std::string localcachedir = config_dir + "/cache/local";
std::string remotecachedir = config_dir + "/cache/remote";
std::vector<std::string> plugins_directories ;
#ifdef __APPLE__
@ -1694,6 +1696,7 @@ int RsServer::StartupRetroShare()
//mConfigMgr->addConfiguration("photo.cfg", photo_ns);
//mConfigMgr->addConfiguration("wire.cfg", wire_ns);
#endif
mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob);
mPluginsManager->addConfigurations(mConfigMgr) ;
@ -1739,12 +1742,46 @@ int RsServer::StartupRetroShare()
{
mPeerMgr->setOwnNetworkMode(RS_NET_MODE_EXT);
mPeerMgr->setOwnVisState(RS_VS_DISC_FULL, RS_VS_DHT_FULL);
}
if (rsInitConfig->hiddenNodeSet)
{
mPeerMgr->setupHiddenNode(rsInitConfig->hiddenNodeAddress, rsInitConfig->hiddenNodePort);
std::cout << "RsServer::StartupRetroShare setting up hidden locations" << std::endl;
if (rsInitConfig->hiddenNodeI2PBOB) {
std::cout << "RsServer::StartupRetroShare setting up BOB" << std::endl;
// we need a local port!
mNetMgr->checkNetAddress();
// add i2p proxy
// bob will use this address
sockaddr_storage i2pInstance;
sockaddr_storage_ipv4_aton(i2pInstance, rsInitConfig->hiddenNodeAddress.c_str());
mPeerMgr->setProxyServerAddress(RS_HIDDEN_TYPE_I2P, i2pInstance);
std::string addr; // will be set by auto proxy service
uint16_t port = rsInitConfig->hiddenNodePort; // unused by bob
bool r = autoProxy->initialSetup(autoProxyType::I2PBOB, addr, port);
if (r && !addr.empty()) {
mPeerMgr->setupHiddenNode(addr, port);
// now enable bob
bobSettings bs;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs);
bs.enableBob = true;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs);
} else {
std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl;
/// TODO add notify for failed bob setup
}
} else {
mPeerMgr->setupHiddenNode(rsInitConfig->hiddenNodeAddress, rsInitConfig->hiddenNodePort);
}
std::cout << "RsServer::StartupRetroShare hidden location set up" << std::endl;
}
else if (isHiddenNode)
{
@ -1753,15 +1790,27 @@ int RsServer::StartupRetroShare()
mNetMgr -> checkNetAddress();
if (rsInitConfig->hiddenNodeSet) {
// newly created location
// mNetMgr->checkNetAddress() will setup ports for us
// trigger updates for auto proxy services
std::vector<autoProxyType::autoProxyType_enum> types;
// i2p bob need to rebuild its command map
types.push_back(autoProxyType::I2PBOB);
rsAutoProxyMonitor::taskSync(types, autoProxyTask::reloadConfig);
}
/**************************************************************************/
/* startup (stuff dependent on Ids/peers is after this point) */
/**************************************************************************/
autoProxy->startAll();
pqih->init_listener();
mNetMgr->addNetListener(pqih); /* add listener so we can reset all sockets later */
/**************************************************************************/
/* load caches and secondary data */
/**************************************************************************/
@ -1788,8 +1837,10 @@ int RsServer::StartupRetroShare()
/* Start up Threads */
/**************************************************************************/
#ifdef RS_ENABLE_GXS
// auto proxy threads
startServiceThread(mI2pBob, "I2P-BOB");
#ifdef RS_ENABLE_GXS
// Must Set the GXS pointers before starting threads.
rsIdentity = mGxsIdService;
rsGxsCircles = mGxsCircles;
@ -1799,6 +1850,8 @@ int RsServer::StartupRetroShare()
rsPosted = mPosted;
rsGxsForums = mGxsForums;
rsGxsChannels = mGxsChannels;
rsGxsTrans = mGxsTrans;
//rsPhoto = mPhoto;
//rsWire = mWire;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,250 @@
#ifndef P3I2PBOB_H
#define P3I2PBOB_H
#include <map>
#include <queue>
#include <sys/types.h>
#include <time.h>
#ifndef WINDOWS_SYS
#include <sys/socket.h>
#endif
#include "services/autoproxy/rsautoproxymonitor.h"
#include "util/rsthreads.h"
#include "pqi/p3cfgmgr.h"
/*
* This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS
* to automatically remote control I2P to setup the needed tunnel.
* BOB is a simple text-based interface: https://geti2p.net/en/docs/api/bob
*
* Note 1:
* One tunnel is enough even for hidden locations since it can be used
* bidirectional. (In contrast to what RS I2P users had to set up manually.)
*
* Note 2:
* BOB tunnels are no SOCKS tunnel. Therefore pqissli2pbob implements a simplified
* proxy specially for BOB tunnels.
*
* Note 3:
* BOB needs a unique name as an ID for each tunnel.
* We use 'RetroShare-' + 8 base32 characters.
*
* Design:
* The service uses three state machines to manage its task:
* int stateMachineBOB();
* mBOBState
* int stateMachineController();
* mState
* mTask
*
* stateMachineBOB:
* This state machine manages the low level communication with BOB. It basically has a linked
* list (currently a implemented as a std::map) that contains a command and the next
* state.
* Each high level operation (start up / shut down / get keys) is represented by a
* chain of states. E.g. the chain to retrieve new keys:
* mCommands[bobState::setnickN] = {setnick, bobState::newkeysN};
* mCommands[bobState::newkeysN] = {newkeys, bobState::getkeys};
* mCommands[bobState::getkeys] = {getkeys, bobState::clear};
* mCommands[bobState::clear] = {clear, bobState::quit};
* mCommands[bobState::quit] = {quit, bobState::cleared};
*
* stateMachineController:
* This state machone manages the high level tasks.
* It is controlled by mState and mTask.
*
* mTast:
* Tracks the high level operation (like start up).
* It will keep its value even when a task is done to track
* the requested BOB state.
* When other operations are performed like a conection check
* the last task gets backed up and is later restored again
*
* mState:
* This state lives only for one operation an manages the communication
* with the BOB instance. This is basically connecting, starting BOB
* protocol and disconnecting
*
* How a task looks like:
* 1) RS sets task using the ticket system
* 2) stateMachineController connects to BOBs control port, sets mBobState to a lists head
* 3) stateMachineBOB processes command chain
* 4) stateMachineBOB is done and sets mBobState to cleared signaling that the connection
* is cleared and can be closed
* 5) stateMachineController disconnects from BOBs control port and updates mState
*/
///
/// \brief The controllerState enum
/// States for the controller to keep track of what he is currently doing
enum controllerState {
csIdel,
csDoConnect,
csConnected,
csWaitForBob,
csDoDisconnect,
csDisconnected,
csError
};
///
/// \brief The controllerTask enum
/// This state tracks the controllers tast (e.g. setup a BOB tunnel or shut down
/// an existing one).
enum controllerTask {
ctIdle,
ctRunSetUp,
ctRunShutDown,
ctRunGetKeys,
ctRunCheck
};
///
/// \brief The bobState enum
/// One state for each message
///
enum bobState {
bsCleared,
bsSetnickC, // chain head for only client tunnel
bsSetnickN, // chain head for getting new (server) keys
bsSetnickS, // chain head for client and server tunnel
bsGetnick,
bsNewkeysC, // part of chain for only client tunnel
bsNewkeysN, // part of chain for getting new (server) keys
bsGetkeys,
bsSetkeys,
bsInhost,
bsOuthost,
bsInport,
bsOutport,
bsInlength,
bsOutlength,
bsInvariance,
bsOutvariance,
bsInquantity,
bsOutquantity,
bsQuiet,
bsStart,
bsStop,
bsClear,
bsList, // chain head for 'list' command
bsQuit
};
///
/// \brief The bobStateInfo struct
/// State machine with commands
/// \todo This could be replaced by a linked list instead of a map
struct bobStateInfo {
std::string command;
bobState nextState;
};
struct bobSettings {
bool enableBob; ///< This field is used by the pqi subsystem to determinine whether SOCKS proxy or BOB is used for I2P connections
std::string keys; ///< (optional) server keys
std::string addr; ///< (optional) hidden service addr. in base32 form
int8_t inLength;
int8_t inQuantity;
int8_t inVariance;
int8_t outLength;
int8_t outQuantity;
int8_t outVariance;
};
///
/// \brief The bobStates struct
/// This container struct is used to pass all states.
/// Additionally, the tunnel name is included to to show it in the GUI.
/// The advantage of a struct is that it can be forward declared.
struct bobStates {
bobState bs;
controllerState cs;
controllerTask ct;
std::string tunnelName;
};
class p3PeerMgr;
class p3I2pBob : public RsTickingThread, public p3Config, public autoProxyService
{
public:
p3I2pBob(p3PeerMgr *peerMgr);
// autoProxyService interface
public:
bool isEnabled();
bool initialSetup(std::string &addr, uint16_t &);
void processTaskAsync(taskTicket *ticket);
void processTaskSync(taskTicket *ticket);
static std::string keyToBase32Addr(const std::string &key);
// RsTickingThread interface
public:
void data_tick();
private:
int stateMachineBOB();
int stateMachineBOB_locked_failure(const std::string &answer, const bobStateInfo &currentState);
int stateMachineController();
int stateMachineController_locked_idle();
int stateMachineController_locked_connected();
int stateMachineController_locked_disconnected();
int stateMachineController_locked_error();
// p3Config interface
protected:
RsSerialiser *setupSerialiser();
bool saveList(bool &cleanup, std::list<RsItem *> &lst);
bool loadList(std::list<RsItem *> &load);
private:
// helpers
void getBOBSettings(bobSettings *settings);
void setBOBSettings(const bobSettings *settings);
void getStates(bobStates *bs);
std::string executeCommand(const std::string &command);
bool connectI2P();
bool disconnectI2P();
void finalizeSettings_locked();
void updateSettings_locked();
std::string recv();
// states for state machines
controllerState mState;
controllerTask mTask;
// used to store old state when in error state
// mStateOld is also used as a flag when an error occured in BOB protocol
controllerState mStateOld;
// mTaskOld is used to keep the previous task (start up / shut down) when requesting keys or checking the connection
controllerTask mTaskOld;
bobSettings mSetting;
bobState mBOBState;
// used variables
p3PeerMgr *mPeerMgr;
bool mConfigLoaded;
int mSocket;
time_t mLastProxyCheck;
sockaddr_storage mI2PProxyAddr;
std::map<bobState, bobStateInfo> mCommands;
std::string mErrorMsg;
std::string mTunnelName;
std::queue<taskTicket *> mPending;
taskTicket *mProcessing;
// mutex
RsMutex mLock;
};
#endif // P3I2PBOB_H

View File

@ -0,0 +1,303 @@
#include "rsautoproxymonitor.h"
#include <unistd.h> /* for usleep() */
rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL;
rsAutoProxyMonitor::rsAutoProxyMonitor()
: mRSShutDown(false), mLock("rs auto proxy monitor")
{
mProxies.clear();
}
rsAutoProxyMonitor *rsAutoProxyMonitor::instance()
{
if (mInstance == NULL)
mInstance = new rsAutoProxyMonitor();
return mInstance;
}
void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service)
{
RS_STACK_MUTEX(mLock);
if (mProxies.find(type) != mProxies.end())
std::cerr << "sAutoProxyMonitor::addProxy type " << type << " already added - OVERWRITING" << std::endl;
mProxies[type] = service;
}
void rsAutoProxyMonitor::startAll()
{
// create ticket
taskTicket *tt = getTicket();
tt->cb = this;
tt->task = autoProxyTask::start;
{
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator it;
// fill types
RS_STACK_MUTEX(mLock);
for (it = mProxies.begin(); it != mProxies.end(); ++it)
if (it->second->isEnabled())
tt->types.push_back(it->first);
}
task(tt);
}
void rsAutoProxyMonitor::stopAll()
{
// create ticket
taskTicket *tt = getTicket();
tt->cb = this;
tt->task = autoProxyTask::stop;
{
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator it;
// fill types
RS_STACK_MUTEX(mLock);
for (it = mProxies.begin(); it != mProxies.end(); ++it)
if (it->second->isEnabled())
tt->types.push_back(it->first);
}
task(tt);
}
void rsAutoProxyMonitor::stopAllRSShutdown()
{
{
RS_STACK_MUTEX(mLock);
mRSShutDown = true;
// remove disabled services
std::vector<autoProxyType::autoProxyType_enum> toRemove;
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator it;
for (it = mProxies.begin(); it != mProxies.end(); ++it) {
if (!it->second->isEnabled()) {
toRemove.push_back(it->first);
}
}
std::vector<autoProxyType::autoProxyType_enum>::const_iterator it2;
for (it2 = toRemove.begin(); it2 != toRemove.end(); ++it2) {
mProxies.erase(*it2);
}
}
// stop all remaining
stopAll();
// wait for shutdown of all services
uint32_t t = 0, timeout = 15;
do {
usleep(1000 * 1000);
RS_STACK_MUTEX(mLock);
std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl;
if (mProxies.empty())
break;
t++;
} while (t < timeout );
}
bool rsAutoProxyMonitor::isEnabled(autoProxyType::autoProxyType_enum t)
{
autoProxyService *s = lookUpService(t);
if (s == NULL)
return false;
return s->isEnabled();
}
bool rsAutoProxyMonitor::initialSetup(autoProxyType::autoProxyType_enum t, std::string &addr, uint16_t &port)
{
autoProxyService *s = lookUpService(t);
if (s == NULL)
return false;
return s->initialSetup(addr, port);
}
void rsAutoProxyMonitor::task(taskTicket *ticket)
{
// sanity checks
if (!ticket->async && ticket->types.size() > 1) {
std::cerr << "(WW) rsAutoProxyMonitor::task synchronous call to multiple services. This can cause problems!" << std::endl;
}
if (ticket->async && !ticket->cb && ticket->data) {
std::cerr << "(WW) rsAutoProxyMonitor::task asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl;
}
if (ticket->types.size() > 1 && ticket->data) {
std::cerr << "(WW) rsAutoProxyMonitor::task call with data to multiple services. This will likely causes memory leak!" << std::endl;
}
std::vector<autoProxyType::autoProxyType_enum>::const_iterator it;
for (it = ticket->types.begin(); it != ticket->types.end(); ++it) {
autoProxyService* s = lookUpService(*it);
if (s == NULL)
continue;
if (ticket->async) {
// copy ticket
taskTicket *tt = new taskTicket();
*tt = *ticket;
tt->types.clear();
tt->types.push_back(*it);
s->processTaskAsync(tt);
} else {
s->processTaskSync(ticket);
}
}
}
void rsAutoProxyMonitor::taskAsync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb, void *data)
{
std::vector<autoProxyType::autoProxyType_enum> types;
types.push_back(type);
taskAsync(types, task, cb, data);
}
void rsAutoProxyMonitor::taskAsync(std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb, void *data)
{
if (!isAsyncTask(task)) {
// Usually the services will reject this ticket.
// Just print a warning - maybe there is some special case where this is a good idea.
std::cerr << "(WW) rsAutoProxyMonitor::taskAsync called with a synchronous task!" << std::endl;
}
taskTicket *tt = getTicket();
tt->task = task;
tt->types = types;
if (cb)
tt->cb = cb;
if (data)
tt->data = data;
instance()->task(tt);
// tickets were copied, clean up
delete tt;
}
void rsAutoProxyMonitor::taskSync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, void *data)
{
std::vector<autoProxyType::autoProxyType_enum> types;
types.push_back(type);
taskSync(types, task, data);
}
void rsAutoProxyMonitor::taskSync(std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, void *data)
{
if (isAsyncTask(task)) {
// Usually the services will reject this ticket.
// Just print a warning - maybe there is some special case where this is a good idea.
std::cerr << "(WW) rsAutoProxyMonitor::taskSync called with an asynchronous task!" << std::endl;
}
taskTicket *tt = getTicket();
tt->async = false;
tt->task = task;
tt->types = types;
if (data)
tt->data = data;
instance()->task(tt);
// call done, clean up
delete tt;
}
void rsAutoProxyMonitor::taskError(taskTicket *t)
{
taskDone(t, autoProxyStatus::error);
}
void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatus_enum status)
{
bool cleanUp = false;
t->result = status;
if (t->cb) {
t->cb->taskFinished(t);
if (t != NULL) {
// callack did not clean up properly
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish callback did not clean up!" << std::endl;
cleanUp = true;
}
} else if (t->async){
// async and no callback
// we must take care of deleting
cleanUp = true;
if(t->data)
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish async call with data attached but no callback set!" << std::endl;
}
if (cleanUp) {
if (t->data) {
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish will try to delete void pointer!" << std::endl;
#pragma GCC diagnostic ignored "-Wdelete-incomplete"
delete t->data;
#pragma GCC diagnostic pop
t->data = NULL;
}
delete t;
t = NULL;
}
}
taskTicket *rsAutoProxyMonitor::getTicket()
{
taskTicket *tt = new taskTicket();
tt->cb = NULL;
tt->data = NULL;
tt->async = true;
tt->result = autoProxyStatus::undefined;
return tt;
}
void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket)
{
{
RS_STACK_MUTEX(mLock);
if (mRSShutDown && ticket->task == autoProxyTask::stop) {
mProxies.erase(ticket->types.front());
}
}
// clean up
if (ticket->data) {
std::cerr << "rsAutoProxyMonitor::taskFinished data set. Will try to delete void pointer" << std::endl;
#pragma GCC diagnostic ignored "-Wdelete-incomplete"
delete ticket->data;
#pragma GCC diagnostic pop
ticket->data = NULL;
}
delete ticket;
ticket = NULL;
}
autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType_enum t)
{
RS_STACK_MUTEX(mLock);
std::map<autoProxyType::autoProxyType_enum, autoProxyService*>::const_iterator itService;
if ((itService = mProxies.find(t)) != mProxies.end()) {
return itService->second;
}
std::cerr << "sAutoProxyMonitor::lookUpService no service for type " << t << " found!" << std::endl;
return NULL;
}
bool rsAutoProxyMonitor::isAsyncTask(autoProxyTask::autoProxyTask_enum t)
{
switch (t) {
case autoProxyTask::start:
case autoProxyTask::stop:
case autoProxyTask::receiveKey:
return true;
break;
default:
break;
}
return false;
}

View File

@ -0,0 +1,216 @@
#ifndef RSAUTOPROXYMONITOR_H
#define RSAUTOPROXYMONITOR_H
#include <vector>
#include <map>
#include <util/rsthreads.h>
class autoProxyCallback;
namespace autoProxyType {
enum autoProxyType_enum {
I2PBOB
};
}
namespace autoProxyTask {
enum autoProxyTask_enum {
/* async tasks */
start, ///< start up proxy
stop, ///< shut down proxy
receiveKey, ///< renew proxy key (if any)
proxyStatusCheck, ///< use to check if the proxy is still running
/* sync tasks */
status, ///< get status from auto proxy
getSettings, ///< get setting from auto proxy
setSettings, ///< set setting of auto proxy
reloadConfig, ///< signal config reload/rebuild
getErrorInfo ///< get error information from auto proxy
};
}
namespace autoProxyStatus {
enum autoProxyStatus_enum {
undefined, ///< undefined - usually not yet set
disabled, ///< used when a task cannot be done (e.g. a disabled service cannot be startet or stopped)
offline, ///< proxy is not set up
online, ///< proxy is set up
ok, ///< generic ok
error ///< generic error
};
}
struct taskTicket {
///
/// \brief types auto proxy service types that should get the ticket
///
std::vector<autoProxyType::autoProxyType_enum> types;
///
/// \brief task the task to satisfy
///
autoProxyTask::autoProxyTask_enum task;
///
/// \brief cb (optional) callback that gets called once the task is done
///
autoProxyCallback *cb;
///
/// \brief result (optional) result
///
autoProxyStatus::autoProxyStatus_enum result;
///
/// \brief data (optional) service dependent data
///
/// Needs to be allocated and freed by caller!
///
void *data;
///
/// \brief async is the call Asynchronous
///
/// Will create a copy of the ticket for each
/// service and delete the original ticket.
///
bool async;
};
class autoProxyCallback {
public:
///
/// \brief taskFinished called when a task is finished
/// \param ticket
///
/// Remove everything: ticket and attached data if any!
///
virtual void taskFinished(taskTicket *&ticket) = 0;
};
class autoProxyService {
public:
///
/// \brief isEnabled must be provided to directly get a result without going through the ticket system
/// \return whether the auto proxy service is enabled or not
///
virtual bool isEnabled() = 0;
///
/// \brief initialSetup used when creating a node
/// \param addr new address for the hidden service
/// \param port new port for the hidden service
/// \return true on success
///
/// This function is used to do an initial setup when creating a new hidden node.
/// Nothing has been set up at this point to the auto proxy service must take care
/// of everything (e.g. starting (and stoping) of needed threads)
///
virtual bool initialSetup(std::string &addr, uint16_t &port) = 0;
///
/// \brief processTaskAsync adds a ticket to the auto proxies task list
/// \param ticket
///
/// Don't call the callback in this function as this can cause dead locks!
///
virtual void processTaskAsync(taskTicket *ticket) = 0;
///
/// \brief processTaskSync taskTicket must be satisfied immediately
/// \param ticket
///
virtual void processTaskSync(taskTicket *ticket) = 0;
};
class rsAutoProxyMonitor : autoProxyCallback
{
public:
static rsAutoProxyMonitor *instance();
///
/// \brief addProxy adds a new auto proxy service to the monitor
/// \param type type of the new auto proxy service
/// \param service pointer to the service
///
void addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service);
// global functions
void startAll();
void stopAll();
void stopAllRSShutdown();
bool isEnabled(autoProxyType::autoProxyType_enum t);
// use this when creating a new node
bool initialSetup(autoProxyType::autoProxyType_enum t, std::string &addr, uint16_t &port);
///
/// \brief task Sends a task to all requested services
/// \param ticket Ticket containing required information
///
/// There are two kind of tasks: asyn and sync.
/// All tasks that involve communication with the target program (e.g. I2P or Tor) are asynchronous.
/// All other task are synchronous (e.g. getting settings)
///
///
/// Synchronous:
/// When you want to get the settings from a service you can call task() with a ticket only listing
/// one service and data pointing to the service's settings class/struct. Set async to false so
/// that the service gets your original ticket. Ther service will process the request (get settings)
/// immediately and when the call to task() is done you can access the settings from your ticket.
///
/// When additionally a call back is set the service will also call it. This can cause deadlocks!
///
///
/// Asynchronous:
/// When you want to start up all services or request new keys for all services you can call task() with a list
/// of services and set async to true. When each service has fullfilled the resquest he will
/// use the callback. The original caller ticket will be copied and each call to the callback
/// will use its copy of the original ticket. The attached data is not copied so each service gets
/// the same pointer!
///
///
/// Note:
/// Services should not delet or allocate anything unless no call back is provided and it is an
/// async call. In that case the service should delete the ticket and the attacked data.
/// Otherwise the caller must take care of cleaning up.
/// This class provides two wrappers to take care of this that should be used: taskError and taskDone
///
/// Note2:
/// This function is private so that each user must use the wrappers taskAsync and taskSync that include
/// more sanity checks
///
private:
void task(taskTicket *ticket);
public:
static void taskAsync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb = NULL, void *data = NULL);
static void taskAsync(std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb = NULL, void *data = NULL);
static void taskSync (autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, void *data = NULL);
static void taskSync (std::vector<autoProxyType::autoProxyType_enum> types, autoProxyTask::autoProxyTask_enum task, void *data = NULL);
// usefull helpers
static void taskError(taskTicket *t);
static void taskDone(taskTicket *t, autoProxyStatus::autoProxyStatus_enum status);
static taskTicket *getTicket();
// autoProxyCallback interface
public:
void taskFinished(taskTicket *&ticket);
private:
rsAutoProxyMonitor();
autoProxyService *lookUpService(autoProxyType::autoProxyType_enum t);
static bool isAsyncTask(autoProxyTask::autoProxyTask_enum t);
std::map<autoProxyType::autoProxyType_enum, autoProxyService*> mProxies;
bool mRSShutDown;
RsMutex mLock;
static rsAutoProxyMonitor *mInstance;
};
#endif // RSAUTOPROXYMONITOR_H

View File

@ -2259,7 +2259,7 @@ void p3MsgService::sendDistantMsgItem(RsMsgItem *msgitem)
msg_serialized_data, msg_serialized_rssize,
signing_key_id, grouter_message_id );
RsGxsTransId gxsMailId;
mGxsTransServ.sendMail( gxsMailId, GxsTransSubServices::P3_MSG_SERVICE,
mGxsTransServ.sendData( gxsMailId, GxsTransSubServices::P3_MSG_SERVICE,
signing_key_id, destination_key_id,
msg_serialized_data, msg_serialized_rssize );

View File

@ -90,7 +90,7 @@ static int clear_tou_socket_error(int s);
#include "tou.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
//static void BIO_set_shutdown(BIO *a,int s) { a->shutdown=s; }
static int BIO_get_shutdown(BIO *a) { return a->shutdown; }

View File

@ -0,0 +1,50 @@
#ifndef RADIX32_H
#define RADIX32_H
#include <string>
#include <string.h>
#include <vector>
#include <stdint.h>
class Radix32
{
public:
static std::string encode(const std::vector<uint8_t> &in) {
return encode(in.data(), in.size());
}
static std::string encode(const uint8_t *data, size_t len) {
std::string out = "";
size_t pos = 1;
uint8_t bits = 8, index;
uint16_t tmp = data[0]; // need min. 16 bits here
while (bits > 0 || pos < len) {
if (bits < 5) {
if (pos < len) {
tmp <<= 8;
tmp |= data[pos++] & 0xFF;
bits += 8;
} else { // last byte
tmp <<= (5 - bits);
bits = 5;
}
}
bits -= 5;
index = (tmp >> bits) & 0x1F;
out.push_back(bintoasc()[index]);
}
// append padding
while(out.length() % 4 != 0)
out.push_back('=');
return out;
}
private:
static const inline char *bintoasc() { static const char bta[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; return bta ; }
};
#endif // RADIX32_H

View File

@ -57,6 +57,10 @@
#include <errno.h>
#endif
#ifndef __GLIBC__
#define canonicalize_file_name(p) realpath(p, NULL)
#endif
/****
* #define RSDIR_DEBUG 1
****/

View File

@ -126,3 +126,24 @@ std::string RsUtil::HashId(const std::string &id, bool reverse)
// out << std::setprecision(15) << getCurrentTS();
// return out.str();
//}
std::vector<uint8_t> RsUtil::BinToSha256(const std::vector<uint8_t> &in)
{
std::vector<uint8_t> out;
SHA256_CTX *sha_ctx = new SHA256_CTX;
uint8_t sha_hash[SHA256_DIGEST_LENGTH] = {0};
SHA256_Init(sha_ctx);
SHA256_Update(sha_ctx, in.data(), in.size());
SHA256_Final(sha_hash, sha_ctx);
for(uint16_t i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
out.push_back(sha_hash[i]);
}
/* cleanup */
delete sha_ctx;
return out;
}

View File

@ -30,6 +30,7 @@
#include <inttypes.h>
#include <string>
#include <vector>
namespace RsUtil {
@ -38,6 +39,7 @@ std::string BinToHex(const char *arr, const uint32_t len);
std::string BinToHex(const unsigned char *arr, const uint32_t len);
std::string NumberToString(uint64_t n, bool hex=false);
std::string HashId(const std::string &id, bool reverse = false);
std::vector<uint8_t> BinToSha256(const std::vector<uint8_t> &in);
//std::string AccurateTimeString();

View File

@ -508,7 +508,7 @@ bool RsRecogn::itemToRadix64(RsItem *item, std::string &radstr)
std::string RsRecogn::getRsaKeyId(RSA *pubkey)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
int len = BN_num_bytes(pubkey -> n);
unsigned char tmp[len];
BN_bn2bin(pubkey -> n, tmp);

View File

@ -61,6 +61,16 @@ int RS_pthread_setname_np(pthread_t __target_thread, const char *__buf) {
#include <iostream>
#endif
void RsThread::go()
{
mShouldStopSemaphore.set(0) ;
mHasStoppedSemaphore.set(0) ;
runloop();
mHasStoppedSemaphore.set(1);
mShouldStopSemaphore.set(0);
}
void *RsThread::rsthread_init(void* p)
{
RsThread *thread = (RsThread *) p;
@ -76,7 +86,7 @@ void *RsThread::rsthread_init(void* p)
std::cerr << "[Thread ID:" << std::hex << pthread_self() << std::dec << "] thread is started. Calling runloop()..." << std::endl;
#endif
thread -> runloop();
thread->go();
return NULL;
}
RsThread::RsThread()
@ -216,14 +226,11 @@ RsTickingThread::RsTickingThread()
void RsSingleJobThread::runloop()
{
mHasStoppedSemaphore.set(0) ;
run() ;
}
void RsTickingThread::runloop()
{
mHasStoppedSemaphore.set(0) ; // first time we are 100% the thread is actually running.
#ifdef DEBUG_THREADS
THREAD_DEBUG << "RsTickingThread::runloop(). Setting stopped=0" << std::endl;
#endif
@ -235,7 +242,6 @@ void RsTickingThread::runloop()
#ifdef DEBUG_THREADS
THREAD_DEBUG << "pqithreadstreamer::runloop(): asked to stop. setting hasStopped=1, and returning. Thread ends." << std::endl;
#endif
mHasStoppedSemaphore.set(1);
return ;
}

View File

@ -263,6 +263,7 @@ class RsThread
protected:
virtual void runloop() =0; /* called once the thread is started. Should be overloaded by subclasses. */
void go() ; // this one calls runloop and also sets the flags correctly when the thread is finished running.
RsSemaphore mHasStoppedSemaphore;
RsSemaphore mShouldStopSemaphore;

View File

@ -25,7 +25,7 @@
#include <stdio.h>
#if !defined(WINDOWS_SYS) && !defined(__ANDROID__)
#if defined(__linux__) && defined(__GLIBC__)
#include <stdlib.h>
#include <execinfo.h>
@ -110,13 +110,13 @@ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames
free(symbollist);
}
#else // !defined(WINDOWS_SYS) && !defined(__ANDROID__)
#else // defined(__linux__) && defined(__GLIBC__)
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
(void) max_frames;
fprintf(out, "TODO: 2016/01/01 print_stacktrace not implemented yet for WINDOWS_SYS and ANDROID\n");
}
#endif // !defined(WINDOWS_SYS) && !defined(__ANDROID__)
#endif // defined(__linux__) && defined(__GLIBC__)
#endif // _STACKTRACE_H_

View File

@ -45,7 +45,7 @@ void test_secret_key(const ops_secret_key_t *skey)
{
RSA* test=RSA_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
test->n=BN_dup(skey->public_key.key.rsa.n);
test->e=BN_dup(skey->public_key.key.rsa.e);
test->d=BN_dup(skey->key.rsa.d);
@ -402,7 +402,7 @@ ops_boolean_t ops_dsa_verify(const unsigned char *hash,size_t hash_length,
osig=DSA_SIG_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
osig->r=sig->r;
osig->s=sig->s;
#else
@ -417,7 +417,7 @@ ops_boolean_t ops_dsa_verify(const unsigned char *hash,size_t hash_length,
already_said=ops_true ;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
osig->r=NULL; // in this case, the values are not copied.
osig->s=NULL;
#endif
@ -427,7 +427,7 @@ ops_boolean_t ops_dsa_verify(const unsigned char *hash,size_t hash_length,
}
odsa=DSA_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
odsa->p=dsa->p;
odsa->q=dsa->q;
odsa->g=dsa->g;
@ -471,7 +471,7 @@ ops_boolean_t ops_dsa_verify(const unsigned char *hash,size_t hash_length,
return ops_false ;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
osig->r=NULL;
osig->s=NULL;
@ -503,7 +503,7 @@ int ops_rsa_public_decrypt(unsigned char *out,const unsigned char *in,
int n;
orsa=RSA_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=rsa->n;
orsa->e=rsa->e;
#else
@ -512,7 +512,7 @@ int ops_rsa_public_decrypt(unsigned char *out,const unsigned char *in,
n=RSA_public_decrypt(length,in,out,orsa,RSA_NO_PADDING);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=orsa->e=NULL;
#endif
RSA_free(orsa);
@ -538,7 +538,7 @@ int ops_rsa_private_encrypt(unsigned char *out,const unsigned char *in,
int n;
orsa=RSA_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=rsa->n; // XXX: do we need n?
orsa->d=srsa->d;
orsa->p=srsa->q;
@ -564,7 +564,7 @@ int ops_rsa_private_encrypt(unsigned char *out,const unsigned char *in,
n=RSA_private_encrypt(length,in,out,orsa,RSA_NO_PADDING);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=orsa->d=orsa->p=orsa->q=NULL;
orsa->e=NULL;
#endif
@ -592,7 +592,7 @@ int ops_rsa_private_decrypt(unsigned char *out,const unsigned char *in,
char errbuf[1024];
orsa=RSA_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=rsa->n; // XXX: do we need n?
orsa->d=srsa->d;
orsa->p=srsa->q;
@ -618,7 +618,7 @@ int ops_rsa_private_decrypt(unsigned char *out,const unsigned char *in,
ERR_error_string(err,&errbuf[0]);
fprintf(stderr,"openssl error : %s\n",errbuf);
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=orsa->d=orsa->p=orsa->q=NULL;
orsa->e=NULL;
#endif
@ -644,7 +644,7 @@ int ops_rsa_public_encrypt(unsigned char *out,const unsigned char *in,
// printf("ops_rsa_public_encrypt: length=%ld\n", length);
orsa=RSA_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=rsa->n;
orsa->e=rsa->e;
#else
@ -664,7 +664,7 @@ int ops_rsa_public_encrypt(unsigned char *out,const unsigned char *in,
BIO_free(fd_out) ;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
orsa->n=orsa->e=NULL;
#endif
RSA_free(orsa);
@ -744,7 +744,7 @@ ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e,
skey->public_key.days_valid=0;
skey->public_key.algorithm= OPS_PKA_RSA;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
skey->public_key.key.rsa.n=BN_dup(rsa->n);
skey->public_key.key.rsa.e=BN_dup(rsa->e);
skey->key.rsa.d=BN_dup(rsa->d);
@ -766,7 +766,7 @@ ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e,
skey->octet_count=0;
skey->checksum=0;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
skey->key.rsa.p=BN_dup(rsa->p);
skey->key.rsa.q=BN_dup(rsa->q);
skey->key.rsa.u=BN_mod_inverse(NULL,rsa->p, rsa->q, ctx);
@ -888,7 +888,7 @@ DSA_SIG* ops_dsa_sign(unsigned char* hashbuf, unsigned hashsize, const ops_dsa_s
DSA_SIG *dsasig;
odsa=DSA_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
odsa->p=dsa->p;
odsa->q=dsa->q;
odsa->g=dsa->g;
@ -901,7 +901,7 @@ DSA_SIG* ops_dsa_sign(unsigned char* hashbuf, unsigned hashsize, const ops_dsa_s
dsasig=DSA_do_sign(hashbuf,hashsize,odsa);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
odsa->p=odsa->q=odsa->g=odsa->pub_key=odsa->priv_key=NULL;
#endif
DSA_free(odsa);

View File

@ -298,7 +298,7 @@ static ops_boolean_t dsa_sign(ops_hash_t *hash, const ops_dsa_public_key_t *dsa,
dsasig=ops_dsa_sign(hashbuf, hashsize, sdsa, dsa);
// convert and write the sig out to memory
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
ops_write_mpi(dsasig->r, cinfo);
ops_write_mpi(dsasig->s, cinfo);
#else

View File

@ -149,6 +149,8 @@ GenCertDialog::GenCertDialog(bool onlyGenerateIdentity, QWidget *parent)
connect(ui.node_input, SIGNAL(textChanged(QString)), this, SLOT(updateCheckLabels()));
connect(ui.reuse_existing_node_CB, SIGNAL(toggled(bool)), this, SLOT(updateCheckLabels()));
connect(ui.cbUseBob, SIGNAL(clicked(bool)), this, SLOT(useBobChecked(bool)));;
entropy_timer = new QTimer ;
entropy_timer->start(20) ;
QObject::connect(entropy_timer,SIGNAL(timeout()),this,SLOT(grabMouse())) ;
@ -161,12 +163,12 @@ GenCertDialog::GenCertDialog(bool onlyGenerateIdentity, QWidget *parent)
ui.keylength_comboBox->addItem("Very high (4096 bits)", QVariant(4096));
#if QT_VERSION >= 0x040700
ui.node_input->setPlaceholderText(tr("[Required] Examples: Home, Laptop,...(Visible to friends).")) ;
ui.hiddenaddr_input->setPlaceholderText(tr("[Optional] Tor/I2P address (Example: xa76giaf6ifda7ri63i263.onion)")) ;
ui.name_input->setPlaceholderText(tr("[Required] Visible to friends, and friends of friends."));
ui.nickname_input->setPlaceholderText(tr("[Optional] Used to write in chat rooms and forums. Can be set later."));
ui.password_input->setPlaceholderText(tr("[Required] This password protects your data. Dont forget it!"));
ui.password_input_2->setPlaceholderText(tr("[Required] Type the same password again here."));
ui.node_input->setPlaceholderText(tr("Node name")) ;
ui.hiddenaddr_input->setPlaceholderText(tr("Tor/I2P address")) ;
ui.name_input->setPlaceholderText(tr("Username"));
ui.nickname_input->setPlaceholderText(tr("Identity name"));
ui.password_input->setPlaceholderText(tr("Password"));
ui.password_input_2->setPlaceholderText(tr("Password again"));
#endif
ui.nickname_input->setMaxLength(RSID_MAXIMUM_NICKNAME_SIZE);
@ -240,7 +242,7 @@ void GenCertDialog::mouseMoveEvent(QMouseEvent *e)
void GenCertDialog::setupState()
{
bool adv_state = ui.adv_checkbox->isChecked();
bool adv_state = ui.adv_checkbox->isChecked();
if(!adv_state)
{
@ -294,12 +296,13 @@ void GenCertDialog::setupState()
ui.entropy_bar->setVisible(true);
ui.genButton->setVisible(true);
ui.genButton->setText(generate_new?tr("Generate new profile and node"):tr("Generate new node"));
ui.genButton->setText(generate_new?tr("Generate"):tr("Generate"));
ui.hiddenaddr_input->setVisible(hidden_state);
ui.hiddenaddr_label->setVisible(hidden_state);
ui.hiddenport_label->setVisible(hidden_state);
ui.hiddenport_spinBox->setVisible(hidden_state);
ui.cbUseBob->setVisible(hidden_state);
if(mEntropyOk && mAllFieldsOk)
{
@ -379,7 +382,22 @@ void GenCertDialog::updateCheckLabels()
else
ui.randomness_check_LB->setPixmap(QPixmap(IMAGE_BAD)) ;
setupState();
setupState();
}
void GenCertDialog::useBobChecked(bool checked)
{
if (checked) {
ui.hiddenaddr_input->setPlaceholderText(tr("I2P instance address with BOB enabled"));
ui.hiddenaddr_label->setText(tr("I2P instance address"));
ui.hiddenport_spinBox->setEnabled(false);
} else {
ui.hiddenaddr_input->setPlaceholderText(tr("hidden service address"));
ui.hiddenaddr_label->setText(tr("hidden address"));
ui.hiddenport_spinBox->setEnabled(true);
}
}
bool GenCertDialog::importIdentity()
@ -454,15 +472,13 @@ void GenCertDialog::genPerson()
{
std::string hl = ui.hiddenaddr_input->text().toStdString();
uint16_t port = ui.hiddenport_spinBox->value();
if (!RsInit::SetHiddenLocation(hl, port)) /* parses it */
{
/* Message Dialog */
QMessageBox::warning(this,
tr("Invalid hidden node"),
tr("Please enter a valid address of the form: 31769173498.onion:7800 or [52 characters].b32.i2p"),
QMessageBox::Ok);
return;
}
bool useBob = ui.cbUseBob->isChecked();
if (useBob && hl.empty())
hl = "127.0.0.1";
RsInit::SetHiddenLocation(hl, port, useBob); /* parses it */
isHiddenLoc = true;
}

View File

@ -45,6 +45,7 @@ private slots:
void switchReuseExistingNode();
void grabMouse();
void updateCheckLabels();
void useBobChecked(bool checked);
private:
void initKeyList();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>533</width>
<height>544</height>
<width>520</width>
<height>541</height>
</rect>
</property>
<property name="windowTitle">
@ -34,13 +34,16 @@
<number>0</number>
</property>
<item>
<widget class="QFrame" name="frame">
<widget class="QFrame" name="profileframe">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
@ -48,13 +51,16 @@
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>9</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="images.qrc">:/images/logo/logo_spash2.png</pixmap>
<pixmap resource="images.qrc">:/images/logo/logo_web_nobackground.png</pixmap>
</property>
<property name="scaledContents">
<bool>false</bool>
@ -105,19 +111,63 @@
</layout>
</item>
<item>
<widget class="QFrame" name="profile_frame">
<widget class="QGroupBox" name="profile_groupBox">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>24</number>
</property>
<property name="topMargin">
<number>24</number>
</property>
<property name="rightMargin">
<number>24</number>
</property>
<property name="bottomMargin">
<number>24</number>
</property>
<item row="0" column="0">
<layout class="QGridLayout" name="profilGLayout">
<item row="14" column="2">
<widget class="QComboBox" name="keylength_comboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>PGP Key Length</string>
</property>
<property name="accessibleDescription">
<string/>
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QLabel" name="randomness_label_">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/randomness.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QLabel" name="password_check_LB">
<property name="text">
@ -125,17 +175,7 @@
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="keylength_label">
<property name="text">
<string>PGP key length</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="9" column="2">
<item row="8" column="2">
<widget class="QLineEdit" name="password_input_2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
@ -163,42 +203,6 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="password_label">
<property name="toolTip">
<string>This password is for PGP</string>
</property>
<property name="text">
<string>Password</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="15" column="2">
<widget class="QComboBox" name="keylength_comboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="password_label_2">
<property name="toolTip">
<string>This password is for PGP</string>
</property>
<property name="text">
<string>Password (check)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="18" column="2">
<widget class="QProgressBar" name="entropy_bar">
<property name="sizePolicy">
@ -229,7 +233,7 @@
</property>
</widget>
</item>
<item row="16" column="2">
<item row="15" column="2">
<widget class="QComboBox" name="nodeType_CB">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -271,16 +275,6 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="node_label">
<property name="text">
<string>Node name</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="profile_name_check_LB">
<property name="text">
@ -365,7 +359,7 @@
</item>
</layout>
</item>
<item row="9" column="3">
<item row="8" column="3">
<widget class="QLabel" name="password2_check_LB">
<property name="text">
<string/>
@ -394,46 +388,6 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="name_label">
<property name="text">
<string>Profile name</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Randomness</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="label_nodeType">
<property name="text">
<string>Node type</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QLabel" name="hiddenaddr_label">
<property name="text">
<string>hidden address</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="17" column="2">
<layout class="QHBoxLayout" name="hiddenInfoHLayout">
<property name="spacing">
@ -496,22 +450,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbUseBob">
<property name="text">
<string>Use BOB</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="10" column="0">
<widget class="QLabel" name="nickname_label">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Chat identity</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="10" column="2">
<item row="9" column="2">
<widget class="QLineEdit" name="nickname_input">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -564,6 +512,191 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="name_label">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/person.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="nickname_label">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/chat-lobbies.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="node_label">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/network.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="keylength_label">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/keyring.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="password_label_2">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>This password is for PGP</string>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/password.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="password_label">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>This password is for PGP</string>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/password.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="hiddenaddr_label">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/hidden.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_nodeType">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/netgraph.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -1403,7 +1403,7 @@ void NewsFeed::openChat(const RsPeerId &peerId)
ChatDialog::chatFriend(ChatId(peerId));
}
void NewsFeed::openComments(uint32_t /*type*/, const RsGxsGroupId &/*groupId*/, const RsGxsMessageId &/*msgId*/, const QString &/*title*/)
void NewsFeed::openComments(uint32_t /*type*/, const RsGxsGroupId &/*groupId*/, const QVector<RsGxsMessageId>& versions,const RsGxsMessageId &/*msgId*/, const QString &/*title*/)
{
std::cerr << "NewsFeed::openComments() Not Handled Yet";
std::cerr << std::endl;

View File

@ -58,7 +58,7 @@ public:
virtual QScrollArea *getScrollArea();
virtual void deleteFeedItem(QWidget *item, uint32_t type);
virtual void openChat(const RsPeerId& peerId);
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const RsGxsMessageId &msgId, const QString &title);
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector<RsGxsMessageId> &versions, const RsGxsMessageId &msgId, const QString &title);
static void testFeeds(uint notifyFlags);
static void testFeed(FeedNotify *feedNotify);

View File

@ -411,7 +411,13 @@ void PostedItem::loadComments()
if (mFeedHolder)
{
QString title = QString::fromUtf8(mPost.mMeta.mMsgName.c_str());
mFeedHolder->openComments(0, mPost.mMeta.mGroupId, mPost.mMeta.mMsgId, title);
#warning (csoler) Posted item versions not handled yet. When it is the case, start here.
QVector<RsGxsMessageId> post_versions ;
post_versions.push_back(mPost.mMeta.mMsgId) ;
mFeedHolder->openComments(0, mPost.mMeta.mGroupId, post_versions,mPost.mMeta.mMsgId, title);
}
}

View File

@ -139,9 +139,9 @@ void PostedListWidget::openChat(const RsPeerId & /*peerId*/)
return;
}
void PostedListWidget::openComments(uint32_t /*feed_type*/, const RsGxsGroupId &groupId, const RsGxsMessageId &msgId, const QString &title)
void PostedListWidget::openComments(uint32_t /*feed_type*/, const RsGxsGroupId &groupId, const QVector<RsGxsMessageId> &versions, const RsGxsMessageId &msgId, const QString &title)
{
emit loadComment(groupId, msgId, title);
emit loadComment(groupId, versions,msgId, title);
}
void PostedListWidget::newPost()

View File

@ -52,7 +52,7 @@ public:
virtual QScrollArea *getScrollArea();
virtual void deleteFeedItem(QWidget *item, uint32_t type);
virtual void openChat(const RsPeerId& peerId);
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const RsGxsMessageId &msgId, const QString &title);
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector<RsGxsMessageId> &versions, const RsGxsMessageId &msgId, const QString &title);
/* GXS functions */
virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>516</width>
<height>569</height>
<width>440</width>
<height>350</height>
</rect>
</property>
<property name="windowTitle">
@ -17,7 +17,10 @@
<iconset resource="images.qrc">
<normaloff>:/images/logo/logo_32.png</normaloff>:/images/logo/logo_32.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="StartDialogVLayout">
<property name="leftMargin">
<number>0</number>
</property>
@ -31,296 +34,324 @@
<number>0</number>
</property>
<item>
<layout class="QGridLayout" name="mainGLayout">
<property name="leftMargin">
<number>0</number>
<widget class="QFrame" name="loginframe">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="rightMargin">
<number>0</number>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="bottomMargin">
<number>0</number>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<item row="0" column="0" colspan="4">
<layout class="QGridLayout" name="topGLayout">
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QLabel" name="rsTopLogo">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>118</red>
<green>116</green>
<blue>108</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="images.qrc">:/images/logo/logo_spash2.png</pixmap>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>48</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="2" rowspan="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>60</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" rowspan="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>60</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QGroupBox" name="profilGBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="loginframeGLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item row="0" column="0" colspan="4">
<layout class="QGridLayout" name="topGLayout">
<property name="leftMargin">
<number>9</number>
<number>16</number>
</property>
<property name="topMargin">
<number>16</number>
</property>
<property name="rightMargin">
<number>16</number>
</property>
<property name="bottomMargin">
<number>16</number>
</property>
<item row="0" column="0">
<spacer name="topLHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Profile - Location:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="maximumSize">
<widget class="QLabel" name="rsTopLogo">
<property name="minimumSize">
<size>
<width>22</width>
<height>22</height>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>85</red>
<green>170</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>118</red>
<green>116</green>
<blue>108</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/person.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="loadName"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/password.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="password_input">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
<property name="placeholderText">
<string>Password</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="autologin_checkbox">
<property name="text">
<string>Remember Password</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="loadButton">
<property name="font">
<font>
<pointsize>12</pointsize>
<pointsize>18</pointsize>
</font>
</property>
<property name="text">
<string>Log In</string>
<string/>
</property>
<property name="default">
<bool>true</bool>
<property name="pixmap">
<pixmap resource="images.qrc">:/images/logo/logo_web_nobackground.png</pixmap>
</property>
<property name="flat">
<bool>false</bool>
</widget>
</item>
<item row="0" column="2">
<spacer name="topRHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="2" rowspan="2">
<spacer name="profileRHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0" colspan="3">
<spacer name="mainVSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" rowspan="2">
<spacer name="profileLHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QGroupBox" name="profilGBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="profilGBoxGLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="loadName_label">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/person.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="loadName"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="password_label">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/icons/svg/password.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="password_input">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
<property name="placeholderText">
<string>Password</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="autologin_checkbox">
<property name="text">
<string>Remember Password</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="loadButton">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Log In</string>
</property>
<property name="default">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="newHLayout">
<item>
<spacer name="newHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="labelProfile">
<property name="toolTip">
<string>Opens a dialog for creating a new profile or
adding locations to an existing profile.
The current identities/locations will not be affected.</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;Create new Profile...&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;&quot;&gt;New Profile/Node&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="labelProfile">
<property name="toolTip">
<string>Opens a dialog for creating a new profile or
adding locations to an existing profile.
The current identities/locations will not be affected.</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;Create new Profile...&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;&quot;&gt;Manage profiles and nodes...&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>

View File

@ -73,7 +73,7 @@
*****/
ChatWidget::ChatWidget(QWidget *parent) :
QWidget(parent), ui(new Ui::ChatWidget)
QWidget(parent), sendingBlocked(false), ui(new Ui::ChatWidget)
{
ui->setupUi(this);
@ -416,9 +416,20 @@ ChatWidget::ChatType ChatWidget::chatType()
return CHATTYPE_UNKNOWN;
}
void ChatWidget::blockSending(QString msg) { ui->sendButton->setToolTip(msg); }
void ChatWidget::blockSending(QString msg)
{
#ifndef RS_ASYNC_CHAT
sendingBlocked = true;
ui->sendButton->setEnabled(false);
#endif
ui->sendButton->setToolTip(msg);
}
void ChatWidget::unblockSending() { updateLenOfChatTextEdit(); }
void ChatWidget::unblockSending()
{
sendingBlocked = false;
updateLenOfChatTextEdit();
}
void ChatWidget::processSettings(bool load)
{
@ -1130,6 +1141,8 @@ void ChatWidget::updateStatusTyping()
void ChatWidget::updateLenOfChatTextEdit()
{
if(sendingBlocked) return;
QTextEdit *chatWidget = ui->chatTextEdit;
QString text;
RsHtml::optimizeHtml(chatWidget, text);
@ -1429,7 +1442,8 @@ void ChatWidget::colorChanged()
void ChatWidget::chooseFont()
{
bool ok;
QFont font = QFontDialog::getFont(&ok, currentFont, this);
//Use NULL as parent as with this QFontDialog don't take care of title nether options.
QFont font = QFontDialog::getFont(&ok, currentFont, NULL, tr("Choose your font."),QFontDialog::DontUseNativeDialog);
if (ok) {
currentFont = font;
setFont();

View File

@ -36,7 +36,6 @@
#include <retroshare/rsmsgs.h>
#include <retroshare/rsfiles.h>
#include <util/rsdeprecate.h>
class QAction;
class QTextEdit;
@ -79,8 +78,9 @@ public:
ChatId getChatId();
ChatType chatType();
RS_DEPRECATED void blockSending(QString msg);
RS_DEPRECATED void unblockSending();
// allow/disallow sendng of messages
void blockSending(QString msg);
void unblockSending();
bool hasNewMessages() { return newMessages; }
bool isTyping() { return typing; }
@ -216,6 +216,8 @@ private:
bool typing;
int peerStatus;
bool sendingBlocked;
time_t lastStatusSendTime;
ChatStyle chatStyle;

View File

@ -37,7 +37,7 @@ public:
virtual QScrollArea *getScrollArea() = 0;
virtual void deleteFeedItem(QWidget *item, uint32_t type) = 0;
virtual void openChat(const RsPeerId& peerId) = 0;
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const RsGxsMessageId &msgId, const QString &title) = 0;
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector<RsGxsMessageId> &msg_versions, const RsGxsMessageId &msgId, const QString &title)=0;
// Workaround for QTBUG-3372
void lockLayout(QWidget *feedItem, bool lock);

View File

@ -35,6 +35,7 @@
#include "util/HandleRichText.h"
#include "util/DateTime.h"
#include "util/stringutil.h"
#include "gui/gxschannels/CreateGxsChannelMsg.h"
#include <iostream>
@ -63,9 +64,25 @@ GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId,
std::cerr << std::endl;
#endif
QVector<RsGxsMessageId> v;
bool self = false;
for(std::set<RsGxsMessageId>::const_iterator it(post.mOlderVersions.begin());it!=post.mOlderVersions.end();++it)
{
if(*it == post.mMeta.mMsgId)
self = true ;
v.push_back(*it) ;
}
if(!self)
v.push_back(post.mMeta.mMsgId);
setMessageVersions(v) ;
setup();
setGroup(group, false);
//setGroup(group, false);
requestGroup();
setPost(post);
requestComment();
}
@ -127,6 +144,7 @@ void GxsChannelPostItem::setup()
connect(ui->commentButton, SIGNAL(clicked()), this, SLOT(loadComments()));
connect(ui->playButton, SIGNAL(clicked()), this, SLOT(play(void)));
connect(ui->editButton, SIGNAL(clicked()), this, SLOT(edit(void)));
connect(ui->copyLinkButton, SIGNAL(clicked()), this, SLOT(copyMessageLink()));
connect(ui->readButton, SIGNAL(toggled(bool)), this, SLOT(readToggled(bool)));
@ -166,6 +184,12 @@ bool GxsChannelPostItem::setGroup(const RsGxsChannelGroup &group, bool doFill)
mGroup = group;
// if not publisher, hide the edit button. Without the publish key, there's no way to edit a message.
std::cerr << "Group subscribe flags = " << std::hex << mGroup.mMeta.mSubscribeFlags << std::dec << std::endl;
if(!IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags))
ui->editButton->hide();
if (doFill) {
fill();
}
@ -301,7 +325,7 @@ void GxsChannelPostItem::loadComment(const uint32_t &token)
if (comNb == 1) {
sComButText = sComButText.append("(1)");
} else if (comNb > 1) {
sComButText = tr("Comments").append("(%1)").arg(comNb);
sComButText = tr("Comments ").append("(%1)").arg(comNb);
}
ui->commentButton->setText(sComButText);
}
@ -690,6 +714,12 @@ void GxsChannelPostItem::download()
updateItem();
}
void GxsChannelPostItem::edit()
{
CreateGxsChannelMsg *msgDialog = new CreateGxsChannelMsg(mGroup.mMeta.mGroupId,mPost.mMeta.mMsgId);
msgDialog->show();
}
void GxsChannelPostItem::play()
{
std::list<SubFileItem *>::iterator it;

View File

@ -78,6 +78,7 @@ private slots:
void readAndClearItem();
void download();
void play();
void edit();
void loadComments();
void readToggled(bool checked);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>840</width>
<height>180</height>
<width>1052</width>
<height>338</height>
</rect>
</property>
<layout class="QGridLayout" name="gxsChannelPostItem_GLayout">
@ -332,6 +332,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editButton">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">

View File

@ -97,11 +97,12 @@ SubFileItem::SubFileItem(const RsFileHash &hash, const std::string &name, const
void SubFileItem::Setup()
{
connect( playButton, SIGNAL( clicked( void ) ), this, SLOT( play ( void ) ) );
connect( downloadButton, SIGNAL( clicked( void ) ), this, SLOT( download ( void ) ) );
connect( cancelButton, SIGNAL( clicked( void ) ), this, SLOT( cancel ( void ) ) );
connect( copyLinkButton, SIGNAL( clicked( void ) ), this, SLOT( copyLink ( void ) ) );
connect( saveButton, SIGNAL( clicked( void ) ), this, SLOT( save ( void ) ) );
connect( playButton, SIGNAL( clicked( ) ), this, SLOT( play ( ) ) );
connect( downloadButton, SIGNAL( clicked( ) ), this, SLOT( download ( ) ) );
connect( cancelButton, SIGNAL( clicked( ) ), this, SLOT( cancel( ) ) );
connect( deleteButton, SIGNAL( clicked( ) ), this, SLOT( del( ) ) );
connect( copyLinkButton, SIGNAL( clicked( ) ), this, SLOT( copyLink ( ) ) );
connect( saveButton, SIGNAL( clicked( ) ), this, SLOT( save ( ) ) );
/* once off check - if remote, check if we have it
* NB: This check might be expensive - and it'll happen often!
@ -129,12 +130,21 @@ void SubFileItem::Setup()
}
}
deleteButton->setVisible(mFlag & SFI_FLAG_ALLOW_DELETE);
downloadButton->setVisible(mMode < SFI_STATE_LOCAL);
cancelButton->setVisible(mMode < SFI_STATE_LOCAL);
smaller();
updateItemStatic();
updateItem();
}
void SubFileItem::del()
{
emit wantsToBeDeleted();
}
bool SubFileItem::done()
{
return (mMode >= SFI_STATE_LOCAL);
@ -176,7 +186,7 @@ void SubFileItem::updateItemStatic()
}
/* get full path for local file */
if ((mMode == SFI_STATE_LOCAL) || (mMode == SFI_STATE_UPLOAD))
if (((mMode == SFI_STATE_LOCAL) || (mMode == SFI_STATE_UPLOAD)))
{
#ifdef DEBUG_ITEM
std::cerr << "SubFileItem::updateItemStatic() STATE=Local/Upload checking path";
@ -190,7 +200,10 @@ void SubFileItem::updateItemStatic()
/* look up path */
if (!rsFiles->FileDetails(mFileHash, hintflags, fi))
{
mMode = SFI_STATE_ERROR;
if(mFlag & SFI_FLAG_ASSUME_FILE_READY)
mMode = SFI_STATE_REMOTE;
else
mMode = SFI_STATE_ERROR;
#ifdef DEBUG_ITEM
std::cerr << "SubFileItem::updateItemStatic() STATE=>Error No Details";
std::cerr << std::endl;
@ -241,6 +254,7 @@ void SubFileItem::updateItemStatic()
case SFI_STATE_REMOTE:
playButton->setEnabled(false);
downloadButton->setEnabled(true);
downloadButton->setVisible(true);
cancelButton->setEnabled(false);
progressBar->setValue(0);

View File

@ -40,7 +40,9 @@ const uint32_t SFI_STATE_UPLOAD = 0x0006;
const uint32_t SFI_TYPE_CHANNEL = 0x0010;
const uint32_t SFI_TYPE_ATTACH = 0x0020;
const uint32_t SFI_FLAG_CREATE = 0x1000;
const uint32_t SFI_FLAG_CREATE = 0x1000;
const uint32_t SFI_FLAG_ALLOW_DELETE = 0x2000;
const uint32_t SFI_FLAG_ASSUME_FILE_READY = 0x4000;
//! This create a gui widget that allows users to access files shared by user
@ -86,10 +88,14 @@ private slots:
void toggle();
void cancel();
void del();
void save();
void updateItem();
signals:
void wantsToBeDeleted();
private:
void Setup();

View File

@ -6,12 +6,21 @@
<rect>
<x>0</x>
<y>0</y>
<width>464</width>
<height>71</height>
<width>547</width>
<height>128</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
@ -26,27 +35,6 @@
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="fileLabel">
<property name="font">
<font>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">File Name</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
@ -210,6 +198,41 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="toolTip">
<string>Remove this item</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/denied16.png</normaloff>:/images/denied16.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="fileLabel">
<property name="font">
<font>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">File Name</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -54,7 +54,7 @@ void GxsCommentContainer::setup()
ui.tabWidget->hideCloseButton(index);
}
void GxsCommentContainer::commentLoad(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId, const QString &title)
void GxsCommentContainer::commentLoad(const RsGxsGroupId &grpId, const std::set<RsGxsMessageId>& msg_versions,const RsGxsMessageId &msgId, const QString &title)
{
QString comments = title;
if (title.length() > MAX_COMMENT_TITLE)
@ -68,7 +68,7 @@ void GxsCommentContainer::commentLoad(const RsGxsGroupId &grpId, const RsGxsMess
QWidget *commentHeader = createHeaderWidget(grpId, msgId);
commentDialog->setCommentHeader(commentHeader);
commentDialog->commentLoad(grpId, msgId);
commentDialog->commentLoad(grpId, msg_versions, msgId);
ui.tabWidget->addTab(commentDialog, comments);
}

View File

@ -40,7 +40,7 @@ public:
GxsCommentContainer(QWidget *parent = 0);
void setup();
void commentLoad(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId, const QString &title);
void commentLoad(const RsGxsGroupId &grpId, const std::set<RsGxsMessageId> &msg_versions, const RsGxsMessageId &msgId, const QString &title);
virtual GxsServiceDialog *createServiceDialog() = 0;
virtual QString getServiceName() = 0;
@ -67,9 +67,9 @@ public:
virtual ~GxsServiceDialog() { return; }
void commentLoad(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId, const QString &title)
void commentLoad(const RsGxsGroupId &grpId, const std::set<RsGxsMessageId>& msg_versions,const RsGxsMessageId &msgId, const QString &title)
{
mContainer->commentLoad(grpId, msgId, title);
mContainer->commentLoad(grpId, msg_versions,msgId, title);
}
private:

View File

@ -59,20 +59,16 @@ GxsCommentDialog::~GxsCommentDialog()
delete(ui);
}
void GxsCommentDialog::commentLoad(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId)
void GxsCommentDialog::commentLoad(const RsGxsGroupId &grpId, const std::set<RsGxsMessageId>& msg_versions,const RsGxsMessageId& most_recent_msgId)
{
std::cerr << "GxsCommentDialog::commentLoad(" << grpId << ", " << msgId << ")";
std::cerr << "GxsCommentDialog::commentLoad(" << grpId << ", most recent msg version: " << most_recent_msgId << ")";
std::cerr << std::endl;
mGrpId = grpId;
mMsgId = msgId;
mMostRecentMsgId = most_recent_msgId;
mMsgVersions = msg_versions;
RsGxsGrpMsgIdPair threadId;
threadId.first = grpId;
threadId.second = msgId;
ui->treeWidget->requestComments(threadId);
ui->treeWidget->requestComments(mGrpId,msg_versions,most_recent_msgId);
}
void GxsCommentDialog::refresh()
@ -80,7 +76,7 @@ void GxsCommentDialog::refresh()
std::cerr << "GxsCommentDialog::refresh()";
std::cerr << std::endl;
commentLoad(mGrpId, mMsgId);
commentLoad(mGrpId, mMsgVersions,mMostRecentMsgId);
}
void GxsCommentDialog::idChooserReady()

View File

@ -39,10 +39,10 @@ public:
virtual ~GxsCommentDialog();
void setCommentHeader(QWidget *header);
void commentLoad(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId);
void commentLoad(const RsGxsGroupId &grpId, const std::set<RsGxsMessageId> &msg_versions, const RsGxsMessageId &most_recent_msgId);
RsGxsGroupId groupId() { return mGrpId; }
RsGxsMessageId messageId() { return mMsgId; }
RsGxsMessageId messageId() { return mMostRecentMsgId; }
private slots:
void refresh();
@ -51,7 +51,8 @@ private slots:
private:
RsGxsGroupId mGrpId;
RsGxsMessageId mMsgId;
RsGxsMessageId mMostRecentMsgId;
std::set<RsGxsMessageId> mMsgVersions;
/* UI - from Designer */
Ui::GxsCommentDialog *ui;

View File

@ -22,8 +22,12 @@
*/
#include <QMimeData>
#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include <QApplication>
#include <QDateTime>
#include <QMenu>
#include <QPainter>
#include "gui/common/RSElidedItemDelegate.h"
#include "gui/gxs/GxsCommentTreeWidget.h"
@ -46,11 +50,73 @@
#define COMMENT_VOTE_ACK 0x001234
#define POST_CELL_SIZE_ROLE (Qt::UserRole+1)
#define POST_COLOR_ROLE (Qt::UserRole+2)
/* Images for context menu icons */
#define IMAGE_MESSAGE ":/images/folder-draft.png"
#define IMAGE_VOTEUP ":/images/vote_up.png"
#define IMAGE_VOTEDOWN ":/images/vote_down.png"
#define IMAGE_VOTEUP ":/images/vote_up.png"
#define IMAGE_VOTEDOWN ":/images/vote_down.png"
// This class allows to draw the item using an appropriate size
class MultiLinesCommentDelegate: public QStyledItemDelegate
{
public:
MultiLinesCommentDelegate(QFontMetricsF f) : qf(f){}
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return index.data(POST_CELL_SIZE_ROLE).toSize() ;
}
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_ASSERT(index.isValid());
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
// disable default icon
opt.icon = QIcon();
opt.text = QString();
// draw default item
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0);
const QRect r = option.rect;
QTextDocument td ;
td.setHtml("<html>"+index.data(Qt::DisplayRole).toString()+"</html>");
QSizeF s = td.documentLayout()->documentSize();
int m = QFontMetricsF(QFont()).height();
QSize full_area(std::min(r.width(),(int)s.width())+m,std::min(r.height(),(int)s.height())+m);
QPixmap px(full_area.width(),full_area.height());
px.fill();
QPainter p(&px) ;
p.setRenderHint(QPainter::Antialiasing);
QPainterPath path ;
path.addRoundedRect(QRectF(m/4.0,m/4.0,s.width()+m/2.0,s.height()+m/2.0),m,m) ;
QPen pen(Qt::gray,m/7.0f);
p.setPen(pen);
p.fillPath(path,QColor::fromHsv( index.data(POST_COLOR_ROLE).toInt()/255.0*360,40,220)); // varies the color according to the post author
p.drawPath(path);
QAbstractTextDocumentLayout::PaintContext ctx;
ctx.clip = QRectF(0,0,s.width(),s.height());
p.translate(QPointF(m/2.0,m/2.0));
td.documentLayout()->draw( &p, ctx );
painter->drawPixmap(r.topLeft(),px);
const_cast<QAbstractItemModel*>(index.model())->setData(index,px.size(),POST_CELL_SIZE_ROLE);
}
private:
QFontMetricsF qf;
};
GxsCommentTreeWidget::GxsCommentTreeWidget(QWidget *parent)
:QTreeWidget(parent), mTokenQueue(NULL), mRsTokenService(NULL), mCommentService(NULL)
@ -62,6 +128,9 @@ GxsCommentTreeWidget::GxsCommentTreeWidget(QWidget *parent)
itemDelegate->setSpacing(QSize(0, 2));
setItemDelegate(itemDelegate);
setWordWrap(true);
setItemDelegateForColumn(PCITEM_COLUMN_COMMENT,new MultiLinesCommentDelegate(QFontMetricsF(font()))) ;
// QFont font = QFont("ARIAL", 10);
// font.setBold(true);
@ -85,14 +154,14 @@ GxsCommentTreeWidget::~GxsCommentTreeWidget()
}
}
void GxsCommentTreeWidget::setCurrentMsgId(QTreeWidgetItem *current, QTreeWidgetItem *previous)
void GxsCommentTreeWidget::setCurrentCommentMsgId(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
Q_UNUSED(previous);
if(current)
{
mCurrentMsgId = RsGxsMessageId(current->text(PCITEM_COLUMN_MSGID).toStdString());
mCurrentCommentMsgId = RsGxsMessageId(current->text(PCITEM_COLUMN_MSGID).toStdString());
}
}
@ -100,9 +169,9 @@ void GxsCommentTreeWidget::customPopUpMenu(const QPoint& /*point*/)
{
QMenu contextMnu( this );
QAction* action = contextMnu.addAction(QIcon(IMAGE_MESSAGE), tr("Reply to Comment"), this, SLOT(replyToComment()));
action->setDisabled(mCurrentMsgId.isNull());
action->setDisabled(mCurrentCommentMsgId.isNull());
action = contextMnu.addAction(QIcon(IMAGE_MESSAGE), tr("Submit Comment"), this, SLOT(makeComment()));
action->setDisabled(mThreadId.first.isNull());
action->setDisabled(mMsgVersions.empty());
contextMnu.addSeparator();
@ -112,7 +181,7 @@ void GxsCommentTreeWidget::customPopUpMenu(const QPoint& /*point*/)
action->setDisabled(mVoterId.isNull());
if (!mCurrentMsgId.isNull())
if (!mCurrentCommentMsgId.isNull())
{
// not implemented yet
/*
@ -138,7 +207,8 @@ void GxsCommentTreeWidget::voteUp()
{
std::cerr << "GxsCommentTreeWidget::voteUp()";
std::cerr << std::endl;
vote(mThreadId.first, mThreadId.second, mCurrentMsgId, mVoterId, true);
vote(mGroupId, mLatestMsgId, mCurrentCommentMsgId, mVoterId, true);
}
@ -146,7 +216,8 @@ void GxsCommentTreeWidget::voteDown()
{
std::cerr << "GxsCommentTreeWidget::voteDown()";
std::cerr << std::endl;
vote(mThreadId.first, mThreadId.second, mCurrentMsgId, mVoterId, false);
vote(mGroupId, mLatestMsgId, mCurrentCommentMsgId, mVoterId, false);
}
void GxsCommentTreeWidget::setVoteId(const RsGxsId &voterId)
@ -216,16 +287,16 @@ void GxsCommentTreeWidget::banUser()
void GxsCommentTreeWidget::makeComment()
{
GxsCreateCommentDialog pcc(mTokenQueue, mCommentService, mThreadId, mThreadId.second, this);
GxsCreateCommentDialog pcc(mTokenQueue, mCommentService, std::make_pair(mGroupId,mLatestMsgId), mLatestMsgId, this);
pcc.exec();
}
void GxsCommentTreeWidget::replyToComment()
{
RsGxsGrpMsgIdPair msgId;
msgId.first = mThreadId.first;
msgId.second = mCurrentMsgId;
GxsCreateCommentDialog pcc(mTokenQueue, mCommentService, msgId, mThreadId.second, this);
msgId.first = mGroupId;
msgId.second = mCurrentCommentMsgId;
GxsCreateCommentDialog pcc(mTokenQueue, mCommentService, msgId, mLatestMsgId, this);
pcc.exec();
}
@ -235,36 +306,44 @@ void GxsCommentTreeWidget::setup(RsTokenService *token_service, RsGxsCommentServ
mCommentService = comment_service;
mTokenQueue = new TokenQueue(token_service, this);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customPopUpMenu(QPoint)));
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(setCurrentMsgId(QTreeWidgetItem*, QTreeWidgetItem*)));
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(setCurrentCommentMsgId(QTreeWidgetItem*, QTreeWidgetItem*)));
return;
}
/* Load Comments */
void GxsCommentTreeWidget::requestComments(const RsGxsGrpMsgIdPair& threadId)
void GxsCommentTreeWidget::requestComments(const RsGxsGroupId& group, const std::set<RsGxsMessageId>& message_versions,const RsGxsMessageId& most_recent_message)
{
/* request comments */
mThreadId = threadId;
service_requestComments(threadId);
mGroupId = group ;
mMsgVersions = message_versions ;
mLatestMsgId = most_recent_message;
service_requestComments(group,message_versions);
}
void GxsCommentTreeWidget::service_requestComments(const RsGxsGrpMsgIdPair& threadId)
void GxsCommentTreeWidget::service_requestComments(const RsGxsGroupId& group_id,const std::set<RsGxsMessageId> & msgIds)
{
/* request comments */
std::cerr << "GxsCommentTreeWidget::service_requestComments(" << threadId.second << ")";
std::cerr << std::endl;
std::cerr << "GxsCommentTreeWidget::service_requestComments for group " << group_id << std::endl;
std::vector<RsGxsGrpMsgIdPair> ids_to_ask;
for(std::set<RsGxsMessageId>::const_iterator it(msgIds.begin());it!=msgIds.end();++it)
{
std::cerr << " asking for msg " << *it << std::endl;
ids_to_ask.push_back(std::make_pair(group_id,*it));
}
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA;
opts.mOptions = RS_TOKREQOPT_MSG_THREAD | RS_TOKREQOPT_MSG_LATEST;
std::vector<RsGxsGrpMsgIdPair> msgIds;
msgIds.push_back(threadId);
uint32_t token;
mTokenQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, GXSCOMMENTS_LOADTHREAD);
mTokenQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, ids_to_ask, GXSCOMMENTS_LOADTHREAD);
}
@ -317,7 +396,7 @@ void GxsCommentTreeWidget::completeItems()
parent->addChild(pit->second);
}
else if (parentId == mThreadId.second)
else if (mMsgVersions.find(parentId) != mMsgVersions.end())
{
std::cerr << "GxsCommentTreeWidget::completeItems() Added to topLevelItems";
std::cerr << std::endl;
@ -391,7 +470,7 @@ void GxsCommentTreeWidget::acknowledgeComment(const uint32_t &token)
mCommentService->acknowledgeComment(token, msgId);
// simply reload data
service_requestComments(mThreadId);
service_requestComments(mGroupId,mMsgVersions);
}
@ -401,7 +480,7 @@ void GxsCommentTreeWidget::acknowledgeVote(const uint32_t &token)
if (mCommentService->acknowledgeVote(token, msgId))
{
// reload data if vote was added.
service_requestComments(mThreadId);
service_requestComments(mGroupId,mMsgVersions);
}
}
@ -441,6 +520,7 @@ void GxsCommentTreeWidget::service_loadThread(const uint32_t &token)
RsGxsId authorId = comment.mMeta.mAuthorId;
item->setId(authorId, PCITEM_COLUMN_AUTHOR, false);
item->setData(PCITEM_COLUMN_COMMENT,POST_COLOR_ROLE,QVariant(authorId.toByteArray()[1]));
text = QString::number(comment.mScore);
item->setText(PCITEM_COLUMN_SCORE, text);

View File

@ -39,7 +39,7 @@ public:
~GxsCommentTreeWidget();
void setup(RsTokenService *token_service, RsGxsCommentService *comment_service);
void requestComments(const RsGxsGrpMsgIdPair& threadId);
void requestComments(const RsGxsGroupId& group, const std::set<RsGxsMessageId> &message_versions, const RsGxsMessageId &most_recent_message);
void getCurrentMsgId(RsGxsMessageId& parentId);
void applyRankings(std::map<RsGxsMessageId, uint32_t>& positions);
@ -49,7 +49,7 @@ public:
protected:
/* to be overloaded */
virtual void service_requestComments(const RsGxsGrpMsgIdPair& threadId);
virtual void service_requestComments(const RsGxsGroupId &group_id, const std::set<RsGxsMessageId> &msgIds);
virtual void service_loadThread(const uint32_t &token);
virtual QTreeWidgetItem *service_createMissingItem(const RsGxsMessageId& parent);
@ -65,7 +65,7 @@ protected:
public slots:
void customPopUpMenu(const QPoint& point);
void setCurrentMsgId(QTreeWidgetItem* current, QTreeWidgetItem* previous);
void setCurrentCommentMsgId(QTreeWidgetItem* current, QTreeWidgetItem* previous);
void makeComment();
@ -85,8 +85,10 @@ protected:
const RsGxsMessageId &parentId, const RsGxsId &authorId, bool up);
/* Data */
RsGxsGrpMsgIdPair mThreadId;
RsGxsMessageId mCurrentMsgId;
RsGxsGroupId mGroupId;
std::set<RsGxsMessageId> mMsgVersions;
RsGxsMessageId mLatestMsgId;
RsGxsMessageId mCurrentCommentMsgId;
RsGxsId mVoterId;
std::map<RsGxsMessageId, QTreeWidgetItem *> mLoadingMap;

View File

@ -64,7 +64,10 @@ void GxsFeedItem::comments(const QString &title)
if (mFeedHolder)
{
mFeedHolder->openComments(feedId(), groupId(), messageId(), title);
if(mMessageVersions.empty())
mFeedHolder->openComments(feedId(), groupId(),QVector<RsGxsMessageId>(1,messageId()), messageId(), title);
else
mFeedHolder->openComments(feedId(), groupId(),mMessageVersions, messageId(), title);
}
}
@ -153,12 +156,12 @@ void GxsFeedItem::requestComment()
opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA;
opts.mOptions = RS_TOKREQOPT_MSG_THREAD | RS_TOKREQOPT_MSG_LATEST;
RsGxsGrpMsgIdPair msgIdPair;
msgIdPair.first = groupId();
msgIdPair.second = messageId();
std::vector<RsGxsGrpMsgIdPair> msgIds;
msgIds.push_back(msgIdPair);
for(uint32_t i=0;i<mMessageVersions.size();++i)
msgIds.push_back(std::make_pair(groupId(),mMessageVersions[i]));
msgIds.push_back(std::make_pair(groupId(),messageId()));
uint32_t token;
mLoadQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, mTokenTypeComment);

View File

@ -35,9 +35,12 @@ public:
GxsFeedItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, bool isHome, RsGxsIfaceHelper *iface, bool autoUpdate);
virtual ~GxsFeedItem();
RsGxsMessageId messageId() { return mMessageId; }
RsGxsMessageId messageId() const { return mMessageId; }
const QVector<RsGxsMessageId>& messageVersions() const { return mMessageVersions ; }
//To be able to update with thread message when comment is received.
void setMessageId( RsGxsMessageId id) {mMessageId = id;}
void setMessageVersions( const QVector<RsGxsMessageId>& v) { mMessageVersions = v;}
protected:
/* load message data */
@ -61,6 +64,7 @@ protected slots:
private:
RsGxsMessageId mMessageId;
QVector<RsGxsMessageId> mMessageVersions ;
uint32_t mTokenTypeMessage;
uint32_t mTokenTypeComment;
};

View File

@ -45,8 +45,8 @@ public:
GxsGroupFeedItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, bool isHome, RsGxsIfaceHelper *iface, bool autoUpdate);
virtual ~GxsGroupFeedItem();
RsGxsGroupId groupId() { return mGroupId; }
uint32_t feedId() { return mFeedId; }
RsGxsGroupId groupId() const { return mGroupId; }
uint32_t feedId() const { return mFeedId; }
protected:
uint32_t nextTokenType() { return ++mNextTokenType; }

View File

@ -525,7 +525,7 @@ void GxsGroupFrameDialog::sharePublishKey()
shareUi.exec();
}
void GxsGroupFrameDialog::loadComment(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId, const QString &title)
void GxsGroupFrameDialog::loadComment(const RsGxsGroupId &grpId, const QVector<RsGxsMessageId>& msg_versions, const RsGxsMessageId &most_recent_msgId, const QString &title)
{
RsGxsCommentService *commentService = getCommentService();
if (!commentService) {
@ -533,7 +533,8 @@ void GxsGroupFrameDialog::loadComment(const RsGxsGroupId &grpId, const RsGxsMess
return;
}
GxsCommentDialog *commentDialog = commentWidget(msgId);
GxsCommentDialog *commentDialog = commentWidget(most_recent_msgId);
if (!commentDialog) {
QString comments = title;
if (title.length() > MAX_COMMENT_TITLE)
@ -544,12 +545,16 @@ void GxsGroupFrameDialog::loadComment(const RsGxsGroupId &grpId, const RsGxsMess
commentDialog = new GxsCommentDialog(this, mInterface->getTokenService(), commentService);
QWidget *commentHeader = createCommentHeaderWidget(grpId, msgId);
QWidget *commentHeader = createCommentHeaderWidget(grpId, most_recent_msgId);
if (commentHeader) {
commentDialog->setCommentHeader(commentHeader);
}
commentDialog->commentLoad(grpId, msgId);
std::set<RsGxsMessageId> msgv;
for(int i=0;i<msg_versions.size();++i)
msgv.insert(msg_versions[i]);
commentDialog->commentLoad(grpId, msgv,most_recent_msgId);
int index = ui->messageTabWidget->addTab(commentDialog, comments);
ui->messageTabWidget->setTabIcon(index, QIcon(IMAGE_COMMENT));
@ -620,12 +625,12 @@ GxsMessageFrameWidget *GxsGroupFrameDialog::createMessageWidget(const RsGxsGroup
connect(msgWidget, SIGNAL(groupChanged(QWidget*)), this, SLOT(messageTabInfoChanged(QWidget*)));
connect(msgWidget, SIGNAL(waitingChanged(QWidget*)), this, SLOT(messageTabWaitingChanged(QWidget*)));
connect(msgWidget, SIGNAL(loadComment(RsGxsGroupId,RsGxsMessageId,QString)), this, SLOT(loadComment(RsGxsGroupId,RsGxsMessageId,QString)));
connect(msgWidget, SIGNAL(loadComment(RsGxsGroupId,QVector<RsGxsMessageId>,RsGxsMessageId,QString)), this, SLOT(loadComment(RsGxsGroupId,QVector<RsGxsMessageId>,RsGxsMessageId,QString)));
return msgWidget;
}
GxsCommentDialog *GxsGroupFrameDialog::commentWidget(const RsGxsMessageId &msgId)
GxsCommentDialog *GxsGroupFrameDialog::commentWidget(const RsGxsMessageId& msgId)
{
int tabCount = ui->messageTabWidget->count();
for (int index = 0; index < tabCount; ++index) {

View File

@ -126,7 +126,7 @@ private slots:
void sharePublishKey();
void loadComment(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId, const QString &title);
void loadComment(const RsGxsGroupId &grpId, const QVector<RsGxsMessageId>& msg_versions,const RsGxsMessageId &most_recent_msgId, const QString &title);
private:
virtual QString text(TextType type) = 0;

View File

@ -54,7 +54,7 @@ public:
signals:
void groupChanged(QWidget *widget);
void waitingChanged(QWidget *widget);
void loadComment(const RsGxsGroupId &groupId, const RsGxsMessageId &msgId, const QString &title);
void loadComment(const RsGxsGroupId &groupId, const QVector<RsGxsMessageId>& msg_versions,const RsGxsMessageId &msgId, const QString &title);
protected:
virtual void setAllMessagesReadDo(bool read, uint32_t &token) = 0;

View File

@ -38,11 +38,15 @@
//#define ENABLE_GENERATE
#define CREATEMSG_CHANNELINFO 0x002
#define CREATEMSG_CHANNELINFO 0x002
#define CREATEMSG_CHANNEL_POST_INFO 0x003
// #define DEBUG_CREATE_GXS_MSG
/** Constructor */
CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId)
: QDialog (NULL, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint), mChannelId(cId) ,mCheckAttachment(true), mAutoMediaThumbNail(false)
CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId, RsGxsMessageId existing_post)
: QDialog (NULL, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint),
mChannelId(cId) , mOrigPostId(existing_post),mCheckAttachment(true), mAutoMediaThumbNail(false)
{
/* Invoke the Qt Designer generated object setup routine */
setupUi(this);
@ -50,7 +54,11 @@ CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId)
mChannelQueue = new TokenQueue(rsGxsChannels->getTokenService(), this);
headerFrame->setHeaderImage(QPixmap(":/images/channels.png"));
headerFrame->setHeaderText(tr("New Channel Post"));
if(!existing_post.isNull())
headerFrame->setHeaderText(tr("Edit Channel Post"));
else
headerFrame->setHeaderText(tr("New Channel Post"));
setAttribute ( Qt::WA_DeleteOnClose, true );
@ -337,43 +345,63 @@ void CreateGxsChannelMsg::parseRsFileListAttachments(const std::string &attachLi
}
void CreateGxsChannelMsg::addAttachment(const RsFileHash &hash, const std::string &fname, uint64_t size, bool local, const RsPeerId &srcId)
void CreateGxsChannelMsg::addAttachment(const RsFileHash &hash, const std::string &fname, uint64_t size, bool local, const RsPeerId &srcId, bool assume_file_ready)
{
/* add a SubFileItem to the attachment section */
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::addAttachment()";
std::cerr << std::endl;
#endif
/* add widget in for new destination */
uint32_t flags = SFI_TYPE_CHANNEL;
uint32_t flags = SFI_TYPE_CHANNEL | SFI_FLAG_ALLOW_DELETE ;
if(assume_file_ready)
flags |= SFI_FLAG_ASSUME_FILE_READY;
if (local)
{
flags |= SFI_STATE_LOCAL;
}
else
{
flags |= SFI_STATE_REMOTE;
}
SubFileItem *file = new SubFileItem(hash, fname, "", size, flags, srcId); // destroyed when fileFrame (this subfileitem) is destroyed
connect(file,SIGNAL(wantsToBeDeleted()),this,SLOT(deleteAttachment())) ;
mAttachments.push_back(file);
QLayout *layout = fileFrame->layout();
layout->addWidget(file);
if (mCheckAttachment)
{
checkAttachmentReady();
}
}
return;
void CreateGxsChannelMsg::deleteAttachment()
{
// grab the item who sent the request
SubFileItem *file_item = qobject_cast<SubFileItem *>(QObject::sender());
for(std::list<SubFileItem*>::iterator it(mAttachments.begin());it!=mAttachments.end();)
if(*it == file_item)
{
SubFileItem *item = *it ;
it = mAttachments.erase(it) ;
fileFrame->layout()->removeWidget(file_item) ;
delete item ;
}
else
++it;
}
void CreateGxsChannelMsg::addExtraFile()
{
/* add a SubFileItem to the attachment section */
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::addExtraFile() opening file dialog";
std::cerr << std::endl;
#endif
QStringList files;
if (misc::getOpenFileNames(this, RshareSettings::LASTDIR_EXTRAFILE, tr("Add Extra File"), "", files)) {
@ -386,8 +414,10 @@ void CreateGxsChannelMsg::addExtraFile()
void CreateGxsChannelMsg::addAttachment(const std::string &path)
{
/* add a SubFileItem to the attachment section */
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::addAttachment()";
std::cerr << std::endl;
#endif
if(mAutoMediaThumbNail)
setThumbNail(path, 2000);
@ -522,8 +552,10 @@ void CreateGxsChannelMsg::checkAttachmentReady()
void CreateGxsChannelMsg::cancelMsg()
{
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::cancelMsg() :"
<< "Deleting EXTRA attachments" << std::endl;
#endif
std::cerr << std::endl;
@ -555,6 +587,15 @@ void CreateGxsChannelMsg::newChannelMsg()
uint32_t token;
mChannelQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, groupIds, CREATEMSG_CHANNELINFO);
if(!mOrigPostId.isNull())
{
GxsMsgReq message_ids;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
message_ids[mChannelId].push_back(mOrigPostId);
mChannelQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, message_ids, CREATEMSG_CHANNEL_POST_INFO);
}
}
}
@ -569,8 +610,10 @@ void CreateGxsChannelMsg::saveChannelInfo(const RsGroupMetaData &meta)
void CreateGxsChannelMsg::sendMsg()
{
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::sendMsg()";
std::cerr << std::endl;
#endif
/* construct message bits */
std::string subject = std::string(misc::removeNewLine(subjectEdit->text()).toUtf8());
@ -628,6 +671,7 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str
post.mMeta.mThreadId.clear() ;
post.mMeta.mMsgId.clear() ;
post.mMeta.mOrigMsgId = mOrigPostId;
post.mMeta.mMsgName = subject;
post.mMsg = msg;
post.mFiles = files;
@ -686,10 +730,47 @@ void CreateGxsChannelMsg::addThumbnail()
thumbnail_label->setPixmap(picture);
}
void CreateGxsChannelMsg::loadChannelPostInfo(const uint32_t &token)
{
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::loadChannelPostInfo()";
std::cerr << std::endl;
#endif
std::vector<RsGxsChannelPost> posts;
rsGxsChannels->getPostData(token, posts);
if (posts.size() != 1)
{
std::cerr << "CreateGxsChannelMsg::loadChannelPostInfo() ERROR INVALID Number of posts in request" << std::endl;
return ;
}
// now populate the widget with the channel post data.
const RsGxsChannelPost& post = posts[0];
if(post.mMeta.mGroupId != mChannelId || post.mMeta.mMsgId != mOrigPostId)
{
std::cerr << "CreateGxsChannelMsg::loadChannelPostInfo() ERROR INVALID post ID or channel ID" << std::endl;
return ;
}
subjectEdit->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())) ;
msgEdit->setText(QString::fromUtf8(post.mMsg.c_str())) ;
for(std::list<RsGxsFile>::const_iterator it(post.mFiles.begin());it!=post.mFiles.end();++it)
addAttachment(it->mHash,it->mName,it->mSize,true,RsPeerId(),true);
picture.loadFromData(post.mThumbnail.mData,post.mThumbnail.mSize,"PNG");
thumbnail_label->setPixmap(picture);
}
void CreateGxsChannelMsg::loadChannelInfo(const uint32_t &token)
{
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::loadChannelInfo()";
std::cerr << std::endl;
#endif
std::list<RsGroupMetaData> groupInfo;
rsGxsChannels->getGroupSummary(token, groupInfo);
@ -708,8 +789,10 @@ void CreateGxsChannelMsg::loadChannelInfo(const uint32_t &token)
void CreateGxsChannelMsg::loadRequest(const TokenQueue *queue, const TokenRequest &req)
{
#ifdef DEBUG_CREATE_GXS_MSG
std::cerr << "CreateGxsChannelMsg::loadRequest() UserType: " << req.mUserType;
std::cerr << std::endl;
#endif
if (queue == mChannelQueue)
{
@ -719,6 +802,9 @@ void CreateGxsChannelMsg::loadRequest(const TokenQueue *queue, const TokenReques
case CREATEMSG_CHANNELINFO:
loadChannelInfo(req.mToken);
break;
case CREATEMSG_CHANNEL_POST_INFO:
loadChannelPostInfo(req.mToken);
break;
default:
std::cerr << "CreateGxsChannelMsg::loadRequest() UNKNOWN UserType ";
std::cerr << std::endl;

View File

@ -38,13 +38,13 @@ class CreateGxsChannelMsg : public QDialog, public TokenResponse, private Ui::Cr
public:
/** Default Constructor */
CreateGxsChannelMsg(const RsGxsGroupId& cId);
CreateGxsChannelMsg(const RsGxsGroupId& cId, RsGxsMessageId existing_post = RsGxsMessageId());
/** Default Destructor */
~CreateGxsChannelMsg();
void addAttachment(const std::string &path);
void addAttachment(const RsFileHash &hash, const std::string &fname, uint64_t size, bool local, const RsPeerId &srcId);
void addAttachment(const RsFileHash &hash, const std::string &fname, uint64_t size, bool local, const RsPeerId &srcId,bool assume_file_ready = false);
void newChannelMsg();
@ -60,6 +60,7 @@ protected:
private slots:
void addExtraFile();
void checkAttachmentReady();
void deleteAttachment();
void cancelMsg();
void sendMsg();
@ -71,6 +72,7 @@ private slots:
private:
void loadChannelInfo(const uint32_t &token);
void loadChannelPostInfo(const uint32_t &token);
void saveChannelInfo(const RsGroupMetaData &group);
void parseRsFileListAttachments(const std::string &attachList);
@ -78,7 +80,9 @@ private:
bool setThumbNail(const std::string& path, int frame);
RsGxsGroupId mChannelId;
RsGxsMessageId mOrigPostId;
RsGroupMetaData mChannelMeta;
RsMsgMetaData mOrigMeta;
bool mChannelMetaLoaded;
std::list<SubFileItem *> mAttachments;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>581</width>
<height>479</height>
<width>875</width>
<height>659</height>
</rect>
</property>
<property name="acceptDrops">
@ -60,7 +60,7 @@
<bool>false</bool>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="channelPostTab">
<attribute name="title">
@ -302,8 +302,8 @@ p, li { white-space: pre-wrap; }
<rect>
<x>0</x>
<y>0</y>
<width>523</width>
<height>24</height>
<width>767</width>
<height>42</height>
</rect>
</property>
<property name="sizePolicy">

View File

@ -207,9 +207,9 @@ void GxsChannelPostsWidget::openChat(const RsPeerId & /*peerId*/)
}
// Callback from Widget->FeedHolder->ServiceDialog->CommentContainer->CommentDialog,
void GxsChannelPostsWidget::openComments(uint32_t /*type*/, const RsGxsGroupId &groupId, const RsGxsMessageId &msgId, const QString &title)
void GxsChannelPostsWidget::openComments(uint32_t /*type*/, const RsGxsGroupId &groupId, const QVector<RsGxsMessageId>& msg_versions,const RsGxsMessageId &msgId, const QString &title)
{
emit loadComment(groupId, msgId, title);
emit loadComment(groupId, msg_versions,msgId, title);
}
void GxsChannelPostsWidget::createMsg()
@ -398,7 +398,27 @@ void GxsChannelPostsWidget::filterChanged(int filter)
void GxsChannelPostsWidget::createPostItem(const RsGxsChannelPost &post, bool related)
{
GxsChannelPostItem *item = NULL;
if (related) {
if(!post.mMeta.mOrigMsgId.isNull())
{
FeedItem *feedItem = ui->feedWidget->findGxsFeedItem(post.mMeta.mGroupId, post.mMeta.mOrigMsgId);
item = dynamic_cast<GxsChannelPostItem*>(feedItem);
if(item)
{
ui->feedWidget->removeFeedItem(item) ;
RsGxsChannelGroup dummyGroup;
dummyGroup.mMeta.mGroupId = groupId();
dummyGroup.mMeta.mSubscribeFlags = 0xffffffff;
GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, dummyGroup, post, true, false);
ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, QDateTime::fromTime_t(post.mMeta.mPublishTs));
return ;
}
}
if (related)
{
FeedItem *feedItem = ui->feedWidget->findGxsFeedItem(post.mMeta.mGroupId, post.mMeta.mMsgId);
item = dynamic_cast<GxsChannelPostItem*>(feedItem);
}
@ -438,8 +458,6 @@ void GxsChannelPostsWidget::insertChannelPosts(std::vector<RsGxsChannelPost> &po
return;
}
std::vector<RsGxsChannelPost>::const_reverse_iterator it;
int count = posts.size();
int pos = 0;
@ -447,18 +465,127 @@ void GxsChannelPostsWidget::insertChannelPosts(std::vector<RsGxsChannelPost> &po
ui->feedWidget->setSortingEnabled(false);
}
for (it = posts.rbegin(); it != posts.rend(); ++it)
{
if (thread && thread->stopped()) {
break;
}
// collect new versions of posts if any
if (thread) {
thread->emitAddPost(qVariantFromValue(*it), related, ++pos, count);
} else {
createPostItem(*it, related);
#ifdef DEBUG_CHANNEL
std::cerr << "Inserting channel posts" << std::endl;
#endif
std::vector<uint32_t> new_versions ;
for (uint32_t i=0;i<posts.size();++i)
{
if(posts[i].mMeta.mOrigMsgId == posts[i].mMeta.mMsgId)
posts[i].mMeta.mOrigMsgId.clear();
#ifdef DEBUG_CHANNEL
std::cerr << " " << i << ": msg_id=" << posts[i].mMeta.mMsgId << ": orig msg id = " << posts[i].mMeta.mOrigMsgId << std::endl;
#endif
if(!posts[i].mMeta.mOrigMsgId.isNull())
new_versions.push_back(i) ;
}
#ifdef DEBUG_CHANNEL
std::cerr << "New versions: " << new_versions.size() << std::endl;
#endif
if(!new_versions.empty())
{
#ifdef DEBUG_CHANNEL
std::cerr << " New versions present. Replacing them..." << std::endl;
std::cerr << " Creating search map." << std::endl;
#endif
// make a quick search map
std::map<RsGxsMessageId,uint32_t> search_map ;
for (uint32_t i=0;i<posts.size();++i)
search_map[posts[i].mMeta.mMsgId] = i ;
for(uint32_t i=0;i<new_versions.size();++i)
{
#ifdef DEBUG_CHANNEL
std::cerr << " Taking care of new version at index " << new_versions[i] << std::endl;
#endif
uint32_t current_index = new_versions[i] ;
uint32_t source_index = new_versions[i] ;
RsGxsMessageId source_msg_id = posts[source_index].mMeta.mMsgId ;
// What we do is everytime we find a replacement post, we climb up the replacement graph until we find the original post
// (or the most recent version of it). When we reach this post, we replace it with the data of the source post.
// In the mean time, all other posts have their MsgId cleared, so that the posts are removed from the list.
std::vector<uint32_t> versions ;
std::map<RsGxsMessageId,uint32_t>::const_iterator vit ;
while(search_map.end() != (vit=search_map.find(posts[current_index].mMeta.mOrigMsgId)))
{
#ifdef DEBUG_CHANNEL
std::cerr << " post at index " << current_index << " replaces a post at position " << vit->second ;
#endif
// Now replace the post only if the new versionis more recent. It may happen indeed that the same post has been corrected multiple
// times. In this case, we only need to replace the post with the newest version
uint32_t prev_index = current_index ;
current_index = vit->second ;
if(posts[current_index].mMeta.mMsgId.isNull()) // This handles the branching situation where this post has been already erased. No need to go down further.
{
#ifdef DEBUG_CHANNEL
std::cerr << " already erased. Stopping." << std::endl;
#endif
break ;
}
if(posts[current_index].mMeta.mPublishTs < posts[source_index].mMeta.mPublishTs)
{
#ifdef DEBUG_CHANNEL
std::cerr << " and is more recent => following" << std::endl;
#endif
for(std::set<RsGxsMessageId>::const_iterator itt(posts[current_index].mOlderVersions.begin());itt!=posts[current_index].mOlderVersions.end();++itt)
posts[source_index].mOlderVersions.insert(*itt);
posts[source_index].mOlderVersions.insert(posts[current_index].mMeta.mMsgId);
posts[current_index].mMeta.mMsgId.clear(); // clear the msg Id so the post will be ignored
}
#ifdef DEBUG_CHANNEL
else
std::cerr << " but is older -> Stopping" << std::endl;
#endif
}
}
}
#ifdef DEBUG_CHANNEL
std::cerr << "Now adding posts..." << std::endl;
#endif
for (std::vector<RsGxsChannelPost>::const_reverse_iterator it = posts.rbegin(); it != posts.rend(); ++it)
{
#ifdef DEBUG_CHANNEL
std::cerr << " adding post: " << (*it).mMeta.mMsgId ;
#endif
if(!(*it).mMeta.mMsgId.isNull())
{
#ifdef DEBUG_CHANNEL
std::cerr << " added" << std::endl;
#endif
if (thread && thread->stopped())
break;
if (thread)
thread->emitAddPost(qVariantFromValue(*it), related, ++pos, count);
else
createPostItem(*it, related);
}
}
#ifdef DEBUG_CHANNEL
else
std::cerr << " skipped" << std::endl;
#endif
}
if (!thread) {
ui->feedWidget->setSortingEnabled(true);

View File

@ -61,7 +61,7 @@ public:
virtual QScrollArea *getScrollArea();
virtual void deleteFeedItem(QWidget *item, uint32_t type);
virtual void openChat(const RsPeerId& peerId);
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const RsGxsMessageId &msgId, const QString &title);
virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector<RsGxsMessageId> &msg_versions, const RsGxsMessageId &msgId, const QString &title);
protected:
/* GxsMessageFramePostWidget */

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>793</width>
<height>465</height>
<width>880</width>
<height>557</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
@ -454,7 +454,7 @@
<string notr="true">&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 Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&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:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;Description&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textInteractionFlags">

View File

@ -1,5 +1,7 @@
<RCC>
<qresource prefix="/">
<file>icons/svg/hidden.svg</file>
<file>icons/svg/randomness.svg</file>
<file>icons/svg/password.svg</file>
<file>icons/stars/star0.png</file>
<file>icons/stars/star1.png</file>
@ -11,6 +13,12 @@
<file>icons/anonymous_blue_128.png</file>
<file>icons/anonymous_green_128.png</file>
<file>icons/aol.png</file>
<file>icons/transport128.png</file>
<file>icons/bandwidth128.png</file>
<file>icons/RTT128.png</file>
<file>icons/DHT128.png</file>
<file>icons/turtle128.png</file>
<file>icons/GRouter128.png</file>
<file>icons/avatar_128.png</file>
<file>icons/avatar_grey_128.png</file>
<file>icons/biohazard_red.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg4155"
version="1.1"
inkscape:version="0.91 r13725"
xml:space="preserve"
width="80"
height="80"
viewBox="0 0 80 80"
sodipodi:docname="hidden.svg"><metadata
id="metadata4161"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4159"><linearGradient
id="linearGradient5584"
osb:paint="solid"><stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop5586" /></linearGradient></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="706"
id="namedview4157"
showgrid="false"
inkscape:zoom="3.6195029"
inkscape:cx="37.953819"
inkscape:cy="49.057609"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g4163" /><g
id="g4163"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.25,0,0,-1.25,0,80)"><path
inkscape:connector-curvature="0"
id="path4167"
style="fill:#039bd5;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 64,32 C 64,14.327 49.673,0 32,0 14.327,0 0,14.327 0,32 0,49.673 14.327,64 32,64 49.673,64 64,49.673 64,32" /><g
transform="matrix(0.47818792,0,0,-0.47818794,8.3042308,56.181608)"
id="g3"><g
id="g5"><path
style="fill:#ffffff"
inkscape:connector-curvature="0"
d="M 69.322,44.716 49.715,64.323 C 60.438,64.072 69.071,55.438 69.322,44.716 Z"
id="path7" /><path
style="fill:#ffffff"
inkscape:connector-curvature="0"
d="M 97.204,45.789 C 96.755,45.26 90.959,38.559 81.802,32.235 l -6.2,6.2 c 5.99,3.954 10.559,8.275 13.011,10.806 -5.378,5.554 -20.913,19.728 -39.372,19.728 -1.334,0 -2.651,-0.082 -3.952,-0.222 l -7.439,7.438 c 3.639,0.91 7.449,1.451 11.391,1.451 26.426,0 47.098,-23.927 47.964,-24.946 1.701,-1.998 1.701,-4.9 -0.001,-6.901 z"
id="path9" /><path
style="fill:#ffffff"
inkscape:connector-curvature="0"
d="m 90.651,15.901 c 0,-0.266 -0.104,-0.52 -0.293,-0.707 l -7.071,-7.07 c -0.391,-0.391 -1.022,-0.391 -1.414,0 L 66.045,23.952 C 60.843,22.059 55.19,20.844 49.241,20.844 22.814,20.844 2.143,44.77 1.276,45.79 c -1.701,2 -1.701,4.902 10e-4,6.903 0.517,0.606 8.083,9.354 19.707,16.319 l -12.86,12.86 c -0.188,0.188 -0.293,0.441 -0.293,0.707 0,0.267 0.105,0.521 0.293,0.707 l 7.071,7.07 c 0.195,0.194 0.451,0.293 0.707,0.293 0.256,0 0.512,-0.099 0.707,-0.293 l 73.75,-73.75 c 0.187,-0.185 0.292,-0.439 0.292,-0.705 z M 9.869,49.241 C 13.5,45.49 21.767,37.812 32.436,33.22 c -2.081,3.166 -3.301,6.949 -3.301,11.021 0,4.665 1.601,8.945 4.27,12.352 l -6.124,6.123 C 19.129,58.196 12.89,52.361 9.869,49.241 Z"
id="path11" /></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg4155"
version="1.1"
inkscape:version="0.91 r13725"
xml:space="preserve"
width="80"
height="80"
viewBox="0 0 80 80"
sodipodi:docname="randomness.svg"><metadata
id="metadata4161"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4159" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="706"
id="namedview4157"
showgrid="false"
inkscape:zoom="5.11875"
inkscape:cx="54.735476"
inkscape:cy="40.772004"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g4163" /><g
id="g4163"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.25,0,0,-1.25,0,80)"><path
inkscape:connector-curvature="0"
id="path4167"
style="fill:#039bd5;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 64,32 C 64,14.327 49.673,0 32,0 14.327,0 0,14.327 0,32 0,49.673 14.327,64 32,64 49.673,64 64,49.673 64,32" /><g
transform="matrix(1.4341283,-0.03685349,-0.03685349,-1.4341283,6.7291558,58.393566)"
id="g3"><g
id="g5"><polygon
style="fill:#ffffff"
points="11.78,8.598 7.526,6.141 7.526,11.054 "
id="polygon7" /><polygon
style="fill:#ffffff"
points="11.78,14.738 7.526,12.282 7.526,17.193 "
id="polygon9" /><polygon
style="fill:#ffffff"
points="11.78,27.02 7.526,24.562 7.526,29.475 "
id="polygon11" /><polygon
style="fill:#ffffff"
points="12.135,27.635 7.881,30.09 12.135,32.546 "
id="polygon13" /><polygon
style="fill:#ffffff"
points="12.135,15.352 7.881,17.809 12.135,20.266 "
id="polygon15" /><polygon
style="fill:#ffffff"
points="12.135,9.211 7.881,11.668 12.135,14.124 "
id="polygon17" /><polygon
style="fill:#ffffff"
points="12.135,3.071 7.881,5.527 12.135,7.983 "
id="polygon19" /><polygon
style="fill:#ffffff"
points="17.099,5.527 12.844,3.071 12.844,7.983 "
id="polygon21" /><polygon
style="fill:#ffffff"
points="17.099,11.668 12.844,9.211 12.844,14.124 "
id="polygon23" /><polygon
style="fill:#ffffff"
points="17.099,17.809 12.844,15.352 12.844,20.266 "
id="polygon25" /><polygon
style="fill:#ffffff"
points="17.099,23.949 12.844,21.493 12.844,26.405 "
id="polygon27" /><polygon
style="fill:#ffffff"
points="17.099,30.09 12.844,27.635 12.844,32.546 "
id="polygon29" /><polygon
style="fill:#ffffff"
points="17.453,30.704 13.199,33.16 17.453,35.616 "
id="polygon31" /><polygon
style="fill:#ffffff"
points="17.453,24.562 13.199,27.02 17.453,29.475 "
id="polygon33" /><polygon
style="fill:#ffffff"
points="17.453,18.422 13.199,20.879 17.453,23.335 "
id="polygon35" /><polygon
style="fill:#ffffff"
points="17.453,12.282 13.199,14.738 17.453,17.193 "
id="polygon37" /><polygon
style="fill:#ffffff"
points="17.453,0 13.199,2.456 17.453,4.913 "
id="polygon39" /><polygon
style="fill:#ffffff"
points="6.462,11.668 2.208,9.211 2.208,14.124 "
id="polygon41" /><polygon
style="fill:#ffffff"
points="6.462,17.809 2.208,15.352 2.208,20.266 "
id="polygon43" /><polygon
style="fill:#ffffff"
points="6.462,23.949 2.208,21.493 2.208,26.405 "
id="polygon45" /><polygon
style="fill:#ffffff"
points="6.817,24.562 2.562,27.02 6.817,29.475 "
id="polygon47" /><polygon
style="fill:#ffffff"
points="6.817,18.422 2.562,20.879 6.817,23.335 "
id="polygon49" /><polygon
style="fill:#ffffff"
points="6.817,12.282 2.562,14.738 6.817,17.193 "
id="polygon51" /><polygon
style="fill:#ffffff"
points="6.817,6.141 2.562,8.598 6.817,11.054 "
id="polygon53" /><polygon
style="fill:#ffffff"
points="22.416,2.456 18.162,0 18.162,4.913 "
id="polygon55" /><polygon
style="fill:#ffffff"
points="22.416,14.738 18.162,12.282 18.162,17.193 "
id="polygon57" /><polygon
style="fill:#ffffff"
points="22.416,20.879 18.162,18.422 18.162,23.335 "
id="polygon59" /><polygon
style="fill:#ffffff"
points="22.416,27.02 18.162,24.562 18.162,29.475 "
id="polygon61" /><polygon
style="fill:#ffffff"
points="22.416,33.16 18.162,30.704 18.162,35.616 "
id="polygon63" /><polygon
style="fill:#ffffff"
points="22.771,27.635 18.517,30.09 22.771,32.546 "
id="polygon65" /><polygon
style="fill:#ffffff"
points="22.771,21.493 18.517,23.949 22.771,26.405 "
id="polygon67" /><polygon
style="fill:#ffffff"
points="22.771,15.352 18.517,17.809 22.771,20.266 "
id="polygon69" /><polygon
style="fill:#ffffff"
points="22.771,9.211 18.517,11.668 22.771,14.124 "
id="polygon71" /><polygon
style="fill:#ffffff"
points="22.771,3.071 18.517,5.527 22.771,7.983 "
id="polygon73" /><polygon
style="fill:#ffffff"
points="27.735,5.527 23.479,3.071 23.479,7.983 "
id="polygon75" /><polygon
style="fill:#ffffff"
points="27.735,11.668 23.479,9.211 23.479,14.124 "
id="polygon77" /><polygon
style="fill:#ffffff"
points="27.735,17.809 23.479,15.352 23.479,20.266 "
id="polygon79" /><polygon
style="fill:#ffffff"
points="27.735,30.09 23.479,27.635 23.479,32.546 "
id="polygon81" /><polygon
style="fill:#ffffff"
points="28.089,24.562 23.835,27.02 28.089,29.475 "
id="polygon83" /><polygon
style="fill:#ffffff"
points="28.089,12.282 23.835,14.738 28.089,17.193 "
id="polygon85" /><polygon
style="fill:#ffffff"
points="28.089,6.141 23.835,8.598 28.089,11.054 "
id="polygon87" /><polygon
style="fill:#ffffff"
points="33.052,8.598 28.798,6.141 28.798,11.054 "
id="polygon89" /><polygon
style="fill:#ffffff"
points="33.052,14.738 28.798,12.282 28.798,17.193 "
id="polygon91" /><polygon
style="fill:#ffffff"
points="33.052,20.879 28.798,18.422 28.798,23.335 "
id="polygon93" /><polygon
style="fill:#ffffff"
points="33.052,27.02 28.798,24.562 28.798,29.475 "
id="polygon95" /><polygon
style="fill:#ffffff"
points="33.408,21.493 29.153,23.949 33.408,26.405 "
id="polygon97" /><polygon
style="fill:#ffffff"
points="33.408,15.352 29.153,17.809 33.408,20.266 "
id="polygon99" /><polygon
style="fill:#ffffff"
points="33.408,9.211 29.153,11.668 33.408,14.124 "
id="polygon101" /></g></g></g></svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1,5 +1,7 @@
<RCC>
<qresource prefix="/">
<file>images/logo/background.png</file>
<file>images/logo/background_lessblue.png</file>
<file>images/logo/logo_spash2.png</file>
<file>images/network_map.png</file>
<file>images/global_switch_on.png</file>
@ -349,6 +351,7 @@
<file>images/logo/logo_512.png</file>
<file>images/logo/logo_info.png</file>
<file>images/logo/logo_splash.png</file>
<file>images/logo/logo_web_nobackground.png</file>
<file>images/logobar/logo_bar_fill.png</file>
<file>images/logobar/logo_bar_start.png</file>
<file>images/logobar/rslogo.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,184 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="144.40031"
height="31.875484"
id="svg6043"
version="1.1"
inkscape:version="0.92.1 r"
viewBox="0 0 144.40032 31.875486"
sodipodi:docname="logo_web_nobackground.svg"
inkscape:export-filename="/home/phenom/GIT/RetroShare/trunk/retroshare-gui/src/gui/images/logo/logo_web_nobackground.png"
inkscape:export-xdpi="265.03128"
inkscape:export-ydpi="265.03128">
<defs
id="defs6045">
<linearGradient
id="linearGradient4183"
inkscape:collect="always">
<stop
id="stop4185"
offset="0"
style="stop-color:#abe3ff;stop-opacity:1" />
<stop
id="stop4187"
offset="1"
style="stop-color:#0e8ecb;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4183"
id="linearGradient4170"
x1="-707.36493"
y1="878.20923"
x2="-694.01666"
y2="892.13776"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4183"
id="linearGradient4172"
gradientUnits="userSpaceOnUse"
x1="2.3214316"
y1="9.6272764"
x2="15.030971"
y2="22.573706" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4183"
id="linearGradient4213"
x1="28.660715"
y1="6.0267878"
x2="10.758928"
y2="10.982145"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4183"
id="linearGradient4221"
x1="18.392859"
y1="30.714291"
x2="23.035715"
y2="12.991074"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:cx="53.37166"
inkscape:cy="7.2519486"
inkscape:document-units="px"
inkscape:current-layer="texts"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1832"
inkscape:window-height="966"
inkscape:window-x="0"
inkscape:window-y="30"
inkscape:window-maximized="1" />
<metadata
id="metadata6048">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="black_circle"
transform="translate(8.2538928e-6,2.2345076)"
style="display:inline">
<circle
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.29999995;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4140"
cx="16.250002"
cy="13.122637"
r="15.357144" />
</g>
<g
inkscape:label="symbol"
inkscape:groupmode="layer"
id="layer1"
transform="translate(709.10597,-869.59315)"
style="display:inline">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:url(#linearGradient4213);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:60.50111771;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 24.779297,2.2382812 A 5.0549051,5.0549051 0 0 0 23.277344,2.40625 5.0549051,5.0549051 0 0 0 19.552734,6.8925781 l -9.482422,2.5410157 c 0.59171,0.9617502 0.910617,2.0899062 0.878907,3.2539062 l 9.474609,-2.539062 a 5.0549051,5.0549051 0 0 0 5.470703,2.023437 5.0549051,5.0549051 0 0 0 3.574219,-6.1914062 5.0549051,5.0549051 0 0 0 -4.689453,-3.7421876 z"
transform="translate(-709.10597,869.59315)"
id="path4148"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:url(#linearGradient4221);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:60.50111771;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 21.496094,12.3125 -2.539063,9.472656 a 5.0549085,5.0549051 0 0 0 -0.912109,0.152344 5.0549085,5.0549051 0 0 0 -3.576172,6.191406 5.0549085,5.0549051 0 0 0 6.191406,3.574219 5.0549085,5.0549051 0 0 0 3.574219,-6.191406 5.0549085,5.0549051 0 0 0 -2.021484,-2.853516 l 2.539062,-9.480469 C 23.623173,13.209234 22.488304,12.922 21.496094,12.3125 Z"
transform="translate(-709.10597,869.59315)"
id="bottom"
inkscape:connector-curvature="0" />
<g
id="left"
style="fill:#abe3ff;fill-opacity:1">
<g
id="g4156"
style="fill:url(#linearGradient4170);fill-opacity:1">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:url(#linearGradient4172);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:60.50111771;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 5.2480469,7.4707031 A 5.0549051,5.0549051 0 0 0 3.7460938,7.640625 5.0549051,5.0549051 0 0 0 0.171875,13.830078 5.0549051,5.0549051 0 0 0 6.3632812,17.40625 5.0549051,5.0549051 0 0 0 7.2304688,17.082031 l 6.9394532,6.9375 c 0.53707,-0.9933 1.354986,-1.832209 2.378906,-2.386719 L 9.6152344,14.699219 A 5.0549051,5.0549051 0 0 0 9.9375,11.214844 5.0549051,5.0549051 0 0 0 5.2480469,7.4707031 Z"
transform="translate(-709.10597,869.59315)"
id="path4146"
inkscape:connector-curvature="0" />
</g>
</g>
<g
id="texts">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
x="-673.66925"
y="887.26001"
id="RETROSHARE"><tspan
sodipodi:role="line"
id="tspan4502"
x="-673.66925"
y="887.26001"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.66666603px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#5eb9e5;fill-opacity:1"
id="tspan4510">RETRO</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start"
id="tspan4522">SHARE</tspan></tspan></text>
<text
transform="scale(1.0202219,0.98017888)"
id="secure"
y="911.17212"
x="-659.19342"
style="font-style:normal;font-weight:normal;font-size:39.57231903px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.98930794px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.8611412px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.98930794px"
y="911.17212"
x="-659.19342"
id="tspan4506"
sodipodi:role="line">secure communication for everyone</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -487,6 +487,20 @@ void NotifyQt::notifyChatLobbyTimeShift(int shift)
emit chatLobbyTimeShift(shift) ;
}
void NotifyQt::notifyConnectionWithoutCert()
{
{
QMutexLocker m(&_mutex) ;
if(!_enabled)
return ;
}
#ifdef NOTIFY_DEBUG
std::cerr << "notifyQt: Received notifyConnectionWithoutCert" << std::endl;
#endif
emit connectionWithoutCert();
}
void NotifyQt::handleChatLobbyTimeShift(int /*shift*/)
{
return ; // we say nothing. The help dialog of lobbies explains this already.

View File

@ -52,6 +52,7 @@ class NotifyQt: public QObject, public NotifyClient
virtual void notifyOwnAvatarChanged() ;
virtual void notifyChatLobbyEvent(uint64_t /* lobby id */, uint32_t /* event type */, const RsGxsId & /*nickname*/, const std::string& /* any string */) ;
virtual void notifyChatLobbyTimeShift(int time_shift) ;
void notifyConnectionWithoutCert();
virtual void notifyOwnStatusMessageChanged() ;
virtual void notifyDiskFull(uint32_t loc,uint32_t size_in_mb) ;
@ -143,6 +144,7 @@ class NotifyQt: public QObject, public NotifyClient
void chatLobbyInviteReceived() ;
void deferredSignatureHandlingRequested() ;
void chatLobbyTimeShift(int time_shift) ;
void connectionWithoutCert();
/* Notify from GUI */
void chatFontChanged();

View File

@ -519,6 +519,21 @@ ServerPage QPlainTextEdit#plainTextEdit {
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2);
}
ServerPage QPlainTextEdit#hiddenpageInHelpPlainTextEdit {
border: 1px solid #DCDC41;
border-radius: 6px;
background: #FFFFD7;
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2);
}
ServerPage QPlainTextEdit#pteBobSimple {
border: 1px solid #DCDC41;
border-radius: 6px;
background: #FFFFD7;
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2);
}
/* ProfileManager */
ProfileManager > QFrame#headerFrame {
@ -665,49 +680,49 @@ IdEditDialog QLabel#info_label
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2);
}
GenCertDialog QComboBox#genPGPuser {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
}
GenCertDialog QSpinBox#hiddenport_spinBox {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
}
GenCertDialog QLineEdit#hiddenaddr_input {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
}
GenCertDialog QLineEdit#password_input_2 {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
}
GenCertDialog QLineEdit#password_input {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
}
GenCertDialog QLineEdit#nickname_input {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
}
GenCertDialog QLineEdit#node_input {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
}
GenCertDialog QLineEdit#name_input {
border: 4px solid #0099cc;
border: 2px solid #0099cc;
border-radius: 6px;
background: white;
font: bold;
@ -772,4 +787,14 @@ StartDialog QPushButton#loadButton {
StartDialog QPushButton#loadButton:hover {
border-image: url(:/images/btn_blue_hover.png) 4;
}
}
StartDialog QFrame#loginframe{
border-image: url(:/images/logo/background_lessblue.png) 0 0 0 0 stretch stretch;
border-width: 0px;
}
GenCertDialog QFrame#profileframe{
background-image: url(:/images/logo/background.png);
background-repeat: repeat;
}

Some files were not shown because too many files have changed in this diff Show More