2017-04-03 21:04:44 +02:00
|
|
|
|
/*
|
|
|
|
|
* libresapi
|
|
|
|
|
* Copyright (C) 2015 electron128 <electron128@yahoo.com>
|
|
|
|
|
* Copyright (C) 2017 Gioacchino Mazzurco <gio@eigenlab.org>
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
|
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2015-04-29 11:57:56 +00:00
|
|
|
|
#include "ChatHandler.h"
|
2015-07-29 15:02:10 +02:00
|
|
|
|
#include "Pagination.h"
|
|
|
|
|
#include "Operators.h"
|
|
|
|
|
#include "GxsResponseTask.h"
|
|
|
|
|
|
|
|
|
|
#include <retroshare/rspeers.h>
|
|
|
|
|
#include <retroshare/rsidentity.h>
|
2017-03-25 18:33:35 +01:00
|
|
|
|
#include <retroshare/rshistory.h>
|
2015-07-29 15:02:10 +02:00
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
2016-04-09 18:32:16 +02:00
|
|
|
|
#include <limits>
|
|
|
|
|
#include <sstream>
|
2016-03-29 08:13:28 +02:00
|
|
|
|
#include <time.h>
|
2015-07-29 15:02:10 +02:00
|
|
|
|
|
|
|
|
|
namespace resource_api
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
std::string id(const ChatHandler::Msg& m)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << m.id;
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamBase& operator << (StreamBase& left, ChatHandler::Msg& m)
|
|
|
|
|
{
|
|
|
|
|
left << makeKeyValueReference("incoming", m.incoming)
|
|
|
|
|
<< makeKeyValueReference("was_send", m.was_send)
|
|
|
|
|
<< makeKeyValueReference("author_id", m.author_id)
|
|
|
|
|
<< makeKeyValueReference("author_name", m.author_name)
|
|
|
|
|
<< makeKeyValueReference("msg", m.msg)
|
|
|
|
|
<< makeKeyValueReference("recv_time", m.recv_time)
|
|
|
|
|
<< makeKeyValueReference("send_time", m.send_time)
|
|
|
|
|
<< makeKeyValueReference("id", m.id);
|
|
|
|
|
StreamBase& ls = left.getStreamToMember("links");
|
|
|
|
|
ls.getStreamToMember();
|
|
|
|
|
for(std::vector<ChatHandler::Triple>::iterator vit = m.links.begin(); vit != m.links.end(); ++vit)
|
|
|
|
|
{
|
|
|
|
|
ls.getStreamToMember() << makeKeyValueReference("first", vit->first)
|
|
|
|
|
<< makeKeyValueReference("second", vit->second)
|
|
|
|
|
<< makeKeyValueReference("third", vit->third);
|
|
|
|
|
}
|
|
|
|
|
return left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool compare_lobby_id(const ChatHandler::Lobby& l1, const ChatHandler::Lobby& l2)
|
|
|
|
|
{
|
2015-09-25 17:00:50 +02:00
|
|
|
|
if(l1.auto_subscribe && !l2.auto_subscribe) return true;
|
|
|
|
|
if(!l1.auto_subscribe && l2.auto_subscribe) return false;
|
|
|
|
|
if(l1.is_private && !l2.is_private) return true;
|
|
|
|
|
if(!l1.is_private && l2.is_private) return false;
|
|
|
|
|
if(l1.subscribed && !l2.subscribed) return true;
|
|
|
|
|
if(!l1.subscribed && l2.subscribed) return false;
|
2015-07-29 15:02:10 +02:00
|
|
|
|
return l1.id < l2.id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamBase& operator <<(StreamBase& left, KeyValueReference<ChatLobbyId> kv)
|
|
|
|
|
{
|
|
|
|
|
if(left.serialise())
|
|
|
|
|
{
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << kv.value;
|
|
|
|
|
left << makeKeyValue(kv.key, ss.str());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::string val;
|
|
|
|
|
left << makeKeyValueReference(kv.key, val);
|
|
|
|
|
std::stringstream ss(val);
|
|
|
|
|
ss >> kv.value;
|
|
|
|
|
}
|
|
|
|
|
return left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamBase& operator << (StreamBase& left, ChatHandler::Lobby& l)
|
|
|
|
|
{
|
2015-10-01 18:49:39 +02:00
|
|
|
|
ChatId chatId(l.id);
|
|
|
|
|
if (l.is_broadcast)
|
|
|
|
|
chatId = ChatId::makeBroadcastId();
|
2015-07-29 15:02:10 +02:00
|
|
|
|
left << makeKeyValueReference("id", l.id)
|
2015-10-01 18:49:39 +02:00
|
|
|
|
<< makeKeyValue("chat_id", chatId.toStdString())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
<< makeKeyValueReference("name",l.name)
|
|
|
|
|
<< makeKeyValueReference("topic", l.topic)
|
|
|
|
|
<< makeKeyValueReference("subscribed", l.subscribed)
|
|
|
|
|
<< makeKeyValueReference("auto_subscribe", l.auto_subscribe)
|
|
|
|
|
<< makeKeyValueReference("is_private", l.is_private)
|
2015-12-05 17:00:57 +01:00
|
|
|
|
<< makeKeyValueReference("is_broadcast", l.is_broadcast)
|
|
|
|
|
<< makeKeyValueReference("gxs_id", l.gxs_id);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
return left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamBase& operator << (StreamBase& left, ChatHandler::ChatInfo& info)
|
|
|
|
|
{
|
|
|
|
|
left << makeKeyValueReference("remote_author_id", info.remote_author_id)
|
|
|
|
|
<< makeKeyValueReference("remote_author_name", info.remote_author_name)
|
|
|
|
|
<< makeKeyValueReference("is_broadcast", info.is_broadcast)
|
2015-11-30 00:02:44 -05:00
|
|
|
|
<< makeKeyValueReference("is_distant_chat_id", info.is_distant_chat_id)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
<< makeKeyValueReference("is_lobby", info.is_lobby)
|
|
|
|
|
<< makeKeyValueReference("is_peer", info.is_peer);
|
|
|
|
|
return left;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-07 14:09:33 +01:00
|
|
|
|
class SendLobbyParticipantsTask: public GxsResponseTask
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SendLobbyParticipantsTask(RsIdentity* idservice, ChatHandler::LobbyParticipantsInfo pi):
|
|
|
|
|
GxsResponseTask(idservice, 0), mParticipantsInfo(pi)
|
|
|
|
|
{
|
|
|
|
|
const std::map<RsGxsId, time_t>& map = mParticipantsInfo.participants;
|
|
|
|
|
for(std::map<RsGxsId, time_t>::const_iterator mit = map.begin(); mit != map.end(); ++mit)
|
|
|
|
|
{
|
|
|
|
|
requestGxsId(mit->first);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
ChatHandler::LobbyParticipantsInfo mParticipantsInfo;
|
|
|
|
|
protected:
|
2016-04-08 01:31:36 +02:00
|
|
|
|
virtual void gxsDoWork(Request &/*req*/, Response &resp)
|
2016-02-07 14:09:33 +01:00
|
|
|
|
{
|
|
|
|
|
resp.mDataStream.getStreamToMember();
|
|
|
|
|
const std::map<RsGxsId, time_t>& map = mParticipantsInfo.participants;
|
|
|
|
|
for(std::map<RsGxsId, time_t>::const_iterator mit = map.begin(); mit != map.end(); ++mit)
|
|
|
|
|
{
|
|
|
|
|
StreamBase& stream = resp.mDataStream.getStreamToMember();
|
|
|
|
|
double last_active = mit->second;
|
|
|
|
|
stream << makeKeyValueReference("last_active", last_active);
|
|
|
|
|
streamGxsId(mit->first, stream.getStreamToMember("identity"));
|
|
|
|
|
}
|
|
|
|
|
resp.mStateToken = mParticipantsInfo.state_token;
|
|
|
|
|
resp.setOk();
|
|
|
|
|
done();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-29 15:02:10 +02:00
|
|
|
|
ChatHandler::ChatHandler(StateTokenServer *sts, RsNotify *notify, RsMsgs *msgs, RsPeers* peers, RsIdentity* identity, UnreadMsgNotify* unread):
|
|
|
|
|
mStateTokenServer(sts), mNotify(notify), mRsMsgs(msgs), mRsPeers(peers), mRsIdentity(identity), mUnreadMsgNotify(unread), mMtx("ChatHandler::mMtx")
|
|
|
|
|
{
|
|
|
|
|
mNotify->registerNotifyClient(this);
|
|
|
|
|
mStateTokenServer->registerTickClient(this);
|
|
|
|
|
|
|
|
|
|
mMsgStateToken = mStateTokenServer->getNewToken();
|
|
|
|
|
mLobbiesStateToken = mStateTokenServer->getNewToken();
|
|
|
|
|
mUnreadMsgsStateToken = mStateTokenServer->getNewToken();
|
|
|
|
|
|
|
|
|
|
addResourceHandler("*", this, &ChatHandler::handleWildcard);
|
|
|
|
|
addResourceHandler("lobbies", this, &ChatHandler::handleLobbies);
|
2017-04-14 17:44:17 +02:00
|
|
|
|
addResourceHandler("create_lobby", this, &ChatHandler::handleCreateLobby);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
addResourceHandler("subscribe_lobby", this, &ChatHandler::handleSubscribeLobby);
|
|
|
|
|
addResourceHandler("unsubscribe_lobby", this, &ChatHandler::handleUnsubscribeLobby);
|
2017-03-29 16:06:39 +02:00
|
|
|
|
addResourceHandler("autosubscribe_lobby", this, &ChatHandler::handleAutoSubsribeLobby);
|
2016-04-08 01:31:36 +02:00
|
|
|
|
addResourceHandler("clear_lobby", this, &ChatHandler::handleClearLobby);
|
2016-02-07 14:09:33 +01:00
|
|
|
|
addResourceHandler("lobby_participants", this, &ChatHandler::handleLobbyParticipants);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
addResourceHandler("messages", this, &ChatHandler::handleMessages);
|
|
|
|
|
addResourceHandler("send_message", this, &ChatHandler::handleSendMessage);
|
|
|
|
|
addResourceHandler("mark_chat_as_read", this, &ChatHandler::handleMarkChatAsRead);
|
|
|
|
|
addResourceHandler("info", this, &ChatHandler::handleInfo);
|
2016-02-14 14:57:41 +01:00
|
|
|
|
addResourceHandler("receive_status", this, &ChatHandler::handleReceiveStatus);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
addResourceHandler("send_status", this, &ChatHandler::handleSendStatus);
|
|
|
|
|
addResourceHandler("unread_msgs", this, &ChatHandler::handleUnreadMsgs);
|
2016-12-07 20:09:14 +01:00
|
|
|
|
addResourceHandler("initiate_distant_chat", this, &ChatHandler::handleInitiateDistantChatConnexion);
|
|
|
|
|
addResourceHandler("distant_chat_status", this, &ChatHandler::handleDistantChatStatus);
|
|
|
|
|
addResourceHandler("close_distant_chat", this, &ChatHandler::handleCloseDistantChatConnexion);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ChatHandler::~ChatHandler()
|
|
|
|
|
{
|
|
|
|
|
mNotify->unregisterNotifyClient(this);
|
|
|
|
|
mStateTokenServer->unregisterTickClient(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::notifyChatMessage(const ChatMessage &msg)
|
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
mRawMsgs.push_back(msg);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 01:31:36 +02:00
|
|
|
|
void ChatHandler::notifyChatCleared(const ChatId &chat_id)
|
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
2016-05-17 16:50:59 +02:00
|
|
|
|
//Remove processed messages
|
2016-04-08 01:31:36 +02:00
|
|
|
|
std::list<Msg>& msgs = mMsgs[chat_id];
|
|
|
|
|
msgs.clear();
|
2016-05-17 16:50:59 +02:00
|
|
|
|
//Remove unprocessed messages
|
|
|
|
|
for(std::list<ChatMessage>::iterator lit = mRawMsgs.begin(); lit != mRawMsgs.end();)
|
|
|
|
|
{
|
|
|
|
|
ChatMessage& msg = *lit;
|
|
|
|
|
if (msg.chat_id == chat_id)
|
|
|
|
|
{
|
|
|
|
|
lit = mRawMsgs.erase(lit);
|
|
|
|
|
} else {
|
|
|
|
|
++lit;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-08 01:31:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-14 14:57:41 +01:00
|
|
|
|
void ChatHandler::notifyChatStatus(const ChatId &chat_id, const std::string &status)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
locked_storeTypingInfo(chat_id, status);
|
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
|
2016-02-14 14:57:41 +01:00
|
|
|
|
void ChatHandler::notifyChatLobbyEvent(uint64_t lobby_id, uint32_t event_type,
|
|
|
|
|
const RsGxsId &nickname, const std::string& any_string)
|
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
if(event_type == RS_CHAT_LOBBY_EVENT_PEER_STATUS)
|
|
|
|
|
{
|
|
|
|
|
locked_storeTypingInfo(ChatId(lobby_id), any_string, nickname);
|
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::tick()
|
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
|
|
|
|
|
// first fetch lobbies
|
|
|
|
|
std::vector<Lobby> lobbies;
|
|
|
|
|
std::list<ChatLobbyId> subscribed_ids;
|
|
|
|
|
mRsMsgs->getChatLobbyList(subscribed_ids);
|
|
|
|
|
for(std::list<ChatLobbyId>::iterator lit = subscribed_ids.begin(); lit != subscribed_ids.end(); ++lit)
|
|
|
|
|
{
|
|
|
|
|
ChatLobbyInfo info;
|
|
|
|
|
if(mRsMsgs->getChatLobbyInfo(*lit,info))
|
|
|
|
|
{
|
|
|
|
|
Lobby l;
|
|
|
|
|
l.id = *lit;
|
|
|
|
|
l.name = info.lobby_name;
|
|
|
|
|
l.topic = info.lobby_topic;
|
|
|
|
|
l.subscribed = true;
|
|
|
|
|
l.auto_subscribe = info.lobby_flags & RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE;
|
|
|
|
|
l.is_private = !(info.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC);
|
2015-10-01 18:49:39 +02:00
|
|
|
|
l.is_broadcast = false;
|
2015-12-05 17:00:57 +01:00
|
|
|
|
l.gxs_id = info.gxs_id;
|
2015-07-29 15:02:10 +02:00
|
|
|
|
lobbies.push_back(l);
|
2016-02-07 14:09:33 +01:00
|
|
|
|
|
|
|
|
|
// update the lobby participants list
|
|
|
|
|
// maybe it causes to much traffic to do this in every tick,
|
|
|
|
|
// because the client would get the whole list every time a message was received
|
|
|
|
|
// we could reduce the checking frequency
|
|
|
|
|
std::map<ChatLobbyId, LobbyParticipantsInfo>::iterator mit = mLobbyParticipantsInfos.find(*lit);
|
|
|
|
|
if(mit == mLobbyParticipantsInfos.end())
|
|
|
|
|
{
|
|
|
|
|
mLobbyParticipantsInfos[*lit].participants = info.gxs_ids;
|
|
|
|
|
mLobbyParticipantsInfos[*lit].state_token = mStateTokenServer->getNewToken();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LobbyParticipantsInfo& pi = mit->second;
|
|
|
|
|
if(!std::equal(pi.participants.begin(), pi.participants.end(), info.gxs_ids.begin()))
|
|
|
|
|
{
|
|
|
|
|
pi.participants = info.gxs_ids;
|
|
|
|
|
mStateTokenServer->replaceToken(pi.state_token);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remove participants info of old lobbies
|
|
|
|
|
std::vector<ChatLobbyId> participants_info_to_delete;
|
|
|
|
|
for(std::map<ChatLobbyId, LobbyParticipantsInfo>::iterator mit = mLobbyParticipantsInfos.begin();
|
|
|
|
|
mit != mLobbyParticipantsInfos.end(); ++mit)
|
|
|
|
|
{
|
|
|
|
|
if(std::find(subscribed_ids.begin(), subscribed_ids.end(), mit->first) == subscribed_ids.end())
|
|
|
|
|
{
|
|
|
|
|
participants_info_to_delete.push_back(mit->first);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-07 14:09:33 +01:00
|
|
|
|
for(std::vector<ChatLobbyId>::iterator vit = participants_info_to_delete.begin(); vit != participants_info_to_delete.end(); ++vit)
|
|
|
|
|
{
|
|
|
|
|
LobbyParticipantsInfo& pi = mLobbyParticipantsInfos[*vit];
|
|
|
|
|
mStateTokenServer->discardToken(pi.state_token);
|
|
|
|
|
mLobbyParticipantsInfos.erase(*vit);
|
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
|
2015-10-01 18:49:39 +02:00
|
|
|
|
{
|
|
|
|
|
Lobby l;
|
|
|
|
|
l.name = "BroadCast";
|
|
|
|
|
l.topic = "Retroshare broadcast chat: messages are sent to all connected friends.";
|
|
|
|
|
l.subscribed = true;
|
|
|
|
|
l.auto_subscribe = false;
|
|
|
|
|
l.is_private = false;
|
|
|
|
|
l.is_broadcast = true;
|
|
|
|
|
lobbies.push_back(l);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 15:02:10 +02:00
|
|
|
|
std::vector<VisibleChatLobbyRecord> unsubscribed_lobbies;
|
|
|
|
|
mRsMsgs->getListOfNearbyChatLobbies(unsubscribed_lobbies);
|
|
|
|
|
for(std::vector<VisibleChatLobbyRecord>::iterator vit = unsubscribed_lobbies.begin(); vit != unsubscribed_lobbies.end(); ++vit)
|
|
|
|
|
{
|
|
|
|
|
const VisibleChatLobbyRecord& info = *vit;
|
|
|
|
|
if(std::find(subscribed_ids.begin(), subscribed_ids.end(), info.lobby_id) == subscribed_ids.end())
|
|
|
|
|
{
|
|
|
|
|
Lobby l;
|
|
|
|
|
l.id = info.lobby_id;
|
|
|
|
|
l.name = info.lobby_name;
|
|
|
|
|
l.topic = info.lobby_topic;
|
|
|
|
|
l.subscribed = false;
|
|
|
|
|
l.auto_subscribe = info.lobby_flags & RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE;
|
|
|
|
|
l.is_private = !(info.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC);
|
2015-10-01 18:49:39 +02:00
|
|
|
|
l.is_broadcast = false;
|
2015-12-05 17:00:57 +01:00
|
|
|
|
l.gxs_id = RsGxsId();
|
2015-07-29 15:02:10 +02:00
|
|
|
|
lobbies.push_back(l);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// process new messages
|
|
|
|
|
bool changed = false;
|
|
|
|
|
bool lobby_unread_count_changed = false;
|
|
|
|
|
std::vector<std::list<ChatMessage>::iterator> done;
|
|
|
|
|
std::vector<RsPeerId> peers_changed;
|
|
|
|
|
|
|
|
|
|
bool gxs_id_failed = false; // to prevent asking for multiple failing gxs ids in one tick, to not flush the cache
|
|
|
|
|
|
|
|
|
|
for(std::list<ChatMessage>::iterator lit = mRawMsgs.begin(); lit != mRawMsgs.end(); ++lit)
|
|
|
|
|
{
|
|
|
|
|
ChatMessage& msg = *lit;
|
|
|
|
|
std::string author_id;
|
|
|
|
|
std::string author_name;
|
|
|
|
|
if(msg.chat_id.isBroadcast())
|
|
|
|
|
{
|
|
|
|
|
author_id = msg.broadcast_peer_id.toStdString();
|
|
|
|
|
author_name = mRsPeers->getPeerName(msg.broadcast_peer_id);
|
|
|
|
|
}
|
2015-11-30 00:02:44 -05:00
|
|
|
|
else if(msg.chat_id.isDistantChatId())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2015-11-30 00:02:44 -05:00
|
|
|
|
DistantChatPeerInfo dcpinfo ;
|
|
|
|
|
|
|
|
|
|
if(!rsMsgs->getDistantChatStatus(msg.chat_id.toDistantChatId(),dcpinfo))
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "(EE) cannot get info for distant chat peer " << msg.chat_id.toDistantChatId() << std::endl;
|
|
|
|
|
continue ;
|
|
|
|
|
}
|
2015-12-05 17:00:57 +01:00
|
|
|
|
|
2015-07-29 15:02:10 +02:00
|
|
|
|
RsIdentityDetails details;
|
2015-12-05 17:00:57 +01:00
|
|
|
|
if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.incoming? dcpinfo.to_id: dcpinfo.own_id, details))
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2015-12-05 17:00:57 +01:00
|
|
|
|
author_id = details.mId.toStdString();
|
2015-07-29 15:02:10 +02:00
|
|
|
|
author_name = details.mNickname;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gxs_id_failed = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(msg.chat_id.isLobbyId())
|
|
|
|
|
{
|
|
|
|
|
author_id = msg.lobby_peer_gxs_id.toStdString();
|
|
|
|
|
RsIdentityDetails details;
|
|
|
|
|
if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.lobby_peer_gxs_id, details))
|
|
|
|
|
{
|
|
|
|
|
author_name = details.mNickname;
|
|
|
|
|
lobby_unread_count_changed = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gxs_id_failed = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(msg.chat_id.isPeerId())
|
|
|
|
|
{
|
|
|
|
|
RsPeerId id;
|
|
|
|
|
if(msg.incoming)
|
|
|
|
|
id = msg.chat_id.toPeerId();
|
|
|
|
|
else
|
|
|
|
|
id = mRsPeers->getOwnId();
|
|
|
|
|
author_id = id.toStdString();
|
|
|
|
|
author_name = mRsPeers->getPeerName(id);
|
|
|
|
|
if(std::find(peers_changed.begin(), peers_changed.end(), msg.chat_id.toPeerId()) == peers_changed.end())
|
|
|
|
|
peers_changed.push_back(msg.chat_id.toPeerId());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Error in ChatHandler::tick(): unhandled chat_id=" << msg.chat_id.toStdString() << std::endl;
|
|
|
|
|
// remove from queue, so msgs with wrong ids to not pile up
|
|
|
|
|
done.push_back(lit);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(mChatInfo.find(msg.chat_id) == mChatInfo.end())
|
|
|
|
|
{
|
|
|
|
|
ChatInfo info;
|
|
|
|
|
info.is_broadcast = msg.chat_id.isBroadcast();
|
2015-11-30 00:02:44 -05:00
|
|
|
|
info.is_distant_chat_id = msg.chat_id.isDistantChatId();
|
2015-07-29 15:02:10 +02:00
|
|
|
|
info.is_lobby = msg.chat_id.isLobbyId();
|
|
|
|
|
info.is_peer = msg.chat_id.isPeerId();
|
|
|
|
|
if(msg.chat_id.isLobbyId())
|
|
|
|
|
{
|
|
|
|
|
for(std::vector<Lobby>::iterator vit = mLobbies.begin(); vit != mLobbies.end(); ++vit)
|
|
|
|
|
{
|
|
|
|
|
if(vit->id == msg.chat_id.toLobbyId())
|
|
|
|
|
info.remote_author_name = vit->name;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-30 00:02:44 -05:00
|
|
|
|
else if(msg.chat_id.isDistantChatId())
|
2017-06-07 21:37:03 +02:00
|
|
|
|
{
|
|
|
|
|
RsIdentityDetails details;
|
|
|
|
|
DistantChatPeerInfo dcpinfo;
|
|
|
|
|
|
|
|
|
|
if( !gxs_id_failed &&
|
|
|
|
|
rsMsgs->getDistantChatStatus(
|
|
|
|
|
msg.chat_id.toDistantChatId(), dcpinfo ) &&
|
|
|
|
|
mRsIdentity->getIdDetails(dcpinfo.to_id, details) )
|
|
|
|
|
{
|
|
|
|
|
info.remote_author_id = details.mId.toStdString();
|
|
|
|
|
info.remote_author_name = details.mNickname;
|
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gxs_id_failed = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(msg.chat_id.isPeerId())
|
|
|
|
|
{
|
|
|
|
|
info.remote_author_id = msg.chat_id.toPeerId().toStdString();
|
|
|
|
|
info.remote_author_name = mRsPeers->getPeerName(msg.chat_id.toPeerId());
|
|
|
|
|
}
|
|
|
|
|
mChatInfo[msg.chat_id] = info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Msg m;
|
|
|
|
|
m.read = !msg.incoming;
|
|
|
|
|
m.incoming = msg.incoming;
|
|
|
|
|
m.was_send = msg.online;
|
|
|
|
|
m.author_id = author_id;
|
|
|
|
|
m.author_name = author_name;
|
|
|
|
|
|
|
|
|
|
// remove html tags from chat message
|
|
|
|
|
// extract links form href
|
2015-09-09 11:53:01 +02:00
|
|
|
|
getPlainText(msg.msg, m.msg, m.links);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
m.recv_time = msg.recvTime;
|
|
|
|
|
m.send_time = msg.sendTime;
|
|
|
|
|
|
|
|
|
|
m.id = RSRandom::random_u32();
|
|
|
|
|
|
|
|
|
|
mMsgs[msg.chat_id].push_back(m);
|
|
|
|
|
done.push_back(lit);
|
|
|
|
|
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
for(std::vector<std::list<ChatMessage>::iterator>::iterator vit = done.begin(); vit != done.end(); ++vit)
|
|
|
|
|
mRawMsgs.erase(*vit);
|
|
|
|
|
|
|
|
|
|
// send changes
|
|
|
|
|
|
|
|
|
|
if(changed)
|
|
|
|
|
{
|
|
|
|
|
mStateTokenServer->replaceToken(mMsgStateToken);
|
|
|
|
|
mStateTokenServer->replaceToken(mUnreadMsgsStateToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(std::vector<RsPeerId>::iterator vit = peers_changed.begin(); vit != peers_changed.end(); ++vit)
|
|
|
|
|
{
|
|
|
|
|
const std::list<Msg>& msgs = mMsgs[ChatId(*vit)];
|
|
|
|
|
uint32_t count = 0;
|
|
|
|
|
for(std::list<Msg>::const_iterator lit = msgs.begin(); lit != msgs.end(); ++lit)
|
|
|
|
|
if(!lit->read)
|
|
|
|
|
count++;
|
|
|
|
|
if(mUnreadMsgNotify)
|
|
|
|
|
mUnreadMsgNotify->notifyUnreadMsgCountChanged(*vit, count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::sort(lobbies.begin(), lobbies.end(), &compare_lobby_id);
|
|
|
|
|
if(lobby_unread_count_changed || mLobbies != lobbies)
|
|
|
|
|
{
|
|
|
|
|
mStateTokenServer->replaceToken(mLobbiesStateToken);
|
|
|
|
|
mLobbies = lobbies;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-09 18:32:16 +02:00
|
|
|
|
static void writeUTF8 ( std::ostream & Out, unsigned int Ch )
|
|
|
|
|
/* writes Ch in UTF-8 encoding to Out. Note this version only deals
|
|
|
|
|
with characters up to 16 bits.
|
|
|
|
|
From: http://www.codecodex.com/wiki/Unescape_HTML_special_characters_from_a_String*/
|
|
|
|
|
{
|
|
|
|
|
if (Ch >= 0x800)
|
|
|
|
|
{
|
|
|
|
|
Out.put(0xE0 | ((Ch >> 12) & 0x0F));
|
|
|
|
|
Out.put(0x80 | ((Ch >> 6) & 0x3F));
|
|
|
|
|
Out.put(0x80 | ((Ch ) & 0x3F));
|
|
|
|
|
}
|
|
|
|
|
else if (Ch >= 0x80)
|
|
|
|
|
{
|
|
|
|
|
Out.put(0xC0 | ((Ch >> 6) & 0x1F));
|
|
|
|
|
Out.put(0x80 | ((Ch ) & 0x3F));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Out.put(Ch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned int stringToDecUInt ( std::string str)
|
|
|
|
|
{
|
|
|
|
|
unsigned int out = 0;
|
|
|
|
|
unsigned int max = std::numeric_limits<int>::max() / 10;
|
|
|
|
|
int lenght = str.length();
|
|
|
|
|
for (int curs = 0; curs < lenght; ++curs) {
|
|
|
|
|
char c = str[curs];
|
|
|
|
|
if ( (c >= '0')
|
|
|
|
|
&& (c <= '9')
|
|
|
|
|
&& (out < max)
|
|
|
|
|
) {
|
|
|
|
|
out *= 10;
|
|
|
|
|
out += (int)( c - '0');
|
|
|
|
|
} else return 0;
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-09 11:53:01 +02:00
|
|
|
|
void ChatHandler::getPlainText(const std::string& in, std::string &out, std::vector<Triple> &links)
|
|
|
|
|
{
|
2015-09-09 13:36:00 +02:00
|
|
|
|
if (in.size() == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (in[0] != '<' || in[in.size() - 1] != '>')
|
|
|
|
|
{
|
|
|
|
|
// It's a plain text message without HTML
|
|
|
|
|
out = in;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-09-09 11:53:01 +02:00
|
|
|
|
bool ignore = false;
|
|
|
|
|
|
|
|
|
|
bool keep_link = false;
|
|
|
|
|
std::string last_six_chars;
|
2015-09-09 13:36:00 +02:00
|
|
|
|
unsigned int tag_start_index = 0;
|
2015-09-09 11:53:01 +02:00
|
|
|
|
Triple current_link;
|
2016-04-09 18:32:16 +02:00
|
|
|
|
bool onEscapeChar = false;
|
|
|
|
|
unsigned int escapeCharIndexStart = -1;
|
|
|
|
|
|
2015-09-09 11:53:01 +02:00
|
|
|
|
for(unsigned int i = 0; i < in.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if(keep_link && in[i] == '"')
|
|
|
|
|
{
|
|
|
|
|
keep_link = false;
|
|
|
|
|
current_link.second = out.size();
|
|
|
|
|
}
|
|
|
|
|
if(last_six_chars == "href=\"")
|
|
|
|
|
{
|
|
|
|
|
keep_link = true;
|
|
|
|
|
current_link.first = out.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// "rising edge" sets mode to ignore
|
|
|
|
|
if(in[i] == '<')
|
|
|
|
|
{
|
2015-09-09 13:36:00 +02:00
|
|
|
|
tag_start_index = i;
|
2015-09-09 11:53:01 +02:00
|
|
|
|
ignore = true;
|
|
|
|
|
}
|
|
|
|
|
if(!ignore || keep_link)
|
|
|
|
|
out += in[i];
|
|
|
|
|
// "falling edge" resets mode to keep
|
2016-04-09 18:32:16 +02:00
|
|
|
|
if(in[i] == '>' && ignore) {
|
2015-09-09 13:36:00 +02:00
|
|
|
|
// leave ignore mode on, if it's a style tag
|
2016-04-09 18:32:16 +02:00
|
|
|
|
if (tag_start_index == 0 || tag_start_index + 6 > i || in.substr(tag_start_index, 6) != "<style") {
|
2015-09-09 13:36:00 +02:00
|
|
|
|
ignore = false;
|
2016-04-09 18:32:16 +02:00
|
|
|
|
tag_start_index = 0;
|
|
|
|
|
}
|
2015-09-09 13:36:00 +02:00
|
|
|
|
}
|
2015-09-09 11:53:01 +02:00
|
|
|
|
|
|
|
|
|
last_six_chars += in[i];
|
|
|
|
|
if(last_six_chars.size() > 6)
|
|
|
|
|
last_six_chars = last_six_chars.substr(1);
|
|
|
|
|
std::string a = "</a>";
|
|
|
|
|
if( current_link.first != -1
|
|
|
|
|
&& last_six_chars.size() >= a.size()
|
|
|
|
|
&& last_six_chars.substr(last_six_chars.size()-a.size()) == a)
|
|
|
|
|
{
|
|
|
|
|
// only allow these protocols
|
|
|
|
|
// we don't want for example javascript:alert(0)
|
|
|
|
|
std::string http = "http://";
|
|
|
|
|
std::string https = "https://";
|
|
|
|
|
std::string retroshare = "retroshare://";
|
|
|
|
|
if( out.substr(current_link.first, http.size()) == http
|
|
|
|
|
|| out.substr(current_link.first, https.size()) == https
|
|
|
|
|
|| out.substr(current_link.first, retroshare.size()) == retroshare)
|
|
|
|
|
{
|
|
|
|
|
current_link.third = out.size();
|
|
|
|
|
links.push_back(current_link);
|
|
|
|
|
}
|
|
|
|
|
current_link = Triple();
|
|
|
|
|
}
|
2016-04-09 18:32:16 +02:00
|
|
|
|
std::string br = "<br/>";
|
|
|
|
|
if(last_six_chars.size() >= br.size()
|
|
|
|
|
&& last_six_chars.substr(last_six_chars.size()-br.size()) == br)
|
|
|
|
|
{
|
|
|
|
|
out += "\n";
|
|
|
|
|
}
|
|
|
|
|
if (in[i] == '&') {
|
|
|
|
|
onEscapeChar = true;
|
|
|
|
|
escapeCharIndexStart = out.length();
|
|
|
|
|
}
|
|
|
|
|
if (ignore || keep_link) {
|
|
|
|
|
onEscapeChar = false;
|
|
|
|
|
escapeCharIndexStart = -1;
|
|
|
|
|
}
|
|
|
|
|
if ((in[i] == ';') && onEscapeChar) {
|
|
|
|
|
onEscapeChar = false;
|
|
|
|
|
bool escapeFound = true;
|
|
|
|
|
std::string escapeReplace = "";
|
|
|
|
|
//Keep only escape value to replace it
|
|
|
|
|
std::string escapeCharValue = out.substr(escapeCharIndexStart,
|
|
|
|
|
out.length() - escapeCharIndexStart - 1);
|
|
|
|
|
if (escapeCharValue[0] == '#') {
|
|
|
|
|
int escapedCharUTF8 = stringToDecUInt(escapeCharValue.substr(1));
|
|
|
|
|
std::ostringstream escapedSStream;
|
|
|
|
|
writeUTF8( escapedSStream, escapedCharUTF8);
|
|
|
|
|
escapeReplace = escapedSStream.str();
|
|
|
|
|
} else if (escapeCharValue == "euro") {
|
|
|
|
|
escapeReplace = "€";
|
|
|
|
|
} else if (escapeCharValue == "nbsp") {
|
|
|
|
|
escapeReplace = " ";
|
|
|
|
|
} else if (escapeCharValue == "quot") {
|
|
|
|
|
escapeReplace = "\"";
|
|
|
|
|
} else if (escapeCharValue == "amp") {
|
|
|
|
|
escapeReplace = "&";
|
|
|
|
|
} else if (escapeCharValue == "lt") {
|
|
|
|
|
escapeReplace = "<";
|
|
|
|
|
} else if (escapeCharValue == "gt") {
|
|
|
|
|
escapeReplace = ">";
|
|
|
|
|
} else if (escapeCharValue == "iexcl") {
|
|
|
|
|
escapeReplace = "¡";
|
|
|
|
|
} else if (escapeCharValue == "cent") {
|
|
|
|
|
escapeReplace = "¢";
|
|
|
|
|
} else if (escapeCharValue == "pound") {
|
|
|
|
|
escapeReplace = "£";
|
|
|
|
|
} else if (escapeCharValue == "curren") {
|
|
|
|
|
escapeReplace = "¤";
|
|
|
|
|
} else if (escapeCharValue == "yen") {
|
|
|
|
|
escapeReplace = "¥";
|
|
|
|
|
} else if (escapeCharValue == "brvbar") {
|
|
|
|
|
escapeReplace = "¦";
|
|
|
|
|
} else if (escapeCharValue == "sect") {
|
|
|
|
|
escapeReplace = "§";
|
|
|
|
|
} else if (escapeCharValue == "uml") {
|
|
|
|
|
escapeReplace = "¨";
|
|
|
|
|
} else if (escapeCharValue == "copy") {
|
|
|
|
|
escapeReplace = "©";
|
|
|
|
|
} else if (escapeCharValue == "ordf") {
|
|
|
|
|
escapeReplace = "ª";
|
|
|
|
|
} else if (escapeCharValue == "not") {
|
|
|
|
|
escapeReplace = "¬";
|
|
|
|
|
} else if (escapeCharValue == "shy") {
|
|
|
|
|
escapeReplace = " ";//?
|
|
|
|
|
} else if (escapeCharValue == "reg") {
|
|
|
|
|
escapeReplace = "®";
|
|
|
|
|
} else if (escapeCharValue == "macr") {
|
|
|
|
|
escapeReplace = "¯";
|
|
|
|
|
} else if (escapeCharValue == "deg") {
|
|
|
|
|
escapeReplace = "°";
|
|
|
|
|
} else if (escapeCharValue == "plusmn") {
|
|
|
|
|
escapeReplace = "±";
|
|
|
|
|
} else if (escapeCharValue == "sup2") {
|
|
|
|
|
escapeReplace = "²";
|
|
|
|
|
} else if (escapeCharValue == "sup3") {
|
|
|
|
|
escapeReplace = "³";
|
|
|
|
|
} else if (escapeCharValue == "acute") {
|
|
|
|
|
escapeReplace = "´";
|
|
|
|
|
} else if (escapeCharValue == "micro") {
|
|
|
|
|
escapeReplace = "µ";
|
|
|
|
|
} else if (escapeCharValue == "para") {
|
|
|
|
|
escapeReplace = "¶";
|
|
|
|
|
} else if (escapeCharValue == "middot") {
|
|
|
|
|
escapeReplace = "·";
|
|
|
|
|
} else if (escapeCharValue == "cedil") {
|
|
|
|
|
escapeReplace = "¸";
|
|
|
|
|
} else if (escapeCharValue == "sup1") {
|
|
|
|
|
escapeReplace = "¹";
|
|
|
|
|
} else if (escapeCharValue == "ordm") {
|
|
|
|
|
escapeReplace = "º";
|
|
|
|
|
} else if (escapeCharValue == "raquo") {
|
|
|
|
|
escapeReplace = "»";
|
|
|
|
|
} else if (escapeCharValue == "frac14") {
|
|
|
|
|
escapeReplace = "¼";
|
|
|
|
|
} else if (escapeCharValue == "frac12") {
|
|
|
|
|
escapeReplace = "½";
|
|
|
|
|
} else if (escapeCharValue == "frac34") {
|
|
|
|
|
escapeReplace = "¾";
|
|
|
|
|
} else if (escapeCharValue == "iquest") {
|
|
|
|
|
escapeReplace = "¿";
|
|
|
|
|
} else if (escapeCharValue == "Agrave") {
|
|
|
|
|
escapeReplace = "À";
|
|
|
|
|
} else if (escapeCharValue == "Aacute") {
|
|
|
|
|
escapeReplace = "Á";
|
|
|
|
|
} else if (escapeCharValue == "Acirc") {
|
|
|
|
|
escapeReplace = "Â";
|
|
|
|
|
} else if (escapeCharValue == "Atilde") {
|
|
|
|
|
escapeReplace = "Ã";
|
|
|
|
|
} else if (escapeCharValue == "Auml") {
|
|
|
|
|
escapeReplace = "Ä";
|
|
|
|
|
} else if (escapeCharValue == "Aring") {
|
|
|
|
|
escapeReplace = "Å";
|
|
|
|
|
} else if (escapeCharValue == "AElig") {
|
|
|
|
|
escapeReplace = "Æ";
|
|
|
|
|
} else if (escapeCharValue == "Ccedil") {
|
|
|
|
|
escapeReplace = "Ç";
|
|
|
|
|
} else if (escapeCharValue == "Egrave") {
|
|
|
|
|
escapeReplace = "È";
|
|
|
|
|
} else if (escapeCharValue == "Eacute") {
|
|
|
|
|
escapeReplace = "É";
|
|
|
|
|
} else if (escapeCharValue == "Ecirc") {
|
|
|
|
|
escapeReplace = "Ê";
|
|
|
|
|
} else if (escapeCharValue == "Euml") {
|
|
|
|
|
escapeReplace = "Ë";
|
|
|
|
|
} else if (escapeCharValue == "Igrave") {
|
|
|
|
|
escapeReplace = "Ì";
|
|
|
|
|
} else if (escapeCharValue == "Iacute") {
|
|
|
|
|
escapeReplace = "Í";
|
|
|
|
|
} else if (escapeCharValue == "Icirc") {
|
|
|
|
|
escapeReplace = "Î";
|
|
|
|
|
} else if (escapeCharValue == "Iuml") {
|
|
|
|
|
escapeReplace = "Ï";
|
|
|
|
|
} else if (escapeCharValue == "ETH") {
|
|
|
|
|
escapeReplace = "Ð";
|
|
|
|
|
} else if (escapeCharValue == "Ntilde") {
|
|
|
|
|
escapeReplace = "Ñ";
|
|
|
|
|
} else if (escapeCharValue == "Ograve") {
|
|
|
|
|
escapeReplace = "Ò";
|
|
|
|
|
} else if (escapeCharValue == "Oacute") {
|
|
|
|
|
escapeReplace = "Ó";
|
|
|
|
|
} else if (escapeCharValue == "Ocirc") {
|
|
|
|
|
escapeReplace = "Ô";
|
|
|
|
|
} else if (escapeCharValue == "Otilde") {
|
|
|
|
|
escapeReplace = "Õ";
|
|
|
|
|
} else if (escapeCharValue == "Ouml") {
|
|
|
|
|
escapeReplace = "Ö";
|
|
|
|
|
} else if (escapeCharValue == "times") {
|
|
|
|
|
escapeReplace = "×";
|
|
|
|
|
} else if (escapeCharValue == "Oslash") {
|
|
|
|
|
escapeReplace = "Ø";
|
|
|
|
|
} else if (escapeCharValue == "Ugrave") {
|
|
|
|
|
escapeReplace = "Ù";
|
|
|
|
|
} else if (escapeCharValue == "Uacute") {
|
|
|
|
|
escapeReplace = "Ú";
|
|
|
|
|
} else if (escapeCharValue == "Ucirc") {
|
|
|
|
|
escapeReplace = "Û";
|
|
|
|
|
} else if (escapeCharValue == "Uuml") {
|
|
|
|
|
escapeReplace = "Ü";
|
|
|
|
|
} else if (escapeCharValue == "Yacute") {
|
|
|
|
|
escapeReplace = "Ý";
|
|
|
|
|
} else if (escapeCharValue == "THORN") {
|
|
|
|
|
escapeReplace = "Þ";
|
|
|
|
|
} else if (escapeCharValue == "szlig") {
|
|
|
|
|
escapeReplace = "ß";
|
|
|
|
|
} else if (escapeCharValue == "agrave") {
|
|
|
|
|
escapeReplace = "à";
|
|
|
|
|
} else if (escapeCharValue == "aacute") {
|
|
|
|
|
escapeReplace = "á";
|
|
|
|
|
} else if (escapeCharValue == "acirc") {
|
|
|
|
|
escapeReplace = "â";
|
|
|
|
|
} else if (escapeCharValue == "atilde") {
|
|
|
|
|
escapeReplace = "ã";
|
|
|
|
|
} else if (escapeCharValue == "auml") {
|
|
|
|
|
escapeReplace = "ä";
|
|
|
|
|
} else if (escapeCharValue == "aring") {
|
|
|
|
|
escapeReplace = "å";
|
|
|
|
|
} else if (escapeCharValue == "aelig") {
|
|
|
|
|
escapeReplace = "æ";
|
|
|
|
|
} else if (escapeCharValue == "ccedil") {
|
|
|
|
|
escapeReplace = "ç";
|
|
|
|
|
} else if (escapeCharValue == "egrave") {
|
|
|
|
|
escapeReplace = "è";
|
|
|
|
|
} else if (escapeCharValue == "eacute") {
|
|
|
|
|
escapeReplace = "é";
|
|
|
|
|
} else if (escapeCharValue == "ecirc") {
|
|
|
|
|
escapeReplace = "ê";
|
|
|
|
|
} else if (escapeCharValue == "euml") {
|
|
|
|
|
escapeReplace = "ë";
|
|
|
|
|
} else if (escapeCharValue == "igrave") {
|
|
|
|
|
escapeReplace = "ì";
|
|
|
|
|
} else if (escapeCharValue == "iacute") {
|
|
|
|
|
escapeReplace = "í";
|
|
|
|
|
} else if (escapeCharValue == "icirc") {
|
|
|
|
|
escapeReplace = "î";
|
|
|
|
|
} else if (escapeCharValue == "iuml") {
|
|
|
|
|
escapeReplace = "ï";
|
|
|
|
|
} else if (escapeCharValue == "eth") {
|
|
|
|
|
escapeReplace = "ð";
|
|
|
|
|
} else if (escapeCharValue == "ntilde") {
|
|
|
|
|
escapeReplace = "ñ";
|
|
|
|
|
} else if (escapeCharValue == "ograve") {
|
|
|
|
|
escapeReplace = "ò";
|
|
|
|
|
} else if (escapeCharValue == "oacute") {
|
|
|
|
|
escapeReplace = "ó";
|
|
|
|
|
} else if (escapeCharValue == "ocirc") {
|
|
|
|
|
escapeReplace = "ô";
|
|
|
|
|
} else if (escapeCharValue == "otilde") {
|
|
|
|
|
escapeReplace = "õ";
|
|
|
|
|
} else if (escapeCharValue == "ouml") {
|
|
|
|
|
escapeReplace = "ö";
|
|
|
|
|
} else if (escapeCharValue == "divide") {
|
|
|
|
|
escapeReplace = "÷";
|
|
|
|
|
} else if (escapeCharValue == "oslash") {
|
|
|
|
|
escapeReplace = "ø";
|
|
|
|
|
} else if (escapeCharValue == "ugrave") {
|
|
|
|
|
escapeReplace = "ù";
|
|
|
|
|
} else if (escapeCharValue == "uacute") {
|
|
|
|
|
escapeReplace = "ú";
|
|
|
|
|
} else if (escapeCharValue == "ucirc") {
|
|
|
|
|
escapeReplace = "û";
|
|
|
|
|
} else if (escapeCharValue == "uuml") {
|
|
|
|
|
escapeReplace = "ü";
|
|
|
|
|
} else if (escapeCharValue == "yacute") {
|
|
|
|
|
escapeReplace = "ý";
|
|
|
|
|
} else if (escapeCharValue == "thorn") {
|
|
|
|
|
escapeReplace = "þ";
|
|
|
|
|
} else {
|
|
|
|
|
escapeFound = false;
|
|
|
|
|
}
|
|
|
|
|
if (escapeFound) {
|
|
|
|
|
out = out.substr(0, escapeCharIndexStart-1);
|
|
|
|
|
out += escapeReplace;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-09 11:53:01 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-14 14:57:41 +01:00
|
|
|
|
void ChatHandler::locked_storeTypingInfo(const ChatId &chat_id, std::string status, RsGxsId lobby_gxs_id)
|
|
|
|
|
{
|
|
|
|
|
TypingLabelInfo& info = mTypingLabelInfo[chat_id];
|
|
|
|
|
info.timestamp = time(0);
|
|
|
|
|
info.status = status;
|
|
|
|
|
mStateTokenServer->replaceToken(info.state_token);
|
|
|
|
|
info.author_id = lobby_gxs_id;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-02 19:10:54 +02:00
|
|
|
|
void ChatHandler::handleWildcard(Request &/*req*/, Response &resp)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
resp.mDataStream.getStreamToMember();
|
|
|
|
|
for(std::map<ChatId, std::list<Msg> >::iterator mit = mMsgs.begin(); mit != mMsgs.end(); ++mit)
|
|
|
|
|
{
|
|
|
|
|
resp.mDataStream.getStreamToMember() << makeValue(mit->first.toStdString());
|
|
|
|
|
}
|
|
|
|
|
resp.setOk();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::handleLobbies(Request &/*req*/, Response &resp)
|
|
|
|
|
{
|
|
|
|
|
tick();
|
|
|
|
|
|
2016-12-10 20:23:30 +01:00
|
|
|
|
{
|
2015-07-29 15:02:10 +02:00
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
resp.mDataStream.getStreamToMember();
|
|
|
|
|
for(std::vector<Lobby>::iterator vit = mLobbies.begin(); vit != mLobbies.end(); ++vit)
|
|
|
|
|
{
|
|
|
|
|
uint32_t unread_msgs = 0;
|
|
|
|
|
ChatId chat_id(vit->id);
|
|
|
|
|
std::map<ChatId, std::list<Msg> >::iterator mit = mMsgs.find(chat_id);
|
|
|
|
|
if(mit != mMsgs.end())
|
|
|
|
|
{
|
|
|
|
|
std::list<Msg>& msgs = mit->second;
|
|
|
|
|
for(std::list<Msg>::iterator lit = msgs.begin(); lit != msgs.end(); ++lit)
|
|
|
|
|
if(!lit->read)
|
|
|
|
|
unread_msgs++;
|
|
|
|
|
}
|
|
|
|
|
resp.mDataStream.getStreamToMember() << *vit << makeKeyValueReference("unread_msg_count", unread_msgs);
|
|
|
|
|
}
|
|
|
|
|
resp.mStateToken = mLobbiesStateToken;
|
2016-12-10 20:23:30 +01:00
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
resp.setOk();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::handleSubscribeLobby(Request &req, Response &resp)
|
|
|
|
|
{
|
|
|
|
|
ChatLobbyId id = 0;
|
|
|
|
|
RsGxsId gxs_id;
|
|
|
|
|
req.mStream << makeKeyValueReference("id", id) << makeKeyValueReference("gxs_id", gxs_id);
|
|
|
|
|
|
|
|
|
|
if(id == 0)
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("Error: id must not be null");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(gxs_id.isNull())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("Error: gxs_id must not be null");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(mRsMsgs->joinVisibleChatLobby(id, gxs_id))
|
|
|
|
|
resp.setOk();
|
|
|
|
|
else
|
|
|
|
|
resp.setFail("lobby join failed. (See console for more info)");
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-07 14:09:33 +01:00
|
|
|
|
void ChatHandler::handleUnsubscribeLobby(Request &req, Response &resp)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
|
|
|
|
ChatLobbyId id = 0;
|
|
|
|
|
req.mStream << makeKeyValueReference("id", id);
|
|
|
|
|
mRsMsgs->unsubscribeChatLobby(id);
|
2016-02-07 14:09:33 +01:00
|
|
|
|
resp.setOk();
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-29 16:06:39 +02:00
|
|
|
|
void ChatHandler::handleAutoSubsribeLobby(Request& req, Response& resp)
|
|
|
|
|
{
|
|
|
|
|
ChatLobbyId chatId = 0;
|
|
|
|
|
bool autosubsribe;
|
|
|
|
|
req.mStream << makeKeyValueReference("chatid", chatId) << makeKeyValueReference("autosubsribe", autosubsribe);
|
|
|
|
|
mRsMsgs->setLobbyAutoSubscribe(chatId, autosubsribe);
|
|
|
|
|
resp.setOk();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 01:31:36 +02:00
|
|
|
|
void ChatHandler::handleClearLobby(Request &req, Response &resp)
|
|
|
|
|
{
|
|
|
|
|
ChatLobbyId id = 0;
|
|
|
|
|
req.mStream << makeKeyValueReference("id", id);
|
2016-04-15 19:08:10 +02:00
|
|
|
|
if (id !=0) {
|
|
|
|
|
notifyChatCleared(ChatId(id));
|
|
|
|
|
} else {
|
|
|
|
|
//Is BroadCast
|
|
|
|
|
notifyChatCleared(ChatId("B"));
|
|
|
|
|
}
|
2016-04-08 01:31:36 +02:00
|
|
|
|
resp.setOk();
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-07 14:09:33 +01:00
|
|
|
|
ResponseTask* ChatHandler::handleLobbyParticipants(Request &req, Response &resp)
|
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
|
|
|
|
|
ChatId id(req.mPath.top());
|
|
|
|
|
if(!id.isLobbyId())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("Path element \""+req.mPath.top()+"\" is not a ChatLobbyId.");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
std::map<ChatLobbyId, LobbyParticipantsInfo>::const_iterator mit = mLobbyParticipantsInfos.find(id.toLobbyId());
|
|
|
|
|
if(mit == mLobbyParticipantsInfos.end())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("lobby not found");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return new SendLobbyParticipantsTask(mRsIdentity, mit->second);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::handleMessages(Request &req, Response &resp)
|
|
|
|
|
{
|
2016-12-10 20:23:30 +01:00
|
|
|
|
/* G10h4ck: Whithout this the request processing won't happen, copied from
|
2017-03-24 12:02:13 +01:00
|
|
|
|
* ChatHandler::handleLobbies, is this a work around or is the right way of
|
2016-12-10 20:23:30 +01:00
|
|
|
|
* doing it? */
|
|
|
|
|
tick();
|
|
|
|
|
|
|
|
|
|
{
|
2015-07-29 15:02:10 +02:00
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
2017-03-26 19:12:04 +02:00
|
|
|
|
ChatId id(req.mPath.top());
|
2017-03-25 18:33:35 +01:00
|
|
|
|
|
2015-07-29 15:02:10 +02:00
|
|
|
|
// make response a list
|
|
|
|
|
resp.mDataStream.getStreamToMember();
|
|
|
|
|
if(id.isNotSet())
|
|
|
|
|
{
|
2017-03-26 19:12:04 +02:00
|
|
|
|
resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id");
|
2017-03-25 18:33:35 +01:00
|
|
|
|
return;
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
std::map<ChatId, std::list<Msg> >::iterator mit = mMsgs.find(id);
|
2016-12-07 20:09:14 +01:00
|
|
|
|
if(mit == mMsgs.end())
|
|
|
|
|
{
|
|
|
|
|
/* set state token, even if not found yet, maybe later messages arrive
|
|
|
|
|
* and then the chat id will be found */
|
|
|
|
|
resp.mStateToken = mMsgStateToken;
|
|
|
|
|
resp.setFail("chat with id=\""+req.mPath.top()+"\" not found");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
resp.mStateToken = mMsgStateToken;
|
|
|
|
|
handlePaginationRequest(req, resp, mit->second);
|
2016-12-10 20:23:30 +01:00
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::handleSendMessage(Request &req, Response &resp)
|
|
|
|
|
{
|
|
|
|
|
std::string chat_id;
|
|
|
|
|
std::string msg;
|
|
|
|
|
req.mStream << makeKeyValueReference("chat_id", chat_id)
|
|
|
|
|
<< makeKeyValueReference("msg", msg);
|
|
|
|
|
ChatId id(chat_id);
|
|
|
|
|
if(id.isNotSet())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("chat_id is invalid");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(mRsMsgs->sendChat(id, msg))
|
|
|
|
|
resp.setOk();
|
|
|
|
|
else
|
|
|
|
|
resp.setFail("failed to send message");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::handleMarkChatAsRead(Request &req, Response &resp)
|
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
2017-03-26 19:12:04 +02:00
|
|
|
|
ChatId id(req.mPath.top());
|
2017-03-25 18:33:35 +01:00
|
|
|
|
|
2015-07-29 15:02:10 +02:00
|
|
|
|
if(id.isNotSet())
|
|
|
|
|
{
|
2017-03-26 19:12:04 +02:00
|
|
|
|
resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id");
|
2015-07-29 15:02:10 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::map<ChatId, std::list<Msg> >::iterator mit = mMsgs.find(id);
|
|
|
|
|
if(mit == mMsgs.end())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("chat not found. Maybe this chat does not have messages yet?");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::list<Msg>& msgs = mit->second;
|
|
|
|
|
for(std::list<Msg>::iterator lit = msgs.begin(); lit != msgs.end(); ++lit)
|
|
|
|
|
{
|
|
|
|
|
lit->read = true;
|
|
|
|
|
}
|
|
|
|
|
// lobby list contains unread msgs, so update it
|
|
|
|
|
if(id.isLobbyId())
|
|
|
|
|
mStateTokenServer->replaceToken(mLobbiesStateToken);
|
|
|
|
|
if(id.isPeerId() && mUnreadMsgNotify)
|
|
|
|
|
mUnreadMsgNotify->notifyUnreadMsgCountChanged(id.toPeerId(), 0);
|
|
|
|
|
|
|
|
|
|
mStateTokenServer->replaceToken(mUnreadMsgsStateToken);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-14 14:57:41 +01:00
|
|
|
|
void ChatHandler::handleInfo(Request &req, Response &resp)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
ChatId id(req.mPath.top());
|
|
|
|
|
if(id.isNotSet())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::map<ChatId, ChatInfo>::iterator mit = mChatInfo.find(id);
|
|
|
|
|
if(mit == mChatInfo.end())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("chat not found.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
resp.mDataStream << mit->second;
|
|
|
|
|
resp.setOk();
|
|
|
|
|
}
|
2015-07-29 15:02:10 +02:00
|
|
|
|
|
2016-02-14 14:57:41 +01:00
|
|
|
|
class SendTypingLabelInfo: public GxsResponseTask
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SendTypingLabelInfo(RsIdentity* identity, RsPeers* peers, ChatId id, const ChatHandler::TypingLabelInfo& info):
|
|
|
|
|
GxsResponseTask(identity), mState(BEGIN), mPeers(peers),mId(id), mInfo(info) {}
|
|
|
|
|
private:
|
|
|
|
|
enum State {BEGIN, WAITING_ID};
|
2015-07-29 15:02:10 +02:00
|
|
|
|
State mState;
|
2016-02-14 14:57:41 +01:00
|
|
|
|
RsPeers* mPeers;
|
|
|
|
|
ChatId mId;
|
|
|
|
|
ChatHandler::TypingLabelInfo mInfo;
|
|
|
|
|
protected:
|
|
|
|
|
void gxsDoWork(Request& /*req*/, Response& resp)
|
|
|
|
|
{
|
2015-07-29 15:02:10 +02:00
|
|
|
|
if(mState == BEGIN)
|
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
// lobby and distant require to fetch a gxs_id
|
|
|
|
|
if(mId.isLobbyId())
|
|
|
|
|
{
|
|
|
|
|
requestGxsId(mInfo.author_id);
|
|
|
|
|
}
|
|
|
|
|
else if(mId.isDistantChatId())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
DistantChatPeerInfo dcpinfo ;
|
|
|
|
|
rsMsgs->getDistantChatStatus(mId.toDistantChatId(), dcpinfo);
|
|
|
|
|
requestGxsId(dcpinfo.to_id);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
2016-02-14 14:57:41 +01:00
|
|
|
|
mState = WAITING_ID;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::string name = "BUG: case not handled in SendTypingLabelInfo";
|
|
|
|
|
if(mId.isPeerId())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
name = mPeers->getPeerName(mId.toPeerId());
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
2016-02-14 14:57:41 +01:00
|
|
|
|
else if(mId.isDistantChatId())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
DistantChatPeerInfo dcpinfo ;
|
|
|
|
|
rsMsgs->getDistantChatStatus(mId.toDistantChatId(), dcpinfo);
|
|
|
|
|
name = getName(dcpinfo.to_id);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
2016-02-14 14:57:41 +01:00
|
|
|
|
else if(mId.isLobbyId())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
name = getName(mInfo.author_id);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
2016-02-14 14:57:41 +01:00
|
|
|
|
else if(mId.isBroadcast())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
name = mPeers->getPeerName(mId.broadcast_status_peer_id);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
2016-02-14 14:57:41 +01:00
|
|
|
|
uint32_t ts = mInfo.timestamp;
|
|
|
|
|
resp.mDataStream << makeKeyValueReference("author_name", name)
|
|
|
|
|
<< makeKeyValueReference("timestamp", ts)
|
|
|
|
|
<< makeKeyValueReference("status_string", mInfo.status);
|
|
|
|
|
resp.mStateToken = mInfo.state_token;
|
2015-07-29 15:02:10 +02:00
|
|
|
|
resp.setOk();
|
|
|
|
|
done();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-02-14 14:57:41 +01:00
|
|
|
|
ResponseTask* ChatHandler::handleReceiveStatus(Request &req, Response &resp)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
ChatId id(req.mPath.top());
|
|
|
|
|
if(id.isNotSet())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id");
|
2016-02-14 14:57:41 +01:00
|
|
|
|
return 0;
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
2016-02-14 14:57:41 +01:00
|
|
|
|
std::map<ChatId, TypingLabelInfo>::iterator mit = mTypingLabelInfo.find(id);
|
|
|
|
|
if(mit == mTypingLabelInfo.end())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-14 14:57:41 +01:00
|
|
|
|
locked_storeTypingInfo(id, "");
|
|
|
|
|
mit = mTypingLabelInfo.find(id);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
2016-02-14 14:57:41 +01:00
|
|
|
|
return new SendTypingLabelInfo(mRsIdentity, mRsPeers, id, mit->second);
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-07 14:23:01 +01:00
|
|
|
|
void ChatHandler::handleSendStatus(Request &req, Response &resp)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
2016-02-07 14:23:01 +01:00
|
|
|
|
std::string chat_id;
|
|
|
|
|
std::string status;
|
|
|
|
|
req.mStream << makeKeyValueReference("chat_id", chat_id)
|
|
|
|
|
<< makeKeyValueReference("status", status);
|
|
|
|
|
ChatId id(chat_id);
|
|
|
|
|
if(id.isNotSet())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("chat_id is invalid");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
mRsMsgs->sendStatusString(id, status);
|
|
|
|
|
resp.setOk();
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-02 19:10:54 +02:00
|
|
|
|
void ChatHandler::handleUnreadMsgs(Request &/*req*/, Response &resp)
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
|
|
|
|
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
|
|
|
|
|
|
|
|
|
|
resp.mDataStream.getStreamToMember();
|
2017-03-24 12:02:13 +01:00
|
|
|
|
for( std::map<ChatId, std::list<Msg> >::const_iterator mit = mMsgs.begin();
|
|
|
|
|
mit != mMsgs.end(); ++mit )
|
2015-07-29 15:02:10 +02:00
|
|
|
|
{
|
|
|
|
|
uint32_t count = 0;
|
2017-04-03 21:04:44 +02:00
|
|
|
|
for( std::list<Msg>::const_iterator lit = mit->second.begin();
|
|
|
|
|
lit != mit->second.end(); ++lit ) if(!lit->read) ++count;
|
2015-07-29 15:02:10 +02:00
|
|
|
|
std::map<ChatId, ChatInfo>::iterator mit2 = mChatInfo.find(mit->first);
|
|
|
|
|
if(mit2 == mChatInfo.end())
|
|
|
|
|
std::cerr << "Error in ChatHandler::handleUnreadMsgs(): ChatInfo not found. It is weird if this happens. Normally it should not happen." << std::endl;
|
|
|
|
|
if(count && (mit2 != mChatInfo.end()))
|
|
|
|
|
{
|
|
|
|
|
resp.mDataStream.getStreamToMember()
|
2017-03-24 12:02:13 +01:00
|
|
|
|
#warning @deprecated using "id" as key can cause problems in some JS based \
|
|
|
|
|
languages like Qml @see chat_id instead
|
|
|
|
|
<< makeKeyValue("id", mit->first.toStdString())
|
|
|
|
|
<< makeKeyValue("chat_id", mit->first.toStdString())
|
2015-07-29 15:02:10 +02:00
|
|
|
|
<< makeKeyValueReference("unread_count", count)
|
|
|
|
|
<< mit2->second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
resp.mStateToken = mUnreadMsgsStateToken;
|
2017-04-03 21:04:44 +02:00
|
|
|
|
resp.setOk();
|
2015-07-29 15:02:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-07 20:09:14 +01:00
|
|
|
|
void ChatHandler::handleInitiateDistantChatConnexion(Request& req, Response& resp)
|
|
|
|
|
{
|
|
|
|
|
std::string own_gxs_hex, remote_gxs_hex;
|
|
|
|
|
|
|
|
|
|
req.mStream << makeKeyValueReference("own_gxs_hex", own_gxs_hex)
|
|
|
|
|
<< makeKeyValueReference("remote_gxs_hex", remote_gxs_hex);
|
|
|
|
|
|
|
|
|
|
RsGxsId sender_id(own_gxs_hex);
|
|
|
|
|
if(sender_id.isNull())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("own_gxs_hex is invalid");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RsGxsId receiver_id(remote_gxs_hex);
|
|
|
|
|
if(receiver_id.isNull())
|
|
|
|
|
{
|
|
|
|
|
resp.setFail("remote_gxs_hex is invalid");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DistantChatPeerId distant_chat_id;
|
|
|
|
|
uint32_t error_code;
|
|
|
|
|
|
2017-06-06 18:57:32 +02:00
|
|
|
|
if(mRsMsgs->initiateDistantChatConnexion( receiver_id, sender_id,
|
|
|
|
|
distant_chat_id, error_code,
|
|
|
|
|
false )) resp.setOk();
|
2016-12-07 20:09:14 +01:00
|
|
|
|
else resp.setFail("Failed to initiate distant chat");
|
|
|
|
|
|
|
|
|
|
ChatId chat_id(distant_chat_id);
|
|
|
|
|
resp.mDataStream << makeKeyValue("chat_id", chat_id.toStdString())
|
|
|
|
|
<< makeKeyValueReference("error_code", error_code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::handleDistantChatStatus(Request& req, Response& resp)
|
|
|
|
|
{
|
|
|
|
|
std::string distant_chat_hex;
|
|
|
|
|
req.mStream << makeKeyValueReference("chat_id", distant_chat_hex);
|
|
|
|
|
|
|
|
|
|
ChatId id(distant_chat_hex);
|
|
|
|
|
DistantChatPeerInfo info;
|
|
|
|
|
if(mRsMsgs->getDistantChatStatus(id.toDistantChatId(), info)) resp.setOk();
|
|
|
|
|
else resp.setFail("Failed to get status for distant chat");
|
|
|
|
|
|
|
|
|
|
resp.mDataStream << makeKeyValue("own_gxs_hex", info.own_id.toStdString())
|
|
|
|
|
<< makeKeyValue("remote_gxs_hex", info.to_id.toStdString())
|
|
|
|
|
<< makeKeyValue("chat_id", info.peer_id.toStdString())
|
|
|
|
|
<< makeKeyValue("status", info.status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatHandler::handleCloseDistantChatConnexion(Request& req, Response& resp)
|
|
|
|
|
{
|
|
|
|
|
std::string distant_chat_hex;
|
|
|
|
|
req.mStream << makeKeyValueReference("distant_chat_hex", distant_chat_hex);
|
|
|
|
|
|
|
|
|
|
DistantChatPeerId chat_id(distant_chat_hex);
|
|
|
|
|
if (mRsMsgs->closeDistantChatConnexion(chat_id)) resp.setOk();
|
|
|
|
|
else resp.setFail("Failed to close distant chat");
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-14 17:44:17 +02:00
|
|
|
|
void ChatHandler::handleCreateLobby(Request& req, Response& resp)
|
|
|
|
|
{
|
|
|
|
|
std::set<RsPeerId> invited_identites;
|
|
|
|
|
std::string lobby_name;
|
|
|
|
|
std::string lobby_topic;
|
|
|
|
|
std::string gxs_id;
|
|
|
|
|
|
|
|
|
|
req.mStream << makeKeyValueReference("lobby_name", lobby_name);
|
|
|
|
|
req.mStream << makeKeyValueReference("lobby_topic", lobby_topic);
|
|
|
|
|
req.mStream << makeKeyValueReference("gxs_id", gxs_id);
|
|
|
|
|
|
|
|
|
|
RsGxsId gxsId(gxs_id);
|
|
|
|
|
|
|
|
|
|
bool lobby_public;
|
|
|
|
|
bool pgp_signed;
|
|
|
|
|
|
|
|
|
|
req.mStream << makeKeyValueReference("lobby_public", lobby_public);
|
|
|
|
|
req.mStream << makeKeyValueReference("pgp_signed", pgp_signed);
|
|
|
|
|
|
|
|
|
|
ChatLobbyFlags lobby_flags;
|
|
|
|
|
|
|
|
|
|
if(lobby_public)
|
|
|
|
|
lobby_flags |= RS_CHAT_LOBBY_FLAGS_PUBLIC;
|
|
|
|
|
|
|
|
|
|
if(pgp_signed)
|
|
|
|
|
lobby_flags |= RS_CHAT_LOBBY_FLAGS_PGP_SIGNED;
|
|
|
|
|
|
|
|
|
|
mRsMsgs->createChatLobby(lobby_name, gxsId, lobby_topic, invited_identites, lobby_flags);
|
|
|
|
|
|
|
|
|
|
tick();
|
|
|
|
|
resp.setOk();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 15:02:10 +02:00
|
|
|
|
} // namespace resource_api
|