RetroShare/libretroshare/src/services/p3msgservice.cc

2499 lines
67 KiB
C++
Raw Normal View History

/*
* libretroshare/src/services msgservice.cc
*
* Services for RetroShare.
*
* Copyright 2004-2008 by Robert Fernie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
#include "retroshare/rsiface.h"
#include "retroshare/rspeers.h"
#include "pqi/pqibin.h"
#include "pqi/pqiarchive.h"
#include "pqi/p3linkmgr.h"
#include "pqi/authgpg.h"
#include "services/p3msgservice.h"
#include "pgp/pgpkeyutil.h"
#include "pqi/p3cfgmgr.h"
#include "pqi/pqinotify.h"
#include "serialiser/rsconfigitems.h"
#include "util/rsdebug.h"
#include "util/rsdir.h"
#include "util/rsstring.h"
#include "util/radix64.h"
#include "util/rsrandom.h"
#include <iomanip>
#include <map>
//#define MSG_DEBUG 1
//#define DEBUG_DISTANT_MSG
//#define DISABLE_DISTANT_MESSAGES
const int msgservicezone = 54319;
static const uint32_t RS_DISTANT_MSG_STATUS_TUNNEL_OK = 0x0001 ;
static const uint32_t RS_DISTANT_MSG_STATUS_TUNNEL_DN = 0x0000 ;
static const uint32_t DISTANT_MSG_HASH_SIZE = 20 ;
static const uint8_t ENCRYPTED_MSG_PROTOCOL_VERSION_01 = 0x37 ;
/* Another little hack ..... unique message Ids
* will be handled in this class.....
* These are unique within this run of the server,
* and are not stored long term....
*
* Only 3 entry points:
* (1) from network....
* (2) from local send
* (3) from storage...
*/
p3MsgService::p3MsgService(p3LinkMgr *lm)
:p3Service(RS_SERVICE_TYPE_MSG), p3Config(CONFIG_TYPE_MSGS),
mLinkMgr(lm), mMsgMtx("p3MsgService"), mMsgUniqueId(time(NULL))
{
_serialiser = new RsMsgSerialiser();
addSerialType(_serialiser);
mDistantMessagingEnabled = true ;
/* Initialize standard tag types */
if(lm)
initStandardTagTypes();
}
uint32_t p3MsgService::getNewUniqueMsgId()
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
return mMsgUniqueId++;
}
int p3MsgService::tick()
{
pqioutput(PQL_DEBUG_BASIC, msgservicezone,
"p3MsgService::tick()");
/* don't worry about increasing tick rate!
* (handled by p3service)
*/
incomingMsgs();
static time_t last_management_time = 0 ;
time_t now = time(NULL) ;
if(now > last_management_time + 5)
{
manageDistantPeers() ;
checkOutgoingMessages();
last_management_time = now ;
}
return 0;
}
int p3MsgService::status()
{
pqioutput(PQL_DEBUG_BASIC, msgservicezone,
"p3MsgService::status()");
return 1;
}
void p3MsgService::processMsg(RsMsgItem *mi, bool incoming)
{
mi -> recvTime = time(NULL);
mi -> msgId = getNewUniqueMsgId();
{
RsStackMutex stack(mMsgMtx); /*** STACK LOCKED MTX ***/
if (incoming)
{
/* from a peer */
mi->msgFlags &= (RS_MSG_FLAGS_ENCRYPTED | RS_MSG_FLAGS_SYSTEM); // remove flags except those
mi->msgFlags |= RS_MSG_FLAGS_NEW;
pqiNotify *notify = getPqiNotify();
if (notify)
{
std::string title, message;
librs::util::ConvertUtf16ToUtf8(mi->subject, title);
librs::util::ConvertUtf16ToUtf8(mi->message, message);
if(mi->msgFlags & RS_MSG_FLAGS_ENCRYPTED)
notify->AddPopupMessage(RS_POPUP_ENCRYPTED_MSG, mi->PeerId(), title, message);
else
notify->AddPopupMessage(RS_POPUP_MSG, mi->PeerId(), title, message);
std::string out;
rs_sprintf(out, "%lu", mi->msgId);
notify->AddFeedItem(RS_FEED_ITEM_MESSAGE, out, "", "");
}
}
else
{
mi->msgFlags |= RS_MSG_OUTGOING;
}
imsg[mi->msgId] = mi;
RsMsgSrcId* msi = new RsMsgSrcId();
msi->msgId = mi->msgId;
msi->srcId = mi->PeerId();
mSrcIds.insert(std::pair<uint32_t, RsMsgSrcId*>(msi->msgId, msi));
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_ADD);
/**** STACK UNLOCKED ***/
}
bool p3MsgService::checkAndRebuildPartialMessage(RsMsgItem *ci)
{
// Check is the item is ending an incomplete item.
//
std::map<std::string,RsMsgItem*>::iterator it = _pendingPartialMessages.find(ci->PeerId()) ;
bool ci_is_partial = ci->msgFlags & RS_MSG_FLAGS_PARTIAL ;
if(it != _pendingPartialMessages.end())
{
#ifdef MSG_DEBUG
std::cerr << "Pending message found. Appending it." << std::endl;
#endif
// Yes, there is. Append the item to ci.
ci->message = it->second->message + ci->message ;
ci->msgFlags |= it->second->msgFlags ;
delete it->second ;
if(!ci_is_partial)
_pendingPartialMessages.erase(it) ;
}
if(ci_is_partial)
{
#ifdef MSG_DEBUG
std::cerr << "Message is partial, storing for later." << std::endl;
#endif
// The item is a partial message. Push it, and wait for the rest.
//
_pendingPartialMessages[ci->PeerId()] = ci ;
return false ;
}
else
{
#ifdef MSG_DEBUG
std::cerr << "Message is complete, using it now." << std::endl;
#endif
return true ;
}
}
int p3MsgService::incomingMsgs()
{
RsMsgItem *mi;
int i = 0;
while((mi = (RsMsgItem *) recvItem()) != NULL)
{
handleIncomingItem(mi) ;
++i ;
}
return i;
}
void p3MsgService::handleIncomingItem(RsMsgItem *mi)
{
bool changed = false ;
if(checkAndRebuildPartialMessage(mi)) // only returns true when a msg is complete.
{
processMsg(mi, true);
changed = true ;
}
if(changed)
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
}
void p3MsgService::statusChange(const std::list<pqipeer> &/*plist*/)
{
/* should do it properly! */
checkOutgoingMessages();
}
void p3MsgService::checkSizeAndSendMessage(RsMsgItem *msg)
{
// We check the message item, and possibly split it into multiple messages, if the message is too big.
static const uint32_t MAX_STRING_SIZE = 15000 ;
std::cerr << "Msg is size " << msg->message.size() << std::endl;
while(msg->message.size() > MAX_STRING_SIZE)
{
// chop off the first 15000 wchars
RsMsgItem *item = new RsMsgItem(*msg) ;
item->message = item->message.substr(0,MAX_STRING_SIZE) ;
msg->message = msg->message.substr(MAX_STRING_SIZE,msg->message.size()-MAX_STRING_SIZE) ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Chopped off msg of size " << item->message.size() << std::endl;
#endif
// Indicate that the message is to be continued.
//
item->msgFlags |= RS_MSG_FLAGS_PARTIAL ;
if(msg->msgFlags & RS_MSG_FLAGS_DISTANT)
sendPrivateMsgItem(item) ;
else
sendItem(item) ;
}
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Chopped off msg of size " << msg->message.size() << std::endl;
#endif
if(msg->msgFlags & RS_MSG_FLAGS_DISTANT)
sendPrivateMsgItem(msg) ;
else
sendItem(msg) ;
}
int p3MsgService::checkOutgoingMessages()
{
/* iterate through the outgoing queue
*
* if online, send
*/
bool changed = false ;
std::list<RsMsgItem*> output_queue ;
{
const std::string ownId = mLinkMgr->getOwnId();
std::list<uint32_t>::iterator it;
std::list<uint32_t> toErase;
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgItem *>::iterator mit;
for(mit = msgOutgoing.begin(); mit != msgOutgoing.end(); mit++)
{
if (mit->second->msgFlags & RS_MSG_FLAGS_TRASH) {
continue;
}
/* find the certificate */
std::string pid = mit->second->PeerId();
bool tunnel_is_ok = false ;
if(mit->second->msgFlags & RS_MSG_FLAGS_DISTANT)
{
// Do we have a tunnel already?
//
#ifdef GROUTER
tunnel_is_ok = true ;
#else
const std::string& hash = mit->second->PeerId() ;
std::map<std::string,DistantMessengingContact>::iterator it = _messenging_contacts.find(hash) ;
if(it != _messenging_contacts.end())
{
tunnel_is_ok = (it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_OK) ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << "checkOutGoingMessages(): distant contact found. tunnel_is_ok = " << tunnel_is_ok << std::endl;
#endif
}
else
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << "checkOutGoingMessages(): distant contact not found. Asking for tunnels for hash " << hash << std::endl;
#endif
// no. Ask for monitoring tunnels.
rsTurtle->monitorTunnels(hash,this) ;
tunnel_is_ok = false ;
DistantMessengingContact& contact( _messenging_contacts[hash] ) ;
contact.status = RS_DISTANT_MSG_STATUS_TUNNEL_DN ;
contact.pending_messages = true ;
}
#endif
}
if(tunnel_is_ok || mLinkMgr->isOnline(pid) || pid == ownId) /* FEEDBACK Msg to Ourselves */
{
/* send msg */
pqioutput(PQL_DEBUG_BASIC, msgservicezone,
"p3MsgService::checkOutGoingMessages() Sending out message");
/* remove the pending flag */
(mit->second)->msgFlags &= ~RS_MSG_FLAGS_PENDING;
output_queue.push_back(mit->second) ;
toErase.push_back(mit->first);
changed = true ;
}
else
{
pqioutput(PQL_DEBUG_BASIC, msgservicezone,
"p3MsgService::checkOutGoingMessages() Delaying until available...");
}
}
/* clean up */
for(it = toErase.begin(); it != toErase.end(); it++)
{
mit = msgOutgoing.find(*it);
if (mit != msgOutgoing.end())
{
msgOutgoing.erase(mit);
}
std::map<uint32_t, RsMsgSrcId*>::iterator srcIt = mSrcIds.find(*it);
if (srcIt != mSrcIds.end()) {
delete (srcIt->second);
mSrcIds.erase(srcIt);
}
}
if (toErase.size() > 0)
{
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
}
for(std::list<RsMsgItem*>::const_iterator it(output_queue.begin());it!=output_queue.end();++it)
{
checkSizeAndSendMessage(*it) ;
if( (*it)->msgFlags & RS_MSG_FLAGS_DISTANT )
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
_messenging_contacts[(*it)->PeerId()].pending_messages = false ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << "checkOutgoingMessages(): removing pending message flag for hash " << (*it)->PeerId() << "." << std::endl;
#endif
}
}
if(changed)
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
return 0;
}
bool p3MsgService::saveList(bool& cleanup, std::list<RsItem*>& itemList)
{
std::map<uint32_t, RsMsgItem *>::iterator mit;
std::map<uint32_t, RsMsgTagType* >::iterator mit2;
std::map<uint32_t, RsMsgTags* >::iterator mit3;
std::map<uint32_t, RsMsgSrcId* >::iterator lit;
std::map<uint32_t, RsMsgParentId* >::iterator mit4;
MsgTagType stdTags;
cleanup = false;
mMsgMtx.lock();
for(mit = imsg.begin(); mit != imsg.end(); mit++)
itemList.push_back(mit->second);
for(lit = mSrcIds.begin(); lit != mSrcIds.end(); lit++)
itemList.push_back(lit->second);
for(mit = msgOutgoing.begin(); mit != msgOutgoing.end(); mit++)
itemList.push_back(mit->second) ;
for(mit2 = mTags.begin(); mit2 != mTags.end(); mit2++)
itemList.push_back(mit2->second);
for(mit3 = mMsgTags.begin(); mit3 != mMsgTags.end(); mit3++)
itemList.push_back(mit3->second);
for(mit4 = mParentId.begin(); mit4 != mParentId.end(); mit4++)
itemList.push_back(mit4->second);
for(std::map<std::string,DistantMessengingInvite>::const_iterator it(_messenging_invites.begin());it!=_messenging_invites.end();++it)
{
RsPublicMsgInviteConfigItem *item = new RsPublicMsgInviteConfigItem ;
item->hash = it->first ;
item->time_stamp = it->second.time_of_validity ;
itemList.push_back(item) ;
}
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ;
RsTlvKeyValue kv;
kv.key = "DISTANT_MESSAGES_ENABLED" ;
kv.value = mDistantMessagingEnabled?"YES":"NO" ;
vitem->tlvkvs.pairs.push_back(kv) ;
itemList.push_back(vitem) ;
return true;
}
void p3MsgService::saveDone()
{
// unlocks mutex which has been locked by savelist
mMsgMtx.unlock();
}
RsSerialiser* p3MsgService::setupSerialiser()
{
RsSerialiser *rss = new RsSerialiser ;
rss->addSerialType(new RsMsgSerialiser(true));
rss->addSerialType(new RsGeneralConfigSerialiser());
return rss;
}
// build list of standard tag types
static void getStandardTagTypes(MsgTagType &tags)
{
/* create standard tag types, the text must be translated in the GUI */
tags.types [RS_MSGTAGTYPE_IMPORTANT] = std::pair<std::string, uint32_t> ("Important", 0xFF0000);
tags.types [RS_MSGTAGTYPE_WORK] = std::pair<std::string, uint32_t> ("Work", 0xFF9900);
tags.types [RS_MSGTAGTYPE_PERSONAL] = std::pair<std::string, uint32_t> ("Personal", 0x009900);
tags.types [RS_MSGTAGTYPE_TODO] = std::pair<std::string, uint32_t> ("Todo", 0x3333FF);
tags.types [RS_MSGTAGTYPE_LATER] = std::pair<std::string, uint32_t> ("Later", 0x993399);
}
// Initialize the standard tag types after load
void p3MsgService::initStandardTagTypes()
{
bool bChanged = false;
std::string ownId = mLinkMgr->getOwnId();
MsgTagType tags;
getStandardTagTypes(tags);
std::map<uint32_t, std::pair<std::string, uint32_t> >::iterator tit;
for (tit = tags.types.begin(); tit != tags.types.end(); tit++) {
std::map<uint32_t, RsMsgTagType*>::iterator mit = mTags.find(tit->first);
if (mit == mTags.end()) {
RsMsgTagType* tagType = new RsMsgTagType();
tagType->PeerId (ownId);
tagType->tagId = tit->first;
tagType->text = tit->second.first;
tagType->rgb_color = tit->second.second;
mTags.insert(std::pair<uint32_t, RsMsgTagType*>(tit->first, tagType));
bChanged = true;
}
}
if (bChanged) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
}
bool p3MsgService::loadList(std::list<RsItem*>& load)
{
RsMsgItem *mitem;
RsMsgTagType* mtt;
RsMsgTags* mti;
RsMsgSrcId* msi;
RsMsgParentId* msp;
RsPublicMsgInviteConfigItem* msv;
std::list<RsMsgItem*> items;
std::list<RsItem*>::iterator it;
std::map<uint32_t, RsMsgTagType*>::iterator tagIt;
std::map<uint32_t, std::string> srcIdMsgMap;
std::map<uint32_t, std::string>::iterator srcIt;
bool distant_messaging_set = false ;
// load items and calculate next unique msgId
for(it = load.begin(); it != load.end(); it++)
{
if (NULL != (mitem = dynamic_cast<RsMsgItem *>(*it)))
{
/* STORE MsgID */
if (mitem->msgId >= mMsgUniqueId) {
mMsgUniqueId = mitem->msgId + 1;
}
items.push_back(mitem);
}
else if(NULL != (mtt = dynamic_cast<RsMsgTagType *>(*it)))
{
// delete standard tags as they are now save in config
if(mTags.end() == (tagIt = mTags.find(mtt->tagId)))
{
mTags.insert(std::pair<uint32_t, RsMsgTagType* >(mtt->tagId, mtt));
}
else
{
delete mTags[mtt->tagId];
mTags.erase(tagIt);
mTags.insert(std::pair<uint32_t, RsMsgTagType* >(mtt->tagId, mtt));
}
}
else if(NULL != (mti = dynamic_cast<RsMsgTags *>(*it)))
{
mMsgTags.insert(std::pair<uint32_t, RsMsgTags* >(mti->msgId, mti));
}
else if(NULL != (msi = dynamic_cast<RsMsgSrcId *>(*it)))
{
srcIdMsgMap.insert(std::pair<uint32_t, std::string>(msi->msgId, msi->srcId));
mSrcIds.insert(std::pair<uint32_t, RsMsgSrcId*>(msi->msgId, msi)); // does not need to be kept
}
else if(NULL != (msp = dynamic_cast<RsMsgParentId *>(*it)))
{
mParentId.insert(std::pair<uint32_t, RsMsgParentId*>(msp->msgId, msp));
}
else if(NULL != (msv = dynamic_cast<RsPublicMsgInviteConfigItem *>(*it)))
{
_messenging_invites[msv->hash].time_of_validity = msv->time_stamp ;
}
RsConfigKeyValueSet *vitem = NULL ;
if(NULL != (vitem = dynamic_cast<RsConfigKeyValueSet*>(*it)))
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
if(kit->key == "DISTANT_MESSAGES_ENABLED")
{
#ifdef MSG_DEBUG
std::cerr << "Loaded config default nick name for distant chat: " << kit->value << std::endl ;
#endif
enableDistantMessaging(kit->value == "YES") ;
distant_messaging_set = true ;
}
}
if(!distant_messaging_set)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << "No config value for distant messaging. Setting it to true." << std::endl;
#endif
enableDistantMessaging(true) ;
}
// sort items into lists
std::list<RsMsgItem*>::iterator msgIt;
for (msgIt = items.begin(); msgIt != items.end(); msgIt++)
{
mitem = *msgIt;
/* STORE MsgID */
if (mitem->msgId == 0) {
mitem->msgId = getNewUniqueMsgId();
}
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
srcIt = srcIdMsgMap.find(mitem->msgId);
if(srcIt != srcIdMsgMap.end()) {
mitem->PeerId(srcIt->second);
srcIdMsgMap.erase(srcIt);
}
/* switch depending on the PENDING
* flags
*/
if (mitem -> msgFlags & RS_MSG_FLAGS_PENDING)
{
//std::cerr << "MSG_PENDING";
//std::cerr << std::endl;
//mitem->print(std::cerr);
msgOutgoing[mitem->msgId] = mitem;
}
else
{
imsg[mitem->msgId] = mitem;
}
}
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
/* remove missing msgId in mSrcIds */
for (srcIt = srcIdMsgMap.begin(); srcIt != srcIdMsgMap.end(); srcIt++) {
std::map<uint32_t, RsMsgSrcId*>::iterator it = mSrcIds.find(srcIt->first);
if (it != mSrcIds.end()) {
delete(it->second);
mSrcIds.erase(it);
}
}
/* remove missing msgId in mParentId */
std::map<uint32_t, RsMsgParentId *>::iterator mit = mParentId.begin();
while (mit != mParentId.end()) {
if (imsg.find(mit->first) == imsg.end()) {
if (msgOutgoing.find(mit->first) == msgOutgoing.end()) {
/* not found */
mParentId.erase(mit++);
continue;
}
}
mit++;
}
return true;
}
void p3MsgService::loadWelcomeMsg()
{
/* Load Welcome Message */
RsMsgItem *msg = new RsMsgItem();
//msg -> PeerId(mLinkMgr->getOwnId());
msg -> sendTime = time(NULL);
msg -> recvTime = time(NULL);
msg -> msgFlags = RS_MSG_FLAGS_NEW;
msg -> subject = L"Welcome to Retroshare";
msg -> message = L"Send and receive messages with your friends...\n";
msg -> message += L"These can hold recommendations from your local shared files.\n\n";
msg -> message += L"Add recommendations through the Local Files Dialog.\n\n";
msg -> message += L"Enjoy.";
msg -> msgId = getNewUniqueMsgId();
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
imsg[msg->msgId] = msg;
IndicateConfigChanged();
}
/***********************************************************************/
/***********************************************************************/
/***********************************************************************/
/***********************************************************************/
/****************************************/
/****************************************/
bool p3MsgService::getMessageSummaries(std::list<MsgInfoSummary> &msgList)
{
/* do stuff */
msgList.clear();
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgItem *>::iterator mit;
for(mit = imsg.begin(); mit != imsg.end(); mit++)
{
MsgInfoSummary mis;
initRsMIS(mit->second, mis);
msgList.push_back(mis);
}
for(mit = msgOutgoing.begin(); mit != msgOutgoing.end(); mit++)
{
MsgInfoSummary mis;
initRsMIS(mit->second, mis);
msgList.push_back(mis);
}
return true;
}
bool p3MsgService::getMessage(const std::string &mId, MessageInfo &msg)
{
std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mId.c_str());
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
mit = imsg.find(msgId);
if (mit == imsg.end())
{
mit = msgOutgoing.find(msgId);
if (mit == msgOutgoing.end())
{
return false;
}
}
/* mit valid */
initRsMI(mit->second, msg);
return true;
}
void p3MsgService::getMessageCount(unsigned int *pnInbox, unsigned int *pnInboxNew, unsigned int *pnOutbox, unsigned int *pnDraftbox, unsigned int *pnSentbox, unsigned int *pnTrashbox)
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
if (pnInbox) *pnInbox = 0;
if (pnInboxNew) *pnInboxNew = 0;
if (pnOutbox) *pnOutbox = 0;
if (pnDraftbox) *pnDraftbox = 0;
if (pnSentbox) *pnSentbox = 0;
if (pnTrashbox) *pnTrashbox = 0;
std::map<uint32_t, RsMsgItem *>::iterator mit;
std::map<uint32_t, RsMsgItem *> *apMsg [2] = { &imsg, &msgOutgoing };
for (int i = 0; i < 2; i++) {
for (mit = apMsg [i]->begin(); mit != apMsg [i]->end(); mit++) {
MsgInfoSummary mis;
initRsMIS(mit->second, mis);
if (mis.msgflags & RS_MSG_TRASH) {
if (pnTrashbox) (*pnTrashbox)++;
continue;
}
switch (mis.msgflags & RS_MSG_BOXMASK) {
case RS_MSG_INBOX:
if (pnInbox) (*pnInbox)++;
if ((mis.msgflags & RS_MSG_NEW) == RS_MSG_NEW) {
if (pnInboxNew) (*pnInboxNew)++;
}
break;
case RS_MSG_OUTBOX:
if (pnOutbox) (*pnOutbox)++;
break;
case RS_MSG_DRAFTBOX:
if (pnDraftbox) (*pnDraftbox)++;
break;
case RS_MSG_SENTBOX:
if (pnSentbox) (*pnSentbox)++;
break;
}
}
}
}
/* remove based on the unique mid (stored in sid) */
bool p3MsgService::removeMsgId(const std::string &mid)
{
std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mid.c_str());
if (msgId == 0) {
std::cerr << "p3MsgService::removeMsgId: Unknown msgId " << msgId << std::endl;
return false;
}
bool changed = false;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
mit = imsg.find(msgId);
if (mit != imsg.end())
{
changed = true;
RsMsgItem *mi = mit->second;
imsg.erase(mit);
delete mi;
}
mit = msgOutgoing.find(msgId);
if (mit != msgOutgoing.end())
{
changed = true ;
RsMsgItem *mi = mit->second;
msgOutgoing.erase(mit);
delete mi;
}
std::map<uint32_t, RsMsgSrcId*>::iterator srcIt = mSrcIds.find(msgId);
if (srcIt != mSrcIds.end()) {
changed = true;
delete (srcIt->second);
mSrcIds.erase(srcIt);
}
}
if(changed) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
setMessageTag(mid, 0, false);
setMsgParentId(msgId, 0);
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
}
return changed;
}
bool p3MsgService::markMsgIdRead(const std::string &mid, bool unreadByUser)
{
std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mid.c_str());
bool changed = false;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
mit = imsg.find(msgId);
if (mit != imsg.end())
{
RsMsgItem *mi = mit->second;
uint32_t msgFlags = mi->msgFlags;
/* remove new state */
mi->msgFlags &= ~(RS_MSG_FLAGS_NEW);
/* set state from user */
if (unreadByUser) {
mi->msgFlags |= RS_MSG_FLAGS_UNREAD_BY_USER;
} else {
mi->msgFlags &= ~RS_MSG_FLAGS_UNREAD_BY_USER;
}
if (mi->msgFlags != msgFlags)
{
changed = true;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
} else {
return false;
}
} /* UNLOCKED */
if (changed) {
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
}
return true;
}
bool p3MsgService::setMsgFlag(const std::string &mid, uint32_t flag, uint32_t mask)
{
std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mid.c_str());
bool changed = false;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
mit = imsg.find(msgId);
if (mit == imsg.end())
{
mit = msgOutgoing.find(msgId);
if (mit == msgOutgoing.end())
{
return false;
}
}
uint32_t oldFlag = mit->second->msgFlags;
mit->second->msgFlags &= ~mask;
mit->second->msgFlags |= flag;
if (mit->second->msgFlags != oldFlag) {
changed = true;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
} /* UNLOCKED */
if (changed) {
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
}
return true;
}
bool p3MsgService::getMsgParentId(const std::string &msgId, std::string &msgParentId)
{
msgParentId.clear();
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgParentId *>::iterator mit = mParentId.find(atoi(msgId.c_str()));
if (mit == mParentId.end()) {
return false;
}
rs_sprintf(msgParentId, "%lu", mit->second->msgParentId);
return true;
}
bool p3MsgService::setMsgParentId(uint32_t msgId, uint32_t msgParentId)
{
std::map<uint32_t, RsMsgParentId *>::iterator mit;
bool changed = false;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
mit = mParentId.find(msgId);
if (mit == mParentId.end())
{
if (msgParentId) {
RsMsgParentId* msp = new RsMsgParentId();
msp->PeerId (mLinkMgr->getOwnId());
msp->msgId = msgId;
msp->msgParentId = msgParentId;
mParentId.insert(std::pair<uint32_t, RsMsgParentId*>(msgId, msp));
changed = true;
}
} else {
if (msgParentId) {
if (mit->second->msgParentId != msgParentId) {
mit->second->msgParentId = msgParentId;
changed = true;
}
} else {
delete mit->second;
mParentId.erase(mit);
changed = true;
}
}
} /* UNLOCKED */
if (changed) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
return true;
}
/****************************************/
/****************************************/
/* Message Items */
int p3MsgService::sendMessage(RsMsgItem *item)
{
pqioutput(PQL_DEBUG_BASIC, msgservicezone,
"p3MsgService::sendMessage()");
item -> msgId = getNewUniqueMsgId(); /* grabs Mtx as well */
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
/* add pending flag */
item->msgFlags |= (RS_MSG_FLAGS_OUTGOING | RS_MSG_FLAGS_PENDING);
/* STORE MsgID */
msgOutgoing[item->msgId] = item;
if (item->PeerId() != mLinkMgr->getOwnId()) {
/* not to the loopback device */
RsMsgSrcId* msi = new RsMsgSrcId();
msi->msgId = item->msgId;
msi->srcId = item->PeerId();
mSrcIds.insert(std::pair<uint32_t, RsMsgSrcId*>(msi->msgId, msi));
}
}
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST, NOTIFY_TYPE_ADD);
checkOutgoingMessages();
return 1;
}
bool p3MsgService::MessageSend(MessageInfo &info)
{
std::list<std::string>::const_iterator pit;
for(pit = info.msgto.begin(); pit != info.msgto.end(); pit++)
{
RsMsgItem *msg = initMIRsMsg(info, *pit);
if (msg)
{
sendMessage(msg);
}
}
for(pit = info.msgcc.begin(); pit != info.msgcc.end(); pit++)
{
RsMsgItem *msg = initMIRsMsg(info, *pit);
if (msg)
{
sendMessage(msg);
}
}
for(pit = info.msgbcc.begin(); pit != info.msgbcc.end(); pit++)
{
RsMsgItem *msg = initMIRsMsg(info, *pit);
if (msg)
{
sendMessage(msg);
}
}
/* send to ourselves as well */
RsMsgItem *msg = initMIRsMsg(info, mLinkMgr->getOwnId());
if (msg)
{
std::list<std::string>::iterator it ;
// Update destination ids in place of distant message hash, since this Outgoing message is for display
//
for(it = msg->msgbcc.ids.begin(); it != msg->msgbcc.ids.end(); it++)
if(info.encryption_keys.find(*it) != info.encryption_keys.end()) *it = info.encryption_keys[*it] ;
for(it = msg->msgcc.ids.begin(); it != msg->msgcc.ids.end(); it++)
if(info.encryption_keys.find(*it) != info.encryption_keys.end()) *it = info.encryption_keys[*it] ;
for(it = msg->msgto.ids.begin(); it != msg->msgto.ids.end(); it++)
if(info.encryption_keys.find(*it) != info.encryption_keys.end()) *it = info.encryption_keys[*it] ;
if (msg->msgFlags & RS_MSG_FLAGS_SIGNED)
msg->msgFlags |= RS_MSG_FLAGS_SIGNATURE_CHECKS; // this is always true, since we are sending the message
/* use processMsg to get the new msgId */
processMsg(msg, false);
// return new message id
rs_sprintf(info.msgId, "%lu", msg->msgId);
}
return true;
}
bool p3MsgService::SystemMessage(const std::wstring &title, const std::wstring &message, uint32_t systemFlag)
{
if ((systemFlag & RS_MSG_SYSTEM) == 0) {
/* no flag specified */
return false;
}
std::string ownId = mLinkMgr->getOwnId();
RsMsgItem *msg = new RsMsgItem();
msg->PeerId(ownId);
msg->msgFlags = 0;
if (systemFlag & RS_MSG_USER_REQUEST) {
msg->msgFlags |= RS_MSG_FLAGS_USER_REQUEST;
}
if (systemFlag & RS_MSG_FRIEND_RECOMMENDATION) {
msg->msgFlags |= RS_MSG_FLAGS_FRIEND_RECOMMENDATION;
}
msg->msgId = 0;
msg->sendTime = time(NULL);
msg->recvTime = 0;
msg->subject = title;
msg->message = message;
msg->msgto.ids.push_back(ownId);
processMsg(msg, true);
return true;
}
bool p3MsgService::MessageToDraft(MessageInfo &info, const std::string &msgParentId)
{
RsMsgItem *msg = initMIRsMsg(info, mLinkMgr->getOwnId());
if (msg)
{
uint32_t msgId = 0;
if (info.msgId.empty() == false) {
msgId = atoi(info.msgId.c_str());
}
if (msgId) {
msg->msgId = msgId;
} else {
msg->msgId = getNewUniqueMsgId(); /* grabs Mtx as well */
}
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
/* add pending flag */
msg->msgFlags |= (RS_MSG_OUTGOING | RS_MSG_FLAGS_DRAFT);
if (msgId) {
// remove existing message
std::map<uint32_t, RsMsgItem *>::iterator mit;
mit = imsg.find(msgId);
if (mit != imsg.end()) {
RsMsgItem *mi = mit->second;
imsg.erase(mit);
delete mi;
}
}
/* STORE MsgID */
imsg[msg->msgId] = msg;
// return new message id
rs_sprintf(info.msgId, "%lu", msg->msgId);
}
setMsgParentId(msg->msgId, atoi(msgParentId.c_str()));
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
return true;
}
return false;
}
bool p3MsgService::getMessageTagTypes(MsgTagType& tags)
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgTagType*>::iterator mit;
for(mit = mTags.begin(); mit != mTags.end(); mit++) {
std::pair<std::string, uint32_t> p(mit->second->text, mit->second->rgb_color);
tags.types.insert(std::pair<uint32_t, std::pair<std::string, uint32_t> >(mit->first, p));
}
return true;
}
bool p3MsgService::setMessageTagType(uint32_t tagId, std::string& text, uint32_t rgb_color)
{
int nNotifyType = 0;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgTagType*>::iterator mit;
mit = mTags.find(tagId);
if (mit == mTags.end()) {
if (tagId < RS_MSGTAGTYPE_USER) {
std::cerr << "p3MsgService::MessageSetTagType: Standard tag type " << tagId << " cannot be inserted" << std::endl;
return false;
}
/* new tag */
RsMsgTagType* tagType = new RsMsgTagType();
tagType->PeerId (mLinkMgr->getOwnId());
tagType->rgb_color = rgb_color;
tagType->tagId = tagId;
tagType->text = text;
mTags.insert(std::pair<uint32_t, RsMsgTagType*>(tagId, tagType));
nNotifyType = NOTIFY_TYPE_ADD;
} else {
if (mit->second->text != text || mit->second->rgb_color != rgb_color) {
/* modify existing tag */
if (tagId >= RS_MSGTAGTYPE_USER) {
mit->second->text = text;
} else {
/* don't change text for standard tag types */
if (mit->second->text != text) {
std::cerr << "p3MsgService::MessageSetTagType: Text " << text << " for standard tag type " << tagId << " cannot be changed" << std::endl;
}
}
mit->second->rgb_color = rgb_color;
nNotifyType = NOTIFY_TYPE_MOD;
}
}
} /* UNLOCKED */
if (nNotifyType) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGE_TAGS, nNotifyType);
return true;
}
return false;
}
bool p3MsgService::removeMessageTagType(uint32_t tagId)
{
if (tagId < RS_MSGTAGTYPE_USER) {
std::cerr << "p3MsgService::MessageRemoveTagType: Can't delete standard tag type " << tagId << std::endl;
return false;
}
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgTagType*>::iterator mit;
mit = mTags.find(tagId);
if (mit == mTags.end()) {
/* tag id not found */
std::cerr << "p3MsgService::MessageRemoveTagType: Tag Id not found " << tagId << std::endl;
return false;
}
/* search for messages with this tag type */
std::map<uint32_t, RsMsgTags*>::iterator mit1;
for (mit1 = mMsgTags.begin(); mit1 != mMsgTags.end(); ) {
RsMsgTags* tag = mit1->second;
std::list<uint32_t>::iterator lit;
lit = std::find(tag->tagIds.begin(), tag->tagIds.end(), tagId);
if (lit != tag->tagIds.end()) {
tag->tagIds.erase(lit);
if (tag->tagIds.size() == 0) {
/* remove empty tag */
delete(tag);
mMsgTags.erase(mit1++);
continue;
}
}
mit1++;
}
/* remove tag type */
delete(mit->second);
mTags.erase(mit);
} /* UNLOCKED */
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGE_TAGS, NOTIFY_TYPE_DEL);
return true;
}
bool p3MsgService::getMessageTag(const std::string &msgId, MsgTagInfo& info)
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
uint32_t mid = atoi(msgId.c_str());
if (mid == 0) {
std::cerr << "p3MsgService::MessageGetMsgTag: Unknown msgId " << msgId << std::endl;
return false;
}
std::map<uint32_t, RsMsgTags*>::iterator mit;
if(mMsgTags.end() != (mit = mMsgTags.find(mid))) {
rs_sprintf(info.msgId, "%lu", mit->second->msgId);
info.tagIds = mit->second->tagIds;
return true;
}
return false;
}
/* set == false && tagId == 0 --> remove all */
bool p3MsgService::setMessageTag(const std::string &msgId, uint32_t tagId, bool set)
{
uint32_t mid = atoi(msgId.c_str());
if (mid == 0) {
std::cerr << "p3MsgService::MessageSetMsgTag: Unknown msgId " << msgId << std::endl;
return false;
}
if (tagId == 0) {
if (set == true) {
std::cerr << "p3MsgService::MessageSetMsgTag: No valid tagId given " << tagId << std::endl;
return false;
}
}
int nNotifyType = 0;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgTags*>::iterator mit;
mit = mMsgTags.find(mid);
if (mit == mMsgTags.end()) {
if (set) {
/* new msg */
RsMsgTags* tag = new RsMsgTags();
tag->PeerId (mLinkMgr->getOwnId());
tag->msgId = mid;
tag->tagIds.push_back(tagId);
mMsgTags.insert(std::pair<uint32_t, RsMsgTags*>(tag->msgId, tag));
nNotifyType = NOTIFY_TYPE_ADD;
}
} else {
RsMsgTags* tag = mit->second;
/* search existing tagId */
std::list<uint32_t>::iterator lit;
if (tagId) {
lit = std::find(tag->tagIds.begin(), tag->tagIds.end(), tagId);
} else {
lit = tag->tagIds.end();
}
if (set) {
if (lit == tag->tagIds.end()) {
tag->tagIds.push_back(tagId);
/* keep the list sorted */
tag->tagIds.sort();
nNotifyType = NOTIFY_TYPE_ADD;
}
} else {
if (tagId == 0) {
/* remove all */
delete(tag);
mMsgTags.erase(mit);
nNotifyType = NOTIFY_TYPE_DEL;
} else {
if (lit != tag->tagIds.end()) {
tag->tagIds.erase(lit);
nNotifyType = NOTIFY_TYPE_DEL;
if (tag->tagIds.size() == 0) {
/* remove empty tag */
delete(tag);
mMsgTags.erase(mit);
}
}
}
}
}
} /* UNLOCKED */
if (nNotifyType) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGE_TAGS, nNotifyType);
return true;
}
return false;
}
bool p3MsgService::resetMessageStandardTagTypes(MsgTagType& tags)
{
MsgTagType standardTags;
getStandardTagTypes(standardTags);
std::map<uint32_t, std::pair<std::string, uint32_t> >::iterator mit;
for (mit = standardTags.types.begin(); mit != standardTags.types.end(); mit++) {
tags.types[mit->first] = mit->second;
}
return true;
}
/* move message to trash based on the unique mid */
bool p3MsgService::MessageToTrash(const std::string &mid, bool bTrash)
{
std::map<uint32_t, RsMsgItem *>::iterator mit;
uint32_t msgId = atoi(mid.c_str());
bool bChanged = false;
bool bFound = false;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
RsMsgItem *mi = NULL;
mit = imsg.find(msgId);
if (mit != imsg.end()) {
mi = mit->second;
} else {
mit = msgOutgoing.find(msgId);
if (mit != msgOutgoing.end()) {
mi = mit->second;
}
}
if (mi) {
bFound = true;
if (bTrash) {
if ((mi->msgFlags & RS_MSG_FLAGS_TRASH) == 0) {
mi->msgFlags |= RS_MSG_FLAGS_TRASH;
bChanged = true;
}
} else {
if (mi->msgFlags & RS_MSG_FLAGS_TRASH) {
mi->msgFlags &= ~RS_MSG_FLAGS_TRASH;
bChanged = true;
}
}
}
}
if (bChanged) {
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
checkOutgoingMessages();
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
}
return bFound;
}
/****************************************/
/****************************************/
/****************************************/
/**** HELPER FNS For Chat/Msg/Channel Lists ************
* These aren't required to be locked, unless
* the data used is from internal stores -> then they should be.
*/
void p3MsgService::initRsMI(RsMsgItem *msg, MessageInfo &mi)
{
mi.msgflags = 0;
/* translate flags, if we sent it... outgoing */
if ((msg->msgFlags & RS_MSG_FLAGS_OUTGOING)
/*|| (msg->PeerId() == mLinkMgr->getOwnId())*/)
{
mi.msgflags |= RS_MSG_OUTGOING;
}
/* if it has a pending flag, then its in the outbox */
if (msg->msgFlags & RS_MSG_FLAGS_PENDING)
{
mi.msgflags |= RS_MSG_PENDING;
}
if (msg->msgFlags & RS_MSG_FLAGS_DRAFT)
{
mi.msgflags |= RS_MSG_DRAFT;
}
if (msg->msgFlags & RS_MSG_FLAGS_NEW)
{
mi.msgflags |= RS_MSG_NEW;
}
if (msg->msgFlags & RS_MSG_FLAGS_SIGNED)
mi.msgflags |= RS_MSG_SIGNED ;
if (msg->msgFlags & RS_MSG_FLAGS_SIGNATURE_CHECKS)
mi.msgflags |= RS_MSG_SIGNATURE_CHECKS ;
if (msg->msgFlags & RS_MSG_FLAGS_ENCRYPTED)
mi.msgflags |= RS_MSG_ENCRYPTED ;
if (msg->msgFlags & RS_MSG_FLAGS_DECRYPTED)
mi.msgflags |= RS_MSG_DECRYPTED ;
if (msg->msgFlags & RS_MSG_FLAGS_TRASH)
{
mi.msgflags |= RS_MSG_TRASH;
}
if (msg->msgFlags & RS_MSG_FLAGS_UNREAD_BY_USER)
{
mi.msgflags |= RS_MSG_UNREAD_BY_USER;
}
if (msg->msgFlags & RS_MSG_FLAGS_REPLIED)
{
mi.msgflags |= RS_MSG_REPLIED;
}
if (msg->msgFlags & RS_MSG_FLAGS_FORWARDED)
{
mi.msgflags |= RS_MSG_FORWARDED;
}
if (msg->msgFlags & RS_MSG_FLAGS_STAR)
{
mi.msgflags |= RS_MSG_STAR;
}
if (msg->msgFlags & RS_MSG_FLAGS_USER_REQUEST)
{
mi.msgflags |= RS_MSG_USER_REQUEST;
}
if (msg->msgFlags & RS_MSG_FLAGS_FRIEND_RECOMMENDATION)
{
mi.msgflags |= RS_MSG_FRIEND_RECOMMENDATION;
}
if (msg->msgFlags & RS_MSG_FLAGS_LOAD_EMBEDDED_IMAGES)
{
mi.msgflags |= RS_MSG_LOAD_EMBEDDED_IMAGES;
}
mi.ts = msg->sendTime;
mi.srcId = msg->PeerId();
{
//msg->msgId;
rs_sprintf(mi.msgId, "%lu", msg->msgId);
}
std::list<std::string>::iterator pit;
for(pit = msg->msgto.ids.begin();
pit != msg->msgto.ids.end(); pit++)
{
mi.msgto.push_back(*pit);
}
for(pit = msg->msgcc.ids.begin();
pit != msg->msgcc.ids.end(); pit++)
{
mi.msgcc.push_back(*pit);
}
for(pit = msg->msgbcc.ids.begin();
pit != msg->msgbcc.ids.end(); pit++)
{
mi.msgbcc.push_back(*pit);
}
mi.title = msg->subject;
mi.msg = msg->message;
mi.attach_title = msg->attachment.title;
mi.attach_comment = msg->attachment.comment;
mi.count = 0;
mi.size = 0;
std::list<RsTlvFileItem>::iterator it;
for(it = msg->attachment.items.begin();
it != msg->attachment.items.end(); it++)
{
FileInfo fi;
fi.fname = RsDirUtil::getTopDir(it->name);
fi.size = it->filesize;
fi.hash = it->hash;
fi.path = it->path;
mi.files.push_back(fi);
mi.count++;
mi.size += fi.size;
}
}
void p3MsgService::initRsMIS(RsMsgItem *msg, MsgInfoSummary &mis)
{
mis.msgflags = 0;
if (msg->msgFlags & RS_MSG_FLAGS_ENCRYPTED)
mis.msgflags |= RS_MSG_ENCRYPTED ;
if (msg->msgFlags & RS_MSG_FLAGS_DECRYPTED)
mis.msgflags |= RS_MSG_DECRYPTED ;
if (msg->msgFlags & RS_MSG_FLAGS_SIGNED)
mis.msgflags |= RS_MSG_SIGNED ;
if (msg->msgFlags & RS_MSG_FLAGS_SIGNATURE_CHECKS)
mis.msgflags |= RS_MSG_SIGNATURE_CHECKS ;
/* translate flags, if we sent it... outgoing */
if ((msg->msgFlags & RS_MSG_FLAGS_OUTGOING)
/*|| (msg->PeerId() == mLinkMgr->getOwnId())*/)
{
mis.msgflags |= RS_MSG_OUTGOING;
}
/* if it has a pending flag, then its in the outbox */
if (msg->msgFlags & RS_MSG_FLAGS_PENDING)
{
mis.msgflags |= RS_MSG_PENDING;
}
if (msg->msgFlags & RS_MSG_FLAGS_DRAFT)
{
mis.msgflags |= RS_MSG_DRAFT;
}
if (msg->msgFlags & RS_MSG_FLAGS_NEW)
{
mis.msgflags |= RS_MSG_NEW;
}
if (msg->msgFlags & RS_MSG_FLAGS_TRASH)
{
mis.msgflags |= RS_MSG_TRASH;
}
if (msg->msgFlags & RS_MSG_FLAGS_UNREAD_BY_USER)
{
mis.msgflags |= RS_MSG_UNREAD_BY_USER;
}
if (msg->msgFlags & RS_MSG_FLAGS_REPLIED)
{
mis.msgflags |= RS_MSG_REPLIED;
}
if (msg->msgFlags & RS_MSG_FLAGS_FORWARDED)
{
mis.msgflags |= RS_MSG_FORWARDED;
}
if (msg->msgFlags & RS_MSG_FLAGS_STAR)
{
mis.msgflags |= RS_MSG_STAR;
}
if (msg->msgFlags & RS_MSG_FLAGS_USER_REQUEST)
{
mis.msgflags |= RS_MSG_USER_REQUEST;
}
if (msg->msgFlags & RS_MSG_FLAGS_FRIEND_RECOMMENDATION)
{
mis.msgflags |= RS_MSG_FRIEND_RECOMMENDATION;
}
if (msg->msgFlags & RS_MSG_FLAGS_LOAD_EMBEDDED_IMAGES)
{
mis.msgflags |= RS_MSG_LOAD_EMBEDDED_IMAGES;
}
mis.srcId = msg->PeerId();
{
//msg->msgId;
rs_sprintf(mis.msgId, "%lu", msg->msgId);
}
mis.title = msg->subject;
mis.count = msg->attachment.items.size();
mis.ts = msg->sendTime;
}
RsMsgItem *p3MsgService::initMIRsMsg(MessageInfo &info, const std::string &to)
{
RsMsgItem *msg = new RsMsgItem();
msg -> PeerId(to);
msg -> msgFlags = 0;
msg -> msgId = 0;
msg -> sendTime = time(NULL);
msg -> recvTime = 0;
msg -> subject = info.title;
msg -> message = info.msg;
std::list<std::string>::iterator pit;
for(pit = info.msgto.begin(); pit != info.msgto.end(); pit++)
{
msg -> msgto.ids.push_back(*pit);
}
for(pit = info.msgcc.begin(); pit != info.msgcc.end(); pit++)
{
msg -> msgcc.ids.push_back(*pit);
}
/* We don't fill in bcc (unless to ourselves) */
if (to == mLinkMgr->getOwnId())
{
for(pit = info.msgbcc.begin(); pit != info.msgbcc.end(); pit++)
{
msg -> msgbcc.ids.push_back(*pit);
}
}
msg -> attachment.title = info.attach_title;
msg -> attachment.comment = info.attach_comment;
RsPeerDetails details ;
if(!rsPeers->getPeerDetails(to,details))
msg->msgFlags |= RS_MSG_FLAGS_DISTANT;
std::list<FileInfo>::iterator it;
for(it = info.files.begin(); it != info.files.end(); it++)
{
RsTlvFileItem mfi;
mfi.hash = it -> hash;
mfi.name = it -> fname;
mfi.filesize = it -> size;
msg -> attachment.items.push_back(mfi);
}
/* translate flags from outside */
if (info.msgflags & RS_MSG_USER_REQUEST)
msg->msgFlags |= RS_MSG_FLAGS_USER_REQUEST;
if (info.msgflags & RS_MSG_FRIEND_RECOMMENDATION)
msg->msgFlags |= RS_MSG_FLAGS_FRIEND_RECOMMENDATION;
if (info.msgflags & RS_MSG_SIGNED)
msg->msgFlags |= RS_MSG_FLAGS_SIGNED;
/* load embedded images from own messages */
msg->msgFlags |= RS_MSG_FLAGS_LOAD_EMBEDDED_IMAGES;
// See if we need to encrypt this message. If so, we replace the msg text
// by the whole message serialized and binary encrypted, so as to obfuscate
// all its content.
//
if(info.encryption_keys.find(to) != info.encryption_keys.end())
encryptMessage(info.encryption_keys[to],msg) ;
//std::cerr << "p3MsgService::initMIRsMsg()" << std::endl;
//msg->print(std::cerr);
return msg;
}
bool p3MsgService::encryptMessage(const std::string& pgp_id,RsMsgItem *item)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << "Encrypting message with public key " << pgp_id << " in place." << std::endl;
#endif
// 0 - append own id to the data.
//
uint32_t rssize = _serialiser->size(item) ;
unsigned char *data = (unsigned char *)malloc(1+rssize+KEY_ID_SIZE) ;
// -1 - setup protocol version
//
#ifdef DEBUG_DISTANT_MSG
std::cerr << " adding protocol version TAG = " << std::hex << (int)ENCRYPTED_MSG_PROTOCOL_VERSION_01 << std::dec << std::endl;
#endif
data[0] = ENCRYPTED_MSG_PROTOCOL_VERSION_01 ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " adding own key ID " << AuthGPG::getAuthGPG()->getGPGOwnId() << std::endl;
#endif
memcpy(&data[1], PGPIdType(AuthGPG::getAuthGPG()->getGPGOwnId()).toByteArray(), KEY_ID_SIZE) ;
// 1 - serialise the whole message item into a binary chunk.
//
#ifdef DEBUG_DISTANT_MSG
std::cerr << " serialising item..." << std::endl;
#endif
if(!_serialiser->serialise(item,&data[1+KEY_ID_SIZE],&rssize))
{
std::cerr << "(EE) p3MsgService::encryptMessage(): Serialization error." << std::endl;
free(data) ;
return false;
}
// 2 - now sign the data, if necessary, and put the signature up front
uint32_t signature_length = 0 ;
unsigned char *signature_data = NULL ;
if(item->msgFlags & RS_MSG_FLAGS_SIGNED)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Signing the message..." << std::endl;
#endif
signature_length = 2000 ;
signature_data = new unsigned char[signature_length] ;
if(!AuthGPG::getAuthGPG()->SignDataBin(data,1+rssize+KEY_ID_SIZE,signature_data,&signature_length))
{
free(data) ;
std::cerr << "Signature failed!" << std::endl;
return false;
}
#ifdef DEBUG_DISTANT_MSG
std::cerr << " After signature: signature size = " << signature_length << std::endl;
#endif
}
#ifdef DEBUG_DISTANT_MSG
std::cerr << " total decrypted size = " << KEY_ID_SIZE + 1 + rssize + signature_length << std::endl;
#endif
// 3 - append the signature to the serialized data.
if(signature_length > 0)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Appending signature." << std::endl;
#endif
data = (uint8_t*)realloc(data,1+rssize+signature_length+KEY_ID_SIZE) ;
memcpy(&data[1+rssize+KEY_ID_SIZE],signature_data,signature_length) ;
}
// 2 - pgp-encrypt the whole chunk with the user-supplied public key.
//
uint32_t encrypted_size = 1+rssize + KEY_ID_SIZE + signature_length + 1000 ;
unsigned char *encrypted_data = new unsigned char[encrypted_size] ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Encrypting for Key ID " << pgp_id << std::endl;
#endif
if(!AuthGPG::getAuthGPG()->encryptDataBin(pgp_id,data,1+rssize+signature_length+KEY_ID_SIZE,encrypted_data,&encrypted_size))
{
free(data) ;
delete[] encrypted_data ;
std::cerr << "Encryption failed!" << std::endl;
return false;
}
free(data) ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Decrypted size = " << 1+rssize+signature_length+KEY_ID_SIZE << std::endl;
std::cerr << " Encrypted size = " << encrypted_size << std::endl;
std::cerr << " First bytes of encrypted data: " << std::hex << (int)encrypted_data[0] << " " << (int)encrypted_data[1] << " " << (int)encrypted_data[2] << std::dec << std::endl;
std::cerr << " Encrypted data hash = " << RsDirUtil::sha1sum(encrypted_data,encrypted_size).toStdString() << std::endl;
#endif
// Now turn the binary encrypted chunk into a readable radix string.
//
std::string armoured_data ;
Radix64::encode((char *)encrypted_data,encrypted_size,armoured_data) ;
delete[] encrypted_data ;
std::wstring encrypted_msg ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Converting to radix64" << std::endl;
#endif
if(!librs::util::ConvertUtf8ToUtf16(armoured_data,encrypted_msg))
return false;
// wipe the item clean and replace the message by the encrypted data.
item->message = encrypted_msg ;
item->subject = L"" ;
item->msgcc.ids.clear() ;
item->msgbcc.ids.clear() ;
item->msgto.ids.clear() ;
item->msgFlags |= RS_MSG_FLAGS_ENCRYPTED ;
item->attachment.TlvClear() ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Done" << std::endl;
#endif
return true ;
}
bool p3MsgService::decryptMessage(const std::string& mId)
{
uint32_t msgId = atoi(mId.c_str());
std::string encrypted_string ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << "Decrypting message with Id " << mId << std::endl;
#endif
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<uint32_t, RsMsgItem *>::iterator mit = imsg.find(msgId);
if(mit == imsg.end() || !librs::util::ConvertUtf16ToUtf8(mit->second->message,encrypted_string))
{
std::cerr << "Can't find this message in msg list. Id=" << mId << std::endl;
return false;
}
}
char *encrypted_data ;
size_t encrypted_size ;
Radix64::decode(encrypted_string,encrypted_data,encrypted_size) ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Message has been radix64 decoded." << std::endl;
#endif
uint32_t decrypted_size = encrypted_size + 500 ;
unsigned char *decrypted_data = new unsigned char[decrypted_size] ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Calling decryption. Encrypted data size = " << encrypted_size << ", Allocated size = " << decrypted_size << std::endl;
std::cerr << " First bytes of encrypted data: " << std::hex << (int)((unsigned char*)encrypted_data)[0] << " " << (int)((unsigned char*)encrypted_data)[1] << " " << (int)((unsigned char*)encrypted_data)[2] << std::dec << std::endl;
std::cerr << " Encrypted data hash = " << RsDirUtil::sha1sum((uint8_t*)encrypted_data,encrypted_size).toStdString() << std::endl;
#endif
if(!AuthGPG::getAuthGPG()->decryptDataBin(encrypted_data,encrypted_size,decrypted_data,&decrypted_size))
{
delete[] encrypted_data ;
delete[] decrypted_data ;
std::cerr << "decryption failed!" << std::endl;
return false;
}
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Message has succesfully decrypted. Decrypted size = " << decrypted_size << std::endl;
#endif
// 1 - get the sender's id
unsigned char protocol_version = decrypted_data[0] ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Read protocol version number " << std::hex << (int)protocol_version << std::dec << std::endl;
#endif
if(protocol_version != ENCRYPTED_MSG_PROTOCOL_VERSION_01)
{
std::cerr << "Bad version number " << std::hex << (int)protocol_version << std::dec << " => packet is dropped." << std::endl;
delete[] encrypted_data ;
delete[] decrypted_data ;
return false;
}
PGPIdType senders_id(&decrypted_data[1]) ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Sender's ID: " << senders_id.toStdString() << std::endl;
#endif
// 2 - deserialize the item
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Deserializing..." << std::endl;
#endif
uint32_t item_size = decrypted_size ; // just needs to be larger than the actual size.
RsMsgItem *item = dynamic_cast<RsMsgItem*>(_serialiser->deserialise(&decrypted_data[1+KEY_ID_SIZE],&item_size)) ;
if(item == NULL)
{
std::cerr << "Decrypted message could not be deserialized." << std::endl;
return false ;
}
// 3 - check signature
bool signature_present = false ;
bool signature_ok = false ;
if(1+item_size + KEY_ID_SIZE < decrypted_size)
{
std::cerr << " Signature is present. Verifying it..." << std::endl;
PGPFingerprintType fingerprint ;
if(!AuthGPG::getAuthGPG()->getKeyFingerprint(senders_id,fingerprint))
{
std::cerr << "Cannot get fingerprint" << std::endl;
return false ;
}
std::cerr << " Fingerprint = " << fingerprint.toStdString() << std::endl;
signature_present = true ;
signature_ok = AuthGPG::getAuthGPG()->VerifySignBin(decrypted_data, 1+KEY_ID_SIZE+item_size, &decrypted_data[1+KEY_ID_SIZE+item_size], decrypted_size - KEY_ID_SIZE - item_size - 1, fingerprint.toStdString()) ;
}
else if(1 + item_size + KEY_ID_SIZE == decrypted_size)
std::cerr << " No signature in this packet" << std::endl;
else
{
std::cerr << "Structural error in packet: sizes do not match. Dropping the message." << std::endl;
return false ;
}
delete[] decrypted_data ;
// 4 - replace the item with the decrypted data, and update flags
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Decrypted message was succesfully deserialized. New message:" << std::endl;
item->print(std::cerr,0) ;
#endif
std::string own_hash ;
std::string own_pgp_id = AuthGPG::getAuthGPG()->getGPGOwnId();
getDistantMessageHash(own_pgp_id,own_hash) ;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
// Keer the id.
RsMsgItem& msgi( *imsg[msgId] ) ;
msgi = *item ; // copy everything
msgi.msgId = msgId ; // restore the correct message id, to make it consistent
msgi.msgFlags &= ~RS_MSG_FLAGS_ENCRYPTED ; // just in case.
msgi.msgFlags |= RS_MSG_FLAGS_DECRYPTED ; // previousy encrypted msg is now decrypted
msgi.PeerId(senders_id.toStdString()) ;
for(std::list<std::string>::iterator it(msgi.msgto.ids.begin());it!=msgi.msgto.ids.end();++it) if(*it == own_hash) *it = own_pgp_id ;
for(std::list<std::string>::iterator it(msgi.msgcc.ids.begin());it!=msgi.msgcc.ids.end();++it) if(*it == own_hash) *it = own_pgp_id ;
for(std::list<std::string>::iterator it(msgi.msgbcc.ids.begin());it!=msgi.msgbcc.ids.end();++it) if(*it == own_hash) *it = own_pgp_id ;
if(signature_present)
{
msgi.msgFlags |= RS_MSG_FLAGS_SIGNED ;
if(signature_ok)
msgi.msgFlags |= RS_MSG_FLAGS_SIGNATURE_CHECKS ; // just in case.
else
msgi.msgFlags &= ~RS_MSG_FLAGS_SIGNATURE_CHECKS ; // just in case.
}
std::map<uint32_t, RsMsgSrcId*>::iterator it = mSrcIds.find(msgi.msgId) ;
if(it == mSrcIds.end())
{
std::cerr << "Warning: could not find message source for id " << msgi.msgId << ". Weird." << std::endl;
RsMsgSrcId* msi = new RsMsgSrcId();
msi->msgId = msgi.msgId;
msi->srcId = senders_id.toStdString() ;
mSrcIds.insert(std::pair<uint32_t, RsMsgSrcId*>(msi->msgId, msi));
}
else
{
std::cerr << "Substituting source name for message id " << msgi.msgId << ": " << it->second->srcId << " -> " << senders_id.toStdString() << std::endl;
it->second->srcId = senders_id.toStdString() ;
}
}
delete item ;
IndicateConfigChanged() ;
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD);
return true ;
}
#ifdef GROUTER
void p3MsgService::connectToGlobalRouter(p3GRouter *gr)
{
mGRouter = gr ;
gr->registerClientService(RS_SERVICE_TYPE_MSG,this) ;
}
#endif
void p3MsgService::connectToTurtleRouter(p3turtle *pt)
{
mTurtle = pt ;
pt->registerTunnelService(this) ;
}
bool p3MsgService::createDistantOfflineMessengingInvite(time_t time_of_validity,TurtleFileHash& hash)
{
unsigned char hash_bytes[DISTANT_MSG_HASH_SIZE] ;
RSRandom::random_bytes( hash_bytes, DISTANT_MSG_HASH_SIZE) ;
hash = t_RsGenericIdType<DISTANT_MSG_HASH_SIZE>(hash_bytes).toStdString(false) ;
DistantMessengingInvite invite ;
invite.time_of_validity = time_of_validity + time(NULL);
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
_messenging_invites[hash] = invite ;
}
IndicateConfigChanged() ;
return true ;
}
void p3MsgService::enableDistantMessaging(bool b)
{
// compute the hash
std::string hash ;
if(!getDistantMessageHash(AuthGPG::getAuthGPG()->getGPGOwnId(),hash))
return ;
bool cchanged = false ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << (b?"Enabling":"Disabling") << " distant messaging, with hash = " << hash << std::endl;
#endif
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<std::string,DistantMessengingInvite>::iterator it = _messenging_invites.find(hash) ;
if(b && it == _messenging_invites.end())
{
DistantMessengingInvite invite ;
invite.time_of_validity = time(NULL) + 10*365*86400; // 10 years from now
_messenging_invites[hash] = invite ;
mDistantMessagingEnabled = true ;
cchanged = true ;
}
if((!b) && it != _messenging_invites.end())
{
_messenging_invites.erase(it) ;
mDistantMessagingEnabled = false ;
cchanged = true ;
}
}
if(cchanged)
IndicateConfigChanged() ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << "List of distant message invites: " << std::endl;
for(std::map<std::string,DistantMessengingInvite>::const_iterator it(_messenging_invites.begin());it!=_messenging_invites.end();++it)
std::cerr << " hash = " << it->first << std::endl;
#endif
}
bool p3MsgService::distantMessagingEnabled()
{
// compute the hash
std::string hash ;
if(!getDistantMessageHash(AuthGPG::getAuthGPG()->getGPGOwnId(),hash))
return false;
bool res ;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
res = _messenging_invites.find(hash) != _messenging_invites.end() ;
}
return res ;
}
bool p3MsgService::getDistantMessageHash(const std::string& pgp_id,std::string& hash)
{
if(pgp_id.length() != 16)
{
std::cerr << "pgp id \"" << pgp_id << "\" is not valid! Something definitly wrong." << std::endl;
return false;
}
hash = RsDirUtil::sha1sum((uint8_t*)pgp_id.c_str(),16).toStdString() ;
// Also check that we have the public key.
return AuthGPG::getAuthGPG()->isKeySupported(pgp_id) ;
}
bool p3MsgService::getDistantOfflineMessengingInvites(std::vector<DistantOfflineMessengingInvite>& invites)
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
for(std::map<std::string,DistantMessengingInvite>::const_iterator it(_messenging_invites.begin());it!=_messenging_invites.end();++it)
{
DistantOfflineMessengingInvite invite ;
invite.hash = it->first ;
invite.issuer_pgp_id = AuthGPG::getAuthGPG()->getGPGOwnId() ;
invite.time_of_validity = it->second.time_of_validity ;
invites.push_back(invite) ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << " adding invite with hash " << invite.hash << std::endl;
#endif
}
return true ;
}
bool p3MsgService::handleTunnelRequest(const std::string& hash,const std::string& /*peer_id*/)
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<std::string,DistantMessengingInvite>::const_iterator it = _messenging_invites.find(hash) ;
#ifdef DEBUG_DISTANT_MSG
if(it != _messenging_invites.end())
{
std::cerr << "p3MsgService::handleTunnelRequest: received TR for hash " << hash << std::endl;
std::cerr << "Responding OK!" << std::endl;
}
#endif
return it != _messenging_invites.end() ;
}
void p3MsgService::manageDistantPeers()
{
// now possibly flush pending messages
#ifdef DEBUG_DISTANT_MSG
std::cerr << "p3MsgService::manageDistantPeers()" << std::endl;
#endif
time_t now = time(NULL) ;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
// clean dead invites.
//
for(std::map<std::string,DistantMessengingInvite>::iterator it(_messenging_invites.begin());it!=_messenging_invites.end();)
if(it->second.time_of_validity < now)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Removing outdated invite " << it->second.time_of_validity << ", hash=" << it->first << std::endl;
#endif
std::map<std::string,DistantMessengingInvite>::iterator tmp(it) ;
++tmp ;
_messenging_invites.erase(it) ;
it = tmp ;
}
else
++it ;
// clean dead contacts.
//
for(std::map<std::string,DistantMessengingContact>::iterator it(_messenging_contacts.begin());it!=_messenging_contacts.end();)
if((!it->second.pending_messages) && it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_DN)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Removing dead contact with no pending msgs and dead tunnel. hash=" << it->first << std::endl;
#endif
std::map<std::string,DistantMessengingContact>::iterator tmp(it) ;
++tmp ;
_messenging_contacts.erase(it) ;
it = tmp ;
}
else
++it ;
}
}
void p3MsgService::addVirtualPeer(const TurtleFileHash& hash, const TurtleVirtualPeerId& vpid,RsTurtleGenericTunnelItem::Direction /*dir*/)
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
// A new tunnel has been created. We need to flush pending messages for the corresponding peer.
//std::map<std::string,DistantMessengingContact>::const_iterator it = _messenging_contacts.find(hash) ;
DistantMessengingContact& contact(_messenging_contacts[hash]) ; // possibly creates it.
contact.virtual_peer_id = vpid ;
contact.last_hit_time = time(NULL) ;
contact.status = RS_DISTANT_MSG_STATUS_TUNNEL_OK ;
#ifdef DEBUG_DISTANT_MSG
std::cerr << "p3MsgService::addVirtualPeer(): adding virtual peer " << vpid << " for hash " << hash << std::endl;
#endif
}
void p3MsgService::removeVirtualPeer(const TurtleFileHash& hash, const TurtleVirtualPeerId& vpid)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << "Removing virtual peer " << vpid << " for hash " << hash << std::endl;
#endif
bool remove_tunnel = false ;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
DistantMessengingContact& contact(_messenging_contacts[hash]) ; // possibly creates it.
contact.status = RS_DISTANT_MSG_STATUS_TUNNEL_DN ;
contact.virtual_peer_id.clear() ;
if(!contact.pending_messages)
remove_tunnel = true ;
}
if(remove_tunnel) // We do that whenever we're client or server. But normally, we should only do it when we're client.
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << "Also removing tunnel, since pending messages have been sent." << std::endl;
#endif
mTurtle->stopMonitoringTunnels(hash) ;
}
}
#ifdef DEBUG_DISTANT_MSG
static void printBinaryData(void *data,uint32_t size)
{
static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ;
for(uint32_t j = 0; j < size; j++)
{
std::cerr << outl[ ( ((uint8_t*)data)[j]>>4) ] ;
std::cerr << outl[ ((uint8_t*)data)[j] & 0xf ] ;
}
}
#endif
void p3MsgService::sendTurtleData(const std::string& hash,RsMsgItem *msgitem)
{
// The item is serialized and turned into a generic turtle item.
uint32_t msg_serialized_rssize = _serialiser->size(msgitem) ;
unsigned char *msg_serialized_data = new unsigned char[msg_serialized_rssize] ;
if(!_serialiser->serialise(msgitem,msg_serialized_data,&msg_serialized_rssize))
{
std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl;
delete[] msg_serialized_data ;
return ;
}
RsTurtleGenericDataItem *item = new RsTurtleGenericDataItem ;
item->data_bytes = malloc(msg_serialized_rssize) ;
item->data_size = msg_serialized_rssize ;
memcpy(item->data_bytes,msg_serialized_data,msg_serialized_rssize) ;
delete[] msg_serialized_data ;
#ifdef DEBUG_DISTANT_MSG
printBinaryData(item->data_bytes,item->data_size) ;
std::cerr << std::endl;
#endif
// do we have a working tunnel for that hash ?
// If not, put on the contact's waiting list.
std::string virtual_peer_id ;
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<std::string,DistantMessengingContact>::const_iterator it = _messenging_contacts.find(hash) ;
if(it == _messenging_contacts.end())
{
std::cerr << "(EE) p3MsgService::sendTurtleData(): Can't find hash " << hash << " in recorded contact list." << std::endl;
delete[] msg_serialized_data ;
return ;
}
if(!it->second.status == RS_DISTANT_MSG_STATUS_TUNNEL_OK)
{
std::cerr << "p3MsgService::sendTurtleData(): tunnel is not ok. Putting items on waiting list." << std::endl;
return ;
}
virtual_peer_id = it->second.virtual_peer_id ;
}
#ifdef DEBUG_DISTANT_MSG
std::cerr << "p3MsgService::sendTurtleData(): Sending through virtual peer: " << virtual_peer_id << std::endl;
std::cerr << " item->data_size = " << item->data_size << std::endl;
std::cerr << " data = " ;
#endif
mTurtle->sendTurtleData(virtual_peer_id,item) ;
}
void p3MsgService::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const std::string& hash,
const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction /*direction*/)
{
RsTurtleGenericDataItem *item = dynamic_cast<RsTurtleGenericDataItem*>(gitem) ;
if(item == NULL)
{
std::cerr << "(EE) p3MsgService::receiveTurtleData(): item is not a data item. That is an error." << std::endl;
return ;
}
#ifdef DISABLE_DISTANT_MESSAGES
std::cerr << "Received distant message item. Protocol is not yet finalized. Droping the item." << std::endl;
delete item ;
return ;
#endif
#ifdef DEBUG_DISTANT_MSG
std::cerr << "p3MsgService::sendTurtleData(): Receiving through virtual peer: " << virtual_peer_id << std::endl;
std::cerr << " gitem->data_size = " << item->data_size << std::endl;
std::cerr << " data = " ;
printBinaryData(item->data_bytes,item->data_size) ;
std::cerr << std::endl;
#else
(void) virtual_peer_id;
#endif
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
std::map<std::string,DistantMessengingContact>::iterator it = _messenging_contacts.find(hash) ;
if(it == _messenging_contacts.end())
{
std::cerr << "(EE) p3MsgService::sendTurtleData(): Can't find hash " << hash << " in recorded contact list." << std::endl;
return ;
}
it->second.status = RS_DISTANT_MSG_STATUS_TUNNEL_OK ;
it->second.last_hit_time = time(NULL) ;
}
RsItem *itm = _serialiser->deserialise(item->data_bytes,&item->data_size) ;
RsMsgItem *mitm = dynamic_cast<RsMsgItem*>(itm) ;
if(mitm != NULL)
{
mitm->PeerId(hash) ;
mitm->msgto.ids.push_back(rsPeers->getGPGOwnId()) ;
handleIncomingItem(mitm) ;
}
else
{
std::cerr << "(EE) p3MsgService::receiveTurtleData(): received item is not a RsMsgItem!!" << std::endl;
delete itm ;
}
}
#ifdef GROUTER
void p3MsgService::sendGRouterData(const std::string& hash,RsMsgItem *msgitem)
{
// The item is serialized and turned into a generic turtle item.
uint32_t msg_serialized_rssize = _serialiser->size(msgitem) ;
unsigned char *msg_serialized_data = new unsigned char[msg_serialized_rssize] ;
if(!_serialiser->serialise(msgitem,msg_serialized_data,&msg_serialized_rssize))
{
std::cerr << "(EE) p3MsgService::sendTurtleData(): Serialization error." << std::endl;
delete[] msg_serialized_data ;
return ;
}
RsGRouterGenericDataItem *item = new RsGRouterGenericDataItem ;
item->data_bytes = (uint8_t*)malloc(msg_serialized_rssize) ;
item->data_size = msg_serialized_rssize ;
memcpy(item->data_bytes,msg_serialized_data,msg_serialized_rssize) ;
delete[] msg_serialized_data ;
mGRouter->sendData(GRouterKeyId(hash),item) ;
}
void p3MsgService::receiveGRouterData(RsGRouterGenericDataItem *gitem,const GRouterKeyId& key)
{
std::cerr << "(WW) p3msgservice::receiveGRouterData(): received message. Not handled yet. Needs implementing." << std::endl;
}
#endif
void p3MsgService::sendPrivateMsgItem(RsMsgItem *msgitem)
{
#ifdef DEBUG_DISTANT_MSG
std::cerr << "p3MsgService::sendDistanteMsgItem(): sending distant msg item to peer " << msgitem->PeerId() << std::endl;
#endif
{
RsStackMutex stack(mMsgMtx); /********** STACK LOCKED MTX ******/
// allocate a new contact. If it does not exist, set its tunnel state to DN
//
std::map<std::string,DistantMessengingContact>::iterator it = _messenging_contacts.find(msgitem->PeerId()) ;
if(it == _messenging_contacts.end())
{
std::cerr << "(EE) p3MsgService::sendPrivateMsgItem(): ERROR: no tunnel for message to send. This should not happen. " << std::endl;
return ;
}
if(it->second.status != RS_DISTANT_MSG_STATUS_TUNNEL_OK)
{
std::cerr << "(WW) p3MsgService::sendPrivateMsgItem(): WARNING: no tunnel for message to send. This should not happen. " << std::endl;
return ;
}
if(!it->second.pending_messages)
std::cerr << "(WW) p3MsgService::sendPrivateMsgItem(): WARNING: no pending message flag. This should not happen. " << std::endl;
}
#ifdef DEBUG_DISTANT_MSG
std::cerr << " Flushing msg " << msgitem->msgId << " for peer id " << msgitem->PeerId() << std::endl;
#endif
#ifdef GROUTER
sendGRouterData(msgitem->PeerId(),msgitem) ;
#else
sendTurtleData(msgitem->PeerId(),msgitem) ;
#endif
}