Moved the chat history into the libretroshare.

Now the history is saved encrypted. Please delete all files with "chat*.xml" in your profile folder.
Added new config p3HistoryMgr and interface p3History.
Added new option to limit the count of the saved history items.
Added new simple html optimizer "RsHtml::optimizeHtml" to reduce the size of the html strings.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4623 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
thunder2 2011-09-29 09:20:09 +00:00
parent c6a68fe05e
commit 29c090fb44
45 changed files with 1721 additions and 1406 deletions

View File

@ -139,6 +139,7 @@ PUBLIC_HEADERS = retroshare/rsblogs.h \
retroshare/rsexpr.h \
retroshare/rsfiles.h \
retroshare/rsforums.h \
retroshare/rshistory.h \
retroshare/rsiface.h \
retroshare/rsinit.h \
retroshare/rsplugin.h \
@ -368,6 +369,7 @@ HEADERS += pqi/authssl.h \
pqi/pqibin.h \
pqi/pqihandler.h \
pqi/pqihash.h \
pqi/p3historymgr.h \
pqi/pqiindic.h \
pqi/pqiipset.h \
pqi/pqilistener.h \
@ -391,6 +393,7 @@ HEADERS += pqi/authssl.h \
HEADERS += rsserver/p3discovery.h \
rsserver/p3face.h \
rsserver/p3history.h \
rsserver/p3msgs.h \
rsserver/p3peers.h \
rsserver/p3photo.h \
@ -406,6 +409,7 @@ HEADERS += serialiser/rsbaseitems.h \
serialiser/rsdistribitems.h \
serialiser/rsforumitems.h \
serialiser/rsgameitems.h \
serialiser/rshistoryitems.h \
serialiser/rsmsgitems.h \
serialiser/rsphotoitems.h \
serialiser/rsserial.h \
@ -490,6 +494,7 @@ SOURCES += pqi/authgpg.cc \
pqi/pqiarchive.cc \
pqi/pqibin.cc \
pqi/pqihandler.cc \
pqi/p3historymgr.cc \
pqi/pqiipset.cc \
pqi/pqiloopback.cc \
pqi/pqimonitor.cc \
@ -512,6 +517,7 @@ SOURCES += rsserver/p3discovery.cc \
rsserver/p3face-config.cc \
rsserver/p3face-msgs.cc \
rsserver/p3face-server.cc \
rsserver/p3history.cc \
rsserver/p3msgs.cc \
rsserver/p3peers.cc \
rsserver/p3photo.cc \
@ -535,6 +541,7 @@ SOURCES += serialiser/rsbaseitems.cc \
serialiser/rsdistribitems.cc \
serialiser/rsforumitems.cc \
serialiser/rsgameitems.cc \
serialiser/rshistoryitems.cc \
serialiser/rsmsgitems.cc \
serialiser/rsphotoitems.cc \
serialiser/rsserial.cc \

View File

@ -81,6 +81,7 @@ const uint32_t CONFIG_TYPE_AUTHSSL = 0x000C;
const uint32_t CONFIG_TYPE_CHAT = 0x0012;
const uint32_t CONFIG_TYPE_STATUS = 0x0013;
const uint32_t CONFIG_TYPE_PLUGINS = 0x0014;
const uint32_t CONFIG_TYPE_HISTORY = 0x0015;
/// turtle router
const uint32_t CONFIG_TYPE_TURTLE = 0x0020;

View File

@ -0,0 +1,417 @@
/*
* libretroshare/src/services: p3HistoryMgr.cc
*
* RetroShare C++ .
*
* Copyright 2011 by Thunder.
*
* 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 "p3historymgr.h"
#include "serialiser/rshistoryitems.h"
#include "serialiser/rsconfigitems.h"
#include "retroshare/rsiface.h"
#include "retroshare/rspeers.h"
#include "serialiser/rsmsgitems.h"
RsHistory *rsHistory = NULL;
p3HistoryMgr::p3HistoryMgr()
: p3Config(CONFIG_TYPE_HISTORY), mHistoryMtx("p3HistoryMgr")
{
nextMsgId = 1;
mPublicEnable = false;
mPrivateEnable = true;
mPublicSaveCount = 0;
mPrivateSaveCount = 0;
}
p3HistoryMgr::~p3HistoryMgr()
{
}
/***** p3HistoryMgr *****/
void p3HistoryMgr::addMessage(bool incoming, const std::string &chatPeerId, const std::string &peerId, const RsChatMsgItem *chatItem)
{
RsStackMutex stack(mHistoryMtx); /********** STACK LOCKED MTX ******/
if (mPublicEnable == false && chatPeerId.empty()) {
// public chat not enabled
return;
}
if (mPrivateEnable == false && chatPeerId.empty() == false) {
// private chat not enabled
return;
}
RsHistoryMsgItem* item = new RsHistoryMsgItem;
item->chatPeerId = chatPeerId;
item->incoming = incoming;
item->peerId = peerId;
item->peerName = rsPeers->getPeerName(item->peerId);
item->sendTime = chatItem->sendTime;
item->recvTime = chatItem->recvTime;
item->message.assign(chatItem->message.begin(), chatItem->message.end());
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> >::iterator mit = mMessages.find(item->chatPeerId);
if (mit != mMessages.end()) {
item->msgId = nextMsgId++;
mit->second.insert(std::make_pair(item->msgId, item));
// check the limit
uint32_t limit;
if (chatPeerId.empty()) {
limit = mPublicSaveCount;
} else {
limit = mPrivateSaveCount;
}
if (limit) {
while (mit->second.size() > limit) {
delete(mit->second.begin()->second);
mit->second.erase(mit->second.begin());
}
}
} else {
std::map<uint32_t, RsHistoryMsgItem*> msgs;
item->msgId = nextMsgId++;
msgs.insert(std::make_pair(item->msgId, item));
mMessages.insert(std::make_pair(item->chatPeerId, msgs));
// no need to check the limit
}
IndicateConfigChanged();
rsicontrol->getNotify().notifyHistoryChanged(item->msgId, NOTIFY_TYPE_ADD);
}
/***** p3Config *****/
RsSerialiser* p3HistoryMgr::setupSerialiser()
{
RsSerialiser *rss = new RsSerialiser;
rss->addSerialType(new RsHistorySerialiser);
rss->addSerialType(new RsGeneralConfigSerialiser());
return rss;
}
bool p3HistoryMgr::saveList(bool& cleanup, std::list<RsItem*>& saveData)
{
cleanup = false;
mHistoryMtx.lock(); /********** STACK LOCKED MTX ******/
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> >::iterator mit;
std::map<uint32_t, RsHistoryMsgItem*>::iterator lit;
for (mit = mMessages.begin(); mit != mMessages.end(); mit++) {
for (lit = mit->second.begin(); lit != mit->second.end(); lit++) {
saveData.push_back(lit->second);
}
}
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet;
RsTlvKeyValue kv;
kv.key = "PUBLIC_ENABLE";
kv.value = mPublicEnable ? "TRUE" : "FALSE";
vitem->tlvkvs.pairs.push_back(kv);
kv.key = "PRIVATE_ENABLE";
kv.value = mPrivateEnable ? "TRUE" : "FALSE";
vitem->tlvkvs.pairs.push_back(kv);
kv.key = "PUBLIC_SAVECOUNT";
std::ostringstream s1;
s1 << mPublicSaveCount;
kv.value = s1.str();
vitem->tlvkvs.pairs.push_back(kv);
kv.key = "PRIVATE_SAVECOUNT";
std::ostringstream s2;
s2 << mPrivateSaveCount;
kv.value = s2.str();
vitem->tlvkvs.pairs.push_back(kv);
saveData.push_back(vitem);
saveCleanupList.push_back(vitem);
return true;
}
void p3HistoryMgr::saveDone()
{
/* clean up the save List */
std::list<RsItem*>::iterator it;
for (it = saveCleanupList.begin(); it != saveCleanupList.end(); ++it) {
delete (*it);
}
saveCleanupList.clear();
/* unlock mutex */
mHistoryMtx.unlock(); /****** MUTEX UNLOCKED *******/
}
bool p3HistoryMgr::loadList(std::list<RsItem*>& load)
{
RsStackMutex stack(mHistoryMtx); /********** STACK LOCKED MTX ******/
RsHistoryMsgItem *msgItem;
std::list<RsItem*>::iterator it;
for (it = load.begin(); it != load.end(); it++) {
if (NULL != (msgItem = dynamic_cast<RsHistoryMsgItem*>(*it))) {
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> >::iterator mit = mMessages.find(msgItem->chatPeerId);
msgItem->msgId = nextMsgId++;
if (mit != mMessages.end()) {
mit->second.insert(std::make_pair(msgItem->msgId, msgItem));
} else {
std::map<uint32_t, RsHistoryMsgItem*> msgs;
msgs.insert(std::make_pair(msgItem->msgId, msgItem));
mMessages.insert(std::make_pair(msgItem->chatPeerId, msgs));
}
// don't delete the item !!
continue;
}
RsConfigKeyValueSet *rskv ;
if (NULL != (rskv = dynamic_cast<RsConfigKeyValueSet*>(*it))) {
for (std::list<RsTlvKeyValue>::const_iterator kit = rskv->tlvkvs.pairs.begin(); kit != rskv->tlvkvs.pairs.end(); kit++) {
if (kit->key == "PUBLIC_ENABLE") {
mPublicEnable = (kit->value == "TRUE") ? TRUE : FALSE;
continue;
}
if (kit->key == "PRIVATE_ENABLE") {
mPrivateEnable = (kit->value == "TRUE") ? TRUE : FALSE;
continue;
}
if (kit->key == "PUBLIC_SAVECOUNT") {
mPublicSaveCount = atoi(kit->value.c_str());
continue;
}
if (kit->key == "PRIVATE_SAVECOUNT") {
mPrivateSaveCount = atoi(kit->value.c_str());
continue;
}
}
delete (*it);
continue;
}
// delete unknown items
delete (*it);
}
return true;
}
/***** p3History *****/
static void convertMsg(const RsHistoryMsgItem* item, HistoryMsg &msg)
{
msg.msgId = item->msgId;
msg.chatPeerId = item->chatPeerId;
msg.incoming = item->incoming;
msg.peerId = item->peerId;
msg.peerName = item->peerName;
msg.sendTime = item->sendTime;
msg.recvTime = item->recvTime;
msg.message = item->message;
}
//static void convertMsg(const HistoryMsg &msg, RsHistoryMsgItem* item)
//{
// item->msgId = msg.msgId;
// item->chatPeerId = msg.chatPeerId;
// item->incoming = msg.incoming;
// item->peerId = msg.peerId;
// item->peerName = msg.peerName;
// item->sendTime = msg.sendTime;
// item->recvTime = msg.recvTime;
// item->message = msg.message;
//}
bool p3HistoryMgr::getMessages(const std::string &chatPeerId, std::list<HistoryMsg> &msgs, uint32_t loadCount)
{
msgs.clear();
RsStackMutex stack(mHistoryMtx); /********** STACK LOCKED MTX ******/
if (mPublicEnable == false && chatPeerId.empty()) {
// public chat not enabled
return false;
}
if (mPrivateEnable == false && chatPeerId.empty() == false) {
// private chat not enabled
return false;
}
uint32_t foundCount = 0;
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> >::iterator mit = mMessages.find(chatPeerId);
if (mit != mMessages.end()) {
std::map<uint32_t, RsHistoryMsgItem*>::reverse_iterator lit;
for (lit = mit->second.rbegin(); lit != mit->second.rend(); lit++) {
HistoryMsg msg;
convertMsg(lit->second, msg);
msgs.insert(msgs.begin(), msg);
foundCount++;
if (loadCount && foundCount >= loadCount) {
break;
}
}
}
return true;
}
bool p3HistoryMgr::getMessage(uint32_t msgId, HistoryMsg &msg)
{
RsStackMutex stack(mHistoryMtx); /********** STACK LOCKED MTX ******/
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> >::iterator mit;
for (mit = mMessages.begin(); mit != mMessages.end(); mit++) {
std::map<uint32_t, RsHistoryMsgItem*>::iterator lit = mit->second.find(msgId);
if (lit != mit->second.end()) {
convertMsg(lit->second, msg);
return true;
}
}
return false;
}
void p3HistoryMgr::clear(const std::string &chatPeerId)
{
RsStackMutex stack(mHistoryMtx); /********** STACK LOCKED MTX ******/
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> >::iterator mit = mMessages.find(chatPeerId);
if (mit == mMessages.end()) {
return;
}
std::map<uint32_t, RsHistoryMsgItem*>::iterator lit;
for (lit = mit->second.begin(); lit != mit->second.end(); lit++) {
delete(lit->second);
}
mit->second.clear();
mMessages.erase(mit);
IndicateConfigChanged();
rsicontrol->getNotify().notifyHistoryChanged(0, NOTIFY_TYPE_MOD);
}
void p3HistoryMgr::removeMessages(const std::list<uint32_t> &msgIds)
{
std::list<uint32_t> ids = msgIds;
std::list<uint32_t> removedIds;
std::list<uint32_t>::iterator iit;
{
RsStackMutex stack(mHistoryMtx); /********** STACK LOCKED MTX ******/
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> >::iterator mit;
for (mit = mMessages.begin(); mit != mMessages.end(); ++mit) {
iit = ids.begin();
while (iit != ids.end()) {
std::map<uint32_t, RsHistoryMsgItem*>::iterator lit = mit->second.find(*iit);
if (lit != mit->second.end()) {
delete(lit->second);
mit->second.erase(lit);
removedIds.push_back(*iit);
iit = ids.erase(iit);
continue;
}
++iit;
}
if (ids.empty()) {
break;
}
}
}
if (removedIds.empty() == false) {
IndicateConfigChanged();
for (iit = removedIds.begin(); iit != removedIds.end(); ++iit) {
rsicontrol->getNotify().notifyHistoryChanged(*iit, NOTIFY_TYPE_DEL);
}
}
}
bool p3HistoryMgr::getEnable(bool ofPublic)
{
return ofPublic ? mPublicEnable : mPrivateEnable;
}
void p3HistoryMgr::setEnable(bool forPublic, bool enable)
{
bool oldValue;
if (forPublic) {
oldValue = mPublicEnable;
mPublicEnable = enable;
} else {
oldValue = mPrivateEnable;
mPrivateEnable = enable;
}
if (oldValue != enable) {
IndicateConfigChanged();
}
}
uint32_t p3HistoryMgr::getSaveCount(bool ofPublic)
{
return ofPublic ? mPublicSaveCount : mPrivateSaveCount;
}
void p3HistoryMgr::setSaveCount(bool forPublic, uint32_t count)
{
uint32_t oldValue;
if (forPublic) {
oldValue = mPublicSaveCount;
mPublicSaveCount = count;
} else {
oldValue = mPrivateSaveCount;
mPrivateSaveCount = count;
}
if (oldValue != count) {
IndicateConfigChanged();
}
}

View File

@ -0,0 +1,86 @@
#ifndef RS_P3_HISTORY_MGR_H
#define RS_P3_HISTORY_MGR_H
/*
* libretroshare/src/services: p3historymgr.h
*
* RetroShare C++
*
* Copyright 2011 by Thunder.
*
* 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 <map>
#include <list>
#include "serialiser/rshistoryitems.h"
#include "retroshare/rshistory.h"
#include "pqi/p3cfgmgr.h"
class RsChatMsgItem;
//! handles history
/*!
* The is a retroshare service which allows peers
* to store the history of the chat messages
*/
class p3HistoryMgr: public p3Config
{
public:
p3HistoryMgr();
virtual ~p3HistoryMgr();
/******** p3HistoryMgr *********/
void addMessage(bool incoming, const std::string &chatPeerId, const std::string &peerId, const RsChatMsgItem *chatItem);
/********* RsHistory ***********/
bool getMessages(const std::string &chatPeerId, std::list<HistoryMsg> &msgs, uint32_t loadCount);
bool getMessage(uint32_t msgId, HistoryMsg &msg);
void clear(const std::string &chatPeerId);
void removeMessages(const std::list<uint32_t> &msgIds);
bool getEnable(bool ofPublic);
void setEnable(bool forPublic, bool enable);
uint32_t getSaveCount(bool ofPublic);
void setSaveCount(bool forPublic, uint32_t count);
/********* p3config ************/
virtual RsSerialiser *setupSerialiser();
virtual bool saveList(bool& cleanup, std::list<RsItem*>& saveData);
virtual void saveDone();
virtual bool loadList(std::list<RsItem*>& load);
private:
uint32_t nextMsgId;
std::map<std::string, std::map<uint32_t, RsHistoryMsgItem*> > mMessages;
bool mPublicEnable;
bool mPrivateEnable;
uint32_t mPublicSaveCount;
uint32_t mPrivateSaveCount;
std::list<RsItem*> saveCleanupList; /* TEMPORARY LIST WHEN SAVING */
RsMutex mHistoryMtx;
};
#endif

View File

@ -30,6 +30,7 @@
#include "pqi/p3peermgr.h"
#include "pqi/p3linkmgr.h"
#include "pqi/p3netmgr.h"
#include "pqi/p3historymgr.h"
//#include "pqi/p3dhtmgr.h" // Only need it for constants.
//#include "tcponudp/tou.h"
@ -109,6 +110,10 @@ p3PeerMgrIMPL::p3PeerMgrIMPL()
{
RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/
mLinkMgr = NULL;
mNetMgr = NULL;
mHistoryMgr = NULL;
/* setup basics of own state */
mOwnState.id = AuthSSL::getAuthSSL()->OwnId();
mOwnState.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId();
@ -130,10 +135,11 @@ p3PeerMgrIMPL::p3PeerMgrIMPL()
return;
}
void p3PeerMgrIMPL::setManagers(p3LinkMgrIMPL *linkMgr, p3NetMgrIMPL *netMgr)
void p3PeerMgrIMPL::setManagers(p3LinkMgrIMPL *linkMgr, p3NetMgrIMPL *netMgr, p3HistoryMgr *historyMgr)
{
mLinkMgr = linkMgr;
mNetMgr = netMgr;
mHistoryMgr = historyMgr;
}
void p3PeerMgrIMPL::setOwnNetworkMode(uint32_t netMode)
@ -537,6 +543,7 @@ bool p3PeerMgrIMPL::removeFriend(const std::string &id)
{
if (mFriendList.end() != (it = mFriendList.find(*rit)))
{
mHistoryMgr->clear(it->second.id);
mFriendList.erase(it);
}
}

View File

@ -113,6 +113,7 @@ class p3NetMgr;
class p3LinkMgrIMPL;
class p3NetMgrIMPL;
class p3HistoryMgr;
class p3PeerMgr
{
@ -279,7 +280,7 @@ virtual bool haveOnceConnected();
p3PeerMgrIMPL();
void setManagers(p3LinkMgrIMPL *linkMgr, p3NetMgrIMPL *netMgr);
void setManagers(p3LinkMgrIMPL *linkMgr, p3NetMgrIMPL *netMgr, p3HistoryMgr *historyMgr);
void tick();
@ -314,7 +315,7 @@ void printPeerLists(std::ostream &out);
p3LinkMgrIMPL *mLinkMgr;
p3NetMgrIMPL *mNetMgr;
p3HistoryMgr *mHistoryMgr;
private:
RsMutex mPeerMtx; /* protects below */

View File

@ -0,0 +1,83 @@
#ifndef RS_HISTORY_INTERFACE_H
#define RS_HISTORY_INTERFACE_H
/*
* libretroshare/src/retroshare: rshistory.h
*
* RetroShare C++ .
*
* Copyright 2011 by Thunder.
*
* 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".
*
*/
class RsHistory;
extern RsHistory *rsHistory;
#include <string>
#include <inttypes.h>
#include <list>
//! data object for message history
/*!
* data object used for message history
*/
class HistoryMsg
{
public:
HistoryMsg()
{
msgId = 0;
incoming = false;
sendTime = 0;
recvTime = 0;
}
public:
uint32_t msgId;
std::string chatPeerId;
bool incoming;
std::string peerId;
std::string peerName;
uint32_t sendTime;
uint32_t recvTime;
std::string message;
};
//! Interface to retroshare for message history
/*!
* Provides an interface for retroshare's message history functionality
*/
class RsHistory
{
public:
virtual bool getMessages(const std::string &chatPeerId, std::list<HistoryMsg> &msgs, uint32_t loadCount) = 0;
virtual bool getMessage(uint32_t msgId, HistoryMsg &msg) = 0;
virtual void removeMessages(const std::list<uint32_t> &msgIds) = 0;
virtual void clear(const std::string &chatPeerId) = 0;
virtual bool getEnable(bool ofPublic) = 0;
virtual void setEnable(bool forPublic, bool enable) = 0;
// 0 = no limit, >0 count of saved messages
virtual uint32_t getSaveCount(bool ofPublic) = 0;
virtual void setSaveCount(bool forPublic, uint32_t count) = 0;
};
#endif

View File

@ -185,7 +185,6 @@ class NotifyBase
virtual void notifyListPreChange(int list, int type) { (void) list; (void) type; return; }
virtual void notifyListChange(int list, int type) { (void) list; (void) type; return; }
virtual void notifyErrorMsg(int list, int sev, std::string msg) { (void) list; (void) sev; (void) msg; return; }
virtual void notifyChat() { return; }
virtual void notifyChatStatus(const std::string& /* peer_id */, const std::string& /* status_string */ ,bool /* is_private */) {}
virtual void notifyCustomState(const std::string& /* peer_id */, const std::string& /* status_string */) {}
virtual void notifyHashingInfo(uint32_t type, const std::string& fileinfo) { (void) type; (void)fileinfo; }
@ -202,6 +201,7 @@ class NotifyBase
virtual void notifyDiscInfoChanged() {}
virtual void notifyDownloadComplete(const std::string& /* fileHash */) {};
virtual void notifyDownloadCompleteCount(uint32_t /* count */) {};
virtual void notifyHistoryChanged(uint32_t /* msgId */, int /* type */) {}
virtual bool askForPassword(const std::string& /* key_details */, bool /* prev_is_bad */, std::string& /* password */ ) { return false ;}
};

View File

@ -125,7 +125,7 @@ public:
#define RS_CHAT_PRIVATE 0x0002
#define RS_CHAT_AVATAR_AVAILABLE 0x0004
class ChatInfo
class ChatInfo
{
public:
std::string rsid;
@ -140,6 +140,7 @@ std::ostream &operator<<(std::ostream &out, const ChatInfo &info);
//std::ostream &operator<<(std::ostream &out, const MsgTagInfo);
//std::ostream &operator<<(std::ostream &out, const MsgTagType);
bool operator==(const ChatInfo&, const ChatInfo&);
class RsMsgs;
extern RsMsgs *rsMsgs;
@ -183,14 +184,14 @@ virtual bool resetMessageStandardTagTypes(MsgTagType& tags) = 0;
/****************************************/
/* Chat */
virtual bool sendPublicChat(std::wstring msg) = 0;
virtual bool sendPrivateChat(std::string id, std::wstring msg) = 0;
virtual bool sendPublicChat(const std::wstring& msg) = 0;
virtual bool sendPrivateChat(const std::string& id, const std::wstring& msg) = 0;
virtual int getPublicChatQueueCount() = 0;
virtual bool getPublicChatQueue(std::list<ChatInfo> &chats) = 0;
virtual int getPrivateChatQueueCount(bool incoming) = 0;
virtual bool getPrivateChatQueueIds(bool incoming, std::list<std::string> &ids) = 0;
virtual bool getPrivateChatQueue(bool incoming, std::string id, std::list<ChatInfo> &chats) = 0;
virtual bool clearPrivateChatQueue(bool incoming, std::string id) = 0;
virtual bool getPrivateChatQueue(bool incoming, const std::string& id, std::list<ChatInfo> &chats) = 0;
virtual bool clearPrivateChatQueue(bool incoming, const std::string& id) = 0;
virtual void sendStatusString(const std::string& id,const std::string& status_string) = 0 ;
virtual void sendGroupChatStatusString(const std::string& status_string) = 0 ;
@ -199,7 +200,7 @@ virtual std::string getCustomStateString() = 0 ;
virtual std::string getCustomStateString(const std::string& peer_id) = 0 ;
// get avatar data for peer pid
virtual void getAvatarData(std::string pid,unsigned char *& data,int& size) = 0 ;
virtual void getAvatarData(const std::string& pid,unsigned char *& data,int& size) = 0 ;
// set own avatar data
virtual void setOwnAvatarData(const unsigned char *data,int size) = 0 ;
virtual void getOwnAvatarData(unsigned char *& data,int& size) = 0 ;

View File

@ -48,7 +48,7 @@
class p3PeerMgrIMPL;
class p3LinkMgrIMPL;
class p3NetMgrIMPL;
class p3HistoryMgr;
/* The Main Interface Class - for controlling the server */
@ -157,6 +157,7 @@ class RsServer: public RsControl, public RsThread
p3PeerMgrIMPL *mPeerMgr;
p3LinkMgrIMPL *mLinkMgr;
p3NetMgrIMPL *mNetMgr;
p3HistoryMgr *mHistoryMgr;
pqipersongrp *pqih;

View File

@ -0,0 +1,77 @@
/*
* libretroshare/src/rsserver: p3history.h
*
* RetroShare C++ Interface.
*
* Copyright 2011 by Thunder.
*
* 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 "p3history.h"
#include "pqi/p3historymgr.h"
p3History::p3History(p3HistoryMgr* historyMgr)
: mHistoryMgr(historyMgr)
{
}
p3History::~p3History()
{
}
bool p3History::getMessages(const std::string &chatPeerId, std::list<HistoryMsg> &msgs, const uint32_t loadCount)
{
return mHistoryMgr->getMessages(chatPeerId, msgs, loadCount);
}
bool p3History::getMessage(uint32_t msgId, HistoryMsg &msg)
{
return mHistoryMgr->getMessage(msgId, msg);
}
void p3History::removeMessages(const std::list<uint32_t> &msgIds)
{
mHistoryMgr->removeMessages(msgIds);
}
void p3History::clear(const std::string &chatPeerId)
{
mHistoryMgr->clear(chatPeerId);
}
bool p3History::getEnable(bool ofPublic)
{
return mHistoryMgr->getEnable(ofPublic);
}
void p3History::setEnable(bool forPublic, bool enable)
{
mHistoryMgr->setEnable(forPublic, enable);
}
uint32_t p3History::getSaveCount(bool ofPublic)
{
return mHistoryMgr->getSaveCount(ofPublic);
}
void p3History::setSaveCount(bool forPublic, uint32_t count)
{
mHistoryMgr->setSaveCount(forPublic, count);
}

View File

@ -0,0 +1,57 @@
#ifndef RS_P3HISTORY_INTERFACE_H
#define RS_P3HISTORY_INTERFACE_H
/*
* libretroshare/src/rsserver: p3history.h
*
* RetroShare C++ Interface.
*
* Copyright 2011 by Thunder.
*
* 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/rshistory.h"
class p3HistoryMgr;
//! Implements abstract interface rsHistory
/*!
* Interfaces with p3HistoryMsg
*/
class p3History : public RsHistory
{
public:
p3History(p3HistoryMgr* historyMgr);
virtual ~p3History();
virtual bool getMessages(const std::string &chatPeerId, std::list<HistoryMsg> &msgs, uint32_t loadCount);
virtual bool getMessage(uint32_t msgId, HistoryMsg &msg);
virtual void removeMessages(const std::list<uint32_t> &msgIds);
virtual void clear(const std::string &chatPeerId);
virtual bool getEnable(bool ofPublic);
virtual void setEnable(bool forPublic, bool enable);
virtual uint32_t getSaveCount(bool ofPublic);
virtual void setSaveCount(bool forPublic, uint32_t count);
private:
p3HistoryMgr* mHistoryMgr;
};
#endif /* RS_P3HISTORY_INTERFACE_H */

View File

@ -50,6 +50,28 @@ RsMsgs *rsMsgs = NULL;
/****************************************/
/****************************************/
std::ostream &operator<<(std::ostream &out, const ChatInfo &info)
{
out << "ChatInfo: rsid: " << info.rsid << std::endl;
out << "chatflags: " << info.chatflags << std::endl;
out << "sendTime: " << info.sendTime << std::endl;
out << "recvTime: " << info.recvTime << std::endl;
std::string message;
message.assign(info.msg.begin(), info.msg.end());
out << "msg: " << message;
return out;
}
bool operator==(const ChatInfo& info1, const ChatInfo& info2)
{
return info1.rsid == info2.rsid &&
info1.chatflags == info2.chatflags &&
info1.sendTime == info2.sendTime &&
info1.recvTime == info2.recvTime &&
info1.msg == info2.msg;
}
bool p3Msgs::getMessageSummaries(std::list<MsgInfoSummary> &msgList)
{
return mMsgSrv->getMessageSummaries(msgList);
@ -156,13 +178,13 @@ bool p3Msgs::resetMessageStandardTagTypes(MsgTagType& tags)
/****************************************/
/****************************************/
bool p3Msgs::sendPublicChat(std::wstring msg)
bool p3Msgs::sendPublicChat(const std::wstring& msg)
{
/* send a message to all for now */
return mChatSrv -> sendPublicChat(msg);
}
bool p3Msgs::sendPrivateChat(std::string id, std::wstring msg)
bool p3Msgs::sendPrivateChat(const std::string& id, const std::wstring& msg)
{
/* send a message to peer */
return mChatSrv -> sendPrivateChat(id, msg);
@ -172,9 +194,10 @@ void p3Msgs::sendGroupChatStatusString(const std::string& status_string)
{
mChatSrv->sendGroupChatStatusString(status_string);
}
void p3Msgs::sendStatusString(const std::string& peer_id,const std::string& status_string)
void p3Msgs::sendStatusString(const std::string& peer_id, const std::string& status_string)
{
mChatSrv->sendStatusString(peer_id,status_string);
mChatSrv->sendStatusString(peer_id, status_string);
}
int p3Msgs::getPublicChatQueueCount()
@ -197,12 +220,12 @@ bool p3Msgs::getPrivateChatQueueIds(bool incoming, std::list<std::string> &ids
return mChatSrv->getPrivateChatQueueIds(incoming, ids);
}
bool p3Msgs::getPrivateChatQueue(bool incoming, std::string id, std::list<ChatInfo> &chats)
bool p3Msgs::getPrivateChatQueue(bool incoming, const std::string& id, std::list<ChatInfo> &chats)
{
return mChatSrv->getPrivateChatQueue(incoming, id, chats);
}
bool p3Msgs::clearPrivateChatQueue(bool incoming, std::string id)
bool p3Msgs::clearPrivateChatQueue(bool incoming, const std::string& id)
{
return mChatSrv->clearPrivateChatQueue(incoming, id);
}
@ -217,7 +240,7 @@ void p3Msgs::setOwnAvatarData(const unsigned char *data,int size)
mChatSrv->setOwnAvatarJpegData(data,size) ;
}
void p3Msgs::getAvatarData(std::string pid,unsigned char *& data,int& size)
void p3Msgs::getAvatarData(const std::string& pid,unsigned char *& data,int& size)
{
mChatSrv->getAvatarJpegData(pid,data,size) ;
}

View File

@ -80,7 +80,7 @@ class p3Msgs: public RsMsgs
/*!
* gets avatar from peer, image data in jpeg format
*/
virtual void getAvatarData(std::string pid,unsigned char *& data,int& size);
virtual void getAvatarData(const std::string& pid,unsigned char *& data,int& size);
/*!
* sets clients avatar, image data should be in jpeg format
@ -111,13 +111,13 @@ class p3Msgs: public RsMsgs
/*!
* public chat sent to all peers
*/
virtual bool sendPublicChat(std::wstring msg);
virtual bool sendPublicChat(const std::wstring& msg);
/*!
* chat is sent to specifc peer
* @param id peer to send chat msg to
*/
virtual bool sendPrivateChat(std::string id, std::wstring msg);
virtual bool sendPrivateChat(const std::string& id, const std::wstring& msg);
/*!
* returns the count of messages in public or private queue
@ -145,19 +145,19 @@ class p3Msgs: public RsMsgs
/*!
* @param chats ref to list of received private chats is stored here
*/
virtual bool getPrivateChatQueue(bool incoming, std::string id, std::list<ChatInfo> &chats);
virtual bool getPrivateChatQueue(bool incoming, const std::string& id, std::list<ChatInfo> &chats);
/*!
* @param clear private chat queue
*/
virtual bool clearPrivateChatQueue(bool incoming, std::string id);
virtual bool clearPrivateChatQueue(bool incoming, const std::string& id);
/*!
* sends immediate status string to a specific peer, e.g. in a private chat
* @param peer_id peer to send status string to
* @param status_string immediate status to send
*/
virtual void sendStatusString(const std::string& peer_id,const std::string& status_string) ;
virtual void sendStatusString(const std::string& peer_id, const std::string& status_string) ;
/*!
* sends immediate status to all peers

View File

@ -1703,6 +1703,7 @@ RsTurtle *rsTurtle = NULL ;
#include "pqi/pqisslpersongrp.h"
#include "pqi/pqiloopback.h"
#include "pqi/p3cfgmgr.h"
#include "pqi/p3historymgr.h"
#include "util/rsdebug.h"
#include "util/rsdir.h"
@ -1741,6 +1742,7 @@ RsTurtle *rsTurtle = NULL ;
#include "rsserver/p3discovery.h"
#include "rsserver/p3photo.h"
#include "rsserver/p3status.h"
#include "rsserver/p3history.h"
#include "rsserver/p3serverconfig.h"
#include "retroshare/rsgame.h"
@ -1850,11 +1852,14 @@ int RsServer::StartupRetroShare()
/* Setup Notify Early - So we can use it. */
rsNotify = new p3Notify();
/* History Manager */
mHistoryMgr = new p3HistoryMgr();
mPeerMgr = new p3PeerMgrIMPL();
mNetMgr = new p3NetMgrIMPL();
mLinkMgr = new p3LinkMgrIMPL(mPeerMgr, mNetMgr);
mPeerMgr->setManagers(mLinkMgr, mNetMgr);
mPeerMgr->setManagers(mLinkMgr, mNetMgr, mHistoryMgr);
mNetMgr->setManagers(mPeerMgr, mLinkMgr);
//load all the SSL certs as friends
@ -2048,7 +2053,7 @@ int RsServer::StartupRetroShare()
ad = new p3disc(mPeerMgr, mLinkMgr, pqih);
#ifndef MINIMAL_LIBRS
msgSrv = new p3MsgService(mLinkMgr);
chatSrv = new p3ChatService(mLinkMgr);
chatSrv = new p3ChatService(mLinkMgr, mHistoryMgr);
mStatusSrv = new p3StatusService(mLinkMgr);
#endif // MINIMAL_LIBRS
@ -2155,7 +2160,8 @@ int RsServer::StartupRetroShare()
#ifndef MINIMAL_LIBRS
mConfigMgr->addConfiguration("msgs.cfg", msgSrv);
mConfigMgr->addConfiguration("chat.cfg", chatSrv);
#ifdef RS_USE_BLOGS
mConfigMgr->addConfiguration("p3History.cfg", mHistoryMgr);
#ifdef RS_USE_BLOGS
mConfigMgr->addConfiguration("blogs.cfg", mBlogs);
#endif
mConfigMgr->addConfiguration("forums.cfg", mForums);
@ -2335,6 +2341,7 @@ int RsServer::StartupRetroShare()
rsBlogs = mBlogs;
#endif
rsStatus = new p3Status(mStatusSrv);
rsHistory = new p3History(mHistoryMgr);
#ifndef RS_RELEASE
rsGameLauncher = gameLauncher;

View File

@ -42,6 +42,7 @@ const uint8_t RS_PKT_TYPE_PEER_CONFIG = 0x02;
const uint8_t RS_PKT_TYPE_CACHE_CONFIG = 0x03;
const uint8_t RS_PKT_TYPE_FILE_CONFIG = 0x04;
const uint8_t RS_PKT_TYPE_PLUGIN_CONFIG = 0x05;
const uint8_t RS_PKT_TYPE_HISTORY_CONFIG = 0x06;
/* GENERAL CONFIG SUBTYPES */
const uint8_t RS_PKT_SUBTYPE_KEY_VALUE = 0x01;

View File

@ -0,0 +1,266 @@
/*
* libretroshare/src/serialiser: rshistoryitems.cc
*
* RetroShare Serialiser.
*
* Copyright 2011 by Thunder.
*
* 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 "serialiser/rshistoryitems.h"
#include "serialiser/rsbaseserial.h"
#include "serialiser/rstlvbase.h"
#include "serialiser/rsconfigitems.h"
/***
#define RSSERIAL_DEBUG 1
***/
#include <iostream>
/*************************************************************************/
RsHistoryMsgItem::RsHistoryMsgItem() : RsItem(RS_PKT_VERSION1, RS_PKT_CLASS_CONFIG, RS_PKT_TYPE_HISTORY_CONFIG, RS_PKT_SUBTYPE_DEFAULT)
{
incoming = false;
sendTime = 0;
recvTime = 0;
msgId = 0;
}
RsHistoryMsgItem::~RsHistoryMsgItem()
{
}
void RsHistoryMsgItem::clear()
{
incoming = false;
peerId.clear();
peerName.clear();
sendTime = 0;
recvTime = 0;
message.clear();
msgId = 0;
}
std::ostream& RsHistoryMsgItem::print(std::ostream &out, uint16_t indent)
{
printRsItemBase(out, "RsHistoryMsgItem", indent);
uint16_t int_Indent = indent + 2;
printIndent(out, int_Indent);
out << "chatPeerid: " << chatPeerId << std::endl;
printIndent(out, int_Indent);
out << "incoming: " << (incoming ? "1" : "0") << std::endl;
printIndent(out, int_Indent);
out << "peerId: " << peerId << std::endl;
printIndent(out, int_Indent);
out << "peerName: " << peerName << std::endl;
printIndent(out, int_Indent);
out << "sendTime: " << sendTime << std::endl;
printIndent(out, int_Indent);
out << "recvTime: " << recvTime << std::endl;
printIndent(out, int_Indent);
std::string cnv_message(message.begin(), message.end());
out << "message: " << cnv_message << std::endl;
printRsItemEnd(out, "RsHistoryMsgItem", indent);
return out;
}
RsHistorySerialiser::RsHistorySerialiser() : RsSerialType(RS_PKT_VERSION1, RS_PKT_CLASS_CONFIG, RS_PKT_TYPE_HISTORY_CONFIG)
{
}
RsHistorySerialiser::~RsHistorySerialiser()
{
}
uint32_t RsHistorySerialiser::sizeHistoryMsgItem(RsHistoryMsgItem* item)
{
uint32_t s = 8; /* header */
s += 2; /* version */
s += GetTlvStringSize(item->chatPeerId);
s += 1; /* incoming */
s += GetTlvStringSize(item->peerId);
s += GetTlvStringSize(item->peerName);
s += 4; /* sendTime */
s += 4; /* recvTime */
s += GetTlvStringSize(item->message);
return s;
}
/* serialise the data to the buffer */
bool RsHistorySerialiser::serialiseHistoryMsgItem(RsHistoryMsgItem* item, void* data, uint32_t* pktsize)
{
uint32_t tlvsize = sizeHistoryMsgItem(item);
uint32_t offset = 0;
if (*pktsize < tlvsize)
return false; /* not enough space */
*pktsize = tlvsize;
bool ok = true;
ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize);
#ifdef RSSERIAL_DEBUG
std::cerr << "RsHistorySerialiser::serialiseItem() Header: " << ok << std::endl;
std::cerr << "RsHistorySerialiser::serialiseItem() Size: " << tlvsize << std::endl;
#endif
/* skip the header */
offset += 8;
/* add mandatory parts first */
ok &= setRawUInt16(data, tlvsize, &offset, 0); // version
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_LOCATION, item->chatPeerId);
uint8_t dummy = item->incoming ? 1 : 0;
ok &= setRawUInt8(data, tlvsize, &offset, dummy);
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_PEERID, item->peerId);
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_NAME, item->peerName);
ok &= setRawUInt32(data, tlvsize, &offset, item->sendTime);
ok &= setRawUInt32(data, tlvsize, &offset, item->recvTime);
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_WSTR_MSG, item->message);
if (offset != tlvsize)
{
ok = false;
#ifdef RSSERIAL_DEBUG
std::cerr << "RsHistorySerialiser::serialiseItem() Size Error! " << std::endl;
#endif
}
return ok;
}
RsHistoryMsgItem *RsHistorySerialiser::deserialiseHistoryMsgItem(void *data, uint32_t *pktsize)
{
/* get the type and size */
uint32_t rstype = getRsItemId(data);
uint32_t rssize = getRsItemSize(data);
uint32_t offset = 0;
if ((RS_PKT_VERSION1 != getRsItemVersion(rstype)) ||
(RS_PKT_CLASS_CONFIG != getRsItemClass(rstype)) ||
(RS_PKT_TYPE_HISTORY_CONFIG != getRsItemType(rstype)) ||
(RS_PKT_SUBTYPE_DEFAULT != getRsItemSubType(rstype)))
{
return NULL; /* wrong type */
}
if (*pktsize < rssize) /* check size */
return NULL; /* not enough data */
/* set the packet length */
*pktsize = rssize;
bool ok = true;
/* ready to load */
RsHistoryMsgItem *item = new RsHistoryMsgItem();
item->clear();
/* skip the header */
offset += 8;
/* get mandatory parts first */
uint16_t version = 0;
ok &= getRawUInt16(data, rssize, &offset, &version);
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_LOCATION, item->chatPeerId);
uint8_t dummy;
ok &= getRawUInt8(data, rssize, &offset, &dummy);
item->incoming = (dummy == 1);
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_PEERID, item->peerId);
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_NAME, item->peerName);
ok &= getRawUInt32(data, rssize, &offset, &(item->sendTime));
ok &= getRawUInt32(data, rssize, &offset, &(item->recvTime));
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_WSTR_MSG, item->message);
if (offset != rssize)
{
/* error */
delete item;
return NULL;
}
if (!ok)
{
delete item;
return NULL;
}
return item;
}
uint32_t RsHistorySerialiser::size(RsItem *item)
{
RsHistoryMsgItem* hi;
if (NULL != (hi = dynamic_cast<RsHistoryMsgItem*>(item)))
{
return sizeHistoryMsgItem(hi);
}
return 0;
}
bool RsHistorySerialiser::serialise(RsItem *item, void *data, uint32_t *pktsize)
{
RsHistoryMsgItem* hi;
if (NULL != (hi = dynamic_cast<RsHistoryMsgItem*>(item)))
{
return serialiseHistoryMsgItem(hi, data, pktsize);
}
return false;
}
RsItem* RsHistorySerialiser::deserialise(void *data, uint32_t *pktsize)
{
/* get the type and size */
uint32_t rstype = getRsItemId(data);
if ((RS_PKT_VERSION1 != getRsItemVersion(rstype)) ||
(RS_PKT_CLASS_CONFIG != getRsItemClass(rstype)) ||
(RS_PKT_TYPE_HISTORY_CONFIG != getRsItemType(rstype)))
{
return NULL; /* wrong type */
}
switch(getRsItemSubType(rstype))
{
case RS_PKT_SUBTYPE_DEFAULT:
return deserialiseHistoryMsgItem(data, pktsize);
}
return NULL;
}
/*************************************************************************/

View File

@ -0,0 +1,75 @@
#ifndef RS_HISTORY_ITEMS_H
#define RS_HISTORY_ITEMS_H
/*
* libretroshare/src/serialiser: rshistoryitems.h
*
* RetroShare Serialiser.
*
* Copyright 2007-2008 by Thunder.
*
* 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 "serialiser/rsserviceids.h"
#include "serialiser/rsserial.h"
/**************************************************************************/
class RsHistoryMsgItem: public RsItem
{
public:
RsHistoryMsgItem();
virtual ~RsHistoryMsgItem();
virtual void clear();
std::ostream& print(std::ostream &out, uint16_t indent = 0);
std::string chatPeerId; // empty for global chat
bool incoming;
std::string peerId;
std::string peerName;
uint32_t sendTime;
uint32_t recvTime;
std::string message;
/* not serialised */
uint32_t msgId;
};
class RsHistorySerialiser: public RsSerialType
{
public:
RsHistorySerialiser();
virtual ~RsHistorySerialiser();
virtual uint32_t size(RsItem*);
virtual bool serialise(RsItem* item, void* data, uint32_t* size);
virtual RsItem* deserialise(void* data, uint32_t* size);
private:
virtual uint32_t sizeHistoryMsgItem(RsHistoryMsgItem*);
virtual bool serialiseHistoryMsgItem (RsHistoryMsgItem* item, void* data, uint32_t* size);
virtual RsHistoryMsgItem* deserialiseHistoryMsgItem(void* data, uint32_t* size);
};
/**************************************************************************/
#endif /* RS_HISTORY_ITEMS_H */

View File

@ -29,6 +29,7 @@
#include "pqi/pqinotify.h"
#include "pqi/pqistore.h"
#include "pqi/p3linkmgr.h"
#include "pqi/p3historymgr.h"
#include "services/p3chatservice.h"
@ -42,8 +43,8 @@
*
*/
p3ChatService::p3ChatService(p3LinkMgr *lm)
:p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm)
p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr)
:p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(historyMgr)
{
addSerialType(new RsChatSerialiser());
@ -67,7 +68,7 @@ int p3ChatService::status()
/***************** Chat Stuff **********************/
int p3ChatService::sendPublicChat(std::wstring &msg)
int p3ChatService::sendPublicChat(const std::wstring &msg)
{
/* go through all the peers */
@ -76,7 +77,8 @@ int p3ChatService::sendPublicChat(std::wstring &msg)
mLinkMgr->getOnlineList(ids);
/* add in own id -> so get reflection */
ids.push_back(mLinkMgr->getOwnId());
std::string ownId = mLinkMgr->getOwnId();
ids.push_back(ownId);
#ifdef CHAT_DEBUG
std::cerr << "p3ChatService::sendChat()";
@ -92,7 +94,7 @@ int p3ChatService::sendPublicChat(std::wstring &msg)
ci->sendTime = time(NULL);
ci->recvTime = ci->sendTime;
ci->message = msg;
#ifdef CHAT_DEBUG
std::cerr << "p3ChatService::sendChat() Item:";
std::cerr << std::endl;
@ -100,6 +102,9 @@ int p3ChatService::sendPublicChat(std::wstring &msg)
std::cerr << std::endl;
#endif
if (*it == ownId) {
mHistoryMgr->addMessage(false, "", ownId, ci);
}
sendItem(ci);
}
@ -220,7 +225,7 @@ void p3ChatService::checkSizeAndSendMessage(RsChatMsgItem *msg)
sendItem(msg) ;
}
bool p3ChatService::sendPrivateChat(std::string &id, std::wstring &msg)
bool p3ChatService::sendPrivateChat(const std::string &id, const std::wstring &msg)
{
// make chat item....
#ifdef CHAT_DEBUG
@ -278,6 +283,8 @@ bool p3ChatService::sendPrivateChat(std::string &id, std::wstring &msg)
std::cerr << std::endl;
#endif
mHistoryMgr->addMessage(false, id, mLinkMgr->getOwnId(), ci);
checkSizeAndSendMessage(ci);
// Check if custom state string has changed, in which case it should be sent to the peer.
@ -428,9 +435,16 @@ void p3ChatService::receiveChatQueue()
if (ci->chatFlags & RS_CHAT_FLAG_PRIVATE) {
privateChanged = true;
privateIncomingList.push_back(ci); // don't delete the item !!
mHistoryMgr->addMessage(true, ci->PeerId(), ci->PeerId(), ci);
} else {
publicChanged = true;
publicList.push_back(ci); // don't delete the item !!
if (ci->PeerId() != mLinkMgr->getOwnId()) {
/* not from loop back */
mHistoryMgr->addMessage(true, "", ci->PeerId(), ci);
}
}
} /* UNLOCK */
}
@ -1088,12 +1102,16 @@ void p3ChatService::statusChange(const std::list<pqipeer> &plist)
if (privateOutgoingList.size()) {
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
std::string ownId = mLinkMgr->getOwnId();
std::list<RsChatMsgItem *>::iterator cit = privateOutgoingList.begin();
while (cit != privateOutgoingList.end()) {
RsChatMsgItem *c = *cit;
if (c->PeerId() == it->id) {
sendItem(c); // delete item
mHistoryMgr->addMessage(false, c->PeerId(), ownId, c);
checkSizeAndSendMessage(c); // delete item
changed = true;

View File

@ -35,6 +35,7 @@
#include "retroshare/rsmsgs.h"
class p3LinkMgr;
class p3HistoryMgr;
//!The basic Chat service.
/**
@ -46,7 +47,7 @@ class p3LinkMgr;
class p3ChatService: public p3Service, public p3Config, public pqiMonitor
{
public:
p3ChatService(p3LinkMgr *cm);
p3ChatService(p3LinkMgr *cm, p3HistoryMgr *historyMgr);
/***** overloaded from p3Service *****/
/*!
@ -65,14 +66,14 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
/*!
* public chat sent to all peers
*/
int sendPublicChat(std::wstring &msg);
int sendPublicChat(const std::wstring &msg);
/********* RsMsgs ***********/
/*!
* chat is sent to specifc peer
* @param id peer to send chat msg to
*/
bool sendPrivateChat(std::string &id, std::wstring &msg);
bool sendPrivateChat(const std::string &id, const std::wstring &msg);
/*!
* can be used to send 'immediate' status msgs, these status updates are meant for immediate use by peer (not saved by rs)
@ -201,6 +202,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
RsChatStatusItem *makeOwnCustomStateStringItem() ;
p3LinkMgr *mLinkMgr;
p3HistoryMgr *mHistoryMgr;
std::list<RsChatMsgItem *> publicList;
std::list<RsChatMsgItem *> privateIncomingList;

View File

@ -242,12 +242,8 @@ HEADERS += rshare.h \
gui/xprogressbar.h \
gui/plugins/PluginInterface.h \
gui/im_history/ImHistoryBrowser.h \
gui/im_history/IMHistoryKeeper.h \
gui/im_history/IMHistoryReader.h \
gui/im_history/IMHistoryItem.h \
gui/im_history/IMHistoryItemDelegate.h \
gui/im_history/IMHistoryItemPainter.h \
gui/im_history/IMHistoryWriter.h \
lang/languagesupport.h \
util/stringutil.h \
util/win32.h \
@ -491,12 +487,8 @@ SOURCES += main.cpp \
gui/MessagesDialog.cpp \
gui/FileTransferInfoWidget.cpp \
gui/im_history/ImHistoryBrowser.cpp \
gui/im_history/IMHistoryKeeper.cpp \
gui/im_history/IMHistoryReader.cpp \
gui/im_history/IMHistoryItem.cpp \
gui/im_history/IMHistoryItemDelegate.cpp \
gui/im_history/IMHistoryItemPainter.cpp \
gui/im_history/IMHistoryWriter.cpp \
gui/help/browser/helpbrowser.cpp \
gui/help/browser/helptextbrowser.cpp \
gui/HelpDialog.cpp \

View File

@ -40,6 +40,7 @@
#include <retroshare/rspeers.h>
#include <retroshare/rsstatus.h>
#include <retroshare/rsmsgs.h>
#include <retroshare/rshistory.h>
#include <retroshare/rsnotify.h>
#include "settings/rsharesettings.h"
#include "notifyqt.h"
@ -198,15 +199,15 @@ FriendsDialog::FriendsDialog(QWidget *parent)
setChatInfo(tr("Welcome to RetroShare's group chat."), QString::fromUtf8("blue"));
if (Settings->valueFromGroup("Chat", QString::fromUtf8("GroupChat_History"), true).toBool()) {
historyKeeper.init(QString::fromStdString(RsInit::RsProfileConfigDirectory()) + "/chatPublic.xml");
if (rsHistory->getEnable(true)) {
int messageCount = Settings->getPublicChatHistoryCount();
if (messageCount > 0) {
QList<IMHistoryItem> historyItems;
historyKeeper.getMessages(historyItems, messageCount);
foreach(IMHistoryItem item, historyItems) {
addChatMsg(item.incoming, true, item.name, item.recvTime, item.messageText);
std::list<HistoryMsg> historyMsgs;
rsHistory->getMessages("", historyMsgs, messageCount);
std::list<HistoryMsg>::iterator it;
for (it = historyMsgs.begin(); it != historyMsgs.end(); it++) {
addChatMsg(it->incoming, true, QString::fromUtf8(it->peerName.c_str()), QDateTime::fromTime_t(it->sendTime), QDateTime::fromTime_t(it->recvTime), QString::fromUtf8(it->message.c_str()));
}
}
}
@ -1429,12 +1430,12 @@ void FriendsDialog::publicChatChanged(int type)
}
}
void FriendsDialog::addChatMsg(bool incoming, bool history, QString &name, QDateTime &recvTime, QString &message)
void FriendsDialog::addChatMsg(bool incoming, bool history, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message)
{
unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS;
// embed smileys ?
if (Settings->valueFromGroup(QString("Chat"), QString::fromUtf8("Emoteicons_GroupChat"), true).toBool()) {
if (Settings->valueFromGroup("Chat", "Emoteicons_GroupChat", true).toBool()) {
formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS;
}
@ -1452,7 +1453,7 @@ void FriendsDialog::addChatMsg(bool incoming, bool history, QString &name, QDate
type = ChatStyle::FORMATMSG_OUTGOING;
}
}
QString formatMsg = style.formatMessage(type, name, recvTime, message, formatFlag);
QString formatMsg = style.formatMessage(type, name, incoming ? recvTime : sendTime, message, formatFlag);
ui.msgText->append(formatMsg);
}
@ -1509,8 +1510,7 @@ void FriendsDialog::insertChat()
emit notifyGroupChat(tr("New group chat"), notifyMsg);
}
historyKeeper.addMessage(incoming, it->rsid, name, sendTime, recvTime, msg);
addChatMsg(incoming, false, name, recvTime, msg);
addChatMsg(incoming, false, name, sendTime, recvTime, msg);
}
}
@ -1555,7 +1555,9 @@ void FriendsDialog::sendMsg()
return;
}
std::wstring message = lineWidget->toHtml().toStdWString();
QString text;
RsHtml::optimizeHtml(lineWidget, text);
std::wstring message = text.toStdWString();
#ifdef FRIENDS_DEBUG
std::string msg(message.begin(), message.end());
@ -1737,7 +1739,7 @@ void FriendsDialog::on_actionDelete_Chat_History_triggered()
{
if ((QMessageBox::question(this, "RetroShare", tr("Do you really want to physically delete the history?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) == QMessageBox::Yes) {
on_actionClear_Chat_History_triggered();
historyKeeper.clear();
rsHistory->clear("");
}
}
@ -2066,7 +2068,7 @@ void FriendsDialog::peerSortIndicatorChanged(int column, Qt::SortOrder)
void FriendsDialog::on_actionMessageHistory_triggered()
{
ImHistoryBrowser imBrowser("", historyKeeper, ui.lineEdit, this);
ImHistoryBrowser imBrowser("", ui.lineEdit, this);
imBrowser.exec();
}

View File

@ -27,8 +27,6 @@
#include "mainpage.h"
#include "im_history/IMHistoryKeeper.h"
// states for sorting (equal values are possible)
// used in BuildSortString - state + name
#define PEER_STATE_ONLINE 1
@ -173,7 +171,7 @@ signals:
private:
void processSettings(bool bLoad);
void addChatMsg(bool incoming, bool history, QString &name, QDateTime &recvTime, QString &message);
void addChatMsg(bool incoming, bool history, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message);
void colorChanged(const QColor &c);
void fontChanged(const QFont &font);
@ -199,7 +197,6 @@ private:
/* (2) Utility Fns */
QTreeWidgetItem *getCurrentPeer();
IMHistoryKeeper historyKeeper;
ChatStyle style;
QColor mCurrentColor;

View File

@ -23,6 +23,8 @@
#include "HandleRichText.h"
#include "gui/RetroShareLink.h"
#include <iostream>
namespace RsHtml {
EmbedInHtmlImg defEmbedImg;
@ -215,4 +217,56 @@ bool findAnchors(const QString &text, QStringList& urls)
return true;
}
static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement)
{
QDomNodeList children = currentElement.childNodes();
for (uint index = 0; index < children.length(); ) {
QDomNode node = children.item(index);
if (node.isElement()) {
QDomElement element = node.toElement();
if (element.tagName().toLower() == "head") {
// remove head
currentElement.removeChild(node);
continue;
}
QDomNode style = element.attributes().namedItem("style");
if (style.isAttr()) {
QDomAttr attr = style.toAttr();
// compress style attribute
QString value = attr.value().simplified();
value.replace("margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;", "margin:0px 0px 0px 0px;");
value.replace("; ", ";");
attr.setValue(value);
}
optimizeHtml(doc, element);
}
++index;
}
}
void optimizeHtml(QTextEdit *textEdit, QString &text)
{
if (textEdit->toHtml() == QTextDocument(textEdit->toPlainText()).toHtml()) {
text = textEdit->toPlainText();
std::cerr << "Optimized text to " << text.length() << " bytes , instead of " << textEdit->toHtml().length() << std::endl;
return;
}
text = textEdit->toHtml();
// remove doctype
text.remove(QRegExp("<!DOCTYPE[^>]*>"));
QDomDocument doc;
if (doc.setContent(text) == false) {
return;
}
QDomElement body = doc.documentElement();
optimizeHtml(doc, body);
text = doc.toString(-1);
std::cerr << "Optimized text to " << text.length() << " bytes , instead of " << textEdit->toHtml().length() << std::endl;
}
} // namespace RsHtml

View File

@ -37,6 +37,8 @@
#define RSHTML_FORMATTEXT_EMBED_SMILEYS 1
#define RSHTML_FORMATTEXT_EMBED_LINKS 2
class QTextEdit;
namespace RsHtml {
@ -111,6 +113,8 @@ extern EmbedInHtmlImg defEmbedImg;
QString formatText(const QString &text, unsigned int flag);
bool findAnchors(const QString &text, QStringList& urls);
void optimizeHtml(QTextEdit *textEdit, QString &text);
} // namespace RsHtml

View File

@ -45,6 +45,7 @@
#include "retroshare/rsinit.h"
#include <retroshare/rsnotify.h>
#include <retroshare/rsstatus.h>
#include <retroshare/rshistory.h>
#include <retroshare/rsiface.h>
#include "gui/settings/rsharesettings.h"
#include "gui/settings/RsharePeerSettings.h"
@ -60,6 +61,7 @@
#include "gui/common/PeerDefs.h"
#include <time.h>
#include <algorithm>
#define appDir QApplication::applicationDirPath()
@ -96,138 +98,116 @@ PopupChatDialog::PopupChatDialog(const std::string &id, const QString &name, QWi
lastChatTime(0), lastChatName("")
{
/* Invoke Qt Designer generated QObject setup routine */
ui.setupUi(this);
/* Invoke Qt Designer generated QObject setup routine */
ui.setupUi(this);
newMessages = false;
typing = false;
m_manualDelete = false;
peerStatus = 0;
newMessages = false;
typing = false;
manualDelete = false;
peerStatus = 0;
last_status_send_time = 0 ;
chatStyle.setStyleFromSettings(ChatStyle::TYPE_PRIVATE);
last_status_send_time = 0 ;
chatStyle.setStyleFromSettings(ChatStyle::TYPE_PRIVATE);
/* Hide or show the frames */
showAvatarFrame(PeerSettings->getShowAvatarFrame(dialogId));
ui.infoframe->setVisible(false);
ui.statusmessagelabel->hide();
/* Hide or show the frames */
showAvatarFrame(PeerSettings->getShowAvatarFrame(dialogId));
ui.infoframe->setVisible(false);
ui.statusmessagelabel->hide();
connect(ui.avatarFrameButton, SIGNAL(toggled(bool)), this, SLOT(showAvatarFrame(bool)));
connect(ui.avatarFrameButton, SIGNAL(toggled(bool)), this, SLOT(showAvatarFrame(bool)));
connect(ui.sendButton, SIGNAL(clicked( ) ), this, SLOT(sendChat( ) ));
connect(ui.addFileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile()));
connect(ui.sendButton, SIGNAL(clicked( ) ), this, SLOT(sendChat( ) ));
connect(ui.addFileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile()));
connect(ui.textboldButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textunderlineButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textitalicButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.attachPictureButton, SIGNAL(clicked()), this, SLOT(addExtraPicture()));
connect(ui.fontButton, SIGNAL(clicked()), this, SLOT(getFont()));
connect(ui.colorButton, SIGNAL(clicked()), this, SLOT(setColor()));
connect(ui.emoteiconButton, SIGNAL(clicked()), this, SLOT(smileyWidget()));
connect(ui.actionSave_Chat_History, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
connect(ui.actionClearOfflineMessages, SIGNAL(triggered()), this, SLOT(clearOfflineMessages()));
connect(ui.textboldButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textunderlineButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.textitalicButton, SIGNAL(clicked()), this, SLOT(setFont()));
connect(ui.attachPictureButton, SIGNAL(clicked()), this, SLOT(addExtraPicture()));
connect(ui.fontButton, SIGNAL(clicked()), this, SLOT(getFont()));
connect(ui.colorButton, SIGNAL(clicked()), this, SLOT(setColor()));
connect(ui.emoteiconButton, SIGNAL(clicked()), this, SLOT(smileyWidget()));
connect(ui.actionSave_Chat_History, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
connect(ui.actionClearOfflineMessages, SIGNAL(triggered()), this, SLOT(clearOfflineMessages()));
connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&, int)), this, SLOT(updateStatus(const QString&, int)));
connect(NotifyQt::getInstance(), SIGNAL(peerHasNewCustomStateString(const QString&, const QString&)), this, SLOT(updatePeersCustomStateString(const QString&, const QString&)));
connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&, int)), this, SLOT(updateStatus(const QString&, int)));
connect(NotifyQt::getInstance(), SIGNAL(peerHasNewCustomStateString(const QString&, const QString&)), this, SLOT(updatePeersCustomStateString(const QString&, const QString&)));
connect(ui.chattextEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint)));
connect(ui.chattextEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenu(QPoint)));
ui.avatarWidget->setFrameType(AvatarWidget::STATUS_FRAME);
ui.avatarWidget->setId(dialogId, false);
ui.avatarWidget->setFrameType(AvatarWidget::STATUS_FRAME);
ui.avatarWidget->setId(dialogId, false);
ui.ownAvatarWidget->setFrameType(AvatarWidget::STATUS_FRAME);
ui.ownAvatarWidget->setOwnId();
ui.ownAvatarWidget->setFrameType(AvatarWidget::STATUS_FRAME);
ui.ownAvatarWidget->setOwnId();
// Create the status bar
resetStatusBar();
// Create the status bar
resetStatusBar();
ui.textboldButton->setIcon(QIcon(QString(":/images/edit-bold.png")));
ui.textunderlineButton->setIcon(QIcon(QString(":/images/edit-underline.png")));
ui.textitalicButton->setIcon(QIcon(QString(":/images/edit-italic.png")));
ui.fontButton->setIcon(QIcon(QString(":/images/fonts.png")));
ui.emoteiconButton->setIcon(QIcon(QString(":/images/emoticons/kopete/kopete020.png")));
ui.textboldButton->setCheckable(true);
ui.textunderlineButton->setCheckable(true);
ui.textitalicButton->setCheckable(true);
ui.textboldButton->setIcon(QIcon(QString(":/images/edit-bold.png")));
ui.textunderlineButton->setIcon(QIcon(QString(":/images/edit-underline.png")));
ui.textitalicButton->setIcon(QIcon(QString(":/images/edit-italic.png")));
ui.fontButton->setIcon(QIcon(QString(":/images/fonts.png")));
ui.emoteiconButton->setIcon(QIcon(QString(":/images/emoticons/kopete/kopete020.png")));
setAcceptDrops(true);
ui.chattextEdit->setAcceptDrops(false);
ui.textboldButton->setCheckable(true);
ui.textunderlineButton->setCheckable(true);
ui.textitalicButton->setCheckable(true);
QMenu * toolmenu = new QMenu();
toolmenu->addAction(ui.actionClear_Chat_History);
toolmenu->addAction(ui.actionDelete_Chat_History);
toolmenu->addAction(ui.actionSave_Chat_History);
toolmenu->addAction(ui.actionClearOfflineMessages);
toolmenu->addAction(ui.actionMessageHistory);
//toolmenu->addAction(ui.action_Disable_Emoticons);
ui.pushtoolsButton->setMenu(toolmenu);
setAcceptDrops(true);
ui.chattextEdit->setAcceptDrops(false);
mCurrentColor.setNamedColor(PeerSettings->getPrivateChatColor(dialogId));
mCurrentFont.fromString(PeerSettings->getPrivateChatFont(dialogId));
QMenu * toolmenu = new QMenu();
toolmenu->addAction(ui.actionClear_Chat_History);
toolmenu->addAction(ui.actionDelete_Chat_History);
toolmenu->addAction(ui.actionSave_Chat_History);
toolmenu->addAction(ui.actionClearOfflineMessages);
toolmenu->addAction(ui.actionMessageHistory);
//toolmenu->addAction(ui.action_Disable_Emoticons);
ui.pushtoolsButton->setMenu(toolmenu);
colorChanged(mCurrentColor);
fontChanged(mCurrentFont);
mCurrentColor.setNamedColor(PeerSettings->getPrivateChatColor(dialogId));
mCurrentFont.fromString(PeerSettings->getPrivateChatFont(dialogId));
// load settings
processSettings(true);
colorChanged(mCurrentColor);
fontChanged(mCurrentFont);
// load style
PeerSettings->getStyle(dialogId, "PopupChatDialog", style);
// load settings
processSettings(true);
// initialize first status
StatusInfo peerStatusInfo;
// No check of return value. Non existing status info is handled as offline.
rsStatus->getStatus(dialogId, peerStatusInfo);
updateStatus(QString::fromStdString(dialogId), peerStatusInfo.status);
// load style
PeerSettings->getStyle(dialogId, "PopupChatDialog", style);
// initialize first custom state string
QString customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(dialogId).c_str());
updatePeersCustomStateString(QString::fromStdString(dialogId), customStateString);
// initialize first status
StatusInfo peerStatusInfo;
// No check of return value. Non existing status info is handled as offline.
rsStatus->getStatus(dialogId, peerStatusInfo);
updateStatus(QString::fromStdString(dialogId), peerStatusInfo.status);
if (Settings->valueFromGroup("Chat", QString::fromUtf8("PrivateChat_History"), true).toBool()) {
historyKeeper.init(QString::fromStdString(RsInit::RsProfileConfigDirectory()) + "/chat_" + QString::fromStdString(dialogId) + ".xml");
// initialize first custom state string
QString customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(dialogId).c_str());
updatePeersCustomStateString(QString::fromStdString(dialogId), customStateString);
// get offline chat messages
std::list<ChatInfo> offlineChat;
std::list<ChatInfo>::iterator offineChatIt;
rsMsgs->getPrivateChatQueueCount(false) && rsMsgs->getPrivateChatQueue(false, dialogId, offlineChat);
if (rsHistory->getEnable(false)) {
// get chat messages from history
std::list<HistoryMsg> historyMsgs;
int messageCount = Settings->getPrivateChatHistoryCount();
if (messageCount > 0) {
rsHistory->getMessages(dialogId, historyMsgs, messageCount);
QList<IMHistoryItem> historyItems;
int messageCount = Settings->getPrivateChatHistoryCount();
if (messageCount > 0) {
historyKeeper.getMessages(historyItems, messageCount);
}
foreach(IMHistoryItem item, historyItems) {
for(offineChatIt = offlineChat.begin(); offineChatIt != offlineChat.end(); offineChatIt++) {
/* are they public? */
if ((offineChatIt->chatflags & RS_CHAT_PRIVATE) == 0) {
/* this should not happen */
continue;
}
std::list<HistoryMsg>::iterator historyIt;
for (historyIt = historyMsgs.begin(); historyIt != historyMsgs.end(); historyIt++) {
addChatMsg(historyIt->incoming, QString::fromUtf8(historyIt->peerName.c_str()), QDateTime::fromTime_t(historyIt->sendTime), QDateTime::fromTime_t(historyIt->recvTime), QString::fromUtf8(historyIt->message.c_str()), TYPE_HISTORY);
}
}
}
QDateTime sendTime = QDateTime::fromTime_t(offineChatIt->sendTime);
QString message = QString::fromStdWString(offineChatIt->msg);
ui.chattextEdit->installEventFilter(this);
if (IMHistoryKeeper::compareItem(item, false, offineChatIt->rsid, sendTime, message)) {
// don't show offline message out of the history
break;
}
}
if (offineChatIt == offlineChat.end()) {
addChatMsg(item.incoming, item.id, item.name, item.sendTime, item.recvTime, item.messageText, TYPE_HISTORY, false);
}
}
}
ui.chattextEdit->installEventFilter(this);
// call once
onPrivateChatChanged(NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_ADD, true);
// add offline chat messages
onPrivateChatChanged(NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_ADD, true);
#ifdef RS_RELEASE_VERSION
ui.attachPictureButton->setVisible(false);
ui.attachPictureButton->setVisible(false);
#endif
}
@ -508,7 +488,7 @@ void PopupChatDialog::onPrivateChatChanged(int list, int type, bool initial /*=
switch (type) {
case NOTIFY_TYPE_ADD:
{
m_savedOfflineChat.clear();
std::list<ChatInfo> savedOfflineChatNew;
QString name = QString::fromUtf8(rsPeers->getPeerName(rsPeers->getOwnId()).c_str());
@ -524,53 +504,45 @@ void PopupChatDialog::onPrivateChatChanged(int list, int type, bool initial /*=
continue;
}
m_savedOfflineChat.push_back(*it);
savedOfflineChatNew.push_back(*it);
if (std::find(savedOfflineChat.begin(), savedOfflineChat.end(), *it) != savedOfflineChat.end()) {
continue;
}
QDateTime sendTime = QDateTime::fromTime_t(it->sendTime);
QDateTime recvTime = QDateTime::fromTime_t(it->recvTime);
QString message = QString::fromStdWString(it->msg);
bool existingMessage;
bool showMessage;
if (initial) {
// show all messages on startup
existingMessage = true;
showMessage = true;
} else {
int hiid;
existingMessage = historyKeeper.findMessage(false, it->rsid, sendTime, message, hiid);
showMessage = !existingMessage;
}
if (showMessage) {
addChatMsg(false, it->rsid, name, sendTime, recvTime, message, TYPE_OFFLINE, !existingMessage);
}
addChatMsg(false, name, sendTime, recvTime, message, TYPE_OFFLINE);
}
}
savedOfflineChat = savedOfflineChatNew;
}
break;
case NOTIFY_TYPE_DEL:
{
if (m_manualDelete == false) {
if (manualDelete == false) {
QString name = QString::fromUtf8(rsPeers->getPeerName(rsPeers->getOwnId()).c_str());
// now show saved offline chat messages as sent
std::list<ChatInfo>::iterator it;
for(it = m_savedOfflineChat.begin(); it != m_savedOfflineChat.end(); it++) {
for(it = savedOfflineChat.begin(); it != savedOfflineChat.end(); ++it) {
QDateTime sendTime = QDateTime::fromTime_t(it->sendTime);
QDateTime recvTime = QDateTime::fromTime_t(it->recvTime);
QString message = QString::fromStdWString(it->msg);
addChatMsg(false, it->rsid, name, sendTime, recvTime, message, TYPE_NORMAL, false);
addChatMsg(false, name, sendTime, recvTime, message, TYPE_NORMAL);
}
}
m_savedOfflineChat.clear();
savedOfflineChat.clear();
}
break;
}
ui.actionClearOfflineMessages->setEnabled(!m_savedOfflineChat.empty());
ui.actionClearOfflineMessages->setEnabled(!savedOfflineChat.empty());
}
}
@ -593,7 +565,7 @@ void PopupChatDialog::insertChatMsgs()
continue;
}
addChatMsg(true, it->rsid, QString::fromUtf8(rsPeers->getPeerName(it->rsid).c_str()), QDateTime::fromTime_t(it->sendTime), QDateTime::fromTime_t(it->recvTime), QString::fromStdWString(it->msg), TYPE_NORMAL, true);
addChatMsg(true, QString::fromUtf8(rsPeers->getPeerName(it->rsid).c_str()), QDateTime::fromTime_t(it->sendTime), QDateTime::fromTime_t(it->recvTime), QString::fromStdWString(it->msg), TYPE_NORMAL);
}
rsMsgs->clearPrivateChatQueue(true, dialogId);
@ -614,10 +586,8 @@ void PopupChatDialog::insertChatMsgs()
}
}
void PopupChatDialog::addChatMsg(bool incoming, const std::string &id, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message, enumChatType chatType, bool addToHistory)
void PopupChatDialog::addChatMsg(bool incoming, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message, enumChatType chatType)
{
std::string ownId = rsPeers->getOwnId();
#ifdef CHAT_DEBUG
std::cout << "PopupChatDialog:addChatMsg message : " << message.toStdString() << std::endl;
#endif
@ -638,11 +608,7 @@ void PopupChatDialog::addChatMsg(bool incoming, const std::string &id, const QSt
type = incoming ? ChatStyle::FORMATMSG_INCOMING : ChatStyle::FORMATMSG_OUTGOING;
}
QString formatMsg = chatStyle.formatMessage(type, name, recvTime, message, formatFlag);
if (addToHistory) {
historyKeeper.addMessage(incoming, id, name, sendTime, recvTime, message);
}
QString formatMsg = chatStyle.formatMessage(type, name, incoming ? sendTime : recvTime, message, formatFlag);
ui.textBrowser->append(formatMsg);
@ -694,7 +660,9 @@ void PopupChatDialog::sendChat()
return;
}
std::wstring msg = chatWidget->toHtml().toStdWString();
QString text;
RsHtml::optimizeHtml(chatWidget, text);
std::wstring msg = text.toStdWString();
if (msg.empty()) {
// nothing to send
@ -718,7 +686,7 @@ void PopupChatDialog::sendChat()
if (rsMsgs->sendPrivateChat(dialogId, msg)) {
QDateTime currentTime = QDateTime::currentDateTime();
addChatMsg(false, ownId, QString::fromUtf8(rsPeers->getPeerName(ownId).c_str()), currentTime, currentTime, QString::fromStdWString(msg), TYPE_NORMAL, true);
addChatMsg(false, QString::fromUtf8(rsPeers->getPeerName(ownId).c_str()), currentTime, currentTime, QString::fromStdWString(msg), TYPE_NORMAL);
}
chatWidget->clear();
@ -832,7 +800,7 @@ void PopupChatDialog::on_actionDelete_Chat_History_triggered()
{
if ((QMessageBox::question(this, "RetroShare", tr("Do you really want to physically delete the history?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)) == QMessageBox::Yes) {
on_actionClear_Chat_History_triggered();
historyKeeper.clear();
rsHistory->clear(dialogId);
}
}
@ -953,7 +921,7 @@ void PopupChatDialog::fileHashingFinished(AttachFileItem* file)
if (rsMsgs->sendPrivateChat(dialogId, msg)) {
QDateTime currentTime = QDateTime::currentDateTime();
addChatMsg(false, ownId, QString::fromUtf8(rsPeers->getPeerName(ownId).c_str()), currentTime, currentTime, QString::fromStdWString(msg), TYPE_NORMAL, true);
addChatMsg(false, QString::fromUtf8(rsPeers->getPeerName(ownId).c_str()), currentTime, currentTime, QString::fromStdWString(msg), TYPE_NORMAL);
}
}
@ -1076,9 +1044,9 @@ void PopupChatDialog::setCurrentFileName(const QString &fileName)
void PopupChatDialog::clearOfflineMessages()
{
m_manualDelete = true;
manualDelete = true;
rsMsgs->clearPrivateChatQueue(false, dialogId);
m_manualDelete = false;
manualDelete = false;
}
void PopupChatDialog::updateStatus(const QString &peer_id, int status)
@ -1150,7 +1118,7 @@ void PopupChatDialog::updatePeersCustomStateString(const QString& peer_id, const
void PopupChatDialog::on_actionMessageHistory_triggered()
{
ImHistoryBrowser imBrowser(dialogId, historyKeeper, ui.chattextEdit, window());
ImHistoryBrowser imBrowser(dialogId, ui.chattextEdit, window());
imBrowser.exec();
}

View File

@ -32,7 +32,6 @@ class AttachFileItem;
class ChatInfo;
#include <retroshare/rsmsgs.h>
#include "gui/im_history/IMHistoryKeeper.h"
#include "ChatStyle.h"
#include "gui/style/RSStyle.h"
@ -77,7 +76,7 @@ protected:
bool eventFilter(QObject *obj, QEvent *ev);
void insertChatMsgs();
void addChatMsg(bool incoming, const std::string &id, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message, enumChatType chatType, bool addToHistory);
void addChatMsg(bool incoming, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &message, enumChatType chatType);
private slots:
void pasteLink() ;
@ -135,16 +134,15 @@ private:
QColor mCurrentColor;
QFont mCurrentFont;
std::list<ChatInfo> m_savedOfflineChat;
std::list<ChatInfo> savedOfflineChat;
QString wholeChat;
QString fileName;
bool newMessages;
bool typing;
int peerStatus;
IMHistoryKeeper historyKeeper;
ChatStyle chatStyle;
bool m_manualDelete;
bool manualDelete;
RSStyle style;

View File

@ -1,51 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include "IMHistoryItem.h"
//============================================================================
IMHistoryItem::IMHistoryItem()
{
hiid = 0;
}
//============================================================================
IMHistoryItem::IMHistoryItem(int hiidIn, bool incomingIn, const std::string &idIn, const QString &nameIn, const QDateTime &sendTimeIn, const QDateTime &recvTimeIn, const QString &messageTextIn)
{
hiid = hiidIn;
incoming = incomingIn;
id = idIn;
name = nameIn;
sendTime = sendTimeIn;
recvTime = recvTimeIn;
messageText = messageTextIn;
}
//============================================================================
//! after qSort() older messages will become first
bool
IMHistoryItem::operator<(const IMHistoryItem& item) const
{
return (recvTime < item.recvTime) ;
}

View File

@ -1,47 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#ifndef __IM_history_item__
#define __IM_history_item__
#include <QDateTime>
#include <QString>
class IMHistoryItem
{
public:
IMHistoryItem();
IMHistoryItem(int hiid, bool incoming, const std::string &id, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &messageText);
int hiid;
bool incoming;
std::string id;
QString name;
QDateTime sendTime;
QDateTime recvTime;
QString messageText;
bool operator<(const IMHistoryItem& item) const;
} ;
#endif

View File

@ -26,8 +26,6 @@
#include <QString>
#include <QStyleOption>
#include "IMHistoryItem.h"
class QPainter;
class IMHistoryItemPainter

View File

@ -1,267 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include "IMHistoryKeeper.h"
#include <iostream>
#include <QFile>
#include <QIODevice>
#include <QTimer>
#include <QtAlgorithms> //for qSort
#include <QXmlStreamReader>
#include "IMHistoryReader.h"
#include "IMHistoryWriter.h"
//=============================================================================
IMHistoryKeeper::IMHistoryKeeper()
{
historyChanged = false;
// save histroy every 10 seconds (when changed)
saveTimer = new QTimer(this);
saveTimer->connect(saveTimer, SIGNAL(timeout()), this, SLOT(saveHistory()));
saveTimer->setInterval(10000);
saveTimer->start();
lasthiid = 0;
};
//=============================================================================
IMHistoryKeeper::~IMHistoryKeeper()
{
saveHistory();
}
//=============================================================================
void IMHistoryKeeper::init(QString historyFileName)
{
lasthiid = 0;
hfName = historyFileName;
loadHistoryFile();
}
//=============================================================================
void IMHistoryKeeper::addMessage(bool incoming, const std::string &id, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &messageText)
{
IMHistoryItem item(++lasthiid, incoming, id, name, sendTime, recvTime, messageText);
hitems.append(item);
historyChanged = true;
emit historyAdd(item);
//std::cerr << "IMHistoryKeeper::addMessage "
// << messageText.toStdString() << "\n";
//std::cerr << "IMHistoryKeeper::addMessage count is" << hitems.count();
}
//=============================================================================
bool IMHistoryKeeper::loadHistoryFile()
{
qDebug() << " IMHistoryKeeper::loadHistoryFile is here";
if (hfName.isEmpty()) {
lastErrorMessage = "history file not set";
return false;
}
QFile fl(hfName);
if (!fl.exists()) {
lastErrorMessage = QString("history file not found (%1)").arg(hfName) ;
return false;
}
IMHistoryReader hreader;
if (!hreader.read(hitems, hfName, lasthiid)) {
lastErrorMessage = hreader.errorMessage();
return false;
}
qSort(hitems.begin(), hitems.end());
qDebug() << " IMHistoryKeeper::loadHistoryFile finished";
historyChanged = false;
return true;
}
//=============================================================================
QString IMHistoryKeeper::errorMessage()
{
QString errorMessage = lastErrorMessage;
lastErrorMessage.clear();
return errorMessage;
}
//=============================================================================
bool IMHistoryKeeper::getMessages(QList<IMHistoryItem> &historyItems, const int messagesCount)
{
int messFound = 0;
historyItems.clear();
QListIterator<IMHistoryItem> hii(hitems);
hii.toBack();
while (hii.hasPrevious()) {
IMHistoryItem hitem = hii.previous();
historyItems.insert(historyItems.begin(), hitem);
messFound++;
if (messagesCount && messFound >= messagesCount) {
break;
}
}
return true; // successful end
}
//=============================================================================
bool IMHistoryKeeper::getMessage(int hiid, IMHistoryItem &item)
{
QList<IMHistoryItem>::iterator it;
for (it = hitems.begin(); it != hitems.end(); it++) {
if (it->hiid == hiid) {
item = *it;
return true;
}
}
return false;
}
//=============================================================================
void IMHistoryKeeper::clear()
{
hitems.clear();
historyChanged = true;
lasthiid = 0;
emit historyClear();
}
//=============================================================================
/*static*/ bool IMHistoryKeeper::compareItem(const IMHistoryItem &item, bool incoming, const std::string &id, const QDateTime &sendTime, const QString &messageText)
{
// "\n" is not saved in xml
QString copyMessage1(messageText);
copyMessage1.replace("\n", "");
QString copyMessage2(item.messageText);
copyMessage2.replace("\n", "");
if (item.incoming == incoming && item.id == id && item.sendTime == sendTime && copyMessage1 == copyMessage2) {
return true;
}
return false;
}
//=============================================================================
bool IMHistoryKeeper::findMessage(bool incoming, const std::string &id, const QDateTime &sendTime, const QString &messageText, int &hiid)
{
hiid = 0;
QList<IMHistoryItem>::const_iterator it;
for (it = hitems.begin(); it != hitems.end(); it++) {
if (compareItem(*it, incoming, id, sendTime, messageText)) {
hiid = it->hiid;
return true;
}
}
return false;
}
//=============================================================================
void IMHistoryKeeper::removeMessage(int hiid)
{
QList<IMHistoryItem>::iterator it;
for (it = hitems.begin(); it != hitems.end(); it++) {
if (it->hiid == hiid) {
emit historyRemove(*it);
hitems.erase(it);
historyChanged = true;
break;
}
}
}
//=============================================================================
void IMHistoryKeeper::removeMessages(QList<int> &hiids)
{
bool changed = false;
QList<IMHistoryItem>::iterator it = hitems.begin();
while (it != hitems.end()) {
if (qFind(hiids, it->hiid) != hiids.end()) {
emit historyRemove(*it);
it = hitems.erase(it);
changed = true;
continue;
}
it++;
}
if (changed) {
historyChanged = true;
}
}
//=============================================================================
void IMHistoryKeeper::saveHistory()
{
if (historyChanged && hfName.isEmpty() == false) {
//=== we have to save all messages
qSort( hitems.begin(), hitems.end() ) ; // not nesessary, but just in case...
// it will not take a long time over ordered array
IMHistoryWriter wri;
wri.write(hitems, hfName);
historyChanged = false;
}
}

View File

@ -1,115 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#ifndef _HISTORY_KEEPER_H_
#define _HISTORY_KEEPER_H_
#include <QObject>
#include <QDebug>
#include <QString>
#include "IMHistoryItem.h"
class QTimer;
//! An engine for instant messaging history management
//! This class holds history for instant messages. It stores all messages
//! in xml file. Something like
//! <?xml version="1.0" encoding="UTF-8"?>
//! <!DOCTYPE history_file>
//! <history_file format_version="1.0">
//! <message sendTime="10000" id="id" name="Name">manual message</message>
//! ...
//! other messages in <message..> ... </message> tags
//! ...
//! </history_file>
//!
//! The class loads all messages from the file after creation, and saves them
//! at destruction. This means, the more history user has, the more memory
//! will be used. Maybe it's not good, but it isn't so large, I think
class IMHistoryKeeper : public QObject
{
Q_OBJECT
public:
IMHistoryKeeper();
//! A destructor
//! Warning: history messages will be saved to the file here. This means,
//! a IMHistoryKeeper object must be deleted properly.
virtual ~IMHistoryKeeper();
//! last error description
QString errorMessage();
//! initialize history keeper
void init(QString historyFileName);
//! Select messages from history
//! Fills given list with items
bool getMessages(QList<IMHistoryItem> &historyItems, const int messagesCount);
//! Get message
bool getMessage(int hiid, IMHistoryItem &item);
//! Adds new message to the history
//! Adds new message to the history, but the message will be saved to
//! file only after destroing the object
void addMessage(bool incoming, const std::string &id, const QString &name, const QDateTime &sendTime, const QDateTime &recvTime, const QString &messageText);
//! Clear the history
void clear();
//! Find message
static bool compareItem(const IMHistoryItem &item, bool incoming, const std::string &id, const QDateTime &sendTime, const QString &messageText);
bool findMessage(bool incoming, const std::string &id, const QDateTime &sendTime, const QString &messageText, int &hiid);
//! Remove item
void removeMessage(int hiid);
//! Remove items
void removeMessages(QList<int> &hiids);
private:
bool loadHistoryFile();
QList<IMHistoryItem> hitems;
QString hfName ; //! history file name
bool historyChanged;
QString lastErrorMessage;
QTimer *saveTimer;
int lasthiid;
private slots:
void saveHistory();
signals:
void historyAdd(IMHistoryItem item) const;
void historyRemove(IMHistoryItem item) const;
void historyClear() const;
};
#endif // _HISTORY_KEEPER_H_

View File

@ -1,206 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include "IMHistoryReader.h"
#include <QFile>
#include <QDebug>
//=============================================================================
IMHistoryReader::IMHistoryReader()
:errMess("No error")
{
// nothing to do here
}
//=============================================================================
bool IMHistoryReader::read(QList<IMHistoryItem>& resultList, const QString fileName, int &lasthiid)
{
errMess = "No error";
resultList.clear();
//==== check for file and open it
QFile fl(fileName);
if (fl.exists()) {
fl.open(QIODevice::ReadOnly);
} else {
errMess = QString("file not found (%1)").arg(fileName);
return false ;
}
//==== set the file, and check it once more
setDevice(&fl);
if (atEnd()) {
errMess = "end of document reached before anything happened";
return false;
}
//==== now, read the first element (it should be document element)
while (!atEnd()) {
readNext();
if (isStartElement()) {
if (name() == "history_file" && attributes().value("format_version") == "1.0") {
readHistory(resultList, lasthiid);
break;
} else {
errMess = "The file is not a history file with format version 1.0";
return false ;
}
}
}
if (error()) {
errMess = errorString();
// } else {
// QList<IMHistoryItem>::const_iterator hii;//history items iterator
// for (hii = result.constBegin(); hii != result.constEnd(); ++hii) {
// resultList << *hii;
// }
}
return !error();
}
//=============================================================================
QString IMHistoryReader::errorMessage()
{
QString result = errMess;
errMess = "No error" ;
return result;
}
//=============================================================================
void IMHistoryReader::readUnknownElement()
{
Q_ASSERT(isStartElement());
qDebug()<< " " << "unknown node " << name().toString();
while (!atEnd()) {
readNext();
if (isEndElement()) {
break;
}
if (isStartElement()) {
readUnknownElement();
}
}
}
//=============================================================================
void IMHistoryReader::readHistory(QList<IMHistoryItem> &historyItems, int &lasthiid)
{
Q_ASSERT(isStartElement());
// qDebug()<< " " << "node with message " << name() ;
historyItems.clear();
lasthiid = 0;
bool recalculate = false;
while (!atEnd()) {
readNext();
if (isEndElement()) {
break;
}
if (isStartElement()) {
if ( name() == "message") {
IMHistoryItem item;
readMessage(item);
if (item.hiid == 0) {
recalculate = true;
} else {
if (item.hiid > lasthiid) {
lasthiid = item.hiid;
}
}
historyItems.append(item);
} else {
readUnknownElement();
}
}
}
if (recalculate) {
// calculate hiid
QList<IMHistoryItem>::iterator item = historyItems.begin();
for (item = historyItems.begin(); item != historyItems.end(); item++) {
if (item->hiid == 0) {
item->hiid = ++lasthiid;
}
}
}
}
//=============================================================================
void IMHistoryReader::readMessage(IMHistoryItem &historyItem)
{
// Q_ASSERT(isStartElement() );
if (isStartElement() && (name() == "message")) {
//=== process attributes
historyItem.hiid = attributes().value("hiid").toString().toInt();
historyItem.incoming = (attributes().value("incoming").toString().toInt() == 1);
historyItem.id = attributes().value("id").toString().toStdString();
historyItem.name = attributes().value("name").toString();
int ti = attributes().value("sendTime").toString().toInt();
historyItem.sendTime = QDateTime::fromTime_t(ti);
ti = attributes().value("recvTime").toString().toInt();
if (ti) {
historyItem.recvTime = QDateTime::fromTime_t(ti);
} else {
historyItem.recvTime = historyItem.sendTime;
}
//=== after processing attributes, read the message text
QString tstr = readElementText();
//=== remove '\0' chars from the string. Is it a QXmlStuff bug,
// if they appear?
for (int i = 0; i< tstr.length(); i++) {
if (tstr.at(i) == '\n') {
tstr.remove(i, 1);
}
}
historyItem.messageText = tstr;
//qDebug() << QString(" readMessage: %1, %2, %3, %4" )
// .arg(rez.text()).arg(rez.sender())
// .arg(rez.receiver()).arg(ti) ;
}
}

View File

@ -1,50 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#ifndef __IM_History_reader__
#define __IM_History_reader__
#include <QXmlStreamReader>
#include <QString>
#include <QStringList>
#include "IMHistoryItem.h"
class IMHistoryReader : public QXmlStreamReader
{
public:
IMHistoryReader();
bool read(QList<IMHistoryItem>& resultList, const QString fileName, int &lasthiid);
QString errorMessage();
private:
void readUnknownElement();
void readHistory(QList<IMHistoryItem> &historyItems, int &lasthiid);
void readMessage(IMHistoryItem &historyItem);
QString errMess;
} ;
#endif

View File

@ -1,93 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include "IMHistoryWriter.h"
#include <QFile>
#include <QDebug>
#include <QDateTime>
//=============================================================================
IMHistoryWriter::IMHistoryWriter()
:errMess("No error")
{
// nothing to do here
}
//=============================================================================
bool IMHistoryWriter::write(QList<IMHistoryItem>& itemList, const QString fileName)
{
qDebug() << " IMHistoryWriter::write is here" ;
errMess = "No error";
if (itemList.size() == 0) {
return remove(fileName);
}
//==== check for file and open it
QFile fl(fileName);
if (fl.open(QIODevice::WriteOnly | QIODevice::Truncate) == false) {
errMess = QString("error opening file %1 (code %2)")
.arg(fileName).arg( fl.error() );
return false;
}
//==== set the file, and check it once more
setDevice(&fl);
writeStartDocument();
writeDTD("<!DOCTYPE history_file>");
writeStartElement("history_file");
writeAttribute("format_version", "1.0");
foreach(IMHistoryItem item, itemList) {
writeStartElement("message");
writeAttribute("hiid", QString::number(item.hiid));
writeAttribute("incoming", QString::number(item.incoming ? 1 : 0));
writeAttribute("id", QString::fromStdString(item.id));
writeAttribute("name", item.name);
writeAttribute("sendTime", QString::number(item.sendTime.toTime_t()));
writeAttribute("recvTime", QString::number(item.recvTime.toTime_t()));
writeCDATA(item.messageText);
writeEndElement();
}
writeEndDocument() ;
fl.close();
qDebug() << " IMHistoryWriter::write done" ;
return true;
}
bool IMHistoryWriter::remove(const QString &fileName)
{
if (!QFile::remove(fileName)) {
qDebug() << " IMHistoryWriter::remove Failed to remove history file";
return false;
}
return true;
}

View File

@ -1,53 +0,0 @@
/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2009 The RetroShare Team, Oleksiy Bilyanskyy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#ifndef __IM_History_writer__
#define __IM_History_writer__
#include <QXmlStreamWriter>
#include <QString>
//#include <QStringList>
#include "IMHistoryItem.h"
class IMHistoryWriter : public QXmlStreamWriter
{
public:
IMHistoryWriter();
bool write(QList<IMHistoryItem>& itemList,
const QString fileName );
//! remove history file
bool remove(const QString& fileName);
QString errorMessage();
private:
QString errMess;
} ;
#endif

View File

@ -34,16 +34,18 @@
#include "IMHistoryItemPainter.h"
#include "rshare.h"
#include <retroshare/rshistory.h>
#include "gui/settings/rsharesettings.h"
#include "gui/notifyqt.h"
#define ROLE_HIID Qt::UserRole
#define ROLE_MSGID Qt::UserRole
#define ROLE_PLAINTEXT Qt::UserRole + 1
#define ROLE_OFFLINE Qt::UserRole + 2
ImHistoryBrowserCreateItemsThread::ImHistoryBrowserCreateItemsThread(ImHistoryBrowser *parent, IMHistoryKeeper &histKeeper)
: QThread(parent), m_historyKeeper(histKeeper)
ImHistoryBrowserCreateItemsThread::ImHistoryBrowserCreateItemsThread(ImHistoryBrowser *parent, const std::string& peerId)
: QThread(parent)
{
m_peerId = peerId;
m_historyBrowser = parent;
stopped = false;
}
@ -68,17 +70,18 @@ void ImHistoryBrowserCreateItemsThread::stop()
void ImHistoryBrowserCreateItemsThread::run()
{
QList<IMHistoryItem> historyItems;
m_historyKeeper.getMessages(historyItems, 0);
std::list<HistoryMsg> historyMsgs;
rsHistory->getMessages(m_peerId, historyMsgs, 0);
int count = historyItems.count();
int count = historyMsgs.size();
int current = 0;
foreach(IMHistoryItem item, historyItems) {
std::list<HistoryMsg>::iterator it;
for (it = historyMsgs.begin(); it != historyMsgs.end(); it++) {
if (stopped) {
break;
}
QListWidgetItem *itemWidget = m_historyBrowser->createItem(item);
QListWidgetItem *itemWidget = m_historyBrowser->createItem(*it);
if (itemWidget) {
m_items.push_back(itemWidget);
emit progress(++current, count);
@ -87,8 +90,8 @@ void ImHistoryBrowserCreateItemsThread::run()
}
/** Default constructor */
ImHistoryBrowser::ImHistoryBrowser(const std::string &peerId, IMHistoryKeeper &histKeeper, QTextEdit *edit, QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags), historyKeeper(histKeeper)
ImHistoryBrowser::ImHistoryBrowser(const std::string &peerId, QTextEdit *edit, QWidget *parent, Qt::WFlags flags)
: QDialog(parent, flags)
{
/* Invoke Qt Designer generated QObject setup routine */
ui.setupUi(this);
@ -97,9 +100,7 @@ ImHistoryBrowser::ImHistoryBrowser(const std::string &peerId, IMHistoryKeeper &h
m_isPrivateChat = !m_peerId.empty();
textEdit = edit;
connect(&historyKeeper, SIGNAL(historyAdd(IMHistoryItem)), this, SLOT(historyAdd(IMHistoryItem)));
connect(&historyKeeper, SIGNAL(historyRemove(IMHistoryItem)), this, SLOT(historyRemove(IMHistoryItem)));
connect(&historyKeeper, SIGNAL(historyClear()), this, SLOT(historyClear()));
connect(NotifyQt::getInstance(), SIGNAL(historyChanged(uint, int)), this, SLOT(historyChanged(uint, int)));
connect(ui.clearFilterButton, SIGNAL(clicked()), this, SLOT(clearFilter()));
connect(ui.filterPatternLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterRegExpChanged()));
@ -110,8 +111,6 @@ ImHistoryBrowser::ImHistoryBrowser(const std::string &peerId, IMHistoryKeeper &h
connect(ui.listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
connect(ui.listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint)));
connect(NotifyQt::getInstance(), SIGNAL(privateChatChanged(int,int)), this, SLOT(privateChatChanged(int,int)));
ui.clearFilterButton->hide();
// embed smileys ?
@ -125,9 +124,6 @@ ImHistoryBrowser::ImHistoryBrowser(const std::string &peerId, IMHistoryKeeper &h
ui.listWidget->setItemDelegate(new IMHistoryItemDelegate);
// call once
privateChatChanged(NOTIFY_LIST_PRIVATE_OUTGOING_CHAT, NOTIFY_TYPE_ADD);
QByteArray geometry = Settings->valueFromGroup("HistorieBrowser", "Geometry", QByteArray()).toByteArray();
if (geometry.isEmpty() == false) {
restoreGeometry(geometry);
@ -138,7 +134,7 @@ ImHistoryBrowser::ImHistoryBrowser(const std::string &peerId, IMHistoryKeeper &h
ui.listWidget->installEventFilter(this);
m_createThread = new ImHistoryBrowserCreateItemsThread(this, historyKeeper);
m_createThread = new ImHistoryBrowserCreateItemsThread(this, m_peerId);
connect(m_createThread, SIGNAL(finished()), this, SLOT(createThreadFinished()));
connect(m_createThread, SIGNAL(progress(int,int)), this, SLOT(createThreadProgress(int,int)));
m_createThread->start();
@ -178,11 +174,11 @@ void ImHistoryBrowser::createThreadFinished()
m_createThread->deleteLater();
m_createThread = NULL;
QList<IMHistoryItem>::iterator histIt;
for (histIt = m_itemsAddedOnLoad.begin(); histIt != m_itemsAddedOnLoad.end(); histIt++) {
QList<HistoryMsg>::iterator histIt;
for (histIt = itemsAddedOnLoad.begin(); histIt != itemsAddedOnLoad.end(); histIt++) {
historyAdd(*histIt);
}
m_itemsAddedOnLoad.clear();
itemsAddedOnLoad.clear();
}
}
}
@ -210,39 +206,56 @@ bool ImHistoryBrowser::eventFilter(QObject *obj, QEvent *event)
return QDialog::eventFilter(obj, event);
}
void ImHistoryBrowser::historyAdd(IMHistoryItem item)
void ImHistoryBrowser::historyAdd(HistoryMsg& msg)
{
if (m_createThread) {
// create later
m_itemsAddedOnLoad.push_back(item);
itemsAddedOnLoad.push_back(msg);
return;
}
QListWidgetItem *itemWidget = createItem(item);
QListWidgetItem *itemWidget = createItem(msg);
if (itemWidget) {
ui.listWidget->addItem(itemWidget);
filterItems(itemWidget);
}
}
void ImHistoryBrowser::historyRemove(IMHistoryItem item)
void ImHistoryBrowser::historyChanged(uint msgId, int type)
{
int count = ui.listWidget->count();
for (int i = 0; i < count; i++) {
QListWidgetItem *itemWidget = ui.listWidget->item(i);
if (itemWidget->data(ROLE_HIID).toString().toInt() == item.hiid) {
delete(ui.listWidget->takeItem(i));
break;
if (type == NOTIFY_TYPE_ADD) {
/* history message added */
HistoryMsg msg;
if (rsHistory->getMessage(msgId, msg) == false) {
return;
}
historyAdd(msg);
return;
}
if (type == NOTIFY_TYPE_DEL) {
/* history message removed */
int count = ui.listWidget->count();
for (int i = 0; i < count; i++) {
QListWidgetItem *itemWidget = ui.listWidget->item(i);
if (itemWidget->data(ROLE_MSGID).toString().toUInt() == msgId) {
delete(ui.listWidget->takeItem(i));
break;
}
}
return;
}
if (type == NOTIFY_TYPE_MOD) {
/* clear history */
ui.listWidget->clear();
return;
}
}
void ImHistoryBrowser::historyClear()
{
ui.listWidget->clear();
}
void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, IMHistoryItem &item)
void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, HistoryMsg& msg)
{
unsigned int formatFlag = CHAT_FORMATMSG_EMBED_LINKS;
@ -250,49 +263,30 @@ void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, IMHistoryItem &item
formatFlag |= CHAT_FORMATMSG_EMBED_SMILEYS;
}
std::list<ChatInfo>::iterator offineChatIt;
for(offineChatIt = m_savedOfflineChat.begin(); offineChatIt != m_savedOfflineChat.end(); offineChatIt++) {
/* are they public? */
if ((offineChatIt->chatflags & RS_CHAT_PRIVATE) == 0) {
/* this should not happen */
continue;
}
QDateTime sendTime = QDateTime::fromTime_t(offineChatIt->sendTime);
QString message = QString::fromStdWString(offineChatIt->msg);
if (IMHistoryKeeper::compareItem(item, false, offineChatIt->rsid, sendTime, message)) {
break;
}
}
ChatStyle::enumFormatMessage type;
if (offineChatIt == m_savedOfflineChat.end()) {
if (item.incoming) {
type = ChatStyle::FORMATMSG_INCOMING;
} else {
type = ChatStyle::FORMATMSG_OUTGOING;
}
if (msg.incoming) {
type = ChatStyle::FORMATMSG_INCOMING;
} else {
type = ChatStyle::FORMATMSG_OOUTGOING;
type = ChatStyle::FORMATMSG_OUTGOING;
}
QString formatMsg = style.formatMessage(type, item.name, item.sendTime, item.messageText, formatFlag);
QString messageText = QString::fromUtf8(msg.message.c_str());
QString formatMsg = style.formatMessage(type, QString::fromUtf8(msg.peerName.c_str()), QDateTime::fromTime_t(msg.sendTime), messageText, formatFlag);
itemWidget->setData(Qt::DisplayRole, qVariantFromValue(IMHistoryItemPainter(formatMsg)));
itemWidget->setData(ROLE_HIID, item.hiid);
itemWidget->setData(ROLE_MSGID, msg.msgId);
itemWidget->setData(ROLE_OFFLINE, (type == ChatStyle::FORMATMSG_OOUTGOING) ? true : false);
/* calculate plain text */
QTextDocument doc;
doc.setHtml(item.messageText);
doc.setHtml(messageText);
itemWidget->setData(ROLE_PLAINTEXT, doc.toPlainText());
}
QListWidgetItem *ImHistoryBrowser::createItem(IMHistoryItem &item)
QListWidgetItem *ImHistoryBrowser::createItem(HistoryMsg& msg)
{
QListWidgetItem *itemWidget = new QListWidgetItem;
fillItem(itemWidget, item);
fillItem(itemWidget, msg);
return itemWidget;
}
@ -346,7 +340,7 @@ void ImHistoryBrowser::filterItems(QListWidgetItem *item)
}
}
void ImHistoryBrowser::getSelectedItems(QList<int> &items)
void ImHistoryBrowser::getSelectedItems(std::list<uint32_t> &items)
{
QList<QListWidgetItem*> itemWidgets = ui.listWidget->selectedItems();
@ -356,16 +350,16 @@ void ImHistoryBrowser::getSelectedItems(QList<int> &items)
if (item->isHidden()) {
continue;
}
items.append(item->data(ROLE_HIID).toString().toInt());
items.push_back(item->data(ROLE_MSGID).toString().toInt());
}
}
void ImHistoryBrowser::itemSelectionChanged()
{
QList<int> hiids;
getSelectedItems(hiids);
std::list<uint32_t> msgIds;
getSelectedItems(msgIds);
if (hiids.size()) {
if (msgIds.size()) {
// activate buttons
ui.copyButton->setEnabled(true);
ui.removeButton->setEnabled(true);
@ -378,8 +372,8 @@ void ImHistoryBrowser::itemSelectionChanged()
void ImHistoryBrowser::customContextMenuRequested(QPoint /*pos*/)
{
QList<int> hiids;
getSelectedItems(hiids);
std::list<uint32_t> msgIds;
getSelectedItems(msgIds);
QListWidgetItem *currentItem = ui.listWidget->currentItem();
@ -400,7 +394,7 @@ void ImHistoryBrowser::customContextMenuRequested(QPoint /*pos*/)
}
}
if (hiids.size()) {
if (msgIds.size()) {
connect(selectAll, SIGNAL(triggered()), ui.listWidget, SLOT(selectAll()));
connect(copyMessage, SIGNAL(triggered()), this, SLOT(copyMessage()));
connect(removeMessages, SIGNAL(triggered()), this, SLOT(removeMessages()));
@ -429,11 +423,11 @@ void ImHistoryBrowser::copyMessage()
{
QListWidgetItem *currentItem = ui.listWidget->currentItem();
if (currentItem) {
int hiid = currentItem->data(ROLE_HIID).toString().toInt();
IMHistoryItem item;
if (historyKeeper.getMessage(hiid, item)) {
uint32_t msgId = currentItem->data(ROLE_MSGID).toString().toInt();
HistoryMsg msg;
if (rsHistory->getMessage(msgId, msg)) {
QTextDocument doc;
doc.setHtml(item.messageText);
doc.setHtml(QString::fromUtf8(msg.message.c_str()));
QApplication::clipboard()->setText(doc.toPlainText());
}
}
@ -441,15 +435,15 @@ void ImHistoryBrowser::copyMessage()
void ImHistoryBrowser::removeMessages()
{
QList<int> hiids;
getSelectedItems(hiids);
std::list<uint32_t> msgIds;
getSelectedItems(msgIds);
historyKeeper.removeMessages(hiids);
rsHistory->removeMessages(msgIds);
}
void ImHistoryBrowser::clearHistory()
{
historyKeeper.clear();
rsHistory->clear(m_peerId);
}
void ImHistoryBrowser::sendMessage()
@ -457,11 +451,11 @@ void ImHistoryBrowser::sendMessage()
if (textEdit) {
QListWidgetItem *currentItem = ui.listWidget->currentItem();
if (currentItem) {
int hiid = currentItem->data(ROLE_HIID).toString().toInt();
IMHistoryItem item;
if (historyKeeper.getMessage(hiid, item)) {
uint32_t msgId = currentItem->data(ROLE_MSGID).toString().toInt();
HistoryMsg msg;
if (rsHistory->getMessage(msgId, msg)) {
textEdit->clear();
textEdit->setText(item.messageText);
textEdit->setText(QString::fromUtf8(msg.message.c_str()));
textEdit->setFocus();
QTextCursor cursor = textEdit->textCursor();
cursor.movePosition(QTextCursor::End);
@ -471,45 +465,3 @@ void ImHistoryBrowser::sendMessage()
}
}
}
void ImHistoryBrowser::privateChatChanged(int list, int type)
{
if (m_isPrivateChat == false) {
return;
}
if (list == NOTIFY_LIST_PRIVATE_OUTGOING_CHAT) {
switch (type) {
case NOTIFY_TYPE_ADD:
{
m_savedOfflineChat.clear();
rsMsgs->getPrivateChatQueueCount(false) && rsMsgs->getPrivateChatQueue(false, m_peerId, m_savedOfflineChat);
}
break;
case NOTIFY_TYPE_DEL:
{
m_savedOfflineChat.clear();
}
break;
}
// recalculate items in history
int count = ui.listWidget->count();
for (int i = 0; i < count; i++) {
QListWidgetItem *itemWidget = ui.listWidget->item(i);
if (itemWidget->data(ROLE_OFFLINE).toBool()) {
int hiid = itemWidget->data(ROLE_HIID).toInt();
IMHistoryItem item;
if (historyKeeper.getMessage(hiid, item) == false) {
continue;
}
fillItem(itemWidget, item);
}
}
filterRegExpChanged();
}
}

View File

@ -27,13 +27,13 @@
#include <QThread>
#include <retroshare/rsmsgs.h>
#include "IMHistoryKeeper.h"
#include "gui/chat/ChatStyle.h"
#include "ui_ImHistoryBrowser.h"
class QTextEdit;
class ImHistoryBrowserCreateItemsThread;
class HistoryMsg;
class ImHistoryBrowser : public QDialog
{
@ -43,7 +43,7 @@ class ImHistoryBrowser : public QDialog
public:
/** Default constructor */
ImHistoryBrowser(const std::string &peerId, IMHistoryKeeper &histKeeper, QTextEdit *edit, QWidget *parent = 0, Qt::WFlags flags = 0);
ImHistoryBrowser(const std::string &peerId, QTextEdit *edit, QWidget *parent = 0, Qt::WFlags flags = 0);
/** Default destructor */
virtual ~ImHistoryBrowser();
@ -54,9 +54,7 @@ private slots:
void createThreadFinished();
void createThreadProgress(int current, int count);
void historyAdd(IMHistoryItem item);
void historyRemove(IMHistoryItem item);
void historyClear();
void historyChanged(uint msgId, int type);
void filterRegExpChanged();
void clearFilter();
@ -69,14 +67,15 @@ private slots:
void clearHistory();
void sendMessage();
void privateChatChanged(int list, int type);
private:
QListWidgetItem *createItem(IMHistoryItem &item);
void fillItem(QListWidgetItem *itemWidget, IMHistoryItem &item);
void historyAdd(HistoryMsg& msg);
QListWidgetItem *createItem(HistoryMsg& msg);
void fillItem(QListWidgetItem *itemWidget, HistoryMsg& msg);
void filterItems(QListWidgetItem *item = NULL);
void getSelectedItems(QList<int> &items);
void getSelectedItems(std::list<uint32_t> &items);
ImHistoryBrowserCreateItemsThread *m_createThread;
@ -84,11 +83,9 @@ private:
bool m_isPrivateChat;
QTextEdit *textEdit;
bool embedSmileys;
IMHistoryKeeper &historyKeeper;
ChatStyle style;
std::list<ChatInfo> m_savedOfflineChat;
QList<IMHistoryItem> m_itemsAddedOnLoad;
QList<HistoryMsg> itemsAddedOnLoad;
/** Qt Designer generated object */
Ui::ImHistoryBrowser ui;
@ -99,7 +96,7 @@ class ImHistoryBrowserCreateItemsThread : public QThread
Q_OBJECT
public:
ImHistoryBrowserCreateItemsThread(ImHistoryBrowser *parent, IMHistoryKeeper &histKeeper);
ImHistoryBrowserCreateItemsThread(ImHistoryBrowser *parent, const std::string& peerId);
~ImHistoryBrowserCreateItemsThread();
void run();
@ -113,8 +110,8 @@ public:
QList<QListWidgetItem*> m_items;
private:
IMHistoryKeeper &m_historyKeeper;
ImHistoryBrowser *m_historyBrowser;
std::string m_peerId;
volatile bool stopped;
};

View File

@ -56,6 +56,7 @@
#include "TagsMenu.h"
#include "gui/common/TagDefs.h"
#include "gui/connect/ConfCertDialog.h"
#include "gui/chat/HandleRichText.h"
#define IMAGE_GROUP16 ":/images/user/group16.png"
#define IMAGE_FRIENDINFO ":/images/peerdetails_16x16.png"
@ -1164,12 +1165,9 @@ bool MessageComposer::sendMessage_internal(bool bDraftbox)
mi.title = misc::removeNewLine(ui.titleEdit->text()).toStdWString();
mi.msg = ui.msgText->toHtml().toStdWString();
if(ui.msgText->toHtml() == QTextDocument(ui.msgText->toPlainText()).toHtml())
{
mi.msg = ui.msgText->toPlainText().toStdWString() ;
std::cerr << "Optimized forum message to " << mi.msg.length() << " bytes , instead of " << ui.msgText->toHtml().length() << std::endl;
}
QString text;
RsHtml::optimizeHtml(ui.msgText, text);
mi.msg = text.toStdWString() ;
/* check for existing title */
if (bDraftbox == false && mi.title.empty()) {

View File

@ -277,11 +277,10 @@ void NotifyQt::notifyHashingInfo(uint32_t type, const std::string& fileinfo)
emit hashingInfoChanged(info);
}
//void NotifyQt::notifyChat()
//{
// std::cerr << "Received chat notification" << std::endl ;
// return;
//}
void NotifyQt::notifyHistoryChanged(uint32_t msgId, int type)
{
emit historyChanged(msgId, type);
}
void NotifyQt::notifyListChange(int list, int type)
{

View File

@ -48,6 +48,7 @@ class NotifyQt: public QObject, public NotifyBase
/* one or more peers has changed the states */
virtual void notifyPeerStatusChangedSummary();
virtual void notifyChannelMsgReadSatusChanged(const std::string& channelId, const std::string& msgId, uint32_t status);
virtual void notifyHistoryChanged(uint32_t msgId, int type);
virtual void notifyDiscInfoChanged() ;
virtual void notifyDownloadComplete(const std::string& fileHash);
@ -90,6 +91,7 @@ class NotifyQt: public QObject, public NotifyBase
void downloadComplete(const QString& /* fileHash */);
void downloadCompleteCountChanged(int /* count */);
void channelMsgReadSatusChanged(const QString& channelId, const QString& msgId, int status);
void historyChanged(uint msgId, int type);
/* Notify from GUI */
void chatStyleChanged(int /*ChatStyle::enumStyleType*/ styleType);

View File

@ -27,6 +27,8 @@
#include "gui/notifyqt.h"
#include "rsharesettings.h"
#include <retroshare/rshistory.h>
#define VARIANT_STANDARD "Standard"
static QString loadStyleInfo(ChatStyle::enumStyleType type, QListWidget *listWidget, QComboBox *comboBox, QString &styleVariant)
@ -96,19 +98,22 @@ bool
ChatPage::save(QString &/*errmsg*/)
{
Settings->beginGroup(QString("Chat"));
Settings->setValue(QString::fromUtf8("Emoteicons_PrivatChat"), ui.checkBox_emoteprivchat->isChecked());
Settings->setValue(QString::fromUtf8("Emoteicons_GroupChat"), ui.checkBox_emotegroupchat->isChecked());
Settings->setValue(QString::fromUtf8("GroupChat_History"), ui.checkBox_groupchathistory->isChecked());
Settings->setValue(QString::fromUtf8("PrivateChat_History"), ui.checkBox_privatechathistory->isChecked());
Settings->endGroup();
Settings->setChatScreenFont(fontTempChat.toString());
Settings->setChatSendMessageWithCtrlReturn(ui.sendMessageWithCtrlReturn->isChecked());
Settings->setPublicChatHistoryCount(ui.groupchatspinBox->value());
Settings->setPrivateChatHistoryCount(ui.privatchatspinBox->value());
Settings->setPublicChatHistoryCount(ui.publicChatLoadCount->value());
Settings->setPrivateChatHistoryCount(ui.privateChatLoadCount->value());
rsHistory->setEnable(true, ui.publicChatEnable->isChecked());
rsHistory->setEnable(false, ui.privateChatEnable->isChecked());
rsHistory->setSaveCount(true, ui.publicChatSaveCount->value());
rsHistory->setSaveCount(false, ui.privateChatSaveCount->value());
ChatStyleInfo info;
QListWidgetItem *item = ui.publicList->currentItem();
@ -146,20 +151,22 @@ void
ChatPage::load()
{
Settings->beginGroup(QString("Chat"));
ui.checkBox_emoteprivchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_PrivatChat"), true).toBool());
ui.checkBox_emotegroupchat->setChecked(Settings->value(QString::fromUtf8("Emoteicons_GroupChat"), true).toBool());
ui.checkBox_groupchathistory->setChecked(Settings->value(QString::fromUtf8("GroupChat_History"), true).toBool());
ui.checkBox_privatechathistory->setChecked(Settings->value(QString::fromUtf8("PrivateChat_History"), true).toBool());
Settings->endGroup();
fontTempChat.fromString(Settings->getChatScreenFont());
ui.sendMessageWithCtrlReturn->setChecked(Settings->getChatSendMessageWithCtrlReturn());
ui.groupchatspinBox->setValue(Settings->getPublicChatHistoryCount());
ui.privatchatspinBox->setValue(Settings->getPrivateChatHistoryCount());
ui.publicChatLoadCount->setValue(Settings->getPublicChatHistoryCount());
ui.privateChatLoadCount->setValue(Settings->getPrivateChatHistoryCount());
ui.publicChatEnable->setChecked(rsHistory->getEnable(true));
ui.privateChatEnable->setChecked(rsHistory->getEnable(false));
ui.publicChatSaveCount->setValue(rsHistory->getSaveCount(true));
ui.privateChatSaveCount->setValue(rsHistory->getSaveCount(false));
ui.labelChatFontPreview->setText(fontTempChat.rawName());
ui.labelChatFontPreview->setFont(fontTempChat);

View File

@ -532,7 +532,24 @@
</property>
</widget>
</item>
<item row="0" column="1" rowspan="6">
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_emotegroupchat">
<property name="text">
<string>Enable Emoticons Group Chat</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="sendMessageWithCtrlReturn">
<property name="text">
<string>Send message with Ctrl+Return</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="4">
<widget class="QGroupBox" name="groupBoxIRCColors">
<property name="maximumSize">
<size>
@ -605,110 +622,161 @@
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="history">
<attribute name="title">
<string>History</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="publicChat">
<property name="title">
<string>Group Chat</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QCheckBox" name="publicChatEnable">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_emotegroupchat">
<property name="text">
<string>Enable Emoticons Group Chat</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_privatechathistory">
<property name="text">
<string>Enable Private Chat History</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox_groupchathistory">
<property name="text">
<string>Enable Group Chat History</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="sendMessageWithCtrlReturn">
<property name="text">
<string>Send message with Ctrl+Return</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Chat History</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Load number of messages (0 = off)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Group Chat</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="groupchatspinBox">
<property name="suffix">
<string/>
</property>
<property name="prefix">
<string/>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Private Chat</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="privatchatspinBox">
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>176</width>
<height>480</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label1">
<property name="text">
<string>Number of saved messages (0 = unlimited)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="publicChatSaveCount">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="suffix">
<string/>
</property>
<property name="prefix">
<string/>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="publicChatLoadCount">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label2">
<property name="text">
<string>Load number of messages (0 = off)</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="privateChat">
<property name="title">
<string>Private Chat</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QCheckBox" name="privateChatEnable">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QLabel" name="label3">
<property name="text">
<string>Number of saved messages (0 = unlimited)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="privateChatSaveCount">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="suffix">
<string/>
</property>
<property name="prefix">
<string/>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="privateChatLoadCount">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label4">
<property name="text">
<string>Load number of messages (0 = off)</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>176</width>
<height>480</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="style">

View File

@ -1131,7 +1131,7 @@ p, li { white-space: pre-wrap; }
<translation>Emoticons für privaten Chat</translation>
</message>
<message>
<location line="+19"/>
<location line="+36"/>
<source>Chat Font</source>
<translation>Chat Schriftart</translation>
</message>
@ -1146,32 +1146,38 @@ p, li { white-space: pre-wrap; }
<translation>Chat Schriftart:</translation>
</message>
<message>
<location line="+30"/>
<location line="-60"/>
<source>Enable Emoticons Group Chat</source>
<translation>Emoticons für Gruppenchat</translation>
</message>
<message>
<location line="+34"/>
<source>Chat History</source>
<translation>Chat History</translation>
<translation type="obsolete">Chat History</translation>
</message>
<message>
<location line="+6"/>
<location line="+154"/>
<location line="+66"/>
<source>Load number of messages (0 = off)</source>
<translation>Lade Anzahl von Nachrichten (0 = aus)</translation>
</message>
<message>
<location line="+9"/>
<location line="-120"/>
<source>Group Chat</source>
<translation>Gruppenchat</translation>
</message>
<message>
<location line="+20"/>
<location line="+15"/>
<location line="+66"/>
<source>Number of saved messages (0 = unlimited)</source>
<translation>Anzahl der gespeicherten Nachrichten (0 = unbegrenzt)</translation>
</message>
<message>
<location line="-15"/>
<source>Private Chat</source>
<translation>Privater Chat</translation>
</message>
<message>
<location line="+49"/>
<location line="+93"/>
<source>Group chat</source>
<translation>Gruppenchat</translation>
</message>
@ -1181,27 +1187,31 @@ p, li { white-space: pre-wrap; }
<translation>Privater Chat</translation>
</message>
<message>
<location line="-354"/>
<location line="-422"/>
<source>General</source>
<translation>Allgemein</translation>
</message>
<message>
<location line="+118"/>
<source>Enable Group Chat History</source>
<translation>Chat Verlauf für Gruppenchat</translation>
<translation type="obsolete">Chat Verlauf für Gruppenchat</translation>
</message>
<message>
<location line="+10"/>
<location line="+38"/>
<source>Send message with Ctrl+Return</source>
<translation>Sende Nachricht mit Strg+Enter</translation>
</message>
<message>
<location line="-17"/>
<source>Enable Private Chat History</source>
<translation>Chat Verlauf für privaten Chat</translation>
<translation type="obsolete">Chat Verlauf für privaten Chat</translation>
</message>
<message>
<location line="+95"/>
<location line="+96"/>
<location line="+66"/>
<source>Enable</source>
<translation>Aktiviert</translation>
</message>
<message>
<location line="+74"/>
<source>Style</source>
<translation>Stil</translation>
</message>
@ -1227,12 +1237,13 @@ p, li { white-space: pre-wrap; }
<translation>Beschreibung:</translation>
</message>
<message>
<location line="-93"/>
<location line="-528"/>
<location line="+435"/>
<source>History</source>
<translation>Verlauf</translation>
</message>
<message>
<location filename="../gui/settings/ChatPage.cpp" line="+197"/>
<location filename="../gui/settings/ChatPage.cpp" line="+204"/>
<source>Incoming message in history</source>
<translation>Eingehehende Nachricht aus dem Verlauf</translation>
</message>
@ -2166,7 +2177,7 @@ p, li { white-space: pre-wrap; }
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:26pt; color:#ffffff;&quot;&gt;Neuer Kanalbeitrag&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location line="+27"/>
<location line="+36"/>
<source>Channel Post</source>
<translation>Kanalbeitrag</translation>
</message>
@ -2236,7 +2247,27 @@ p, li { white-space: pre-wrap; }
<translation>Drag&apos;n&apos;Drop Dateien aus den Suchergebnissen</translation>
</message>
<message>
<location filename="../gui/channels/CreateChannelMsg.cpp" line="+162"/>
<location filename="../gui/channels/CreateChannelMsg.cpp" line="+88"/>
<source>Paste RetroShare Links</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
<source>Paste RetroShare Link</source>
<translation type="unfinished">RetroShare Link einfügen</translation>
</message>
<message>
<location line="+30"/>
<source>Channel security policy prevents you from posting files that you don&apos;t have. If you have these files, you need to share them before, or attach them explicitly:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+5"/>
<source>You can only post files that you do have</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+98"/>
<location line="+6"/>
<source>Drop file error.</source>
<translation>Dateifehler bei Drag&apos;n&apos;Drop.</translation>
@ -3862,7 +3893,7 @@ p, li { white-space: pre-wrap; }
<translation type="unfinished"></translation>
</message>
<message>
<location line="+857"/>
<location line="+872"/>
<location line="+81"/>
<source>RetroShare</source>
<translation></translation>
@ -3878,7 +3909,7 @@ p, li { white-space: pre-wrap; }
<translation>Du kannst einem anonymen Autor nicht antworten</translation>
</message>
<message>
<location line="-1257"/>
<location line="-1272"/>
<source>Your Forums</source>
<translation>Deine Foren</translation>
</message>
@ -4021,7 +4052,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../gui/ForumsDialog.cpp" line="+146"/>
<location line="+1032"/>
<location line="+1047"/>
<source>Start New Thread</source>
<translation>Erstelle neues Thema</translation>
</message>
@ -4049,7 +4080,7 @@ p, li { white-space: pre-wrap; }
<translation>Inhalt</translation>
</message>
<message>
<location filename="../gui/ForumsDialog.cpp" line="-1019"/>
<location filename="../gui/ForumsDialog.cpp" line="-1034"/>
<location line="+3"/>
<source>Mark as read</source>
<translation>Als gelesen markieren</translation>
@ -4070,7 +4101,7 @@ p, li { white-space: pre-wrap; }
<context>
<name>ForumsFillThread</name>
<message>
<location line="+1399"/>
<location line="+1419"/>
<location line="+114"/>
<source>Anonymous</source>
<translation>Anonym</translation>
@ -4184,7 +4215,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location line="+9"/>
<location filename="../gui/FriendsDialog.cpp" line="+451"/>
<location filename="../gui/FriendsDialog.cpp" line="+452"/>
<source>Add Friend</source>
<translation>Freund hinzufügen</translation>
</message>
@ -4455,7 +4486,7 @@ p, li { white-space: pre-wrap; }
<message>
<location line="+131"/>
<source>Do you want to remove this Friend?</source>
<translation>Willst du diesen Freund entfernen?</translation>
<translation>Möchtest du diesen Freund entfernen?</translation>
</message>
<message>
<location line="+84"/>
@ -4469,9 +4500,9 @@ p, li { white-space: pre-wrap; }
<translation>Neuer Gruppenchat</translation>
</message>
<message>
<location line="+229"/>
<location line="+230"/>
<source>Do you really want to physically delete the history?</source>
<translation>Willst Du wirklich den Nachrichtenverlauf physisch löschen?</translation>
<translation>Möchtest du wirklich den Nachrichtenverlauf physisch löschen?</translation>
</message>
<message>
<location line="+87"/>
@ -5710,7 +5741,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location line="+32"/>
<location filename="../gui/im_history/ImHistoryBrowser.cpp" line="+389"/>
<location filename="../gui/im_history/ImHistoryBrowser.cpp" line="+383"/>
<source>Copy</source>
<translation>Kopieren</translation>
</message>
@ -6116,7 +6147,7 @@ Die folgenden Wege sind möglich:</translation>
<message>
<location line="+859"/>
<source>Do you really want to exit RetroShare ?</source>
<translation>Willst Du RetroShare wirklich beenden?</translation>
<translation>Möchtest du RetroShare wirklich beenden?</translation>
</message>
<message>
<location line="+2"/>
@ -6161,7 +6192,7 @@ Bitte gib etwas Speicher frei und drücke OK.</translation>
<name>MessageComposer</name>
<message>
<location filename="../gui/msgs/MessageComposer.ui" line="+17"/>
<location filename="../gui/msgs/MessageComposer.cpp" line="+833"/>
<location filename="../gui/msgs/MessageComposer.cpp" line="+832"/>
<source>Compose</source>
<translation>Verfassen</translation>
</message>
@ -6314,7 +6345,7 @@ Bitte gib etwas Speicher frei und drücke OK.</translation>
<translation>Setzt Schriftart auf Codestil</translation>
</message>
<message>
<location filename="../gui/msgs/MessageComposer.cpp" line="+1094"/>
<location filename="../gui/msgs/MessageComposer.cpp" line="+1091"/>
<source>To</source>
<translation>An</translation>
</message>
@ -6399,7 +6430,7 @@ Bitte gib etwas Speicher frei und drücke OK.</translation>
<translation>Blockquote hinzufügen</translation>
</message>
<message>
<location filename="../gui/msgs/MessageComposer.cpp" line="-1183"/>
<location filename="../gui/msgs/MessageComposer.cpp" line="-1180"/>
<source>&amp;Left</source>
<translation>&amp;Links</translation>
</message>
@ -6420,12 +6451,12 @@ Bitte gib etwas Speicher frei und drücke OK.</translation>
</message>
<message>
<location line="+218"/>
<location line="+1660"/>
<location line="+1657"/>
<source>Save Message</source>
<translation>Nachricht speichern</translation>
</message>
<message>
<location line="-1659"/>
<location line="-1656"/>
<source>Message has not been Sent.
Do you want to save message to draft box?</source>
<translation>Nachricht wurde noch nicht gesendet.
@ -6473,7 +6504,7 @@ Möchtest Du die Nachricht in den Entwürfen speichern?</translation>
<translation>Fwd:</translation>
</message>
<message>
<location line="+82"/>
<location line="+79"/>
<location line="+119"/>
<source>RetroShare</source>
<translation></translation>
@ -6634,7 +6665,7 @@ Möchtest Du die Nachricht in den Entwürfen speichern?</translation>
<source>Message has not been Sent.
Do you want to save message ?</source>
<translation>Nachricht noch nicht versandt.
Willst Du die Nachricht speichern ?</translation>
Möchtest du die Nachricht speichern ?</translation>
</message>
<message>
<location line="+25"/>
@ -6647,7 +6678,7 @@ Willst Du die Nachricht speichern ?</translation>
<translation>Unterstützte Bilddateien (*.png *.jpeg *.jpg *.gif)</translation>
</message>
<message>
<location line="+119"/>
<location line="+111"/>
<source>Add Extra File</source>
<translation>Zusätzliche Datei hinzufügen</translation>
</message>
@ -6668,7 +6699,7 @@ Willst Du die Nachricht speichern ?</translation>
<translation>Datei nicht gefunden oder Dateiname nicht akzeptiert.</translation>
</message>
<message>
<location line="-2135"/>
<location line="-2124"/>
<source>Friend Recommendation(s)</source>
<translation>Freundempfehlung(en)</translation>
</message>
@ -8751,7 +8782,7 @@ p, li { white-space: pre-wrap; }
<context>
<name>PopupChatDialog</name>
<message>
<location filename="../gui/chat/PopupChatDialog.cpp" line="+740"/>
<location filename="../gui/chat/PopupChatDialog.cpp" line="+709"/>
<source>Hide Avatar</source>
<translation>Avatar verstecken</translation>
</message>
@ -8763,7 +8794,7 @@ p, li { white-space: pre-wrap; }
<message>
<location line="+88"/>
<source>Do you really want to physically delete the history?</source>
<translation>Willst Du wirklich den Nachrichtenverlauf physisch löschen?</translation>
<translation>Möchtest du wirklich den Nachrichtenverlauf physisch löschen?</translation>
</message>
<message>
<location line="+18"/>
@ -8891,10 +8922,10 @@ p, li { white-space: pre-wrap; }
<translation>Text Datei (*.txt );;Alle Dateien (*)</translation>
</message>
<message>
<location line="-659"/>
<location line="-647"/>
<source>Your Friend is offline
Do you want to send them a Message instead</source>
<translation>Dein Freund ist Offline willst du ihm stattdessen eine Nachricht senden</translation>
<translation>Dein Freund ist Offline. Möchtest du ihm stattdessen eine Nachricht senden</translation>
</message>
<message>
<location filename="../gui/chat/PopupChatDialog.ui" line="-445"/>
@ -8902,7 +8933,7 @@ Do you want to send them a Message instead</source>
<translation>Bild anhängen</translation>
</message>
<message>
<location filename="../gui/chat/PopupChatDialog.cpp" line="+698"/>
<location filename="../gui/chat/PopupChatDialog.cpp" line="+686"/>
<source>is Idle and may not reply</source>
<translation>antwortet möglicherweise nicht, da der Status auf &quot;Untätig&quot; gesetzt wurde</translation>
</message>
@ -8922,7 +8953,7 @@ Do you want to send them a Message instead</source>
<translation>ist Offline.</translation>
</message>
<message>
<location line="-664"/>
<location line="-652"/>
<source>Paste RetroShare Link</source>
<translation>RetroShare Link einfügen</translation>
</message>
@ -10729,7 +10760,7 @@ p, li { white-space: pre-wrap; }
<message>
<location line="+42"/>
<source>Do you want to remove this Friend?</source>
<translation>Willst du diesen Freund entfernen?</translation>
<translation>Möchtest du diesen Freund entfernen?</translation>
</message>
<message>
<location line="+76"/>