From 162ef7368fa8c37aae028d87a2e8c4061b761b2a Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 9 Aug 2019 10:06:23 +0200 Subject: [PATCH 001/100] Add str_to_a32 and a32_to_str functions --- src/strongvelope/strongvelope.cpp | 24 ++++++++++++++++++++++++ src/strongvelope/strongvelope.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 5d42f0c79..1ec18c7ae 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -624,6 +624,30 @@ ProtocolHandler::ProtocolHandler(karere::Id ownHandle, } } +template +std::vector ProtocolHandler::str_to_a32(std::string data) +{ + std::vector data32((data.size() + 3) >> 2); + for (int i = 0; i < data.size(); ++i) + { + data32[i >> 2] |= (data[i] & 255) << (24 - (i & 3) * 8); + } + return data32; +} + +template +std::string ProtocolHandler::a32_to_str(std::vector data) +{ + size_t size = data.size() * sizeof(T); + char result [size]; + for (int i = 0; i < size; ++i) + { + result[i] = (data[i >> 2] >> (24 - (i & 3) * 8)) & 255; + } + + return std::string (result, size); +} + unsigned int ProtocolHandler::getCacheVersion() const { return mCacheVersion; diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index 0aaf3d8b2..34a3efc0e 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -454,6 +454,12 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable virtual void onHistoryReload(); virtual uint64_t getPublicHandle() const; virtual void setPublicHandle(const uint64_t ph); + + template + static std::vector str_to_a32(std::string data); + + template + static std::string a32_to_str(std::vector data); }; } namespace chatd From 2310dbbb68ecea6e53e74f0b4e95abcfea43c1aa Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 9 Aug 2019 10:11:25 +0200 Subject: [PATCH 002/100] Add encrypt and decrypt reaction --- src/chatdICrypto.h | 16 ++++++ src/strongvelope/strongvelope.cpp | 92 +++++++++++++++++++++++++++++++ src/strongvelope/strongvelope.h | 6 ++ 3 files changed, 114 insertions(+) diff --git a/src/chatdICrypto.h b/src/chatdICrypto.h index 230b63715..78fa445ac 100644 --- a/src/chatdICrypto.h +++ b/src/chatdICrypto.h @@ -158,6 +158,22 @@ class ICrypto virtual void setPublicHandle(const uint64_t ph) = 0; + /** + * @brief Encrypts a reaction with xxtea. + * @param msg The message associated to the reaction. + * @param reaction An UTF-8 string. + */ + virtual promise::Promise> + reactionEncrypt(Message* msg, const char *reaction) = 0; + + /** + * @brief Decrypts a reaction with xxtea. + * @param msg The message associated to the reaction. + * @param reaction The encrypted reaction. + */ + virtual promise::Promise> + reactionDecrypt(Message* msg, std::string reaction) = 0; + /** * @brief The crypto module is destroyed when that chatid is left or the client is destroyed */ diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 1ec18c7ae..15d459c7b 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -648,6 +648,98 @@ std::string ProtocolHandler::a32_to_str(std::vector data) return std::string (result, size); } +promise::Promise> +ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) +{ + auto wptr = weakHandle(); + return getKey(UserKeyId(msg->userid, msg->keyid)) + .then([this, wptr, msg, reaction](const std::shared_ptr& data) + { + std::string msgId = msg->id().toString(); + std::string react (reaction, strlen(reaction)); + std::string keyBin (data->buf(), data->dataSize()); + + std::vector key32 = str_to_a32(keyBin); + std::vector msgId32 = str_to_a32(msgId); + + // key32 XOR msgId32 --> Cypherkey to encrypt reaction + std::vector cypherKey(key32.size()); + for (int i = 0; i < key32.size(); i++) + { + cypherKey[i] = key32[i] ^ msgId32[i % msgId32.size()]; + } + + // Add padding to reaction + size_t roundSize = ceil(static_cast(react.size()) / 4) * 4; + size_t diff = roundSize - react.size(); + if (diff > 0) + { + for (int i = 0; i < diff; i++) + { + react.insert(react.begin(), '\0'); + } + } + + // Concat msgid[0..4] with emoji (padded) + size_t emojiLen = roundSize + 4; + char plaintext [emojiLen]; + memcpy(plaintext, msgId.data(), 4); + memcpy(plaintext + 4, react.data(), roundSize); + + // emoji32 (b_to_vector) + std::vector emoji32 = str_to_a32(std::string(plaintext, emojiLen)); + + // Encrypt reaction + ::mega::xxteaEncrypt(&emoji32[0], 2, &cypherKey[0], false); + + // Convert encrypted reaction to uint32 array + std::string result = a32_to_str(emoji32); + std::shared_ptrbuf; + buf.reset(new Buffer(result.data(), result.size())); + return buf; + }); +} + +promise::Promise> +ProtocolHandler::reactionDecrypt(Message* msg, std::string reaction) +{ + auto wptr = weakHandle(); + return getKey(UserKeyId(msg->userid, msg->keyid)) + .then([this, wptr, msg, reaction](const std::shared_ptr& data) + { + std::string msgId = msg->id().toString(); + std::string keyBin (data->buf(), data->dataSize()); + std::vector key32 = str_to_a32(keyBin); + std::vector msgId32 = str_to_a32(msgId); + + // key32 XOR msgId32 --> Cypherkey to encrypt reaction + std::vector cypherKey(key32.size()); + for (int i = 0; i < key32.size(); i++) + { + cypherKey[i] = key32[i] ^ msgId32[i % msgId32.size()]; + } + + std::vector reaction32 = str_to_a32(reaction); + ::mega::xxteaDecrypt(&reaction32[0], reaction32.size(), &cypherKey[0], false); + std::string decrypted = a32_to_str(reaction32); + + int count = 0; + for (int i = 4; i < decrypted.size(); ++i) + { + if (decrypted[i] != '\0') + {count ++;} + } + + char *resultEmoji = new char[count]; + memcpy(resultEmoji, (char *) (decrypted.data() + 4 + (4-count)), count); + std::string aux(resultEmoji, count); + + std::shared_ptrbuf; + buf.reset(new Buffer(aux.data(), aux.size())); + return buf; + }); +} + unsigned int ProtocolHandler::getCacheVersion() const { return mCacheVersion; diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index 34a3efc0e..f09b00352 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -460,6 +460,12 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable template static std::string a32_to_str(std::vector data); + + virtual promise::Promise> + reactionEncrypt(chatd::Message* msg, const char *reaction); + + virtual promise::Promise> + reactionDecrypt(chatd::Message* msg, std::string reaction); }; } namespace chatd From 7ffab3af2f35f8a4a944f805278c44d2ca021041 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 9 Aug 2019 12:03:19 +0200 Subject: [PATCH 003/100] Add support to encrypt/decrypt reactions for public chats --- src/strongvelope/strongvelope.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 15d459c7b..7476f650e 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -651,9 +651,18 @@ std::string ProtocolHandler::a32_to_str(std::vector data) promise::Promise> ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) { + promise::Promise> symPms; + if (isPublicChat()) + { + symPms = mUnifiedKeyDecrypted; + } + else + { + symPms = getKey(UserKeyId(msg->userid, msg->keyid)); + } + auto wptr = weakHandle(); - return getKey(UserKeyId(msg->userid, msg->keyid)) - .then([this, wptr, msg, reaction](const std::shared_ptr& data) + return symPms.then([this, wptr, msg, reaction](const std::shared_ptr& data) { std::string msgId = msg->id().toString(); std::string react (reaction, strlen(reaction)); @@ -703,9 +712,18 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) promise::Promise> ProtocolHandler::reactionDecrypt(Message* msg, std::string reaction) { + promise::Promise> symPms; + if (isPublicChat()) + { + symPms = mUnifiedKeyDecrypted; + } + else + { + symPms = getKey(UserKeyId(msg->userid, msg->keyid)); + } + auto wptr = weakHandle(); - return getKey(UserKeyId(msg->userid, msg->keyid)) - .then([this, wptr, msg, reaction](const std::shared_ptr& data) + return symPms.then([this, wptr, msg, reaction](const std::shared_ptr& data) { std::string msgId = msg->id().toString(); std::string keyBin (data->buf(), data->dataSize()); From 1929a38169cd3b5c4ea212a7622692f2c9f495d6 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 9 Aug 2019 12:09:23 +0200 Subject: [PATCH 004/100] Add command ADDREACTION - Increment chatd protocol version - Add + operator overload to add a string to COMMAND. In case of ADDREACTION command the payload length must be added as a uint8 but the existing operators added the payload length as a uint32. --- src/chatd.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/chatd.h | 6 ++++- src/chatdMsg.h | 7 +++++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index f86eb12f1..f7d70dc1e 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1353,6 +1353,26 @@ string Command::toString(const StaticBuffer& data) return tmpString; } + case OP_ADDREACTION: + { + string tmpString; + karere::Id chatid = data.read(1); + karere::Id userid = data.read(9); + karere::Id msgid = data.read(17); + int8_t len = data.read(25); + const char *reaction = data.readPtr(26, len); + tmpString.append("ADDREACTION chatid: "); + tmpString.append(ID_CSTR(chatid)); + tmpString.append(", userid: "); + tmpString.append(ID_CSTR(userid)); + tmpString.append(", msgid: "); + tmpString.append(ID_CSTR(msgid)); + tmpString.append(", len: "); + tmpString.append(std::to_string(len)); + tmpString.append(", reaction: "); + tmpString.append(std::string(reaction, len)); + return tmpString; + } default: return opcodeToStr(opcode); } @@ -2170,9 +2190,15 @@ void Connection::execCommand(const StaticBuffer& buf) READ_CHATID(0); READ_ID(userid, 8); READ_ID(msgid, 16); - READ_32(reaction, 24); + READ_8(payloadLen, 24); + std::string reaction (buf.readPtr(pos, payloadLen), payloadLen); + pos += payloadLen; + CHATDS_LOG_DEBUG("%s: recv ADDREACTION from user %s to message %s reaction %d", - ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction); + ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction.c_str()); + + auto& chat = mChatdClient.chats(chatid); + chat.onAddReaction(msgid, reaction); break; } case OP_DELREACTION: @@ -2479,6 +2505,28 @@ void Chat::sendSync() sendCommand(Command(OP_SYNC) + mChatId); } + +void Chat::addReaction(Message *message, const char *reaction) +{ + auto wptr = weakHandle(); + marshallCall([wptr, this, message, reaction]() + { + if (wptr.deleted()) + return; + + mCrypto->reactionEncrypt(message, reaction) + .then([this, wptr, message](std::shared_ptr data) + { + if (wptr.deleted()) + return; + + std::string encReaction (data->buf(), data->bufSize()); + sendCommand(Command(OP_ADDREACTION) + mChatId + message->userid + message->id() + (int8_t)data->bufSize() + encReaction); + }); + }, mChatdClient.mKarereClient->appCtx); +} + + bool Chat::isFetchingNodeHistory() const { return (!mFetchRequest.empty() && (mFetchRequest.front() == FetchType::kFetchNodeHistory)); @@ -4688,6 +4736,25 @@ void Chat::onUserLeave(Id userid) } } +void Chat::onAddReaction(Id msgId, std::string reaction) +{ + Idx messageIdx = msgIndexFromId(msgId); + Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : NULL; + if (message) + { + auto wptr = weakHandle(); + mCrypto->reactionDecrypt(message, reaction) + .then([this, wptr, message](std::shared_ptr data) + { + if (wptr.deleted()) + return; + + std::string reaction (data->buf(), data->bufSize()); + message->mReactions[reaction].push_back(message->userid); + }); + } +} + void Chat::onPreviewersUpdate(uint32_t numPrev) { if ((mNumPreviewers == numPrev) diff --git a/src/chatd.h b/src/chatd.h index 395726e84..1ad8aff24 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -851,6 +851,7 @@ class Chat: public karere::DeleteTrackable bool msgNodeHistIncoming(Message* msg); void onUserJoin(karere::Id userid, Priv priv); void onUserLeave(karere::Id userid); + void onAddReaction(karere::Id msgId, std::string reaction); void onPreviewersUpdate(uint32_t numPrev); void onJoinComplete(); void loadAndProcessUnsent(); @@ -1280,6 +1281,7 @@ class Chat: public karere::DeleteTrackable uint32_t getNumPreviewers() const; void clearHistory(); void sendSync(); + void addReaction(Message *message, const char *reaction); void setPublicHandle(uint64_t ph); uint64_t getPublicHandle() const; bool previewMode(); @@ -1386,7 +1388,9 @@ class Client : public karere::DeleteTrackable // * Add echo for SEEN command (with seen-pointer up-to-date) // - Version 5: // * Changes at CALLDATA protocol (new state) - static const unsigned chatdVersion = 5; + // - Version 6: + // * Add commands ADDREACTION DELREACTION REACTIONSN + static const unsigned chatdVersion = 6; Client(karere::Client *aKarereClient); ~Client(); diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 436d602a2..7c1f43eed 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -6,6 +6,7 @@ #include #include #include "karereId.h" +#include enum { @@ -590,6 +591,7 @@ class Message: public Buffer mutable void* userp; mutable uint8_t userFlags = 0; bool richLinkRemoved = 0; + std::map> mReactions; karere::Id id() const { return mId; } void setId(karere::Id aId, bool isXid) { mId = aId; mIdIsXid = isXid; } @@ -780,6 +782,11 @@ class Command: public Buffer append(msg.buf(), msg.dataSize()); return std::move(*this); } + Command&& operator+(const std::string& msg) + { + append(msg.data(), msg.size()); + return std::move(*this); + } bool isMessage() const { auto op = opcode(); From 74e6f3c584c21dc600494378093e1d5a288cf0b1 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Mon, 12 Aug 2019 17:36:07 +0200 Subject: [PATCH 005/100] Fix reactions management in Messages - Replace reaction map by a vector to a new structure Reaction. This action will solve the problem to obtain the reactions in the same order as we received. - Add new methods to manage reactions in Messsage class --- src/chatd.cpp | 13 +++--- src/chatd.h | 2 +- src/chatdMsg.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index f7d70dc1e..d8f697864 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2186,7 +2186,6 @@ void Connection::execCommand(const StaticBuffer& buf) } case OP_ADDREACTION: { - //TODO: to be implemented READ_CHATID(0); READ_ID(userid, 8); READ_ID(msgid, 16); @@ -2198,7 +2197,7 @@ void Connection::execCommand(const StaticBuffer& buf) ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction.c_str()); auto& chat = mChatdClient.chats(chatid); - chat.onAddReaction(msgid, reaction); + chat.onAddReaction(msgid, userid, reaction); break; } case OP_DELREACTION: @@ -4736,7 +4735,7 @@ void Chat::onUserLeave(Id userid) } } -void Chat::onAddReaction(Id msgId, std::string reaction) +void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) { Idx messageIdx = msgIndexFromId(msgId); Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : NULL; @@ -4744,13 +4743,15 @@ void Chat::onAddReaction(Id msgId, std::string reaction) { auto wptr = weakHandle(); mCrypto->reactionDecrypt(message, reaction) - .then([this, wptr, message](std::shared_ptr data) + .then([this, wptr, message, userId](std::shared_ptr data) { if (wptr.deleted()) return; - std::string reaction (data->buf(), data->bufSize()); - message->mReactions[reaction].push_back(message->userid); + message->addReaction(std::string (data->buf(), data->bufSize()), userId); + }); + } +} }); } } diff --git a/src/chatd.h b/src/chatd.h index 1ad8aff24..87abf084e 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -851,7 +851,7 @@ class Chat: public karere::DeleteTrackable bool msgNodeHistIncoming(Message* msg); void onUserJoin(karere::Id userid, Priv priv); void onUserLeave(karere::Id userid); - void onAddReaction(karere::Id msgId, std::string reaction); + void onAddReaction(karere::Id msgId, karere::Id userId, std::string reaction); void onPreviewersUpdate(uint32_t numPrev); void onJoinComplete(); void loadAndProcessUnsent(); diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 7c1f43eed..1789cde31 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -6,7 +6,6 @@ #include #include #include "karereId.h" -#include enum { @@ -520,6 +519,32 @@ class Message: public Buffer Priv privilege = PRIV_INVALID; }; + struct Reaction + { + /** @brief Contains a UTF-8 string that represents the reaction + * and a vector of userid associated to that reaction. */ + std::string mReaction; + std::vector mUsers; + + Reaction(std::string reaction) + { + this->mReaction = reaction; + } + + /** @brief Returns the userId index in case that exists. Otherwise returns -1 **/ + int userIndex(karere::Id userId) + { + for (size_t i = 0; i < mUsers.size(); i++) + { + if (mUsers.at(i) == userId) + { + return i; + } + } + return -1; + } + }; + class CallEndedInfo { public: @@ -591,7 +616,7 @@ class Message: public Buffer mutable void* userp; mutable uint8_t userFlags = 0; bool richLinkRemoved = 0; - std::map> mReactions; + std::vector mReactions; karere::Id id() const { return mId; } void setId(karere::Id aId, bool isXid) { mId = aId; mIdIsXid = isXid; } @@ -733,6 +758,89 @@ class Message: public Buffer return std::string(buf()+2, dataSize()-2); } + /** @brief Returns a vector with all the reactions of the message **/ + std::vector getReactions() + { + std::vector reactions; + for (size_t i = 0; i < mReactions.size(); i++) + { + reactions.push_back(mReactions.at(i).mReaction); + } + return reactions; + } + + /** @brief Returns a vector with the userid's associated to an specific reaction **/ + std::vector* getReactionUsers(std::string reaction) + { + for (size_t i = 0; i < mReactions.size(); i++) + { + if (mReactions.at(i).mReaction.compare(reaction) == 0) + { + return &(mReactions.at(i).mUsers); + } + } + return NULL; + } + + /** @brief Returns the reaction index in case that exists. Otherwise returns -1 **/ + int getReactionIndex(std::string reaction) + { + for (int i = 0; i < mReactions.size(); i++) + { + if (mReactions.at(i).mReaction.compare(reaction) == 0) + { + return i; + } + } + return -1; + } + + /** @brief Add a reaction for an specific userid **/ + void addReaction(std::string reaction, karere::Id userId) + { + Reaction *r = NULL; + int reactIndex = getReactionIndex(reaction); + if (reactIndex > 0) + { + r = &mReactions.at(reactIndex); + } + else + { + Reaction auxr = Reaction(reaction); + mReactions.emplace_back(auxr); + reactIndex = getReactionIndex(reaction); + r = &mReactions.at(reactIndex); + } + + assert(r); + int userIndex = r->userIndex(userId); + if (userIndex < 0) + { + r->mUsers.emplace_back(userId); + } + } + + /** @brief Delete a reaction for an specific userid **/ + void delReaction(std::string reaction, karere::Id userId) + { + int reactIndex = getReactionIndex(reaction); + if (reactIndex >= 0) + { + Reaction *r = &mReactions.at(reactIndex); + assert(r); + + int userIndex = r->userIndex(userId); + if (userIndex >= 0) + { + r->mUsers.erase(r->mUsers.begin() + userIndex); + if (r->mUsers.size() == 0) + { + mReactions.erase(mReactions.begin() + reactIndex); + } + } + } + } + /** @brief Throws an exception if this is not a management message. */ void throwIfNotManagementMsg() const { if (!isManagementMessage()) throw std::runtime_error("Not a management message"); } From a0f8ba3bed6d1e3feaa8e8a18c1e4062ae1a2e2b Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Mon, 12 Aug 2019 17:39:36 +0200 Subject: [PATCH 006/100] Add support for DELREACTION command --- src/chatd.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/chatd.h | 2 ++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index d8f697864..25a96b768 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1373,6 +1373,26 @@ string Command::toString(const StaticBuffer& data) tmpString.append(std::string(reaction, len)); return tmpString; } + case OP_DELREACTION: + { + string tmpString; + karere::Id chatid = data.read(1); + karere::Id userid = data.read(9); + karere::Id msgid = data.read(17); + int8_t len = data.read(25); + const char *reaction = data.readPtr(26, len); + tmpString.append("DELREACTION chatid: "); + tmpString.append(ID_CSTR(chatid)); + tmpString.append(", userid: "); + tmpString.append(ID_CSTR(userid)); + tmpString.append(", msgid: "); + tmpString.append(ID_CSTR(msgid)); + tmpString.append(", len: "); + tmpString.append(std::to_string(len)); + tmpString.append(", reaction: "); + tmpString.append(std::string(reaction, len)); + return tmpString; + } default: return opcodeToStr(opcode); } @@ -2202,13 +2222,18 @@ void Connection::execCommand(const StaticBuffer& buf) } case OP_DELREACTION: { - //TODO: to be implemented READ_CHATID(0); READ_ID(userid, 8); READ_ID(msgid, 16); - READ_32(reaction, 24); + READ_8(payloadLen, 24); + std::string reaction (buf.readPtr(pos, payloadLen), payloadLen); + pos += payloadLen; + CHATDS_LOG_DEBUG("%s: recv DELREACTION from user %s to message %s reaction %d", - ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction); + ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction.c_str()); + + auto& chat = mChatdClient.chats(chatid); + chat.onDelReaction(msgid, userid, reaction); break; } case OP_SYNC: @@ -2525,6 +2550,26 @@ void Chat::addReaction(Message *message, const char *reaction) }, mChatdClient.mKarereClient->appCtx); } +void Chat::delReaction(Message *message, const char *reaction) +{ + auto wptr = weakHandle(); + marshallCall([wptr, this, message, reaction]() + { + if (wptr.deleted()) + return; + + mCrypto->reactionEncrypt(message, reaction) + .then([this, wptr, message](std::shared_ptr data) + { + if (wptr.deleted()) + return; + + std::string encReaction (data->buf(), data->bufSize()); + sendCommand(Command(OP_DELREACTION) + mChatId + message->userid + message->id() + (int8_t)data->bufSize() + encReaction); + }); + }, mChatdClient.mKarereClient->appCtx); +} + bool Chat::isFetchingNodeHistory() const { @@ -4752,6 +4797,21 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) }); } } + +void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) +{ + Idx messageIdx = msgIndexFromId(msgId); + Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : NULL; + if (message) + { + auto wptr = weakHandle(); + mCrypto->reactionDecrypt(message, reaction) + .then([this, wptr, message, userId](std::shared_ptr data) + { + if (wptr.deleted()) + return; + + message->delReaction(std::string (data->buf(), data->bufSize()), userId); }); } } diff --git a/src/chatd.h b/src/chatd.h index 87abf084e..83eb230b6 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -852,6 +852,7 @@ class Chat: public karere::DeleteTrackable void onUserJoin(karere::Id userid, Priv priv); void onUserLeave(karere::Id userid); void onAddReaction(karere::Id msgId, karere::Id userId, std::string reaction); + void onDelReaction(karere::Id msgId, karere::Id userId, std::string reaction); void onPreviewersUpdate(uint32_t numPrev); void onJoinComplete(); void loadAndProcessUnsent(); @@ -1282,6 +1283,7 @@ class Chat: public karere::DeleteTrackable void clearHistory(); void sendSync(); void addReaction(Message *message, const char *reaction); + void delReaction(Message *message, const char *reaction); void setPublicHandle(uint64_t ph); uint64_t getPublicHandle() const; bool previewMode(); From 5fa0b9bcfad3a29dce9a43a1e391c114a5c0d427 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 20 Aug 2019 16:04:13 +0200 Subject: [PATCH 007/100] Remove str_to_a32 and a32_to_str functions Functions str_to_a32 and a32_to_str has been moved to ::mega:Utils so we have to remove the strongvelope copies and DataTranslation class --- src/megachatapi_impl.cpp | 39 ++++----------------------- src/megachatapi_impl.h | 21 --------------- src/strongvelope/strongvelope.cpp | 45 +++++++++---------------------- src/strongvelope/strongvelope.h | 6 ----- 4 files changed, 17 insertions(+), 94 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 8257e0a01..45e10c5d0 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -8384,38 +8384,6 @@ MegaChatRichPreviewPrivate::~MegaChatRichPreviewPrivate() } -std::vector DataTranslation::b_to_vector(const std::string& data) -{ - int length = data.length(); - std::vector vector(length / sizeof(int32_t)); - - for (int i = 0; i < length; ++i) - { - // i >> 2 = i / 4 - vector[i >> 2] |= (data[i] & 255) << (24 - (i & 3) * 8); - } - - return vector; -} - -std::string DataTranslation::vector_to_b(std::vector vector) -{ - int length = vector.size() * sizeof(int32_t); - char* data = new char[length]; - - for (int i = 0; i < length; ++i) - { - // i >> 2 = i / 4 - data[i] = (vector[i >> 2] >> (24 - (i & 3) * 8)) & 255; - } - - std::string dataToReturn(data, length); - - delete[] data; - - return dataToReturn; -} - std::string JSonUtils::generateAttachNodeJSon(MegaNodeList *nodes, uint8_t type) { std::string ret; @@ -8450,7 +8418,8 @@ std::string JSonUtils::generateAttachNodeJSon(MegaNodeList *nodes, uint8_t type) Base64::atob(base64Key, (::mega::byte*)tempKey, FILENODEKEYLENGTH); delete [] base64Key; - std::vector keyVector = DataTranslation::b_to_vector(std::string(tempKey, FILENODEKEYLENGTH)); + // This call must be done with type = + std::vector keyVector = ::mega::Utils::str_to_a32(std::string(tempKey, FILENODEKEYLENGTH)); rapidjson::Value keyVectorNode(rapidjson::kArrayType); if (keyVector.size() != 8) { @@ -8600,7 +8569,9 @@ MegaNodeList *JSonUtils::parseAttachNodeJSon(const char *json) return NULL; } } - std::string key = DataTranslation::vector_to_b(kElements); + + // This call must be done with type = + std::string key = ::mega::Utils::a32_to_str(kElements); // size rapidjson::Value::ConstMemberIterator iteratorSize = file.FindMember("s"); diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index 51dbfcea6..b8d47446f 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -1290,27 +1290,6 @@ class MegaChatContainsMetaPrivate : public MegaChatContainsMeta MegaChatGeolocation *mGeolocation = NULL; }; -class DataTranslation -{ -public: - /** - * @brief Transform binary string into a vector. For example: string.length() = 32 => vector.size() = 8 - * The vector output is similar to "[669070598,-250738112,2059051645,-1942187558, 324123143, 86148965]" - * @param data string in binary format - * @return vector - */ - static std::vector b_to_vector(const std::string& data); - - /** - * @brief Transform int32_t vector into a birnary string. For example: string.length() = 32 => vector.size() = 8 - * The vector input is similar to "[669070598,-250738112,2059051645,-1942187558, 324123143, 86148965]" - * @param vector vector of int32_t - * @return binary string - */ - static std::string vector_to_b(std::vector vector); - -}; - class JSonUtils { public: diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 7476f650e..107f86a48 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -624,30 +624,6 @@ ProtocolHandler::ProtocolHandler(karere::Id ownHandle, } } -template -std::vector ProtocolHandler::str_to_a32(std::string data) -{ - std::vector data32((data.size() + 3) >> 2); - for (int i = 0; i < data.size(); ++i) - { - data32[i >> 2] |= (data[i] & 255) << (24 - (i & 3) * 8); - } - return data32; -} - -template -std::string ProtocolHandler::a32_to_str(std::vector data) -{ - size_t size = data.size() * sizeof(T); - char result [size]; - for (int i = 0; i < size; ++i) - { - result[i] = (data[i >> 2] >> (24 - (i & 3) * 8)) & 255; - } - - return std::string (result, size); -} - promise::Promise> ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) { @@ -668,8 +644,9 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) std::string react (reaction, strlen(reaction)); std::string keyBin (data->buf(), data->dataSize()); - std::vector key32 = str_to_a32(keyBin); - std::vector msgId32 = str_to_a32(msgId); + // Inside this function str_to_a32 and a32_to_str calls must be done with type = + std::vector key32 = ::mega::Utils::str_to_a32(keyBin); + std::vector msgId32 = ::mega::Utils::str_to_a32(msgId); // key32 XOR msgId32 --> Cypherkey to encrypt reaction std::vector cypherKey(key32.size()); @@ -695,14 +672,14 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) memcpy(plaintext, msgId.data(), 4); memcpy(plaintext + 4, react.data(), roundSize); - // emoji32 (b_to_vector) - std::vector emoji32 = str_to_a32(std::string(plaintext, emojiLen)); + // emoji32 + std::vector emoji32 = ::mega::Utils::str_to_a32(std::string(plaintext, emojiLen)); // Encrypt reaction ::mega::xxteaEncrypt(&emoji32[0], 2, &cypherKey[0], false); // Convert encrypted reaction to uint32 array - std::string result = a32_to_str(emoji32); + std::string result = ::mega::Utils::a32_to_str(emoji32); std::shared_ptrbuf; buf.reset(new Buffer(result.data(), result.size())); return buf; @@ -727,8 +704,10 @@ ProtocolHandler::reactionDecrypt(Message* msg, std::string reaction) { std::string msgId = msg->id().toString(); std::string keyBin (data->buf(), data->dataSize()); - std::vector key32 = str_to_a32(keyBin); - std::vector msgId32 = str_to_a32(msgId); + + // Inside this function str_to_a32 and a32_to_str calls must be done with type = + std::vector key32 = ::mega::Utils::str_to_a32(keyBin); + std::vector msgId32 = ::mega::Utils::str_to_a32(msgId); // key32 XOR msgId32 --> Cypherkey to encrypt reaction std::vector cypherKey(key32.size()); @@ -737,9 +716,9 @@ ProtocolHandler::reactionDecrypt(Message* msg, std::string reaction) cypherKey[i] = key32[i] ^ msgId32[i % msgId32.size()]; } - std::vector reaction32 = str_to_a32(reaction); + std::vector reaction32 = ::mega::Utils::str_to_a32(reaction); ::mega::xxteaDecrypt(&reaction32[0], reaction32.size(), &cypherKey[0], false); - std::string decrypted = a32_to_str(reaction32); + std::string decrypted = ::mega::Utils::a32_to_str(reaction32); int count = 0; for (int i = 4; i < decrypted.size(); ++i) diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index f09b00352..10759936f 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -455,12 +455,6 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable virtual uint64_t getPublicHandle() const; virtual void setPublicHandle(const uint64_t ph); - template - static std::vector str_to_a32(std::string data); - - template - static std::string a32_to_str(std::vector data); - virtual promise::Promise> reactionEncrypt(chatd::Message* msg, const char *reaction); From aa550fca3df9468d9df45322dfc444390433d534 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 21 Aug 2019 14:45:57 +0200 Subject: [PATCH 008/100] Add REACTIONSN command Add left commands to opcodeToStr --- src/chatd.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- src/chatd.h | 4 ++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 25a96b768..b07c17e68 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1352,7 +1352,6 @@ string Command::toString(const StaticBuffer& data) tmpString.append(std::to_string(count)); return tmpString; } - case OP_ADDREACTION: { string tmpString; @@ -1393,6 +1392,18 @@ string Command::toString(const StaticBuffer& data) tmpString.append(std::string(reaction, len)); return tmpString; } + case OP_REACTIONSN: + { + string tmpString; + karere::Id chatid = data.read(1); + int8_t rsn = data.read(9); + + tmpString.append("REACTIONSN chatid: "); + tmpString.append(ID_CSTR(chatid)); + tmpString.append(", rsn: "); + tmpString.append(std::to_string(rsn)); + return tmpString; + } default: return opcodeToStr(opcode); } @@ -2236,6 +2247,16 @@ void Connection::execCommand(const StaticBuffer& buf) chat.onDelReaction(msgid, userid, reaction); break; } + case OP_REACTIONSN: + { + READ_CHATID(0); + READ_8(rsn, 8); + + CHATDS_LOG_DEBUG("%s: recv REACTIONSN rsn %d", ID_CSTR(chatid), rsn); + auto& chat = mChatdClient.chats(chatid); + chat.onReactionSn(rsn); + break; + } case OP_SYNC: { READ_CHATID(0); @@ -2570,6 +2591,15 @@ void Chat::delReaction(Message *message, const char *reaction) }, mChatdClient.mKarereClient->appCtx); } +void Chat::sendReactionSn() +{ + if (!mReactionSn) + { + return; + } + + sendCommand(Command(OP_REACTIONSN) + mChatId + static_cast(mReactionSn)); +} bool Chat::isFetchingNodeHistory() const { @@ -4816,6 +4846,11 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) } } +void Chat::onReactionSn(int rsn) +{ + mReactionSn = rsn; +} + void Chat::onPreviewersUpdate(uint32_t numPrev) { if ((mNumPreviewers == numPrev) @@ -4871,6 +4906,9 @@ void Chat::setOnlineState(ChatState state) if (state == kChatStateOnline) { + // Send REACTIONSN after a reconnection + sendReactionSn(); + if (mChatdClient.areAllChatsLoggedIn(connection().shardNo())) { mChatdClient.mKarereClient->initStats().shardEnd(InitStats::kStatsLoginChatd, connection().shardNo()); @@ -5133,7 +5171,11 @@ const char* Command::opcodeToStr(uint8_t code) RET_ENUM_NAME(HANDLEJOINRANGEHIST); RET_ENUM_NAME(SYNC); RET_ENUM_NAME(NEWNODEMSG); + RET_ENUM_NAME(CALLTIME); RET_ENUM_NAME(NODEHIST); + RET_ENUM_NAME(NUMBYHANDLE); + RET_ENUM_NAME(HANDLELEAVE); + RET_ENUM_NAME(REACTIONSN); default: return "(invalid opcode)"; }; } diff --git a/src/chatd.h b/src/chatd.h index 83eb230b6..c68a4b2c8 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -829,6 +829,8 @@ class Chat: public karere::DeleteTrackable bool mDecryptionAttachmentsHalted = false; /** True when node-attachments are pending to decrypt and history is truncated --> discard message being decrypted */ bool mTruncateAttachment = false; + /** Indicates the reaction sequence number for this chatroom */ + int mReactionSn = 0; // ==== std::map mPendingEdits; std::map mRefidToIdxMap; @@ -853,6 +855,7 @@ class Chat: public karere::DeleteTrackable void onUserLeave(karere::Id userid); void onAddReaction(karere::Id msgId, karere::Id userId, std::string reaction); void onDelReaction(karere::Id msgId, karere::Id userId, std::string reaction); + void onReactionSn(int rsn); void onPreviewersUpdate(uint32_t numPrev); void onJoinComplete(); void loadAndProcessUnsent(); @@ -1284,6 +1287,7 @@ class Chat: public karere::DeleteTrackable void sendSync(); void addReaction(Message *message, const char *reaction); void delReaction(Message *message, const char *reaction); + void sendReactionSn(); void setPublicHandle(uint64_t ph); uint64_t getPublicHandle() const; bool previewMode(); From a9cc7b1890a95cabb59615e69bbec3f1d5309ca2 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 22 Aug 2019 10:15:48 +0200 Subject: [PATCH 009/100] Add reaction commands documentation --- src/chatdMsg.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 1789cde31..942022145 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -323,14 +323,14 @@ enum Opcode OP_ECHO = 32, /** - * @brief + * @brief * * User add a reaction to message */ OP_ADDREACTION = 33, /** - * @brief + * @brief * * User delete a reaction to message */ @@ -415,6 +415,22 @@ enum Opcode */ OP_HANDLELEAVE = 47, + /** + ** @brief + * + * C->S: send to chatd the current reaction sequence number for a chatroom. + * This command must be send upon a reconnection, only if we have stored + * a valid rsn (rsn != 0) and only after send JOIN/JOINRANGEHIST + * or HANDLEJOIN/HANDLEJOINRANGEHIST. + * + * S->C: inform about any change in the reactions associated to a chatroom + * by receiving the current reaction sequence number. + * + * Send: + * Receive: + */ + OP_REACTIONSN = 48, + OP_LAST = OP_HANDLELEAVE, OP_INVALIDCODE = 0xFF }; From 8d42d212379f28cad07895fce3d283f2514fb030 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 23 Aug 2019 13:54:03 +0200 Subject: [PATCH 010/100] Modify karere cache schema to support reactions --- src/chatClient.cpp | 19 ++++++++++++++++++- src/chatdDb.h | 37 +++++++++++++++++++++++++++++++++++++ src/dbSchema.sql | 4 +++- src/karereCommon.cpp | 4 +++- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/chatClient.cpp b/src/chatClient.cpp index d525e6b5a..731f638fc 100644 --- a/src/chatClient.cpp +++ b/src/chatClient.cpp @@ -274,7 +274,7 @@ bool Client::openDb(const std::string& sid) { // no chats --> only update cache schema KR_LOG_WARNING("Updating schema of MEGAchat cache..."); - db.query("ALTER TABLE `chats` ADD mode tinyint"); + db.query("ALTER TABLE `chats` ADD mode tinyint default 0"); db.query("ALTER TABLE `chats` ADD unified_key blob"); db.query("update vars set value = ? where name = 'schema_version'", currentVersion); db.commit(); @@ -290,6 +290,23 @@ bool Client::openDb(const std::string& sid) ok = true; KR_LOG_WARNING("Database version has been updated to %s", gDbSchemaVersionSuffix); } + else if (cachedVersionSuffix == "7" && (strcmp(gDbSchemaVersionSuffix, "8") == 0)) + { + KR_LOG_WARNING("Updating schema of MEGAchat cache..."); + + // Add reactionsn to chats table + db.query("ALTER TABLE `chats` ADD rsn blob"); + + // Create new table for chat reactions + db.simpleQuery("CREATE TABLE chat_reactions(chatid int64 not null, msgid int64 not null," + " userid int64 not null, reaction text," + " UNIQUE(chatid, msgid, userid, reaction))"); + + db.query("update vars set value = ? where name = 'schema_version'", currentVersion); + db.commit(); + ok = true; + KR_LOG_WARNING("Database version has been updated to %s", gDbSchemaVersionSuffix); + } } } diff --git a/src/chatdDb.h b/src/chatdDb.h index 27c4c60db..aa9e6e892 100644 --- a/src/chatdDb.h +++ b/src/chatdDb.h @@ -532,6 +532,43 @@ class ChatdSqliteDb: public chatd::DbInterface messages.push_back(msg); } } + + virtual std::string getReactionSn() + { + SqliteStmt stmt(mDb, "select rsn from chats where chatid = ?"); + stmt << mChat.chatId(); + stmt.stepMustHaveData(__FUNCTION__); + return stmt.stringCol(0); + } + + virtual void setReactionSn(std::string rsn) + { + mDb.query("update chats set rsn = ? where chatid = ?", rsn, mChat.chatId()); + assertAffectedRowCount(1); + } + + virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) + { + mDb.query("insert into chat_reactions(chatid, msgid, userid, reaction)" + "values(?,?,?,?)", mChat.chatId(), msgId, userId, reaction); + } + + virtual void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) + { + mDb.query("delete from chat_reactions where chatid = ? and msgid = ? and userid = ? and reaction = ?", + mChat.chatId(), msgId, userId, reaction); + } + + virtual void getMessageReactions(karere::Id msgId, ::mega::multimap& reactions) + { + SqliteStmt stmt(mDb, "select reaction, userid from chat_reactions where chatid = ? and msgid = ?"); + stmt << mChat.chatId(); + stmt << msgId; + while (stmt.step()) + { + reactions.insert(std::pair(stmt.stringCol(0), stmt.uint64Col(1))); + } + } }; #endif diff --git a/src/dbSchema.sql b/src/dbSchema.sql index a8a423db9..ae2a1165f 100644 --- a/src/dbSchema.sql +++ b/src/dbSchema.sql @@ -13,7 +13,7 @@ CREATE TABLE chats(chatid int64 unique primary key, shard tinyint, own_priv tinyint, peer int64 default -1, peer_priv tinyint default 0, title text, ts_created int64 not null default 0, last_seen int64 default 0, last_recv int64 default 0, archived tinyint default 0, - mode tinyint default 0, unified_key blob); + mode tinyint default 0, unified_key blob, rsn blob); CREATE TABLE contacts(userid int64 PRIMARY KEY, email text, visibility int, since int64 not null default 0); @@ -39,3 +39,5 @@ CREATE TABLE node_history(idx int not null, chatid int64 not null, msgid int64 n userid int64, keyid int not null, type tinyint, updated smallint, ts int, is_encrypted tinyint, data blob, backrefid int64 not null, UNIQUE(chatid,msgid), UNIQUE(chatid,idx)); +CREATE TABLE chat_reactions(chatid int64 not null, msgid int64 not null, userid int64 not null, + reaction text, UNIQUE(chatid, msgid, userid, reaction)); diff --git a/src/karereCommon.cpp b/src/karereCommon.cpp index 1142d0847..378f4ad18 100644 --- a/src/karereCommon.cpp +++ b/src/karereCommon.cpp @@ -14,13 +14,15 @@ namespace rtcModule {void globalCleanup(); } namespace karere { -const char* gDbSchemaVersionSuffix = "7"; +const char* gDbSchemaVersionSuffix = "8"; /* 2 --> +3: invalidate cached chats to reload history (so call-history msgs are fetched) 3 --> +4: invalidate both caches, SDK + MEGAchat, if there's at least one chat (so deleted chats are re-fetched from API) 4 --> +5: modify attachment, revoke, contact and containsMeta and create a new table node_history 5 --> +6: invalidate both caches, SDK + MEGAchat, (so deleted chats are re-fetched from API) if there's at least one chat, otherwise modify cache structure to support public chats + 6 --> +7: update keyid for truncate messages in db + 7 --> +8: modify chats and create a new table chat_reactions */ bool gCatchException = true; From 0d7eac967aa378ca970d8bf7ce037c209341ad9a Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 23 Aug 2019 14:09:32 +0200 Subject: [PATCH 011/100] Manage errors in encrypt/decrypt reaction --- src/chatd.cpp | 24 ++++++++++++++++++++++++ src/strongvelope/strongvelope.cpp | 8 ++++++++ 2 files changed, 32 insertions(+) diff --git a/src/chatd.cpp b/src/chatd.cpp index b07c17e68..c6a47d314 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2567,6 +2567,10 @@ void Chat::addReaction(Message *message, const char *reaction) std::string encReaction (data->buf(), data->bufSize()); sendCommand(Command(OP_ADDREACTION) + mChatId + message->userid + message->id() + (int8_t)data->bufSize() + encReaction); + }) + .fail([this](const ::promise::Error& err) + { + CHATID_LOG_DEBUG("Error encrypting reaction: %s", err.what()); }); }, mChatdClient.mKarereClient->appCtx); } @@ -2587,6 +2591,10 @@ void Chat::delReaction(Message *message, const char *reaction) std::string encReaction (data->buf(), data->bufSize()); sendCommand(Command(OP_DELREACTION) + mChatId + message->userid + message->id() + (int8_t)data->bufSize() + encReaction); + }) + .fail([this](const ::promise::Error& err) + { + CHATID_LOG_DEBUG("Error encrypting reaction: %s", err.what()); }); }, mChatdClient.mKarereClient->appCtx); } @@ -4824,8 +4832,16 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) return; message->addReaction(std::string (data->buf(), data->bufSize()), userId); + }) + .fail([this](const ::promise::Error& err) + { + CHATID_LOG_DEBUG("Error decrypting reaction: %s", err.what()); }); } + else + { + CHATID_LOG_DEBUG("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); + } } void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) @@ -4842,8 +4858,16 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) return; message->delReaction(std::string (data->buf(), data->bufSize()), userId); + }) + .fail([this](const ::promise::Error& err) + { + CHATID_LOG_DEBUG("Error decrypting reaction: %s", err.what()); }); } + else + { + CHATID_LOG_DEBUG("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); + } } void Chat::onReactionSn(int rsn) diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 107f86a48..5751b8af3 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -683,6 +683,10 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) std::shared_ptrbuf; buf.reset(new Buffer(result.data(), result.size())); return buf; + }) + .fail([](const ::promise::Error& err) + { + return err; }); } @@ -734,6 +738,10 @@ ProtocolHandler::reactionDecrypt(Message* msg, std::string reaction) std::shared_ptrbuf; buf.reset(new Buffer(aux.data(), aux.size())); return buf; + }) + .fail([](const ::promise::Error& err) + { + return err; }); } From b361283a00a205f7f8e4a0e662f6875c74a602ca Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 23 Aug 2019 14:22:44 +0200 Subject: [PATCH 012/100] Save reaction sn in memory as a karere Id --- src/chatd.cpp | 20 +++++++++++--------- src/chatd.h | 8 ++++++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index c6a47d314..5293a43ed 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1396,12 +1396,11 @@ string Command::toString(const StaticBuffer& data) { string tmpString; karere::Id chatid = data.read(1); - int8_t rsn = data.read(9); - + karere::Id rsn = data.read(9); tmpString.append("REACTIONSN chatid: "); tmpString.append(ID_CSTR(chatid)); tmpString.append(", rsn: "); - tmpString.append(std::to_string(rsn)); + tmpString.append(ID_CSTR(rsn)); return tmpString; } default: @@ -1757,6 +1756,9 @@ Chat::Chat(Connection& conn, Id chatid, Listener* listener, mLastSeenIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastSeenId); mLastReceivedIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastReceivedId); + std::string rsn(mDbInterface->getReactionSn()); + mReactionSn = (!rsn.empty()) ? Id(rsn.data(), rsn.size()) : Id::inval(); + if ((mHaveAllHistory = mDbInterface->chatVar("have_all_history"))) { CHATID_LOG_DEBUG("All backward history of chat is available locally"); @@ -2250,9 +2252,8 @@ void Connection::execCommand(const StaticBuffer& buf) case OP_REACTIONSN: { READ_CHATID(0); - READ_8(rsn, 8); - - CHATDS_LOG_DEBUG("%s: recv REACTIONSN rsn %d", ID_CSTR(chatid), rsn); + READ_ID(rsn, 8); + CHATDS_LOG_DEBUG("%s: recv REACTIONSN rsn %s", ID_CSTR(chatid), ID_CSTR(rsn)); auto& chat = mChatdClient.chats(chatid); chat.onReactionSn(rsn); break; @@ -2601,12 +2602,12 @@ void Chat::delReaction(Message *message, const char *reaction) void Chat::sendReactionSn() { - if (!mReactionSn) + if (!mReactionSn.isValid()) { return; } - sendCommand(Command(OP_REACTIONSN) + mChatId + static_cast(mReactionSn)); + sendCommand(Command(OP_REACTIONSN) + mChatId + mReactionSn.val); } bool Chat::isFetchingNodeHistory() const @@ -4870,9 +4871,10 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) } } -void Chat::onReactionSn(int rsn) +void Chat::onReactionSn(Id rsn) { mReactionSn = rsn; + CALL_DB(setReactionSn, mReactionSn.toString()); } void Chat::onPreviewersUpdate(uint32_t numPrev) diff --git a/src/chatd.h b/src/chatd.h index c68a4b2c8..c1c4bd37c 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -830,7 +830,7 @@ class Chat: public karere::DeleteTrackable /** True when node-attachments are pending to decrypt and history is truncated --> discard message being decrypted */ bool mTruncateAttachment = false; /** Indicates the reaction sequence number for this chatroom */ - int mReactionSn = 0; + karere::Id mReactionSn = karere::Id::inval(); // ==== std::map mPendingEdits; std::map mRefidToIdxMap; @@ -855,7 +855,7 @@ class Chat: public karere::DeleteTrackable void onUserLeave(karere::Id userid); void onAddReaction(karere::Id msgId, karere::Id userId, std::string reaction); void onDelReaction(karere::Id msgId, karere::Id userId, std::string reaction); - void onReactionSn(int rsn); + void onReactionSn(karere::Id rsn); void onPreviewersUpdate(uint32_t numPrev); void onJoinComplete(); void loadAndProcessUnsent(); @@ -1570,6 +1570,10 @@ class DbInterface virtual void clearHistory() = 0; virtual Idx getIdxOfMsgidFromNodeHistory(karere::Id msgid) = 0; + + // <<<--- Reaction methods --->>> + virtual std::string getReactionSn() = 0; + virtual void setReactionSn(std::string rsn) = 0; }; } From f2119861b81d79b2a6f0b46d4386799f59e2538d Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 23 Aug 2019 14:27:16 +0200 Subject: [PATCH 013/100] Add/Remove reactions from cache --- src/chatd.cpp | 22 ++++++++++++++++++---- src/chatd.h | 2 ++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 5293a43ed..d55bdbd83 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2226,7 +2226,7 @@ void Connection::execCommand(const StaticBuffer& buf) std::string reaction (buf.readPtr(pos, payloadLen), payloadLen); pos += payloadLen; - CHATDS_LOG_DEBUG("%s: recv ADDREACTION from user %s to message %s reaction %d", + CHATDS_LOG_DEBUG("%s: recv ADDREACTION from user %s to message %s reaction %s", ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction.c_str()); auto& chat = mChatdClient.chats(chatid); @@ -2242,7 +2242,7 @@ void Connection::execCommand(const StaticBuffer& buf) std::string reaction (buf.readPtr(pos, payloadLen), payloadLen); pos += payloadLen; - CHATDS_LOG_DEBUG("%s: recv DELREACTION from user %s to message %s reaction %d", + CHATDS_LOG_DEBUG("%s: recv DELREACTION from user %s to message %s reaction %s", ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction.c_str()); auto& chat = mChatdClient.chats(chatid); @@ -4825,6 +4825,11 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : NULL; if (message) { + if (reaction.empty()) + { + CHATID_LOG_DEBUG("onAddReaction: Error, reaction received is empty"); + return; + } auto wptr = weakHandle(); mCrypto->reactionDecrypt(message, reaction) .then([this, wptr, message, userId](std::shared_ptr data) @@ -4832,7 +4837,9 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) if (wptr.deleted()) return; - message->addReaction(std::string (data->buf(), data->bufSize()), userId); + std::string reaction (data->buf(), data->bufSize()); + message->addReaction(reaction, userId); + CALL_DB(addReaction, message->mId, userId, reaction.c_str()); }) .fail([this](const ::promise::Error& err) { @@ -4851,6 +4858,11 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : NULL; if (message) { + if (reaction.empty()) + { + CHATID_LOG_DEBUG("onDelReaction: Error, reaction received is empty"); + return; + } auto wptr = weakHandle(); mCrypto->reactionDecrypt(message, reaction) .then([this, wptr, message, userId](std::shared_ptr data) @@ -4858,7 +4870,9 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) if (wptr.deleted()) return; - message->delReaction(std::string (data->buf(), data->bufSize()), userId); + std::string reaction (data->buf(), data->bufSize()); + message->delReaction(reaction, userId); + CALL_DB(delReaction, message->mId, userId, reaction.c_str()); }) .fail([this](const ::promise::Error& err) { diff --git a/src/chatd.h b/src/chatd.h index c1c4bd37c..1dfde3619 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1574,6 +1574,8 @@ class DbInterface // <<<--- Reaction methods --->>> virtual std::string getReactionSn() = 0; virtual void setReactionSn(std::string rsn) = 0; + virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; + virtual void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; }; } From 17c9f4c9194ef7cf37b22593d6807f9addb80619 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 23 Aug 2019 14:28:49 +0200 Subject: [PATCH 014/100] Load reactions upon chat messages fetching from cache --- src/chatd.cpp | 9 +++++++++ src/chatd.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/chatd.cpp b/src/chatd.cpp index d55bdbd83..174e05a4e 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1819,6 +1819,15 @@ Idx Chat::getHistoryFromDb(unsigned count) CALL_DB(fetchDbHistory, lownum()-1, count, messages); for (auto msg: messages) { + // Load msg reactions from cache + ::mega::multimap reactions; + CALL_DB(getMessageReactions, msg->id(), reactions); + ::mega::multimap::iterator it; + for (it = reactions.begin(); it != reactions.end(); it++) + { + msg->addReaction(it->first, it->second); + } + msgIncoming(false, msg, true); //increments mLastHistFetch/DecryptCount, may reset mHasMoreHistoryInDb if this msgid == mLastKnownMsgid } if (mNextHistFetchIdx == CHATD_IDX_INVALID) diff --git a/src/chatd.h b/src/chatd.h index 1dfde3619..f9f16858c 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1576,6 +1576,7 @@ class DbInterface virtual void setReactionSn(std::string rsn) = 0; virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; virtual void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; + virtual void getMessageReactions(karere::Id msgId, ::mega::multimap& reactions) = 0; }; } From cb53176df61c7d0393bc30ffcf896ad2ffdae05f Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Mon, 26 Aug 2019 13:35:59 +0200 Subject: [PATCH 015/100] Don't allow to ADD/DELREACTION for management messages --- src/chatd.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/chatd.cpp b/src/chatd.cpp index 174e05a4e..cfd38f03a 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4839,6 +4839,13 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) CHATID_LOG_DEBUG("onAddReaction: Error, reaction received is empty"); return; } + + if (message->isManagementMessage()) + { + CHATID_LOG_DEBUG("onAddReaction: Error, reaction received for a management message"); + return; + } + auto wptr = weakHandle(); mCrypto->reactionDecrypt(message, reaction) .then([this, wptr, message, userId](std::shared_ptr data) @@ -4872,6 +4879,13 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) CHATID_LOG_DEBUG("onDelReaction: Error, reaction received is empty"); return; } + + if (message->isManagementMessage()) + { + CHATID_LOG_DEBUG("onDelReaction: Error, reaction received for a management message"); + return; + } + auto wptr = weakHandle(); mCrypto->reactionDecrypt(message, reaction) .then([this, wptr, message, userId](std::shared_ptr data) From 7b5ec994a29f6de0892797ec951328193d515341 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Mon, 26 Aug 2019 13:46:26 +0200 Subject: [PATCH 016/100] Add hasreaction method --- src/megachatapi.cpp | 5 +++++ src/megachatapi.h | 7 +++++++ src/megachatapi_impl.cpp | 7 +++++++ src/megachatapi_impl.h | 2 ++ 4 files changed, 21 insertions(+) diff --git a/src/megachatapi.cpp b/src/megachatapi.cpp index 7f18c84a6..1c0150d73 100644 --- a/src/megachatapi.cpp +++ b/src/megachatapi.cpp @@ -1550,6 +1550,11 @@ int MegaChatMessage::getType() const return MegaChatMessage::TYPE_INVALID; } +bool MegaChatMessage::hasReactions() const +{ + return false; +} + int64_t MegaChatMessage::getTimestamp() const { return 0; diff --git a/src/megachatapi.h b/src/megachatapi.h index a7589485f..802f92f9e 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -1209,6 +1209,13 @@ class MegaChatMessage */ virtual int getType() const; + /** + * @brief Returns if the message has any reaction. + * + * @return Returns true if the message has any reaction, otherwise returns false. + */ + bool hasReactions() const; + /** * @brief Returns the timestamp of the message. * @return Returns the timestamp of the message. diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 45e10c5d0..8b11aa09a 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -7143,6 +7143,7 @@ MegaChatMessagePrivate::MegaChatMessagePrivate(const MegaChatMessage *msg) this->status = msg->getStatus(); this->ts = msg->getTimestamp(); this->type = msg->getType(); + this->mHasReactions = msg->hasReactions(); this->changed = msg->getChanges(); this->edited = msg->isEdited(); this->deleted = msg->isDeleted(); @@ -7186,6 +7187,7 @@ MegaChatMessagePrivate::MegaChatMessagePrivate(const Message &msg, Message::Stat this->tempId = msg.isSending() ? (MegaChatHandle) msg.id() : MEGACHAT_INVALID_HANDLE; this->rowId = MEGACHAT_INVALID_HANDLE; this->type = msg.type; + this->mHasReactions = msg.mReactions.size() ? true : false; this->ts = msg.ts; this->status = status; this->index = index; @@ -7325,6 +7327,11 @@ int MegaChatMessagePrivate::getType() const return type; } +bool MegaChatMessagePrivate::hasReactions() const +{ + return mHasReactions; +} + int64_t MegaChatMessagePrivate::getTimestamp() const { return ts; diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index b8d47446f..931b7100c 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -808,6 +808,7 @@ class MegaChatMessagePrivate : public MegaChatMessage virtual int getMsgIndex() const; virtual MegaChatHandle getUserHandle() const; virtual int getType() const; + virtual bool hasReactions() const; virtual int64_t getTimestamp() const; virtual const char *getContent() const; virtual bool isEdited() const; @@ -858,6 +859,7 @@ class MegaChatMessagePrivate : public MegaChatMessage bool deleted; int priv; // certain messages need additional info, like priv changes int code; // generic field for additional information (ie. the reason of manual sending) + bool mHasReactions; std::vector *megaChatUsers = NULL; mega::MegaNodeList *megaNodeList = NULL; mega::MegaHandleList *megaHandleList = NULL; From 4b88e55651b8755ae8e7ac2a3689f1a147ec6d2c Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 28 Aug 2019 17:35:31 +0200 Subject: [PATCH 017/100] Adjust condition and add method to clean reactions vector in Message --- src/chatdMsg.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 942022145..2624d6850 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -811,12 +811,18 @@ class Message: public Buffer return -1; } + /** @brief Clean reactions */ + void cleanReactions() + { + mReactions.clear(); + } + /** @brief Add a reaction for an specific userid **/ void addReaction(std::string reaction, karere::Id userId) { Reaction *r = NULL; int reactIndex = getReactionIndex(reaction); - if (reactIndex > 0) + if (reactIndex >= 0) { r = &mReactions.at(reactIndex); } From 809b4f7532587cb2b43988071fdf846c6f0644d8 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 28 Aug 2019 17:39:35 +0200 Subject: [PATCH 018/100] Fix bug upon ADD/DELREACTION command sent The user that sends ADD/DELREACTION must be own user. --- src/chatd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index cfd38f03a..288c51328 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2576,7 +2576,7 @@ void Chat::addReaction(Message *message, const char *reaction) return; std::string encReaction (data->buf(), data->bufSize()); - sendCommand(Command(OP_ADDREACTION) + mChatId + message->userid + message->id() + (int8_t)data->bufSize() + encReaction); + sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); }) .fail([this](const ::promise::Error& err) { @@ -2600,7 +2600,7 @@ void Chat::delReaction(Message *message, const char *reaction) return; std::string encReaction (data->buf(), data->bufSize()); - sendCommand(Command(OP_DELREACTION) + mChatId + message->userid + message->id() + (int8_t)data->bufSize() + encReaction); + sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); }) .fail([this](const ::promise::Error& err) { From 07158198590bde5d299e0ee51d03addfc8eb286e Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 28 Aug 2019 17:45:00 +0200 Subject: [PATCH 019/100] Clean reactions upon chat truncate We need to clean all the reactions for the chatroom in cache, and clean reactions for the truncate message in RAM --- src/chatd.cpp | 10 ++++++++++ src/chatd.h | 1 + src/chatdDb.h | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/src/chatd.cpp b/src/chatd.cpp index 288c51328..696c53192 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4160,6 +4160,16 @@ void Chat::handleTruncate(const Message& msg, Idx idx) deleteMessagesBefore(idx); removePendingRichLinks(idx); + // clean reactions for truncate message + Message *truncatemsg = (idx != CHATD_IDX_INVALID) ? findOrNull(idx) : NULL; + if (truncatemsg) + { + truncatemsg->cleanReactions(); + } + + // clean all reactions for this chat in DB + CALL_DB(cleanReactions); + // update last-seen pointer if (mLastSeenIdx != CHATD_IDX_INVALID) { diff --git a/src/chatd.h b/src/chatd.h index f9f16858c..67ed446ee 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1574,6 +1574,7 @@ class DbInterface // <<<--- Reaction methods --->>> virtual std::string getReactionSn() = 0; virtual void setReactionSn(std::string rsn) = 0; + virtual void cleanReactions() = 0; virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; virtual void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; virtual void getMessageReactions(karere::Id msgId, ::mega::multimap& reactions) = 0; diff --git a/src/chatdDb.h b/src/chatdDb.h index aa9e6e892..9e63e59f1 100644 --- a/src/chatdDb.h +++ b/src/chatdDb.h @@ -547,6 +547,11 @@ class ChatdSqliteDb: public chatd::DbInterface assertAffectedRowCount(1); } + virtual void cleanReactions() + { + mDb.query("delete from chat_reactions where chatid = ?", mChat.chatId()); + } + virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) { mDb.query("insert into chat_reactions(chatid, msgid, userid, reaction)" From bc154ac1aa895fd63365b83f70432ad1fd6391a7 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 09:56:37 +0200 Subject: [PATCH 020/100] Add method onReactionUpdate to notify apps when the number of users that reacted to a message with a specific reaction has changed. --- src/chatd.cpp | 9 +++++++++ src/chatd.h | 10 ++++++++++ src/megachatapi_impl.cpp | 13 +++++++++++++ src/megachatapi_impl.h | 3 ++- 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 696c53192..9972d9056 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4866,6 +4866,10 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) std::string reaction (data->buf(), data->bufSize()); message->addReaction(reaction, userId); CALL_DB(addReaction, message->mId, userId, reaction.c_str()); + + std::vector *users = message->getReactionUsers(reaction); + int count = users ? users->size() : 0; + CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), count); }) .fail([this](const ::promise::Error& err) { @@ -4906,6 +4910,11 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) std::string reaction (data->buf(), data->bufSize()); message->delReaction(reaction, userId); CALL_DB(delReaction, message->mId, userId, reaction.c_str()); + + + std::vector *users = message->getReactionUsers(reaction); + int count = users ? users->size() : 0; + CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), count); }) .fail([this](const ::promise::Error& err) { diff --git a/src/chatd.h b/src/chatd.h index 67ed446ee..610f48ec3 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -302,6 +302,16 @@ class Listener */ virtual void onLastMessageTsUpdated(uint32_t /*ts*/) {} + /** + * @brief Called when the number of users that reacted to a message with a + * specific reaction has changed. + * + * @param msgid The id of the message associated to the reaction. + * @param reaction The UTF-8 reaction + * @param count The number of users that reacted to that message + */ + virtual void onReactionUpdate(karere::Id /*msgid*/, const char* /*reaction*/, int /*count*/){} + /** * @brief Called when a chat is going to reload its history after the server rejects JOINRANGEHIST */ diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 8b11aa09a..9b01eb0da 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -5656,6 +5656,14 @@ void MegaChatRoomHandler::fireOnMessageReceived(MegaChatMessage *msg) delete msg; } +void MegaChatRoomHandler::fireOnReactionUpdate(MegaChatHandle msgid, const char *reaction, int count) +{ + for (set::iterator it = roomListeners.begin(); it != roomListeners.end(); it++) + { + (*it)->onReactionUpdate(chatApi, msgid, reaction, count); + } +} + void MegaChatRoomHandler::fireOnMessageUpdate(MegaChatMessage *msg) { for(set::iterator it = roomListeners.begin(); it != roomListeners.end() ; it++) @@ -5684,6 +5692,11 @@ void MegaChatRoomHandler::onUserTyping(karere::Id user) fireOnChatRoomUpdate(chat); } +void MegaChatRoomHandler::onReactionUpdate(karere::Id msgid, const char *reaction, int count) +{ + fireOnReactionUpdate(msgid, reaction, count); +} + void MegaChatRoomHandler::onUserStopTyping(karere::Id user) { MegaChatRoomPrivate *chat = (MegaChatRoomPrivate *) chatApiImpl->getChatRoom(chatid); diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index 931b7100c..b963f856e 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -456,7 +456,7 @@ class MegaChatRoomHandler :public karere::IApp::IChatHandler void fireOnMessageReceived(MegaChatMessage *msg); void fireOnMessageUpdate(MegaChatMessage *msg); void fireOnHistoryReloaded(MegaChatRoom *chat); - + void fireOnReactionUpdate(MegaChatHandle msgid, const char *reaction, int count); // karere::IApp::IChatHandler implementation #ifndef KARERE_DISABLE_WEBRTC virtual rtcModule::ICallHandler* callHandler(); @@ -500,6 +500,7 @@ class MegaChatRoomHandler :public karere::IApp::IChatHandler virtual void onLastMessageTsUpdated(uint32_t ts); virtual void onHistoryReloaded(); virtual void onChatModeChanged(bool mode); + virtual void onReactionUpdate(karere::Id msgid, const char *reaction, int count); bool isRevoked(MegaChatHandle h); // update access to attachments From eaa977e9c5fc1f6457ce507aebfa0046ef6690d5 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 10:40:22 +0200 Subject: [PATCH 021/100] Add methods to add/remove/retrieve reactions in MegaChatApi --- src/megachatapi.cpp | 25 +++++++++ src/megachatapi.h | 42 ++++++++++++++ src/megachatapi_impl.cpp | 115 +++++++++++++++++++++++++++++++++++++++ src/megachatapi_impl.h | 4 ++ 4 files changed, 186 insertions(+) diff --git a/src/megachatapi.cpp b/src/megachatapi.cpp index 1c0150d73..f79c0a44b 100644 --- a/src/megachatapi.cpp +++ b/src/megachatapi.cpp @@ -1011,6 +1011,26 @@ void MegaChatApi::removeChatNotificationListener(MegaChatNotificationListener *l pImpl->removeChatNotificationListener(listener); } +void MegaChatApi::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +{ + pImpl->addReaction(chatid, msgid, reaction); +} + +void MegaChatApi::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +{ + pImpl->delReaction(chatid, msgid, reaction); +} + +MegaStringList* MegaChatApi::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) +{ + return pImpl->getMessageReactions(chatid, msgid); +} + +MegaHandleList* MegaChatApi::getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +{ + return pImpl->getReactionUsers(chatid, msgid, reaction); +} + MegaChatRequest::~MegaChatRequest() { } MegaChatRequest *MegaChatRequest::copy() { @@ -1515,6 +1535,11 @@ void MegaChatRoomListener::onHistoryReloaded(MegaChatApi * /*api*/, MegaChatRoom } +void MegaChatRoomListener::onReactionUpdate(MegaChatApi* /*api*/, MegaChatHandle /*msgid*/, const char* /*reaction*/, int /*count*/) +{ + +} + MegaChatMessage *MegaChatMessage::copy() const { return NULL; diff --git a/src/megachatapi.h b/src/megachatapi.h index 802f92f9e..a567d9c44 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4573,6 +4573,47 @@ class MegaChatApi */ void removeChatNotificationListener(MegaChatNotificationListener* listener); + /** + * @brief Adds a reaction for a message in a chatroom. + * + * @param chatid MegaChatHandle that identifies the chatroom + * @param msgid MegaChatHandle that identifies the message + * @param reaction UTF-8 NULL terminated string that represents the reaction + */ + void addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + + /** + * @brief Removes a reaction for a message in a chatroom. + * + * @param chatid MegaChatHandle that identifies the chatroom + * @param msgid MegaChatHandle that identifies the message + * @param reaction UTF-8 NULL terminated string that represents the reaction + */ + void delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + + /** + * @brief Gets a list of reactions associated to a message + * You take the ownership of the returned value. + * + * @param chatid MegaChatHandle that identifies the chatroom + * @param msgid MegaChatHandle that identifies the message + * + * @return a list with the reactions associated to a message + */ + mega::MegaStringList* getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid); + + /** + * @brief Gets a list of users that reacted to a message with a specific reaction + * You take the ownership of the returned value. + * + * @param chatid MegaChatHandle that identifies the chatroom + * @param msgid MegaChatHandle that identifies the message + * @param reaction UTF-8 NULL terminated string that represents the reaction + * + * @return a list with the users that reacted to a message with a specific reaction + */ + mega::MegaHandleList* getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + #ifndef KARERE_DISABLE_WEBRTC /** * @brief Register a listener to receive all events about calls @@ -5476,6 +5517,7 @@ class MegaChatRoomListener * @param chat MegaChatRoom whose local history is about to be discarded */ virtual void onHistoryReloaded(MegaChatApi* api, MegaChatRoom *chat); + virtual void onReactionUpdate(MegaChatApi* /*api*/, MegaChatHandle /*msgid*/, const char* /*reaction*/, int /*count*/); }; /** diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 9b01eb0da..2f5e76a65 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4162,6 +4162,117 @@ void MegaChatApiImpl::removeChatNotificationListener(MegaChatNotificationListene sdkMutex.unlock(); } +void MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +{ + sdkMutex.lock(); + ChatRoom *chatroom = findChatRoom(chatid); + if (chatroom) + { + Chat &chat = chatroom->chat(); + Idx index = chat.msgIndexFromId(msgid); + if (index != CHATD_IDX_INVALID) // only confirmed messages have index + { + Message *msg = chat.findOrNull(index); + if (msg) + { + if (!msg->isManagementMessage()) + { + chat.addReaction(msg, reaction); + } + } + else + { + API_LOG_ERROR("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", index, msgid); + } + } + } + sdkMutex.unlock(); +} + +void MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +{ + sdkMutex.lock(); + ChatRoom *chatroom = findChatRoom(chatid); + if (chatroom) + { + Chat &chat = chatroom->chat(); + Idx index = chat.msgIndexFromId(msgid); + if (index != CHATD_IDX_INVALID) // only confirmed messages have index + { + Message *msg = chat.findOrNull(index); + if (msg) + { + if (!msg->isManagementMessage()) + { + chat.delReaction(msg, reaction); + } + } + else + { + API_LOG_ERROR("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", index, msgid); + } + } + } + sdkMutex.unlock(); +} + +MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) +{ + MegaStringList *reacts = NULL; + sdkMutex.lock(); + + ChatRoom *chatroom = findChatRoom(chatid); + if (chatroom) + { + Chat &chat = chatroom->chat(); + Message *msg = findMessage(chatid, msgid); + if (msg) + { + std::vector reactions = msg->getReactions(); + char **reactArray = NULL; + if (reactions.size()) + { + reactArray = new char*[reactions.size()]; + for (int i = 0; i < reactions.size(); ++i) + { + char *device = MegaApi::strdup(reactions[i].c_str()); + reactArray[i] = device; + } + } + reacts = new MegaStringListPrivate(reactArray, reactions.size()); + delete [] reactArray; + } + } + sdkMutex.unlock(); + return reacts; +} + +MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +{ + MegaHandleListPrivate *userList = NULL; + sdkMutex.lock(); + + ChatRoom *chatroom = findChatRoom(chatid); + if (chatroom) + { + Message *msg = findMessage(chatid, msgid); + if (msg) + { + std::vector*users = msg->getReactionUsers(std::string(reaction)); + if (users) + { + userList = new MegaHandleListPrivate(); + for (int i = 0; i < users->size(); ++i) + { + userList->addMegaHandle(users->at(i)); + } + } + } + } + sdkMutex.unlock(); + return userList; +} + IApp::IChatHandler *MegaChatApiImpl::createChatHandler(ChatRoom &room) { return getChatRoomHandler(room.chatid()); @@ -5745,6 +5856,10 @@ void MegaChatRoomHandler::handleHistoryMessage(MegaChatMessage *message) if (message->getType() == MegaChatMessage::TYPE_NODE_ATTACHMENT) { MegaNodeList *nodeList = message->getMegaNodeList(); + if (!nodeList) + { + return; + } for (int i = 0; i < nodeList->size(); i++) { MegaChatHandle h = nodeList->get(i)->getHandle(); diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index b963f856e..91ecdb396 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -1001,6 +1001,8 @@ class MegaChatApiImpl : void removeChatListener(MegaChatListener *listener); void removeChatRoomListener(MegaChatHandle chatid, MegaChatRoomListener *listener); void removeChatNotificationListener(MegaChatNotificationListener *listener); + mega::MegaStringList* getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid); + mega::MegaHandleList* getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); #ifndef KARERE_DISABLE_WEBRTC void addChatCallListener(MegaChatCallListener *listener); void removeChatCallListener(MegaChatCallListener *listener); @@ -1111,6 +1113,8 @@ class MegaChatApiImpl : int loadMessages(MegaChatHandle chatid, int count); bool isFullHistoryLoaded(MegaChatHandle chatid); + void addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + void delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); MegaChatMessage *getMessage(MegaChatHandle chatid, MegaChatHandle msgid); MegaChatMessage *getMessageFromNodeHistory(MegaChatHandle chatid, MegaChatHandle msgid); MegaChatMessage *getManualSendingMessage(MegaChatHandle chatid, MegaChatHandle rowid); From 3e1dee421d610b7a928dd44471b9316b81670bfd Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 10:45:49 +0200 Subject: [PATCH 022/100] Add method to notify reactions updates in QT bindings --- bindings/qt/QTMegaChatEvent.h | 3 ++- bindings/qt/QTMegaChatRoomListener.cpp | 19 +++++++++++++++++++ bindings/qt/QTMegaChatRoomListener.h | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/bindings/qt/QTMegaChatEvent.h b/bindings/qt/QTMegaChatEvent.h index cad3d601c..1ef519988 100644 --- a/bindings/qt/QTMegaChatEvent.h +++ b/bindings/qt/QTMegaChatEvent.h @@ -33,7 +33,8 @@ class QTMegaChatEvent: public QEvent OnAttachmentLoaded, OnAttachmentReceived, OnAttachmentDeleted, - OnAttachmentTruncated + OnAttachmentTruncated, + onReactionUpdated }; QTMegaChatEvent(MegaChatApi *megaChatApi, Type type); diff --git a/bindings/qt/QTMegaChatRoomListener.cpp b/bindings/qt/QTMegaChatRoomListener.cpp index 8eb76890f..d3aaed61a 100644 --- a/bindings/qt/QTMegaChatRoomListener.cpp +++ b/bindings/qt/QTMegaChatRoomListener.cpp @@ -42,6 +42,22 @@ void QTMegaChatRoomListener::onMessageReceived(MegaChatApi *api, MegaChatMessage QCoreApplication::postEvent(this, event, INT_MIN); } +void QTMegaChatRoomListener::onReactionUpdate(MegaChatApi *api, MegaChatHandle msgid, const char *reaction, int count) +{ + QTMegaChatEvent *event = new QTMegaChatEvent(api, (QEvent::Type)QTMegaChatEvent::onReactionUpdated); + event->setChatHandle(msgid); + event->setWidth(count); + if (reaction) + { + size_t size = strlen(reaction) + 1; + char *buf = new char[size]; + memcpy(buf, reaction, size); + event->setBuffer(buf); + } + + QCoreApplication::postEvent(this, event, INT_MIN); +} + void QTMegaChatRoomListener::onMessageUpdate(MegaChatApi *api, MegaChatMessage *msg) { QTMegaChatEvent *event = new QTMegaChatEvent(api, (QEvent::Type)QTMegaChatEvent::OnMessageUpdate); @@ -76,6 +92,9 @@ void QTMegaChatRoomListener::customEvent(QEvent *e) case QTMegaChatEvent::OnHistoryReloaded: if (listener) listener->onHistoryReloaded(event->getMegaChatApi(), event->getChatRoom()); break; + case QTMegaChatEvent::onReactionUpdated: + if (listener) listener->onReactionUpdate(event->getMegaChatApi(), event->getChatHandle(), event->getBuffer(), event->getWidth()); + break; default: break; } diff --git a/bindings/qt/QTMegaChatRoomListener.h b/bindings/qt/QTMegaChatRoomListener.h index ac85f314f..7c17fbb7a 100644 --- a/bindings/qt/QTMegaChatRoomListener.h +++ b/bindings/qt/QTMegaChatRoomListener.h @@ -19,7 +19,7 @@ class QTMegaChatRoomListener : public QObject, public MegaChatRoomListener virtual void onMessageReceived(MegaChatApi* api, MegaChatMessage *msg); virtual void onMessageUpdate(MegaChatApi* api, MegaChatMessage *msg); virtual void onHistoryReloaded(MegaChatApi *api, MegaChatRoom *chat); - + virtual void onReactionUpdate(MegaChatApi *api, MegaChatHandle msgid, const char *reaction, int count); protected: virtual void customEvent(QEvent * event); From 18d3debd573fd9b4e230e4135b4deab10f5064a4 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 11:14:24 +0200 Subject: [PATCH 023/100] Add reaction class to QtApp --- contrib/QtCreator/MEGAChatQt/MEGAChatQt.pro | 9 +- examples/qtmegachatapi/reaction.cpp | 124 ++++++++++++++++++++ examples/qtmegachatapi/reaction.h | 36 ++++++ examples/qtmegachatapi/reaction.ui | 110 +++++++++++++++++ 4 files changed, 276 insertions(+), 3 deletions(-) create mode 100644 examples/qtmegachatapi/reaction.cpp create mode 100644 examples/qtmegachatapi/reaction.h create mode 100644 examples/qtmegachatapi/reaction.ui diff --git a/contrib/QtCreator/MEGAChatQt/MEGAChatQt.pro b/contrib/QtCreator/MEGAChatQt/MEGAChatQt.pro index e8ef34c76..19beb4ee7 100644 --- a/contrib/QtCreator/MEGAChatQt/MEGAChatQt.pro +++ b/contrib/QtCreator/MEGAChatQt/MEGAChatQt.pro @@ -37,7 +37,8 @@ SOURCES += ../../../examples/qtmegachatapi/MegaChatApplication.cpp \ ../../../examples/qtmegachatapi/chatMessage.cpp \ ../../../examples/qtmegachatapi/chatGroupDialog.cpp \ ../../../examples/qtmegachatapi/listItemController.cpp \ - ../../../examples/qtmegachatapi/SettingWindow.cpp + ../../../examples/qtmegachatapi/SettingWindow.cpp \ + ../../../examples/qtmegachatapi/reaction.cpp HEADERS += ../../../examples/qtmegachatapi/MegaChatApplication.h \ ../../../examples/qtmegachatapi/MainWindow.h \ @@ -52,7 +53,8 @@ HEADERS += ../../../examples/qtmegachatapi/MegaChatApplication.h \ ../../../examples/qtmegachatapi/chatMessage.h \ ../../../examples/qtmegachatapi/chatGroupDialog.h \ ../../../examples/qtmegachatapi/listItemController.h \ - ../../../examples/qtmegachatapi/SettingWindow.h + ../../../examples/qtmegachatapi/SettingWindow.h \ + ../../../examples/qtmegachatapi/reaction.h FORMS += ../../../examples/qtmegachatapi/LoginDialog.ui \ ../../../examples/qtmegachatapi/MainWindow.ui \ @@ -61,7 +63,8 @@ FORMS += ../../../examples/qtmegachatapi/LoginDialog.ui \ ../../../examples/qtmegachatapi/settingsDialog.ui \ ../../../examples/qtmegachatapi/chatMessageWidget.ui \ ../../../examples/qtmegachatapi/chatGroupDialog.ui \ - ../../../examples/qtmegachatapi/SettingWindow.ui + ../../../examples/qtmegachatapi/SettingWindow.ui \ + ../../../examples/qtmegachatapi/reaction.ui CONFIG(USE_WEBRTC) { SOURCES += ../../../examples/qtmegachatapi/callGui.cpp \ diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp new file mode 100644 index 000000000..6bb35c435 --- /dev/null +++ b/examples/qtmegachatapi/reaction.cpp @@ -0,0 +1,124 @@ +#include +#include +#include "reaction.h" +#include "ui_reaction.h" + +Reaction::Reaction(ChatMessage *parent, const char *reactionString, int count) : + QWidget((QWidget *)parent), + ui(new Ui::Reaction) +{ + mChatMessage = parent; + ui->setupUi(this); + mCount = count; + mReactionString = reactionString ? reactionString :std::string(); + + QString text(mReactionString.c_str()); + text.append(" ") + .append(std::to_string(count).c_str()); + + ui->mReaction->setText(text); + setAttribute(::Qt::WA_Hover, true); +} + +Reaction::~Reaction() +{ + delete ui; +} + +void Reaction::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu menu(this); + auto actAdd = menu.addAction(tr("Add reaction")); + connect(actAdd, SIGNAL(triggered()), this, SLOT(onAddReact())); + auto actRemove = menu.addAction(tr("Remove reaction")); + connect(actRemove, SIGNAL(triggered()), this, SLOT(onRemoveReact())); + auto actCopy = menu.addAction(tr("Copy UTF-8")); + connect(actCopy, SIGNAL(triggered()), this, SLOT(onCopyReact())); + + QPoint pos = ui->mReaction->pos(); + pos.setX(pos.x() + ui->mReaction->width()); + pos.setY(pos.y() + ui->mReaction->height()); + menu.exec(mapToGlobal(pos)); + menu.deleteLater(); +} + +std::string Reaction::getReactionString() const +{ + return mReactionString; +} + +void Reaction::updateReactionCount(int count) +{ + if (!count) + { + return; + } + + mCount = count; + QString text(mReactionString.c_str()); + text.append(" ") + .append(std::to_string(count).c_str()); + + ui->mReaction->setText(text.toStdString().c_str()); +} + +void Reaction::onCopyReact() +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(mReactionString.c_str()); +} + +void Reaction::onRemoveReact() +{ + ChatWindow *chatwindow = mChatMessage->getChatWindow(); + if (!chatwindow) + { + return; + } + + MegaChatHandle chatid = mChatMessage->getChatId(); + MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); + const char *reaction = mReactionString.c_str(); + chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction); +} + +void Reaction::onAddReact() +{ + ChatWindow *chatwindow = mChatMessage->getChatWindow(); + if (!chatwindow) + { + return; + } + + MegaChatHandle chatid = mChatMessage->getChatId(); + MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); + const char *reaction = mReactionString.c_str(); + chatwindow->getMegaChatApi()->addReaction(chatid, msgid, reaction); +} + +void Reaction::enterEvent(QEvent *event) +{ + megachat::MegaChatApi *megachatApi = mChatMessage->getMegaChatApi(); + std::unique_ptr <::mega::MegaHandleList> users (megachatApi->getReactionUsers(mChatMessage->getChatId(), mChatMessage->getMessage()->getMsgId(), mReactionString.c_str())); + std::unique_ptr chatRoom(megachatApi->getChatRoom(mChatMessage->getChatId())); + if (!megachatApi || !users || !chatRoom) + { + return; + } + + QString text; + for (unsigned int i = 0; i < users->size(); i++) + { + const char *autorizationToken = chatRoom->getAuthorizationToken(); + const char *firstName = mChatMessage->getChatWindow()->getMainWin()->getApp()->getFirstname(users->get(i), autorizationToken); + + if (firstName) + { + text.append(firstName).append("\n"); + } + + delete [] autorizationToken; + delete [] firstName; + } + ui->mReaction->setToolTip(text); +} diff --git a/examples/qtmegachatapi/reaction.h b/examples/qtmegachatapi/reaction.h new file mode 100644 index 000000000..6d4c72bda --- /dev/null +++ b/examples/qtmegachatapi/reaction.h @@ -0,0 +1,36 @@ +#ifndef REACTION_H +#define REACTION_H + +#include +#include "chatMessage.h" + +class ChatMessage; +namespace Ui { +class Reaction; +} + +class Reaction : public QWidget +{ + Q_OBJECT + +public: + Reaction(ChatMessage *parent, const char *reactionString, int count = 0); + ~Reaction(); + void contextMenuEvent(QContextMenuEvent *event); + std::string getReactionString() const; + void updateReactionCount(int mCount); + void enterEvent(QEvent * event); + +private: + Ui::Reaction *ui; + ChatMessage *mChatMessage; + std::string mReactionString; + int mCount; + +public slots: + void onCopyReact(); + void onRemoveReact(); + void onAddReact(); +}; + +#endif // REACTION_H diff --git a/examples/qtmegachatapi/reaction.ui b/examples/qtmegachatapi/reaction.ui new file mode 100644 index 000000000..67bbc02bf --- /dev/null +++ b/examples/qtmegachatapi/reaction.ui @@ -0,0 +1,110 @@ + + + Reaction + + + + 0 + 0 + 60 + 35 + + + + + 60 + 35 + + + + + 60 + 35 + + + + Qt::DefaultContextMenu + + + Form + + + + + + 2 + + + + + + + + 0 + 0 + 60 + 35 + + + + + 60 + 35 + + + + + 0 + 0 + + + + + DejaVu Sans + 10 + + + + -2 + + + Qt::LeftToRight + + + + QLabel + { + border: 2px solid blue; + border-radius: 10px; + margin: 6px; + } + QLabel:hover + { + border: 2px solid red; + border-radius: 10px; + } + + + + X + + + true + + + Qt::AlignCenter + + + false + + + 1 + + + -1 + + + + + + From 55d79bf9a21df3652a3de54b7e31c68a28380191 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 11:19:09 +0200 Subject: [PATCH 024/100] Add condition to protect in addReaction/delReaction/getReactionUsers --- src/megachatapi.h | 6 ++++-- src/megachatapi_impl.cpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/megachatapi.h b/src/megachatapi.h index a567d9c44..25d532f6e 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4598,7 +4598,8 @@ class MegaChatApi * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message * - * @return a list with the reactions associated to a message + * @return return a list with the reactions associated to a message. If there's no reactions + * associated to the message return NULL. */ mega::MegaStringList* getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid); @@ -4610,7 +4611,8 @@ class MegaChatApi * @param msgid MegaChatHandle that identifies the message * @param reaction UTF-8 NULL terminated string that represents the reaction * - * @return a list with the users that reacted to a message with a specific reaction + * @return return a list with the users that reacted to a message with a specific reaction. + * If the reaction doesn't exists for this message return NULL. */ mega::MegaHandleList* getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 2f5e76a65..46f44217f 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4164,6 +4164,11 @@ void MegaChatApiImpl::removeChatNotificationListener(MegaChatNotificationListene void MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { + if (!reaction) + { + return; + } + sdkMutex.lock(); ChatRoom *chatroom = findChatRoom(chatid); if (chatroom) @@ -4191,6 +4196,11 @@ void MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, c void MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { + if (!reaction) + { + return; + } + sdkMutex.lock(); ChatRoom *chatroom = findChatRoom(chatid); if (chatroom) @@ -4249,6 +4259,11 @@ MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, Mega MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { + if (!reaction) + { + return NULL; + } + MegaHandleListPrivate *userList = NULL; sdkMutex.lock(); From 96ef55620936c37bdf6a45a09351558fbf7d1ec4 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 11:22:31 +0200 Subject: [PATCH 025/100] Add a list of predefined reactions in QtApp settings --- examples/qtmegachatapi/uiSettings.cpp | 13 +++++++++++++ examples/qtmegachatapi/uiSettings.h | 1 + 2 files changed, 14 insertions(+) diff --git a/examples/qtmegachatapi/uiSettings.cpp b/examples/qtmegachatapi/uiSettings.cpp index a332d409e..ea67661ff 100644 --- a/examples/qtmegachatapi/uiSettings.cpp +++ b/examples/qtmegachatapi/uiSettings.cpp @@ -21,3 +21,16 @@ QColor gAvatarColors[16] = { "cadetblue", "#db00d3", "darkturquoise", "lightblue", "honeydew", "lightyellow", "violet", "turquoise" }; + +QStringList utf8reactionsList = { + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 80")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 81")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 82")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 83")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 84")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 85")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 86")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 87")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 88")), + QString::fromUtf8(QByteArray::fromHex("F0 9F 98 89")) +}; diff --git a/examples/qtmegachatapi/uiSettings.h b/examples/qtmegachatapi/uiSettings.h index f6052e6a1..dd7d50561 100644 --- a/examples/qtmegachatapi/uiSettings.h +++ b/examples/qtmegachatapi/uiSettings.h @@ -7,4 +7,5 @@ extern QChar kOnlineSymbol_InProgress; extern QChar kOnlineSymbol_Set; extern QString kOnlineStatusBtnStyle; + extern QStringList utf8reactionsList; #endif // UI_SETTINGS_H From b06711ff2ad472a7457e853a09392f8366f3d69b Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 12:56:46 +0200 Subject: [PATCH 026/100] Add support for reactions in ChatMessage class in QtApp - Add widget to show reactions --- examples/qtmegachatapi/chatMessage.cpp | 108 ++++++++++++++++++++ examples/qtmegachatapi/chatMessage.h | 11 ++ examples/qtmegachatapi/chatMessageWidget.ui | 27 +++++ 3 files changed, 146 insertions(+) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 95b020d67..29a7279b0 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -3,6 +3,7 @@ #include "ui_chatMessageWidget.h" #include #include +#include "uiSettings.h" const char *messageStatus[] = { @@ -35,6 +36,19 @@ ChatMessage::ChatMessage(ChatWindow *parent, megachat::MegaChatApi *mChatApi, me delete chatRoom; updateContent(); + std::unique_ptr<::mega::MegaStringList> reactions(mChatWindow->mMegaChatApi->getMessageReactions(mChatId, mMessage->getMsgId())); + if (reactions) + { + for (int i = 0; i < reactions->size(); i++) + { + std::unique_ptr<::mega::MegaHandleList> users(megaChatApi->getReactionUsers(this->mChatId, this->mMessage->getMsgId(),reactions->get(i))); + int count = users ? users->size() : 0; + Reaction *reaction = new Reaction(this, reactions->get(i), count); + ui->mReactions->layout()->addWidget(reaction); + mReactions.emplace_back(std::shared_ptr(reaction)); + } + } + connect(ui->mMsgDisplay, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onMessageCtxMenu(const QPoint&))); updateToolTip(); show(); @@ -42,10 +56,43 @@ ChatMessage::ChatMessage(ChatWindow *parent, megachat::MegaChatApi *mChatApi, me ChatMessage::~ChatMessage() { + clearReactions(); delete mMessage; delete ui; } +void ChatMessage::updateReaction(const char *reaction, int count) +{ + bool found = false; + for (int i = 0; i < mReactions.size(); i++) + { + std::shared_ptr r = mReactions.at(i); + if (r && r->getReactionString().compare(reaction) == 0) + { + found = true; + if (count == 0) + { + QLayoutItem *item = ui->mReactions->layout()->takeAt(i); + if (item) + { + item->widget()->deleteLater(); + delete item; + } + mReactions.erase(mReactions.begin() + i); + } + r->updateReactionCount(count); + break; + } + } + + if (!found && count) + { + Reaction *r = new Reaction(this, reaction, count); + ui->mReactions->layout()->addWidget(r); + mReactions.emplace_back(std::shared_ptr(r)); + } +} + void ChatMessage::updateToolTip() { QString tooltip; @@ -177,6 +224,11 @@ QString ChatMessage::nodelistText() { QString text; ::mega::MegaNodeList *nodeList = mMessage->getMegaNodeList(); + if (!nodeList) + { + return text; + } + for(int i = 0; i < nodeList->size(); i++) { const char *auxNodeHandle_64 = mChatWindow->mMegaApi->handleToBase64(nodeList->get(i)->getHandle()); @@ -193,6 +245,32 @@ QString ChatMessage::nodelistText() return text; } +megachat::MegaChatHandle ChatMessage::getChatId() const +{ + return mChatId; +} + +megachat::MegaChatApi *ChatMessage::getMegaChatApi() const +{ + return megaChatApi; +} + +ChatWindow *ChatMessage::getChatWindow() const +{ + return mChatWindow; +} + +void ChatMessage::clearReactions() +{ + QLayoutItem *item; + while ((item = ui->mReactions->layout()->takeAt(0)) != NULL) + { + item->widget()->deleteLater(); + delete item; + } + mReactions.clear(); +} + void ChatMessage::updateContent() { if (mMessage->isEdited()) @@ -481,6 +559,21 @@ void ChatMessage::markAsEdited() void ChatMessage::onMessageCtxMenu(const QPoint& point) { QMenu *menu = ui->mMsgDisplay->createStandardContextMenu(point); + if (!mMessage->isManagementMessage()) + { + QMenu *reactMenu = menu->addMenu("Add reaction"); + for (int i = 0; i < utf8reactionsList.size(); i++) + { + std::string react = utf8reactionsList.at(i).toStdString(); + auto actR = reactMenu->addAction(tr(react.c_str())); + connect(actR, &QAction::triggered, this, [=](){onMessageAddReaction(react.c_str());}); + } + + auto action = menu->addAction(tr("Add reaction (CUSTOM)")); + action->setData(QVariant::fromValue(this)); + connect(action, SIGNAL(triggered()), this, SLOT(onMessageAddReaction())); + } + if (isMine() && !mMessage->isManagementMessage()) { if (mMessage->isEditable()) @@ -523,6 +616,21 @@ void ChatMessage::onMessageEditAction() startEditingMsgWidget(); } +void ChatMessage::onMessageAddReaction(const char *reactionStr) +{ + QString reaction = reactionStr + ? reactionStr + : mChatWindow->mMainWin->mApp->getText("Add reaction").c_str(); + + if (reaction.isEmpty()) + { + return; + } + + std::string utfstring = reaction.toUtf8().toStdString(); + mChatWindow->mMegaChatApi->addReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); +} + void ChatMessage::onMessageRemoveLinkAction() { megaChatApi->removeRichLink(mChatId, mMessage->getMsgId()); diff --git a/examples/qtmegachatapi/chatMessage.h b/examples/qtmegachatapi/chatMessage.h index 26780e813..a753530cf 100644 --- a/examples/qtmegachatapi/chatMessage.h +++ b/examples/qtmegachatapi/chatMessage.h @@ -1,13 +1,17 @@ #ifndef CHATMESSAGE_H #define CHATMESSAGE_H +#include #include #include #include #include "megachatapi.h" #include "ui_chatMessageWidget.h" #include "chatWindow.h" +#include "reaction.h" + class ChatWindow; +class Reaction; namespace Ui { class ChatMessageWidget; } @@ -26,6 +30,7 @@ class ChatMessage: public QWidget QListWidgetItem *mListWidgetItem; ChatWindow *mChatWindow; friend class ChatWindow; + std::vector > mReactions; public: ChatMessage(ChatWindow *window, megachat::MegaChatApi *mChatApi, megachat::MegaChatHandle mChatId, megachat::MegaChatMessage *msg); @@ -47,6 +52,11 @@ class ChatMessage: public QWidget void setMessage(megachat::MegaChatMessage *message); void clearEdit(); void setManualMode(bool manualMode); + ChatWindow *getChatWindow() const; + megachat::MegaChatApi *getMegaChatApi() const; + megachat::MegaChatHandle getChatId() const; + void updateReaction(const char *reaction, int count); + void clearReactions(); public slots: void onDiscardManualSending(); @@ -56,6 +66,7 @@ class ChatMessage: public QWidget void onMessageCtxMenu(const QPoint& point); void onMessageDelAction(); void onMessageEditAction(); + void onMessageAddReaction(const char *reactionStr = NULL); void onMessageRemoveLinkAction(); void onNodeDownloadOrImport(mega::MegaNode *node, bool import); void onNodePlay(::mega::MegaNode *node); diff --git a/examples/qtmegachatapi/chatMessageWidget.ui b/examples/qtmegachatapi/chatMessageWidget.ui index f1f481a65..2b86ea67a 100644 --- a/examples/qtmegachatapi/chatMessageWidget.ui +++ b/examples/qtmegachatapi/chatMessageWidget.ui @@ -298,6 +298,33 @@ p, li { white-space: pre-wrap; } + + + + + 40 + 40 + + + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + + From 8381c884ccda0638f5bc7154df662fdfc19c480c Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 13:00:22 +0200 Subject: [PATCH 027/100] Implement onReactionUpdate in ChatWindow class - Clean all reactions upon reception of chat truncate --- examples/qtmegachatapi/chatWindow.cpp | 15 +++++++++++++++ examples/qtmegachatapi/chatWindow.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/examples/qtmegachatapi/chatWindow.cpp b/examples/qtmegachatapi/chatWindow.cpp index 7d4af0fae..2ee0ab57d 100644 --- a/examples/qtmegachatapi/chatWindow.cpp +++ b/examples/qtmegachatapi/chatWindow.cpp @@ -359,6 +359,7 @@ void ChatWindow::truncateChatUI() for (itMessages = mMsgsWidgetsMap.begin(); itMessages != mMsgsWidgetsMap.end(); itMessages++) { ChatMessage *auxMessage = itMessages->second; + auxMessage->clearReactions(); int row = ui->mMessageList->row(auxMessage->getWidgetItem()); QListWidgetItem *auxItem = ui->mMessageList->takeItem(row); mMsgsWidgetsMap.erase(itMessages); @@ -427,6 +428,11 @@ ChatListItemController *ChatWindow::getChatItemController() { mMainWin->getChatControllerById(mChatRoom->getChatId()); } + +MainWindow *ChatWindow::getMainWin() const +{ + return mMainWin; +} #endif void ChatWindow::onMessageReceived(megachat::MegaChatApi*, megachat::MegaChatMessage *msg) @@ -498,6 +504,15 @@ void ChatWindow::onHistoryReloaded(megachat::MegaChatApi *, megachat::MegaChatRo truncateChatUI(); } +void ChatWindow::onReactionUpdate(megachat::MegaChatApi *, megachat::MegaChatHandle msgid, const char *reaction, int count) +{ + ChatMessage *msg = findChatMessage(msgid); + if (msg) + { + msg->updateReaction(reaction, count); + } +} + void ChatWindow::onAttachmentLoaded(MegaChatApi */*api*/, MegaChatMessage *msg) { if (msg) diff --git a/examples/qtmegachatapi/chatWindow.h b/examples/qtmegachatapi/chatWindow.h index d8757f731..21404b5f1 100644 --- a/examples/qtmegachatapi/chatWindow.h +++ b/examples/qtmegachatapi/chatWindow.h @@ -50,6 +50,7 @@ class ChatWindow : public QDialog, void onMessageUpdate(megachat::MegaChatApi *api, megachat::MegaChatMessage *msg); void onMessageLoaded(megachat::MegaChatApi *api, megachat::MegaChatMessage *msg); void onHistoryReloaded(megachat::MegaChatApi *api, megachat::MegaChatRoom *chat); + void onReactionUpdate(megachat::MegaChatApi *, megachat::MegaChatHandle msgid, const char *reaction, int count); void onAttachmentLoaded(MegaChatApi *api, MegaChatMessage *msg); void onAttachmentReceived(MegaChatApi *api, MegaChatMessage *msg); void onAttachmentDeleted(MegaChatApi *api, MegaChatHandle msgid); @@ -85,6 +86,7 @@ class ChatWindow : public QDialog, void setCallGui(CallGui *callGui); #endif ChatListItemController *getChatItemController(); + MainWindow *getMainWin() const; protected: Ui::ChatWindowUi *ui; From 258691165e76a9f74243abd7affed31591f85acb Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 13:04:03 +0200 Subject: [PATCH 028/100] Check if chatroom is not NULL in getLastMessageSenderName and updateToolTip --- examples/qtmegachatapi/chatItemWidget.cpp | 24 +++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/examples/qtmegachatapi/chatItemWidget.cpp b/examples/qtmegachatapi/chatItemWidget.cpp index 0fc54cc8f..99b0ce3bb 100644 --- a/examples/qtmegachatapi/chatItemWidget.cpp +++ b/examples/qtmegachatapi/chatItemWidget.cpp @@ -84,9 +84,14 @@ ChatItemWidget::ChatItemWidget(MainWindow *mainWindow, const megachat::MegaChatL void ChatItemWidget::updateToolTip(const megachat::MegaChatListItem *item, const char *author) { + megachat::MegaChatRoom *chatRoom = mMegaChatApi->getChatRoom(mChatId); + if (!chatRoom) + { + return; + } + QString text = NULL; std::string senderHandle; - megachat::MegaChatRoom *chatRoom = mMegaChatApi->getChatRoom(mChatId); megachat::MegaChatHandle lastMessageId = item->getLastMessageId(); int lastMessageType = item->getLastMessageType(); std::string lastMessage; @@ -324,15 +329,18 @@ const char *ChatItemWidget::getLastMessageSenderName(megachat::MegaChatHandle ms else { megachat::MegaChatRoom *chatRoom = this->mMegaChatApi->getChatRoom(mChatId); - const char *msg = chatRoom->getPeerFirstnameByHandle(msgUserId); - size_t len = msg ? strlen(msg) : 0; - if (len) + if (chatRoom) { - msgAuthor = new char[len + 1]; - strncpy(msgAuthor, msg, len); - msgAuthor[len] = '\0'; + const char *msg = chatRoom->getPeerFirstnameByHandle(msgUserId); + size_t len = msg ? strlen(msg) : 0; + if (len) + { + msgAuthor = new char[len + 1]; + strncpy(msgAuthor, msg, len); + msgAuthor[len] = '\0'; + } + delete chatRoom; } - delete chatRoom; } return msgAuthor; } From b060286d720977ab4189af1a22abe37ea72bc482 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 17:07:37 +0200 Subject: [PATCH 029/100] Adjust reactionEncrypt to accept reaction as std::string in order to be captured in promise - Code styling --- src/chatd.cpp | 10 ++++++---- src/chatdICrypto.h | 4 ++-- src/strongvelope/strongvelope.cpp | 15 +++++++-------- src/strongvelope/strongvelope.h | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 9972d9056..c5ff519ab 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2563,13 +2563,14 @@ void Chat::sendSync() void Chat::addReaction(Message *message, const char *reaction) { + std::string reactionString (reaction, strlen(reaction)); auto wptr = weakHandle(); - marshallCall([wptr, this, message, reaction]() + marshallCall([wptr, this, message, &reactionString]() { if (wptr.deleted()) return; - mCrypto->reactionEncrypt(message, reaction) + mCrypto->reactionEncrypt(message, reactionString) .then([this, wptr, message](std::shared_ptr data) { if (wptr.deleted()) @@ -2587,13 +2588,14 @@ void Chat::addReaction(Message *message, const char *reaction) void Chat::delReaction(Message *message, const char *reaction) { + std::string reactionString (reaction, strlen(reaction)); auto wptr = weakHandle(); - marshallCall([wptr, this, message, reaction]() + marshallCall([wptr, this, message, &reactionString]() { if (wptr.deleted()) return; - mCrypto->reactionEncrypt(message, reaction) + mCrypto->reactionEncrypt(message, reactionString) .then([this, wptr, message](std::shared_ptr data) { if (wptr.deleted()) diff --git a/src/chatdICrypto.h b/src/chatdICrypto.h index 78fa445ac..1be6a1746 100644 --- a/src/chatdICrypto.h +++ b/src/chatdICrypto.h @@ -164,7 +164,7 @@ class ICrypto * @param reaction An UTF-8 string. */ virtual promise::Promise> - reactionEncrypt(Message* msg, const char *reaction) = 0; + reactionEncrypt(Message *msg, std::string reaction) = 0; /** * @brief Decrypts a reaction with xxtea. @@ -172,7 +172,7 @@ class ICrypto * @param reaction The encrypted reaction. */ virtual promise::Promise> - reactionDecrypt(Message* msg, std::string reaction) = 0; + reactionDecrypt(Message *msg, std::string reaction) = 0; /** * @brief The crypto module is destroyed when that chatid is left or the client is destroyed diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 5751b8af3..09409ed20 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -625,7 +625,7 @@ ProtocolHandler::ProtocolHandler(karere::Id ownHandle, } promise::Promise> -ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) +ProtocolHandler::reactionEncrypt(Message *msg, std::string reaction) { promise::Promise> symPms; if (isPublicChat()) @@ -638,10 +638,9 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) } auto wptr = weakHandle(); - return symPms.then([this, wptr, msg, reaction](const std::shared_ptr& data) + return symPms.then([this, wptr, msg, &reaction](const std::shared_ptr& data) { std::string msgId = msg->id().toString(); - std::string react (reaction, strlen(reaction)); std::string keyBin (data->buf(), data->dataSize()); // Inside this function str_to_a32 and a32_to_str calls must be done with type = @@ -656,13 +655,13 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) } // Add padding to reaction - size_t roundSize = ceil(static_cast(react.size()) / 4) * 4; - size_t diff = roundSize - react.size(); + size_t roundSize = ceil(static_cast(reaction.size()) / 4) * 4; + size_t diff = roundSize - reaction.size(); if (diff > 0) { for (int i = 0; i < diff; i++) { - react.insert(react.begin(), '\0'); + reaction.insert(reaction.begin(), '\0'); } } @@ -670,7 +669,7 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) size_t emojiLen = roundSize + 4; char plaintext [emojiLen]; memcpy(plaintext, msgId.data(), 4); - memcpy(plaintext + 4, react.data(), roundSize); + memcpy(plaintext + 4, reaction.data(), roundSize); // emoji32 std::vector emoji32 = ::mega::Utils::str_to_a32(std::string(plaintext, emojiLen)); @@ -691,7 +690,7 @@ ProtocolHandler::reactionEncrypt(Message* msg, const char *reaction) } promise::Promise> -ProtocolHandler::reactionDecrypt(Message* msg, std::string reaction) +ProtocolHandler::reactionDecrypt(Message *msg, std::string reaction) { promise::Promise> symPms; if (isPublicChat()) diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index 10759936f..9b330ce7a 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -456,10 +456,10 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable virtual void setPublicHandle(const uint64_t ph); virtual promise::Promise> - reactionEncrypt(chatd::Message* msg, const char *reaction); + reactionEncrypt(chatd::Message *msg, std::string reaction); virtual promise::Promise> - reactionDecrypt(chatd::Message* msg, std::string reaction); + reactionDecrypt(chatd::Message *msg, std::string reaction); }; } namespace chatd From 20091eac1277a48bfbf55aa98252b347d4587044 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 17:17:12 +0200 Subject: [PATCH 030/100] Encode reactions to B64 for chatd logs entries --- src/chatd.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index c5ff519ab..174d8117f 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1369,7 +1369,7 @@ string Command::toString(const StaticBuffer& data) tmpString.append(", len: "); tmpString.append(std::to_string(len)); tmpString.append(", reaction: "); - tmpString.append(std::string(reaction, len)); + tmpString.append(base64urlencode(reaction, len)); return tmpString; } case OP_DELREACTION: @@ -1380,6 +1380,7 @@ string Command::toString(const StaticBuffer& data) karere::Id msgid = data.read(17); int8_t len = data.read(25); const char *reaction = data.readPtr(26, len); + tmpString.append("DELREACTION chatid: "); tmpString.append(ID_CSTR(chatid)); tmpString.append(", userid: "); @@ -1389,7 +1390,7 @@ string Command::toString(const StaticBuffer& data) tmpString.append(", len: "); tmpString.append(std::to_string(len)); tmpString.append(", reaction: "); - tmpString.append(std::string(reaction, len)); + tmpString.append(base64urlencode(reaction, len)); return tmpString; } case OP_REACTIONSN: @@ -2236,7 +2237,8 @@ void Connection::execCommand(const StaticBuffer& buf) pos += payloadLen; CHATDS_LOG_DEBUG("%s: recv ADDREACTION from user %s to message %s reaction %s", - ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction.c_str()); + ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), + base64urlencode(reaction.data(), reaction.size()).c_str()); auto& chat = mChatdClient.chats(chatid); chat.onAddReaction(msgid, userid, reaction); @@ -2252,7 +2254,8 @@ void Connection::execCommand(const StaticBuffer& buf) pos += payloadLen; CHATDS_LOG_DEBUG("%s: recv DELREACTION from user %s to message %s reaction %s", - ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), reaction.c_str()); + ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), + base64urlencode(reaction.data(), reaction.size()).c_str()); auto& chat = mChatdClient.chats(chatid); chat.onDelReaction(msgid, userid, reaction); From 33e6a71e7a9354142abd8066e38f7ee15719f91e Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 17:18:49 +0200 Subject: [PATCH 031/100] Adjust utf8reactionsList format --- examples/qtmegachatapi/uiSettings.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/qtmegachatapi/uiSettings.cpp b/examples/qtmegachatapi/uiSettings.cpp index ea67661ff..21515669c 100644 --- a/examples/qtmegachatapi/uiSettings.cpp +++ b/examples/qtmegachatapi/uiSettings.cpp @@ -23,14 +23,14 @@ QColor gAvatarColors[16] = { }; QStringList utf8reactionsList = { - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 80")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 81")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 82")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 83")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 84")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 85")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 86")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 87")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 88")), - QString::fromUtf8(QByteArray::fromHex("F0 9F 98 89")) + QString::fromUtf8("\xF0\x9F\x98\x80"), + QString::fromUtf8("\xF0\x9F\x98\x81"), + QString::fromUtf8("\xF0\x9F\x98\x82"), + QString::fromUtf8("\xF0\x9F\x98\x83"), + QString::fromUtf8("\xF0\x9F\x98\x84"), + QString::fromUtf8("\xF0\x9F\x98\x85"), + QString::fromUtf8("\xF0\x9F\x98\x86"), + QString::fromUtf8("\xF0\x9F\x98\x87"), + QString::fromUtf8("\xF0\x9F\x98\x88"), + QString::fromUtf8("\xF0\x9F\x98\x89") }; From 712c70a43441af8ccb085bc98f391bc3d128aa84 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 29 Aug 2019 17:20:43 +0200 Subject: [PATCH 032/100] Add getter to return MegachatApplication --- examples/qtmegachatapi/MainWindow.cpp | 5 +++++ examples/qtmegachatapi/MainWindow.h | 1 + 2 files changed, 6 insertions(+) diff --git a/examples/qtmegachatapi/MainWindow.cpp b/examples/qtmegachatapi/MainWindow.cpp index b1f4d33a1..32c925999 100644 --- a/examples/qtmegachatapi/MainWindow.cpp +++ b/examples/qtmegachatapi/MainWindow.cpp @@ -281,6 +281,11 @@ void MainWindow::onChatCallUpdate(megachat::MegaChatApi */*api*/, megachat::Mega } } +MegaChatApplication* MainWindow::getApp() const +{ + return mApp; +} + #endif ChatWindow *MainWindow::getChatWindowIfExists(MegaChatHandle chatId) diff --git a/examples/qtmegachatapi/MainWindow.h b/examples/qtmegachatapi/MainWindow.h index e932736d4..bf6e0125b 100644 --- a/examples/qtmegachatapi/MainWindow.h +++ b/examples/qtmegachatapi/MainWindow.h @@ -164,6 +164,7 @@ class MainWindow : #ifndef KARERE_DISABLE_WEBRTC void onChatCallUpdate(megachat::MegaChatApi *api, megachat::MegaChatCall *call); #endif + MegaChatApplication* getApp() const; protected: MegaLoggerApplication *mLogger; From 28b8659d9ffc9a310d1827d34947f0a031821bcd Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Fri, 30 Aug 2019 14:49:16 +0200 Subject: [PATCH 033/100] Don't persist reactions in cache for public chatrooms in preview mode --- src/chatd.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 174d8117f..36ee19142 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1756,8 +1756,7 @@ Chat::Chat(Connection& conn, Id chatid, Listener* listener, mLastReceivedId = info.lastRecvId; mLastSeenIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastSeenId); mLastReceivedIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastReceivedId); - - std::string rsn(mDbInterface->getReactionSn()); + std::string rsn = (!this->previewMode()) ? mDbInterface->getReactionSn() : std::string(); mReactionSn = (!rsn.empty()) ? Id(rsn.data(), rsn.size()) : Id::inval(); if ((mHaveAllHistory = mDbInterface->chatVar("have_all_history"))) @@ -4173,7 +4172,10 @@ void Chat::handleTruncate(const Message& msg, Idx idx) } // clean all reactions for this chat in DB - CALL_DB(cleanReactions); + if (!previewMode()) + { + CALL_DB(cleanReactions); + } // update last-seen pointer if (mLastSeenIdx != CHATD_IDX_INVALID) @@ -4870,7 +4872,11 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) std::string reaction (data->buf(), data->bufSize()); message->addReaction(reaction, userId); - CALL_DB(addReaction, message->mId, userId, reaction.c_str()); + + if (!previewMode()) + { + CALL_DB(addReaction, message->mId, userId, reaction.c_str()); + } std::vector *users = message->getReactionUsers(reaction); int count = users ? users->size() : 0; @@ -4914,8 +4920,11 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) std::string reaction (data->buf(), data->bufSize()); message->delReaction(reaction, userId); - CALL_DB(delReaction, message->mId, userId, reaction.c_str()); + if (!previewMode()) + { + CALL_DB(delReaction, message->mId, userId, reaction.c_str()); + } std::vector *users = message->getReactionUsers(reaction); int count = users ? users->size() : 0; @@ -4935,7 +4944,10 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) void Chat::onReactionSn(Id rsn) { mReactionSn = rsn; - CALL_DB(setReactionSn, mReactionSn.toString()); + if (!previewMode()) + { + CALL_DB(setReactionSn, mReactionSn.toString()); + } } void Chat::onPreviewersUpdate(uint32_t numPrev) From 49fbe01b6e4c3c22a0e0fa4a730a01955f65b2c9 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Mon, 2 Sep 2019 15:03:50 +0200 Subject: [PATCH 034/100] Capture reaction properly in marshallcall --- src/chatd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index eae469493..b7358f648 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2567,7 +2567,7 @@ void Chat::addReaction(Message *message, const char *reaction) { std::string reactionString (reaction, strlen(reaction)); auto wptr = weakHandle(); - marshallCall([wptr, this, message, &reactionString]() + marshallCall([wptr, this, message, reactionString]() { if (wptr.deleted()) return; @@ -2592,7 +2592,7 @@ void Chat::delReaction(Message *message, const char *reaction) { std::string reactionString (reaction, strlen(reaction)); auto wptr = weakHandle(); - marshallCall([wptr, this, message, &reactionString]() + marshallCall([wptr, this, message, reactionString]() { if (wptr.deleted()) return; From 1dcf24a0c10f6bd9ce545e1d6c4a8b7f3ab95c6f Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Mon, 2 Sep 2019 15:39:54 +0200 Subject: [PATCH 035/100] Adjust add/delReaction methods to return an errorcode Add method to check if a specific reaction has been added previously or not. --- src/chatdMsg.h | 13 +++++ src/megachatapi.cpp | 8 +-- src/megachatapi.h | 38 ++++++++++++++- src/megachatapi_impl.cpp | 102 +++++++++++++++++++++++++++++---------- src/megachatapi_impl.h | 4 +- 5 files changed, 131 insertions(+), 34 deletions(-) diff --git a/src/chatdMsg.h b/src/chatdMsg.h index fcda15af1..807794fcb 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -785,6 +785,19 @@ class Message: public Buffer return reactions; } + /** @brief Returns true if the user has reacted to this message with this reaction **/ + bool hasReacted(std::string reaction, karere::Id uh) + { + for (size_t i = 0; i < mReactions.size(); i++) + { + if (mReactions.at(i).mReaction.compare(reaction) == 0) + { + return (mReactions.at(i).userIndex(uh) >= 0); + } + } + return false; + } + /** @brief Returns a vector with the userid's associated to an specific reaction **/ std::vector* getReactionUsers(std::string reaction) { diff --git a/src/megachatapi.cpp b/src/megachatapi.cpp index f79c0a44b..b90c128a0 100644 --- a/src/megachatapi.cpp +++ b/src/megachatapi.cpp @@ -1011,14 +1011,14 @@ void MegaChatApi::removeChatNotificationListener(MegaChatNotificationListener *l pImpl->removeChatNotificationListener(listener); } -void MegaChatApi::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +int MegaChatApi::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { - pImpl->addReaction(chatid, msgid, reaction); + return pImpl->addReaction(chatid, msgid, reaction); } -void MegaChatApi::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +int MegaChatApi::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { - pImpl->delReaction(chatid, msgid, reaction); + return pImpl->delReaction(chatid, msgid, reaction); } MegaStringList* MegaChatApi::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) diff --git a/src/megachatapi.h b/src/megachatapi.h index 25d532f6e..6b7e0b6cf 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4575,21 +4575,55 @@ class MegaChatApi /** * @brief Adds a reaction for a message in a chatroom. + * The reactions updates will be notified one by one through the MegaChatRoomListener + * specified at MegaChatApi::openChatRoom (and through any other listener you may have + * registered by calling MegaChatApi::addChatRoomListener). + * + * The corresponding callback is MegaChatRoomListener::onReactionUpdate + * + * Possible return values for this function are: + * - MegaChatError::ERROR_OK - If any error occurred. + * - MegaChatError::ERROR_ARGS - If reaction is NULL + * - MegaChatError::ERROR_NOENT - If the chatroom or message + * doesn't exists or if the message it's a management message + * - MegaChatError::ERROR_ACCESS if our own privilege is different than + * MegaChatPeerList::PRIV_STANDARD or MegaChatPeerList::PRIV_MODERATOR + * - MegaChatError::API_EEXIST if our own user has reacted previously with this reaction + * for this message * * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message * @param reaction UTF-8 NULL terminated string that represents the reaction + * + * @return returns an error code. */ - void addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + int addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); /** * @brief Removes a reaction for a message in a chatroom. + * The reactions updates will be notified one by one through the MegaChatRoomListener + * specified at MegaChatApi::openChatRoom (and through any other listener you may have + * registered by calling MegaChatApi::addChatRoomListener). + * + * The corresponding callback is MegaChatRoomListener::onReactionUpdate + * + * Possible return values for this function are: + * - MegaChatError::ERROR_OK - If any error occurred. + * - MegaChatError::ERROR_ARGS - If reaction is NULL + * - MegaChatError::ERROR_NOENT - If the chatroom or message + * doesn't exists or if the message it's a management message + * - MegaChatError::ERROR_ACCESS if our own privilege is different than + * MegaChatPeerList::PRIV_STANDARD or MegaChatPeerList::PRIV_MODERATOR + * - MegaChatError::API_EEXIST if our own user has not reacted previously with this reaction + * for this message * * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message * @param reaction UTF-8 NULL terminated string that represents the reaction + * + * @return returns an error code. */ - void delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + int delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); /** * @brief Gets a list of reactions associated to a message diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 46f44217f..5f1f97f16 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4162,68 +4162,118 @@ void MegaChatApiImpl::removeChatNotificationListener(MegaChatNotificationListene sdkMutex.unlock(); } -void MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +int MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { if (!reaction) { - return; + return MegaChatError::ERROR_ARGS; } + int errorCode = MegaChatError::ERROR_OK; sdkMutex.lock(); ChatRoom *chatroom = findChatRoom(chatid); - if (chatroom) + if (!chatroom) { - Chat &chat = chatroom->chat(); - Idx index = chat.msgIndexFromId(msgid); - if (index != CHATD_IDX_INVALID) // only confirmed messages have index + errorCode = MegaChatError::ERROR_NOENT; + } + else + { + if (chatroom->ownPriv() < MegaChatPeerList::PRIV_STANDARD) { - Message *msg = chat.findOrNull(index); - if (msg) + errorCode = MegaChatError::ERROR_ACCESS; + } + else + { + Chat &chat = chatroom->chat(); + Idx index = chat.msgIndexFromId(msgid); + if (index == CHATD_IDX_INVALID) { - if (!msg->isManagementMessage()) - { - chat.addReaction(msg, reaction); - } + errorCode = MegaChatError::ERROR_NOENT; } else { - API_LOG_ERROR("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", index, msgid); + Message *msg = chat.findOrNull(index); + if (!msg) + { + errorCode = MegaChatError::ERROR_NOENT; + } + else + { + if (msg->isManagementMessage()) + { + errorCode = MegaChatError::ERROR_NOENT; + } + else if (msg->hasReacted(reaction, mClient->myHandle())) + { + errorCode = MegaChatError::ERROR_EXIST; + } + else + { + chat.addReaction(msg, reaction); + } + } } } } sdkMutex.unlock(); + return errorCode; } -void MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +int MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { if (!reaction) { - return; + return MegaChatError::ERROR_ARGS; } + int errorCode = MegaChatError::ERROR_OK; sdkMutex.lock(); ChatRoom *chatroom = findChatRoom(chatid); - if (chatroom) + if (!chatroom) { - Chat &chat = chatroom->chat(); - Idx index = chat.msgIndexFromId(msgid); - if (index != CHATD_IDX_INVALID) // only confirmed messages have index + errorCode = MegaChatError::ERROR_ARGS; + } + else + { + if (chatroom->ownPriv() < MegaChatPeerList::PRIV_STANDARD) { - Message *msg = chat.findOrNull(index); - if (msg) + errorCode = MegaChatError::ERROR_ACCESS; + } + else + { + Chat &chat = chatroom->chat(); + Idx index = chat.msgIndexFromId(msgid); + if (index == CHATD_IDX_INVALID) { - if (!msg->isManagementMessage()) - { - chat.delReaction(msg, reaction); - } + errorCode = MegaChatError::ERROR_ARGS; } else { - API_LOG_ERROR("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", index, msgid); + Message *msg = chat.findOrNull(index); + if (!msg) + { + errorCode = MegaChatError::ERROR_ARGS; + } + else + { + if (msg->isManagementMessage()) + { + errorCode = MegaChatError::ERROR_ARGS; + } + else if (!msg->hasReacted(reaction, mClient->myHandle())) + { + errorCode = MegaChatError::ERROR_EXIST; + } + else + { + chat.delReaction(msg, reaction); + } + } } } } sdkMutex.unlock(); + return errorCode; } MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index 91ecdb396..93305cdd7 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -1113,8 +1113,8 @@ class MegaChatApiImpl : int loadMessages(MegaChatHandle chatid, int count); bool isFullHistoryLoaded(MegaChatHandle chatid); - void addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); - void delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + int addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + int delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); MegaChatMessage *getMessage(MegaChatHandle chatid, MegaChatHandle msgid); MegaChatMessage *getMessageFromNodeHistory(MegaChatHandle chatid, MegaChatHandle msgid); MegaChatMessage *getManualSendingMessage(MegaChatHandle chatid, MegaChatHandle rowid); From fd28a7d09494f97dc714d901e196f864aa27c2aa Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Mon, 2 Sep 2019 17:04:41 +0200 Subject: [PATCH 036/100] Show a message in QtApp if AddDelReaction returns an error --- examples/qtmegachatapi/chatMessage.cpp | 41 +++++++++++++++++++++----- examples/qtmegachatapi/chatMessage.h | 2 +- examples/qtmegachatapi/reaction.cpp | 21 +++++++++++-- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 29a7279b0..b4267ed31 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -561,17 +561,25 @@ void ChatMessage::onMessageCtxMenu(const QPoint& point) QMenu *menu = ui->mMsgDisplay->createStandardContextMenu(point); if (!mMessage->isManagementMessage()) { - QMenu *reactMenu = menu->addMenu("Add reaction"); + QMenu *addReactMenu = menu->addMenu("Add reaction"); for (int i = 0; i < utf8reactionsList.size(); i++) { std::string react = utf8reactionsList.at(i).toStdString(); - auto actR = reactMenu->addAction(tr(react.c_str())); - connect(actR, &QAction::triggered, this, [=](){onMessageAddReaction(react.c_str());}); + auto actReact = addReactMenu->addAction(tr(react.c_str())); + connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false, react.c_str());}); } + auto actReact = addReactMenu->addAction(tr("Add reaction (CUSTOM)")); + connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false);}); - auto action = menu->addAction(tr("Add reaction (CUSTOM)")); - action->setData(QVariant::fromValue(this)); - connect(action, SIGNAL(triggered()), this, SLOT(onMessageAddReaction())); + QMenu *delReactMenu = menu->addMenu("Del reaction"); + for (int i = 0; i < utf8reactionsList.size(); i++) + { + std::string react = utf8reactionsList.at(i).toStdString(); + auto delReact = delReactMenu->addAction(tr(react.c_str())); + connect(delReact, &QAction::triggered, this, [=](){onManageReaction(true, react.c_str());}); + } + auto delReact = delReactMenu->addAction(tr("Del reaction (CUSTOM)")); + connect(delReact, &QAction::triggered, this, [=](){onManageReaction(true);}); } if (isMine() && !mMessage->isManagementMessage()) @@ -616,7 +624,7 @@ void ChatMessage::onMessageEditAction() startEditingMsgWidget(); } -void ChatMessage::onMessageAddReaction(const char *reactionStr) +void ChatMessage::onManageReaction(bool del, const char *reactionStr) { QString reaction = reactionStr ? reactionStr @@ -628,7 +636,24 @@ void ChatMessage::onMessageAddReaction(const char *reactionStr) } std::string utfstring = reaction.toUtf8().toStdString(); - mChatWindow->mMegaChatApi->addReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); + + int res = 0; + if (del) + { + res = mChatWindow->mMegaChatApi->delReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); + } + else + { + res = mChatWindow->mMegaChatApi->addReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); + } + + if (res != MegaChatError::ERROR_OK) + { + QMessageBox msg; + msg.setIcon(QMessageBox::Information); + msg.setText(std::to_string(res).c_str()); + msg.exec(); + } } void ChatMessage::onMessageRemoveLinkAction() diff --git a/examples/qtmegachatapi/chatMessage.h b/examples/qtmegachatapi/chatMessage.h index a753530cf..481deeb3d 100644 --- a/examples/qtmegachatapi/chatMessage.h +++ b/examples/qtmegachatapi/chatMessage.h @@ -66,7 +66,7 @@ class ChatMessage: public QWidget void onMessageCtxMenu(const QPoint& point); void onMessageDelAction(); void onMessageEditAction(); - void onMessageAddReaction(const char *reactionStr = NULL); + void onManageReaction(bool del, const char *reactionStr = NULL); void onMessageRemoveLinkAction(); void onNodeDownloadOrImport(mega::MegaNode *node, bool import); void onNodePlay(::mega::MegaNode *node); diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index 6bb35c435..8c6dc4d5b 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -79,7 +79,15 @@ void Reaction::onRemoveReact() MegaChatHandle chatid = mChatMessage->getChatId(); MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); const char *reaction = mReactionString.c_str(); - chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction); + int res = chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction); + if (res != MegaChatError::ERROR_OK) + { + QMessageBox msg; + msg.setParent(nullptr); + msg.setIcon(QMessageBox::Information); + msg.setText(std::to_string(res).c_str()); + msg.exec(); + } } void Reaction::onAddReact() @@ -93,7 +101,16 @@ void Reaction::onAddReact() MegaChatHandle chatid = mChatMessage->getChatId(); MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); const char *reaction = mReactionString.c_str(); - chatwindow->getMegaChatApi()->addReaction(chatid, msgid, reaction); + int res = chatwindow->getMegaChatApi()->addReaction(chatid, msgid, reaction); + if (res != MegaChatError::ERROR_OK) + { + QMessageBox msg; + msg.setParent(nullptr); + msg.setIcon(QMessageBox::Information); + msg.setText(std::to_string(res).c_str()); + msg.exec(); + } + } void Reaction::enterEvent(QEvent *event) From 566c457329bce8cbf584f76ed5d08a28560dd101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 3 Sep 2019 10:14:34 +0200 Subject: [PATCH 037/100] Avoid notify terminating user participanting at reconnection state --- src/megachatapi_impl.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 8257e0a01..7150087bf 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -7671,6 +7671,12 @@ void MegaChatCallHandler::onStateChange(uint8_t newState) break; case rtcModule::ICall::kStateTerminating: { + if (chatCall->getStatus() == MegaChatCall::CALL_STATUS_RECONNECTING) + { + // if reconnecting skip terminating state, if reconnection not successful finisht notify call destroyed + return; + } + chatCall->setIsRinging(false); state = MegaChatCall::CALL_STATUS_TERMINATING_USER_PARTICIPATION; chatCall->setTermCode(call->termCode()); From 44ecad6b6901c662ddc18cfebbf3ad3343f4daed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Tue, 3 Sep 2019 10:17:03 +0200 Subject: [PATCH 038/100] Destroy call at 1to1 chatroom when user finishes it --- src/megachatapi_impl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 7150087bf..3ef024c20 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -7711,12 +7711,14 @@ void MegaChatCallHandler::onDestroy(rtcModule::TermCode reason, bool /*byPeer*/, if (chatCall != NULL) { chatid = chatCall->getChatid(); + MegaChatRoom *chatRoom = megaChatApi->getChatRoom(chatid); + assert(chatRoom); MegaHandleList *peeridParticipants = chatCall->getPeeridParticipants(); MegaHandleList *clientidParticipants = chatCall->getClientidParticipants(); bool uniqueParticipant = (peeridParticipants && peeridParticipants->size() == 1 && peeridParticipants->get(0) == megaChatApi->getMyUserHandle() && clientidParticipants->get(0) == megaChatApi->getMyClientidHandle(chatid)); - if (peeridParticipants && peeridParticipants->size() > 0 && !uniqueParticipant) + if (peeridParticipants && peeridParticipants->size() > 0 && !uniqueParticipant && chatRoom->isGroup()) { if (chatCall->getStatus() != MegaChatCall::CALL_STATUS_RECONNECTING) { @@ -7732,6 +7734,7 @@ void MegaChatCallHandler::onDestroy(rtcModule::TermCode reason, bool /*byPeer*/, megaChatApi->removeCall(chatid); } + delete chatRoom; delete peeridParticipants; delete clientidParticipants; } From 4a4203f81fd912eea73e4fdce3663e89206a4b32 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 3 Sep 2019 10:55:21 +0200 Subject: [PATCH 039/100] Minor adjustments --- examples/qtmegachatapi/chatMessage.cpp | 4 ++-- examples/qtmegachatapi/reaction.cpp | 4 ++-- src/chatd.cpp | 29 ++++++++++++-------------- src/chatd.h | 6 +++--- src/chatdMsg.h | 22 +++++++++---------- src/megachatapi.h | 22 ++++++++++--------- src/megachatapi_impl.cpp | 10 +++++---- 7 files changed, 49 insertions(+), 48 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index b4267ed31..f31bcb66c 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -561,7 +561,7 @@ void ChatMessage::onMessageCtxMenu(const QPoint& point) QMenu *menu = ui->mMsgDisplay->createStandardContextMenu(point); if (!mMessage->isManagementMessage()) { - QMenu *addReactMenu = menu->addMenu("Add reaction"); + QMenu *addReactMenu = menu->addMenu("React"); for (int i = 0; i < utf8reactionsList.size(); i++) { std::string react = utf8reactionsList.at(i).toStdString(); @@ -571,7 +571,7 @@ void ChatMessage::onMessageCtxMenu(const QPoint& point) auto actReact = addReactMenu->addAction(tr("Add reaction (CUSTOM)")); connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false);}); - QMenu *delReactMenu = menu->addMenu("Del reaction"); + QMenu *delReactMenu = menu->addMenu("Del react"); for (int i = 0; i < utf8reactionsList.size(); i++) { std::string react = utf8reactionsList.at(i).toStdString(); diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index 8c6dc4d5b..db363165d 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -28,9 +28,9 @@ Reaction::~Reaction() void Reaction::contextMenuEvent(QContextMenuEvent *event) { QMenu menu(this); - auto actAdd = menu.addAction(tr("Add reaction")); + auto actAdd = menu.addAction(tr("React")); connect(actAdd, SIGNAL(triggered()), this, SLOT(onAddReact())); - auto actRemove = menu.addAction(tr("Remove reaction")); + auto actRemove = menu.addAction(tr("Del react")); connect(actRemove, SIGNAL(triggered()), this, SLOT(onRemoveReact())); auto actCopy = menu.addAction(tr("Copy UTF-8")); connect(actCopy, SIGNAL(triggered()), this, SLOT(onCopyReact())); diff --git a/src/chatd.cpp b/src/chatd.cpp index b7358f648..42e3c9fad 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1380,7 +1380,6 @@ string Command::toString(const StaticBuffer& data) karere::Id msgid = data.read(17); int8_t len = data.read(25); const char *reaction = data.readPtr(26, len); - tmpString.append("DELREACTION chatid: "); tmpString.append(ID_CSTR(chatid)); tmpString.append(", userid: "); @@ -1756,7 +1755,7 @@ Chat::Chat(Connection& conn, Id chatid, Listener* listener, mLastReceivedId = info.lastRecvId; mLastSeenIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastSeenId); mLastReceivedIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastReceivedId); - std::string rsn = (!this->previewMode()) ? mDbInterface->getReactionSn() : std::string(); + std::string rsn = (!previewMode()) ? mDbInterface->getReactionSn() : std::string(); mReactionSn = (!rsn.empty()) ? Id(rsn.data(), rsn.size()) : Id::inval(); if ((mHaveAllHistory = mDbInterface->chatVar("have_all_history"))) @@ -2563,16 +2562,15 @@ void Chat::sendSync() } -void Chat::addReaction(Message *message, const char *reaction) +void Chat::addReaction(Message *message, std::string reaction) { - std::string reactionString (reaction, strlen(reaction)); auto wptr = weakHandle(); - marshallCall([wptr, this, message, reactionString]() + marshallCall([wptr, this, message, reaction]() { if (wptr.deleted()) return; - mCrypto->reactionEncrypt(message, reactionString) + mCrypto->reactionEncrypt(message, reaction) .then([this, wptr, message](std::shared_ptr data) { if (wptr.deleted()) @@ -2588,16 +2586,15 @@ void Chat::addReaction(Message *message, const char *reaction) }, mChatdClient.mKarereClient->appCtx); } -void Chat::delReaction(Message *message, const char *reaction) +void Chat::delReaction(Message *message, std::string reaction) { - std::string reactionString (reaction, strlen(reaction)); auto wptr = weakHandle(); - marshallCall([wptr, this, message, reactionString]() + marshallCall([wptr, this, message, reaction]() { if (wptr.deleted()) return; - mCrypto->reactionEncrypt(message, reactionString) + mCrypto->reactionEncrypt(message, reaction) .then([this, wptr, message](std::shared_ptr data) { if (wptr.deleted()) @@ -4859,7 +4856,7 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) if (message->isManagementMessage()) { - CHATID_LOG_DEBUG("onAddReaction: Error, reaction received for a management message"); + CHATID_LOG_DEBUG("onAddReaction: Error, reaction received for a management message with id(%d)", msgId); return; } @@ -4884,12 +4881,12 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) }) .fail([this](const ::promise::Error& err) { - CHATID_LOG_DEBUG("Error decrypting reaction: %s", err.what()); + CHATID_LOG_DEBUG("onAddReaction: Error decrypting reaction: %s", err.what()); }); } else { - CHATID_LOG_DEBUG("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); + CHATID_LOG_DEBUG("onAddReaction: Failed to find the message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); } } @@ -4907,7 +4904,7 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) if (message->isManagementMessage()) { - CHATID_LOG_DEBUG("onDelReaction: Error, reaction received for a management message"); + CHATID_LOG_DEBUG("onDelReaction: Error, reaction received for a management message with id(%d)", msgId); return; } @@ -4932,12 +4929,12 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) }) .fail([this](const ::promise::Error& err) { - CHATID_LOG_DEBUG("Error decrypting reaction: %s", err.what()); + CHATID_LOG_DEBUG("onDelReaction: Error decrypting reaction: %s", err.what()); }); } else { - CHATID_LOG_DEBUG("Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); + CHATID_LOG_DEBUG("onDelReaction: Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); } } diff --git a/src/chatd.h b/src/chatd.h index 610f48ec3..5f4491303 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -308,7 +308,7 @@ class Listener * * @param msgid The id of the message associated to the reaction. * @param reaction The UTF-8 reaction - * @param count The number of users that reacted to that message + * @param count The number of users that reacted to that message with this reaction */ virtual void onReactionUpdate(karere::Id /*msgid*/, const char* /*reaction*/, int /*count*/){} @@ -1295,8 +1295,8 @@ class Chat: public karere::DeleteTrackable uint32_t getNumPreviewers() const; void clearHistory(); void sendSync(); - void addReaction(Message *message, const char *reaction); - void delReaction(Message *message, const char *reaction); + void addReaction(Message *message, std::string reaction); + void delReaction(Message *message, std::string reaction); void sendReactionSn(); void setPublicHandle(uint64_t ph); uint64_t getPublicHandle() const; diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 807794fcb..77c758c4c 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -323,16 +323,18 @@ enum Opcode OP_ECHO = 32, /** - * @brief + * @brief * - * User add a reaction to message + * C->S: user adds a reaction to message + * S->C: server response to the command */ OP_ADDREACTION = 33, /** - * @brief + * @brief * - * User delete a reaction to message + * C->S: user delete a reaction to message + * S->C: server response to the command */ OP_DELREACTION = 34, @@ -416,18 +418,16 @@ enum Opcode OP_HANDLELEAVE = 47, /** - ** @brief + ** @brief * * C->S: send to chatd the current reaction sequence number for a chatroom. * This command must be send upon a reconnection, only if we have stored - * a valid rsn (rsn != 0) and only after send JOIN/JOINRANGEHIST + * a valid rsn and only after send JOIN/JOINRANGEHIST * or HANDLEJOIN/HANDLEJOINRANGEHIST. * * S->C: inform about any change in the reactions associated to a chatroom * by receiving the current reaction sequence number. * - * Send: - * Receive: */ OP_REACTIONSN = 48, @@ -538,13 +538,13 @@ class Message: public Buffer struct Reaction { /** @brief Contains a UTF-8 string that represents the reaction - * and a vector of userid associated to that reaction. */ + * and a vector of userid's associated to that reaction. */ std::string mReaction; std::vector mUsers; Reaction(std::string reaction) { - this->mReaction = reaction; + mReaction = reaction; } /** @brief Returns the userId index in case that exists. Otherwise returns -1 **/ @@ -785,7 +785,7 @@ class Message: public Buffer return reactions; } - /** @brief Returns true if the user has reacted to this message with this reaction **/ + /** @brief Returns true if the user has reacted to this message with the specified reaction **/ bool hasReacted(std::string reaction, karere::Id uh) { for (size_t i = 0; i < mReactions.size(); i++) diff --git a/src/megachatapi.h b/src/megachatapi.h index 6b7e0b6cf..2b0133ba0 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -3287,8 +3287,10 @@ class MegaChatApi /** * @brief Allows a logged in operator/moderator to truncate their chat, i.e. to clear * the entire chat history up to a certain message. All earlier messages are wiped, - * but this specific message will be overwritten by a management message. You can - * expect a call to \c MegaChatRoomListener::onMessageUpdate where the message + * but this specific message will be overwritten by a management message. In addition + * all reactions associated to the message are wiped and must be cleared by applications. + * + * You can expect a call to \c MegaChatRoomListener::onMessageUpdate where the message * will have no content and it will be of type \c MegaChatMessage::TYPE_TRUNCATE. * * The associated request type with this request is MegaChatRequest::TYPE_TRUNCATE_HISTORY @@ -3308,10 +3310,12 @@ class MegaChatApi void truncateChat(MegaChatHandle chatid, MegaChatHandle messageid, MegaChatRequestListener *listener = NULL); /** - * @brief Allows a logged in operator/moderator to clear the entire history of a chat + * @brief Allows a logged in operator/moderator to clear the entire chat history up + * to a certain message. All earlier messages are wiped, but this specific message + * will be overwritten by a management message. In addition all reactions associated + * to the message are wiped and must be cleared by applications. * - * If the history is not already empty, the latest message will be overwritten by - * a management message. You can expect a call to \c MegaChatRoomListener::onMessageUpdate + * You can expect a call to \c MegaChatRoomListener::onMessageUpdate * where the message will have no content and it will be of type * \c MegaChatMessage::TYPE_TRUNCATE. * @@ -4579,10 +4583,9 @@ class MegaChatApi * specified at MegaChatApi::openChatRoom (and through any other listener you may have * registered by calling MegaChatApi::addChatRoomListener). * - * The corresponding callback is MegaChatRoomListener::onReactionUpdate - * + * The corresponding callback is MegaChatRoomListener::onReactionUpdate. * Possible return values for this function are: - * - MegaChatError::ERROR_OK - If any error occurred. + * - MegaChatError::ERROR_OK - If no errors occurred. * - MegaChatError::ERROR_ARGS - If reaction is NULL * - MegaChatError::ERROR_NOENT - If the chatroom or message * doesn't exists or if the message it's a management message @@ -4606,9 +4609,8 @@ class MegaChatApi * registered by calling MegaChatApi::addChatRoomListener). * * The corresponding callback is MegaChatRoomListener::onReactionUpdate - * * Possible return values for this function are: - * - MegaChatError::ERROR_OK - If any error occurred. + * - MegaChatError::ERROR_OK - If no errors occurred. * - MegaChatError::ERROR_ARGS - If reaction is NULL * - MegaChatError::ERROR_NOENT - If the chatroom or message * doesn't exists or if the message it's a management message diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 5f1f97f16..99b9dcdc1 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4209,7 +4209,8 @@ int MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, co } else { - chat.addReaction(msg, reaction); + std::string reactionString(reaction, strlen(reaction)); + chat.addReaction(msg, reactionString); } } } @@ -4266,7 +4267,8 @@ int MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, co } else { - chat.delReaction(msg, reaction); + std::string reactionString(reaction, strlen(reaction)); + chat.delReaction(msg, reactionString); } } } @@ -4295,8 +4297,8 @@ MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, Mega reactArray = new char*[reactions.size()]; for (int i = 0; i < reactions.size(); ++i) { - char *device = MegaApi::strdup(reactions[i].c_str()); - reactArray[i] = device; + char *reaction = MegaApi::strdup(reactions[i].c_str()); + reactArray[i] = reaction; } } reacts = new MegaStringListPrivate(reactArray, reactions.size()); From 931d2c497058d5c0fba2140ef890e3d80eb32853 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 3 Sep 2019 10:57:27 +0200 Subject: [PATCH 040/100] Minor changes in encrypt/decryptreaction --- src/strongvelope/strongvelope.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 4888f5006..c2c651b17 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -638,8 +638,9 @@ ProtocolHandler::reactionEncrypt(Message *msg, std::string reaction) } auto wptr = weakHandle(); - return symPms.then([this, wptr, msg, &reaction](const std::shared_ptr& data) + return symPms.then([wptr, msg, &reaction](const std::shared_ptr& data) { + wptr.throwIfDeleted(); std::string msgId = msg->id().toString(); std::string keyBin (data->buf(), data->dataSize()); @@ -665,7 +666,7 @@ ProtocolHandler::reactionEncrypt(Message *msg, std::string reaction) } } - // Concat msgid[0..4] with emoji (padded) + // Concat msgid[0..4] with emoji (previously padded) size_t emojiLen = roundSize + 4; char plaintext [emojiLen]; memcpy(plaintext, msgId.data(), 4); @@ -675,7 +676,7 @@ ProtocolHandler::reactionEncrypt(Message *msg, std::string reaction) std::vector emoji32 = ::mega::Utils::str_to_a32(std::string(plaintext, emojiLen)); // Encrypt reaction - ::mega::xxteaEncrypt(&emoji32[0], 2, &cypherKey[0], false); + ::mega::xxteaEncrypt(&emoji32[0], emoji32.size(), &cypherKey[0], false); // Convert encrypted reaction to uint32 array std::string result = ::mega::Utils::a32_to_str(emoji32); @@ -703,8 +704,9 @@ ProtocolHandler::reactionDecrypt(Message *msg, std::string reaction) } auto wptr = weakHandle(); - return symPms.then([this, wptr, msg, reaction](const std::shared_ptr& data) + return symPms.then([wptr, msg, reaction](const std::shared_ptr& data) { + wptr.throwIfDeleted(); std::string msgId = msg->id().toString(); std::string keyBin (data->buf(), data->dataSize()); @@ -727,10 +729,12 @@ ProtocolHandler::reactionDecrypt(Message *msg, std::string reaction) for (int i = 4; i < decrypted.size(); ++i) { if (decrypted[i] != '\0') - {count ++;} + { + count ++; + } } - char *resultEmoji = new char[count]; + char *resultEmoji = new char[count]; memcpy(resultEmoji, (char *) (decrypted.data() + 4 + (4-count)), count); std::string aux(resultEmoji, count); From a0e360e24c5f5f361b7e1d435eba468228fd2e6d Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 3 Sep 2019 16:32:57 +0200 Subject: [PATCH 041/100] Adjust MegaChatApi::addReaction and MegaChatApi::delReaction to return MegaChatError --- examples/qtmegachatapi/chatMessage.cpp | 12 ++++++------ examples/qtmegachatapi/reaction.cpp | 21 ++++++++++++--------- src/megachatapi.cpp | 4 ++-- src/megachatapi.h | 16 ++++++++++------ src/megachatapi_impl.cpp | 22 ++++++++++++++-------- src/megachatapi_impl.h | 4 ++-- 6 files changed, 46 insertions(+), 33 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index f31bcb66c..b9d022a07 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -561,7 +561,7 @@ void ChatMessage::onMessageCtxMenu(const QPoint& point) QMenu *menu = ui->mMsgDisplay->createStandardContextMenu(point); if (!mMessage->isManagementMessage()) { - QMenu *addReactMenu = menu->addMenu("React"); + QMenu *addReactMenu = menu->addMenu("React to this message"); for (int i = 0; i < utf8reactionsList.size(); i++) { std::string react = utf8reactionsList.at(i).toStdString(); @@ -571,7 +571,7 @@ void ChatMessage::onMessageCtxMenu(const QPoint& point) auto actReact = addReactMenu->addAction(tr("Add reaction (CUSTOM)")); connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false);}); - QMenu *delReactMenu = menu->addMenu("Del react"); + QMenu *delReactMenu = menu->addMenu("Del reaction"); for (int i = 0; i < utf8reactionsList.size(); i++) { std::string react = utf8reactionsList.at(i).toStdString(); @@ -636,8 +636,7 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) } std::string utfstring = reaction.toUtf8().toStdString(); - - int res = 0; + MegaChatError *res = NULL; if (del) { res = mChatWindow->mMegaChatApi->delReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); @@ -647,13 +646,14 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) res = mChatWindow->mMegaChatApi->addReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); } - if (res != MegaChatError::ERROR_OK) + if (res->getErrorCode() != MegaChatError::ERROR_OK) { QMessageBox msg; msg.setIcon(QMessageBox::Information); - msg.setText(std::to_string(res).c_str()); + msg.setText(res->toString()); msg.exec(); } + delete res; } void ChatMessage::onMessageRemoveLinkAction() diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index db363165d..61182af28 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -28,9 +28,9 @@ Reaction::~Reaction() void Reaction::contextMenuEvent(QContextMenuEvent *event) { QMenu menu(this); - auto actAdd = menu.addAction(tr("React")); + auto actAdd = menu.addAction(tr("React to this message")); connect(actAdd, SIGNAL(triggered()), this, SLOT(onAddReact())); - auto actRemove = menu.addAction(tr("Del react")); + auto actRemove = menu.addAction(tr("Del reaction")); connect(actRemove, SIGNAL(triggered()), this, SLOT(onRemoveReact())); auto actCopy = menu.addAction(tr("Copy UTF-8")); connect(actCopy, SIGNAL(triggered()), this, SLOT(onCopyReact())); @@ -79,15 +79,17 @@ void Reaction::onRemoveReact() MegaChatHandle chatid = mChatMessage->getChatId(); MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); const char *reaction = mReactionString.c_str(); - int res = chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction); - if (res != MegaChatError::ERROR_OK) + + MegaChatError *res = chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction); + if (res->getErrorCode() != MegaChatError::ERROR_OK) { QMessageBox msg; msg.setParent(nullptr); msg.setIcon(QMessageBox::Information); - msg.setText(std::to_string(res).c_str()); + msg.setText(res->toString()); msg.exec(); } + delete res; } void Reaction::onAddReact() @@ -101,16 +103,17 @@ void Reaction::onAddReact() MegaChatHandle chatid = mChatMessage->getChatId(); MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); const char *reaction = mReactionString.c_str(); - int res = chatwindow->getMegaChatApi()->addReaction(chatid, msgid, reaction); - if (res != MegaChatError::ERROR_OK) + + MegaChatError *res = chatwindow->getMegaChatApi()->addReaction(chatid, msgid, reaction); + if (res->getErrorCode() != MegaChatError::ERROR_OK) { QMessageBox msg; msg.setParent(nullptr); msg.setIcon(QMessageBox::Information); - msg.setText(std::to_string(res).c_str()); + msg.setText(res->toString()); msg.exec(); } - + delete res; } void Reaction::enterEvent(QEvent *event) diff --git a/src/megachatapi.cpp b/src/megachatapi.cpp index b90c128a0..9913c075f 100644 --- a/src/megachatapi.cpp +++ b/src/megachatapi.cpp @@ -1011,12 +1011,12 @@ void MegaChatApi::removeChatNotificationListener(MegaChatNotificationListener *l pImpl->removeChatNotificationListener(listener); } -int MegaChatApi::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +MegaChatError *MegaChatApi::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { return pImpl->addReaction(chatid, msgid, reaction); } -int MegaChatApi::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +MegaChatError *MegaChatApi::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { return pImpl->delReaction(chatid, msgid, reaction); } diff --git a/src/megachatapi.h b/src/megachatapi.h index 2b0133ba0..4f88d595b 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4583,8 +4583,10 @@ class MegaChatApi * specified at MegaChatApi::openChatRoom (and through any other listener you may have * registered by calling MegaChatApi::addChatRoomListener). * + * You take the ownership of the returned value. + * * The corresponding callback is MegaChatRoomListener::onReactionUpdate. - * Possible return values for this function are: + * Possible error codes associated to MegaChatError can be: * - MegaChatError::ERROR_OK - If no errors occurred. * - MegaChatError::ERROR_ARGS - If reaction is NULL * - MegaChatError::ERROR_NOENT - If the chatroom or message @@ -4598,9 +4600,9 @@ class MegaChatApi * @param msgid MegaChatHandle that identifies the message * @param reaction UTF-8 NULL terminated string that represents the reaction * - * @return returns an error code. + * @return returns MegaChatError with an error code associated. */ - int addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + MegaChatError *addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); /** * @brief Removes a reaction for a message in a chatroom. @@ -4608,8 +4610,10 @@ class MegaChatApi * specified at MegaChatApi::openChatRoom (and through any other listener you may have * registered by calling MegaChatApi::addChatRoomListener). * + * You take the ownership of the returned value. + * * The corresponding callback is MegaChatRoomListener::onReactionUpdate - * Possible return values for this function are: + * Possible error codes associated to MegaChatError can be: * - MegaChatError::ERROR_OK - If no errors occurred. * - MegaChatError::ERROR_ARGS - If reaction is NULL * - MegaChatError::ERROR_NOENT - If the chatroom or message @@ -4623,9 +4627,9 @@ class MegaChatApi * @param msgid MegaChatHandle that identifies the message * @param reaction UTF-8 NULL terminated string that represents the reaction * - * @return returns an error code. + * @return returns MegaChatError with an error code associated. */ - int delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + MegaChatError *delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); /** * @brief Gets a list of reactions associated to a message diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 99b9dcdc1..5cf2ac0c8 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4162,14 +4162,16 @@ void MegaChatApiImpl::removeChatNotificationListener(MegaChatNotificationListene sdkMutex.unlock(); } -int MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +MegaChatErrorPrivate *MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { + int errorCode = MegaChatError::ERROR_OK; + MegaChatErrorPrivate *megaChatError; if (!reaction) { - return MegaChatError::ERROR_ARGS; + megaChatError = new MegaChatErrorPrivate(MegaChatError::ERROR_ARGS); + return megaChatError; } - int errorCode = MegaChatError::ERROR_OK; sdkMutex.lock(); ChatRoom *chatroom = findChatRoom(chatid); if (!chatroom) @@ -4217,17 +4219,20 @@ int MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaChatHandle msgid, co } } sdkMutex.unlock(); - return errorCode; + megaChatError = new MegaChatErrorPrivate(errorCode); + return megaChatError; } -int MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { + int errorCode = MegaChatError::ERROR_OK; + MegaChatErrorPrivate *megaChatError; if (!reaction) { - return MegaChatError::ERROR_ARGS; + megaChatError = new MegaChatErrorPrivate(MegaChatError::ERROR_ARGS); + return megaChatError; } - int errorCode = MegaChatError::ERROR_OK; sdkMutex.lock(); ChatRoom *chatroom = findChatRoom(chatid); if (!chatroom) @@ -4275,7 +4280,8 @@ int MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, co } } sdkMutex.unlock(); - return errorCode; + megaChatError = new MegaChatErrorPrivate(errorCode); + return megaChatError; } MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index 93305cdd7..d07dee7c2 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -1113,8 +1113,8 @@ class MegaChatApiImpl : int loadMessages(MegaChatHandle chatid, int count); bool isFullHistoryLoaded(MegaChatHandle chatid); - int addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); - int delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + MegaChatErrorPrivate *addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + MegaChatErrorPrivate *delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); MegaChatMessage *getMessage(MegaChatHandle chatid, MegaChatHandle msgid); MegaChatMessage *getMessageFromNodeHistory(MegaChatHandle chatid, MegaChatHandle msgid); MegaChatMessage *getManualSendingMessage(MegaChatHandle chatid, MegaChatHandle rowid); From d34f21fcd011a2ef5e3b2f1555f7b3a3e94bf052 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 4 Sep 2019 11:54:33 +0200 Subject: [PATCH 042/100] Fix wrong errorcodes return in delReaction --- src/megachatapi_impl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 5cf2ac0c8..4b7a60185 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4237,7 +4237,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh ChatRoom *chatroom = findChatRoom(chatid); if (!chatroom) { - errorCode = MegaChatError::ERROR_ARGS; + errorCode = MegaChatError::ERROR_NOENT; } else { @@ -4251,20 +4251,20 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh Idx index = chat.msgIndexFromId(msgid); if (index == CHATD_IDX_INVALID) { - errorCode = MegaChatError::ERROR_ARGS; + errorCode = MegaChatError::ERROR_NOENT; } else { Message *msg = chat.findOrNull(index); if (!msg) { - errorCode = MegaChatError::ERROR_ARGS; + errorCode = MegaChatError::ERROR_NOENT; } else { if (msg->isManagementMessage()) { - errorCode = MegaChatError::ERROR_ARGS; + errorCode = MegaChatError::ERROR_NOENT; } else if (!msg->hasReacted(reaction, mClient->myHandle())) { From 56ee819460263c973a420f3ef5509319aaaf65e1 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 4 Sep 2019 13:35:00 +0200 Subject: [PATCH 043/100] Fix bug in getMessageReactions --- src/megachatapi_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 4b7a60185..0b3555bd2 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4306,9 +4306,9 @@ MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, Mega char *reaction = MegaApi::strdup(reactions[i].c_str()); reactArray[i] = reaction; } + reacts = new MegaStringListPrivate(reactArray, reactions.size()); + delete [] reactArray; } - reacts = new MegaStringListPrivate(reactArray, reactions.size()); - delete [] reactArray; } } sdkMutex.unlock(); From 1ceee13e1f8bc504aadbaf2ae2cb295822ed54b5 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 4 Sep 2019 14:07:05 +0200 Subject: [PATCH 044/100] Make connect in PublicChatManagement test after anonymous init --- tests/sdk_test/sdk_test.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/sdk_test/sdk_test.cpp b/tests/sdk_test/sdk_test.cpp index 6373e3666..62c0bdae0 100644 --- a/tests/sdk_test/sdk_test.cpp +++ b/tests/sdk_test/sdk_test.cpp @@ -1472,11 +1472,18 @@ void MegaChatApiTest::TEST_PublicChatManagement(unsigned int a1, unsigned int a2 // Login in primary account char *sessionPrimary = login(a1); - // Init anonymous in secondary account + // Init anonymous in secondary account and connect initState[a2] = megaChatApi[a2]->initAnonymous(); ASSERT_CHAT_TEST(initState[a2] == MegaChatApi::INIT_ANONYMOUS, "Init sesion in anonymous mode failed"); char *sessionAnonymous = megaApi[a2]->dumpSession(); + bool *flagRequestConnect = &requestFlagsChat[a2][MegaChatRequest::TYPE_CONNECT]; *flagRequestConnect = false; + bool *loggedInFlag = &mLoggedInAllChats[a2]; *loggedInFlag = false; + mChatConnectionOnline[a2] = false; + megaChatApi[a2]->connect(); + ASSERT_CHAT_TEST(waitForResponse(flagRequestConnect), "Expired timeout for connect request"); + ASSERT_CHAT_TEST(!lastErrorChat[a2], "Error connect to chat. Error: " + std::to_string(lastErrorChat[a2])); + // Create a public chat with no peers nor title, this chat will be reused by the rest of the tests MegaChatHandle chatid = MEGACHAT_INVALID_HANDLE; bool *flagCreateChatRoom = &requestFlagsChat[a1][MegaChatRequest::TYPE_CREATE_CHATROOM]; *flagCreateChatRoom = false; From 4534cb7ce74c988d2fadf5bb8dd82301210b8a6b Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 4 Sep 2019 16:53:03 +0200 Subject: [PATCH 045/100] Add TEST_Reactions --- tests/sdk_test/sdk_test.cpp | 155 ++++++++++++++++++++++++++++++++++++ tests/sdk_test/sdk_test.h | 3 + 2 files changed, 158 insertions(+) diff --git a/tests/sdk_test/sdk_test.cpp b/tests/sdk_test/sdk_test.cpp index 62c0bdae0..5b5071dbf 100644 --- a/tests/sdk_test/sdk_test.cpp +++ b/tests/sdk_test/sdk_test.cpp @@ -31,6 +31,7 @@ int main(int argc, char **argv) // Tests that requires a groupchat (start with public chat, converted into private) EXECUTE_TEST(t.TEST_PublicChatManagement(0, 1), "TEST Publicchat management"); EXECUTE_TEST(t.TEST_GroupChatManagement(0, 1), "TEST Groupchat management"); + EXECUTE_TEST(t.TEST_Reactions(0, 1), "TEST Chat Reactions"); EXECUTE_TEST(t.TEST_ClearHistory(0, 1), "TEST Clear history"); EXECUTE_TEST(t.TEST_GroupLastMessage(0, 1), "TEST Last message (group)"); @@ -1682,6 +1683,153 @@ void MegaChatApiTest::TEST_PublicChatManagement(unsigned int a1, unsigned int a2 sessionSecondary = NULL; } +/** + * @brief TEST_Reactions + * + * Requirements: + * - Both accounts should be conctacts + * (if not accomplished, the test automatically solves the above) + * + * This test does the following: + * - Create a group chat room or select an existing one + * - Change another account privileges to readonly + * - Send message + * - Check reactions in message (error) + * - Add reaction with NULL reaction (error) + * - Add reaction with invalid chat (error) + * - Add reaction with invalid message (error) + * + Add reaction without enough permissions (error) + * - Add reaction + * - Add duplicate reaction (error) + * - Check reactions in message + * - Remove reaction with NULL reaction (error) + * - Remove reaction with invalid chat (error) + * - Remove reaction with invalid message (error) + * + Remove reaction without enough permissions (error) + * - Remove reaction + * - Remove non-existent reaction (error) + */ +void MegaChatApiTest::TEST_Reactions(unsigned int a1, unsigned int a2) +{ + // Login both accounts + char *sessionPrimary = login(a1); + char *sessionSecondary = login(a2); + + // Prepare peers, privileges... + MegaUser *user = megaApi[a1]->getContact(mAccounts[a2].getEmail().c_str()); + if (!user || (user->getVisibility() != MegaUser::VISIBILITY_VISIBLE)) + { + makeContact(a1, a2); + delete user; + user = megaApi[a1]->getContact(mAccounts[a2].getEmail().c_str()); + } + + // Get a group chatroom with both users + MegaChatHandle uh = user->getHandle(); + delete user; + user = NULL; + MegaChatPeerList *peers = MegaChatPeerList::createInstance(); + peers->addPeer(uh, MegaChatPeerList::PRIV_STANDARD); + MegaChatHandle chatid = getGroupChatRoom(a1, a2, peers, MegaChatPeerList::PRIV_MODERATOR); + delete peers; + peers = NULL; + + // Open chatroom + TestChatRoomListener *chatroomListener = new TestChatRoomListener(this, megaChatApi, chatid); + ASSERT_CHAT_TEST(megaChatApi[a1]->openChatRoom(chatid, chatroomListener), "Can't open chatRoom account " + std::to_string(a1+1)); + ASSERT_CHAT_TEST(megaChatApi[a2]->openChatRoom(chatid, chatroomListener), "Can't open chatRoom account " + std::to_string(a2+1)); + + // Change peer privileges to Read-only + bool *flagUpdatePeerPermision = &requestFlagsChat[a1][MegaChatRequest::TYPE_UPDATE_PEER_PERMISSIONS]; *flagUpdatePeerPermision = false; + bool *peerUpdated0 = &peersUpdated[a1]; *peerUpdated0 = false; + bool *peerUpdated1 = &peersUpdated[a2]; *peerUpdated1 = false; + bool *mngMsgRecv = &chatroomListener->msgReceived[a1]; *mngMsgRecv = false; + MegaChatHandle *uhAction = &chatroomListener->uhAction[a1]; *uhAction = MEGACHAT_INVALID_HANDLE; + int *priv = &chatroomListener->priv[a1]; *priv = MegaChatRoom::PRIV_UNKNOWN; + megaChatApi[a1]->updateChatPermissions(chatid, uh, MegaChatRoom::PRIV_RO); + ASSERT_CHAT_TEST(waitForResponse(flagUpdatePeerPermision), "Timeout expired for update privilege of peer"); + ASSERT_CHAT_TEST(!lastErrorChat[a1], "Failed to update privilege of peer Error: " + lastErrorMsgChat[a1] + " (" + std::to_string(lastErrorChat[a1]) + ")"); + ASSERT_CHAT_TEST(waitForResponse(peerUpdated0), "Timeout expired for receiving peer update"); + ASSERT_CHAT_TEST(waitForResponse(peerUpdated1), "Timeout expired for receiving peer update"); + ASSERT_CHAT_TEST(waitForResponse(mngMsgRecv), "Timeout expired for receiving management message"); + ASSERT_CHAT_TEST(*uhAction == uh, "User handle from message doesn't match"); + ASSERT_CHAT_TEST(*priv == MegaChatRoom::PRIV_RO, "Privilege is incorrect"); + + // Send a message and wait for reception by target user + string msg0 = "HI " + mAccounts[a1].getEmail() + " - Testing reactions"; + bool *msgConfirmed = &chatroomListener->msgConfirmed[a1]; *msgConfirmed = false; + bool *msgReceived = &chatroomListener->msgReceived[a2]; *msgReceived = false; + bool *msgDelivered = &chatroomListener->msgDelivered[a1]; *msgDelivered = false; + chatroomListener->clearMessages(a1); + chatroomListener->clearMessages(a2); + MegaChatMessage *messageSent = megaChatApi[a1]->sendMessage(chatid, msg0.c_str()); + ASSERT_CHAT_TEST(waitForResponse(msgConfirmed), "Timeout expired for receiving confirmation by server"); // for confirmation, sendMessage() is synchronous + MegaChatHandle msgId = chatroomListener->mConfirmedMessageHandle[a1]; + ASSERT_CHAT_TEST(chatroomListener->hasArrivedMessage(a1, msgId), "Message not received"); + ASSERT_CHAT_TEST(msgId != MEGACHAT_INVALID_HANDLE, "Wrong message id at origin"); + ASSERT_CHAT_TEST(waitForResponse(msgReceived), "Timeout expired for receiving message by target user"); // for reception + ASSERT_CHAT_TEST(chatroomListener->hasArrivedMessage(a2, msgId), "Wrong message id at destination"); + MegaChatMessage *messageReceived = megaChatApi[a2]->getMessage(chatid, msgId); // message should be already received, so in RAM + ASSERT_CHAT_TEST(messageReceived && !strcmp(msg0.c_str(), messageReceived->getContent()), "Content of message doesn't match"); + + // Check reactions for the message sent above (It shouldn't exist any reaction) + ::mega::unique_ptr reactionsList; + reactionsList.reset(megaChatApi[a1]->getMessageReactions(chatid, msgId)); + ASSERT_CHAT_TEST(!reactionsList, "getMessageReactions Error: The message shouldn't have reactions"); + ::mega::unique_ptr userList; + userList.reset(megaChatApi[a1]->getReactionUsers(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(!userList, "getReactionUsers Error: The reaction shouldn't exist"); + + // Add reaction + ::mega::unique_ptr res; + res.reset(megaChatApi[a1]->addReaction(chatid, msgId, NULL)); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_ARGS, "addReaction: Unexpected error for NULL reaction param. Error:" + std::string(res->getErrorString())); + res.reset(megaChatApi[a1]->addReaction(NULL, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_NOENT, "addReaction: Unexpected error for invalid chat. Error:" + std::string(res->getErrorString())); + res.reset(megaChatApi[a1]->addReaction(chatid, NULL, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_NOENT, "addReaction: Unexpected error for invalid message. Error:" + std::string(res->getErrorString())); + res.reset(megaChatApi[a2]->addReaction(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_ACCESS, "addReaction: Unexpected error adding reaction without enough permissions. Error:" + std::string(res->getErrorString())); + bool *reactionReceived = &chatroomListener->reactionReceived[a1]; *reactionReceived = false; + res.reset(megaChatApi[a1]->addReaction(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_OK, "addReaction: failed to add a reaction. Error:" + std::string(res->getErrorString())); + ASSERT_CHAT_TEST(waitForResponse(reactionReceived), "Expired timeout for add reaction"); + res.reset(megaChatApi[a1]->addReaction(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_EXIST, "addReaction: Unexpected error for existing reaction. Error:" + std::string(res->getErrorString())); + + // Check reactions + reactionsList.reset(megaChatApi[a1]->getMessageReactions(chatid, msgId)); + ASSERT_CHAT_TEST(reactionsList, "getMessageReactions Error: The message doesn't have reactions"); + userList.reset(megaChatApi[a1]->getReactionUsers(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(userList, "getReactionUsers Error: The reaction doesn't exists"); + + // Del reaction + res.reset(megaChatApi[a1]->delReaction(chatid, msgId, NULL)); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_ARGS, "delReaction: Unexpected error for NULL reaction param. Error:" + std::string(res->getErrorString())); + res.reset(megaChatApi[a1]->delReaction(NULL, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_NOENT, "delReaction: Unexpected error for invalid chat. Error:" + std::string(res->getErrorString())); + res.reset(megaChatApi[a1]->delReaction(chatid, NULL, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_NOENT, "delReaction: Unexpected error for invalid message. Error:" + std::string(res->getErrorString())); + res.reset(megaChatApi[a2]->delReaction(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_ACCESS, "delReaction: Unexpected error removing reaction without enough permissions. Error:" + std::string(res->getErrorString())); + reactionReceived = &chatroomListener->reactionReceived[a1]; *reactionReceived = false; + res.reset(megaChatApi[a1]->delReaction(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_OK, "delReaction: failed to remove a reaction. Error:" + std::string(res->getErrorString())); + ASSERT_CHAT_TEST(waitForResponse(reactionReceived), "Expired timeout for remove reaction"); + res.reset(megaChatApi[a1]->delReaction(chatid, msgId, "😰")); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_EXIST, "delReaction: Unexpected error for unexisting reaction. Error:" + std::string(res->getErrorString())); + + // Close chatroom + megaChatApi[a1]->closeChatRoom(chatid, chatroomListener); + megaChatApi[a2]->closeChatRoom(chatid, chatroomListener); + + delete chatroomListener; + delete [] sessionPrimary; + sessionPrimary = NULL; + delete [] sessionSecondary; + sessionSecondary = NULL; +} + /** * @brief TEST_OfflineMode * @@ -4186,6 +4334,7 @@ TestChatRoomListener::TestChatRoomListener(MegaChatApiTest *t, MegaChatApi **api this->msgAttachmentReceived[i] = false; this->msgContactReceived[i] = false; this->msgRevokeAttachmentReceived[i] = false; + this->reactionReceived[i] = false; this->mConfirmedMessageHandle[i] = MEGACHAT_INVALID_HANDLE; this->mEditedMessageHandle[i] = MEGACHAT_INVALID_HANDLE; } @@ -4349,6 +4498,12 @@ void TestChatRoomListener::onMessageReceived(MegaChatApi *api, MegaChatMessage * msgReceived[apiIndex] = true; } +void TestChatRoomListener::onReactionUpdate(MegaChatApi *api, MegaChatHandle msgid, const char *reaction, int count) +{ + unsigned int apiIndex = getMegaChatApiIndex(api); + reactionReceived[apiIndex] = true; +} + void TestChatRoomListener::onMessageUpdate(MegaChatApi *api, MegaChatMessage *msg) { unsigned int apiIndex = getMegaChatApiIndex(api); diff --git a/tests/sdk_test/sdk_test.h b/tests/sdk_test/sdk_test.h index a031ed90b..0ee1432b1 100644 --- a/tests/sdk_test/sdk_test.h +++ b/tests/sdk_test/sdk_test.h @@ -188,6 +188,7 @@ class MegaChatApiTest : void TEST_EditAndDeleteMessages(unsigned int a1, unsigned int a2); void TEST_GroupChatManagement(unsigned int a1, unsigned int a2); void TEST_PublicChatManagement(unsigned int a1, unsigned int a2); + void TEST_Reactions(unsigned int a1, unsigned int a2); void TEST_OfflineMode(unsigned int a1, unsigned int a2); void TEST_ClearHistory(unsigned int a1, unsigned int a2); void TEST_SwitchAccounts(unsigned int a1, unsigned int a2); @@ -382,6 +383,7 @@ class TestChatRoomListener : public megachat::MegaChatRoomListener bool msgAttachmentReceived[NUM_ACCOUNTS]; bool msgContactReceived[NUM_ACCOUNTS]; bool msgRevokeAttachmentReceived[NUM_ACCOUNTS]; + bool reactionReceived[NUM_ACCOUNTS]; megachat::MegaChatHandle mConfirmedMessageHandle[NUM_ACCOUNTS]; megachat::MegaChatHandle mEditedMessageHandle[NUM_ACCOUNTS]; @@ -402,6 +404,7 @@ class TestChatRoomListener : public megachat::MegaChatRoomListener virtual void onMessageLoaded(megachat::MegaChatApi* megaChatApi, megachat::MegaChatMessage *msg); // loaded by getMessages() virtual void onMessageReceived(megachat::MegaChatApi* megaChatApi, megachat::MegaChatMessage *msg); virtual void onMessageUpdate(megachat::MegaChatApi* megaChatApi, megachat::MegaChatMessage *msg); // new or updated + virtual void onReactionUpdate(megachat::MegaChatApi *api, megachat::MegaChatHandle msgid, const char *reaction, int count); private: unsigned int getMegaChatApiIndex(megachat::MegaChatApi *api); From c61b15f56674e80f48ed32d541e4089d77a1c5d6 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez <34646869+jgandres@users.noreply.github.com> Date: Fri, 13 Sep 2019 10:11:58 +0200 Subject: [PATCH 046/100] Update examples/qtmegachatapi/chatMessage.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Sergio Hernández --- examples/qtmegachatapi/chatMessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index b9d022a07..966a750f3 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -41,7 +41,7 @@ ChatMessage::ChatMessage(ChatWindow *parent, megachat::MegaChatApi *mChatApi, me { for (int i = 0; i < reactions->size(); i++) { - std::unique_ptr<::mega::MegaHandleList> users(megaChatApi->getReactionUsers(this->mChatId, this->mMessage->getMsgId(),reactions->get(i))); + std::unique_ptr<::mega::MegaHandleList> users(megaChatApi->getReactionUsers(mChatId, mMessage->getMsgId(), reactions->get(i))); int count = users ? users->size() : 0; Reaction *reaction = new Reaction(this, reactions->get(i), count); ui->mReactions->layout()->addWidget(reaction); From 59671fecd1d717f7d86b0c7b57254d37f4456f26 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez <34646869+jgandres@users.noreply.github.com> Date: Fri, 13 Sep 2019 10:13:00 +0200 Subject: [PATCH 047/100] Update examples/qtmegachatapi/chatMessage.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Sergio Hernández --- examples/qtmegachatapi/chatMessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 966a750f3..c59b88e11 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -66,7 +66,7 @@ void ChatMessage::updateReaction(const char *reaction, int count) bool found = false; for (int i = 0; i < mReactions.size(); i++) { - std::shared_ptr r = mReactions.at(i); + std::shared_ptr r = mReactions.at(i); if (r && r->getReactionString().compare(reaction) == 0) { found = true; From 885771b56f0db2f7be7290a41c1e7b92f976a09f Mon Sep 17 00:00:00 2001 From: Javier Gonzalez <34646869+jgandres@users.noreply.github.com> Date: Fri, 13 Sep 2019 10:13:48 +0200 Subject: [PATCH 048/100] Update examples/qtmegachatapi/chatMessage.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Sergio Hernández --- examples/qtmegachatapi/chatMessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index c59b88e11..1d68c215b 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -67,7 +67,7 @@ void ChatMessage::updateReaction(const char *reaction, int count) for (int i = 0; i < mReactions.size(); i++) { std::shared_ptr r = mReactions.at(i); - if (r && r->getReactionString().compare(reaction) == 0) + if (r->getReactionString().compare(reaction) == 0) { found = true; if (count == 0) From 2b32fbc214116a8c8662c544c193a68de26d9c9b Mon Sep 17 00:00:00 2001 From: Javier Gonzalez <34646869+jgandres@users.noreply.github.com> Date: Fri, 13 Sep 2019 10:16:00 +0200 Subject: [PATCH 049/100] Update examples/qtmegachatapi/chatMessage.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Sergio Hernández --- examples/qtmegachatapi/chatMessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 1d68c215b..50be1f0e2 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -263,7 +263,7 @@ ChatWindow *ChatMessage::getChatWindow() const void ChatMessage::clearReactions() { QLayoutItem *item; - while ((item = ui->mReactions->layout()->takeAt(0)) != NULL) + while ((item = ui->mReactions->layout()->takeAt(0))) { item->widget()->deleteLater(); delete item; From 30837f690c884890466386c530cc36d24b3f2aba Mon Sep 17 00:00:00 2001 From: Javier Gonzalez <34646869+jgandres@users.noreply.github.com> Date: Fri, 13 Sep 2019 10:19:55 +0200 Subject: [PATCH 050/100] Update examples/qtmegachatapi/chatMessage.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Sergio Hernández --- examples/qtmegachatapi/chatMessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 50be1f0e2..ca31b6d0c 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -628,7 +628,7 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) { QString reaction = reactionStr ? reactionStr - : mChatWindow->mMainWin->mApp->getText("Add reaction").c_str(); + : mChatWindow->mMainWin->mApp->getText(del ? "Del reaction" : "Add reaction", false).c_str(); if (reaction.isEmpty()) { From fd8ec995545a87382394cc748dd35f5661741cee Mon Sep 17 00:00:00 2001 From: Javier Gonzalez <34646869+jgandres@users.noreply.github.com> Date: Fri, 13 Sep 2019 10:24:50 +0200 Subject: [PATCH 051/100] Minor adjustments and adjust code style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Sergio Hernández --- examples/qtmegachatapi/chatMessage.cpp | 3 +-- examples/qtmegachatapi/reaction.cpp | 15 +++++++-------- src/megachatapi.h | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index ca31b6d0c..88a7a9ecf 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -636,7 +636,7 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) } std::string utfstring = reaction.toUtf8().toStdString(); - MegaChatError *res = NULL; + std::unique_ptr res; if (del) { res = mChatWindow->mMegaChatApi->delReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); @@ -653,7 +653,6 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) msg.setText(res->toString()); msg.exec(); } - delete res; } void ChatMessage::onMessageRemoveLinkAction() diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index 61182af28..8daf0e0d3 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -4,13 +4,13 @@ #include "ui_reaction.h" Reaction::Reaction(ChatMessage *parent, const char *reactionString, int count) : - QWidget((QWidget *)parent), + static_cast(parent), ui(new Ui::Reaction) { mChatMessage = parent; ui->setupUi(this); mCount = count; - mReactionString = reactionString ? reactionString :std::string(); + mReactionString = reactionString ? reactionString : std::string(); QString text(mReactionString.c_str()); text.append(" ") @@ -80,16 +80,15 @@ void Reaction::onRemoveReact() MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); const char *reaction = mReactionString.c_str(); - MegaChatError *res = chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction); + std::unique_ptr res(chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction)); if (res->getErrorCode() != MegaChatError::ERROR_OK) { QMessageBox msg; msg.setParent(nullptr); - msg.setIcon(QMessageBox::Information); - msg.setText(res->toString()); + msg.setIcon(QMessageBox::Error); + msg.setText(res->toErrorString()); msg.exec(); } - delete res; } void Reaction::onAddReact() @@ -119,8 +118,8 @@ void Reaction::onAddReact() void Reaction::enterEvent(QEvent *event) { megachat::MegaChatApi *megachatApi = mChatMessage->getMegaChatApi(); - std::unique_ptr <::mega::MegaHandleList> users (megachatApi->getReactionUsers(mChatMessage->getChatId(), mChatMessage->getMessage()->getMsgId(), mReactionString.c_str())); - std::unique_ptr chatRoom(megachatApi->getChatRoom(mChatMessage->getChatId())); + std::unique_ptr <::mega::MegaHandleList> users(megachatApi->getReactionUsers(mChatMessage->getChatId(), mChatMessage->getMessage()->getMsgId(), mReactionString.c_str())); + std::unique_ptr chatRoom(megachatApi->getChatRoom(mChatMessage->getChatId())); if (!megachatApi || !users || !chatRoom) { return; diff --git a/src/megachatapi.h b/src/megachatapi.h index 4f88d595b..d4c240919 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4633,11 +4633,11 @@ class MegaChatApi /** * @brief Gets a list of reactions associated to a message + * * You take the ownership of the returned value. * * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message - * * @return return a list with the reactions associated to a message. If there's no reactions * associated to the message return NULL. */ From c7b0ae3d898bdbb6b5f0657e4b7567e440a0a137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 16 Sep 2019 14:16:51 +0200 Subject: [PATCH 052/100] Adjust initialization order for GroupChat in preview mode That way, the chat is available in cache to read the reaction SN by the Chat ctor. --- src/chatClient.cpp | 8 ++++---- src/chatd.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/chatClient.cpp b/src/chatClient.cpp index ac62c5eb7..9dc55acfc 100644 --- a/src/chatClient.cpp +++ b/src/chatClient.cpp @@ -2046,10 +2046,6 @@ GroupChatRoom::GroupChatRoom(ChatRoomList& parent, const uint64_t& chatid, :ChatRoom(parent, chatid, true, aShard, aOwnPriv, ts, aIsArchived, title), mRoomGui(nullptr) { - initWithChatd(true, unifiedKey, 0, publicHandle); // strongvelope only needs the public handle in preview mode (to fetch user attributes via `mcuga`) - mChat->setPublicHandle(publicHandle); // chatd always need to know the public handle in preview mode (to send HANDLEJOIN) - mUrl = aUrl; - //save to db auto db = parent.mKarereClient.db; @@ -2062,6 +2058,10 @@ GroupChatRoom::GroupChatRoom(ChatRoomList& parent, const uint64_t& chatid, "own_priv, ts_created, mode, unified_key) values(?,?,-1,0,?,?,2,?)", mChatid, mShardNo, mOwnPriv, mCreationTs, unifiedKeyBuf); + initWithChatd(true, unifiedKey, 0, publicHandle); // strongvelope only needs the public handle in preview mode (to fetch user attributes via `mcuga`) + mChat->setPublicHandle(publicHandle); // chatd always need to know the public handle in preview mode (to send HANDLEJOIN) + mUrl = aUrl; + initChatTitle(title, strongvelope::kDecrypted, true); mRoomGui = addAppItem(); diff --git a/src/chatd.cpp b/src/chatd.cpp index 42e3c9fad..c275186de 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1755,8 +1755,8 @@ Chat::Chat(Connection& conn, Id chatid, Listener* listener, mLastReceivedId = info.lastRecvId; mLastSeenIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastSeenId); mLastReceivedIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastReceivedId); - std::string rsn = (!previewMode()) ? mDbInterface->getReactionSn() : std::string(); - mReactionSn = (!rsn.empty()) ? Id(rsn.data(), rsn.size()) : Id::inval(); + std::string reactionSn = mDbInterface->getReactionSn(); + mReactionSn = !reactionSn.empty() ? Id(reactionSn.data(), reactionSn.size()) : Id::inval(); if ((mHaveAllHistory = mDbInterface->chatVar("have_all_history"))) { From 7d0d7a9556060acb6e9a1f1ce8472bf1c7341b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 16 Sep 2019 14:58:36 +0200 Subject: [PATCH 053/100] Fix compilation issues --- examples/qtmegachatapi/chatMessage.cpp | 4 ++-- examples/qtmegachatapi/reaction.cpp | 6 +++--- src/chatd.cpp | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 88a7a9ecf..49d4de7de 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -639,11 +639,11 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) std::unique_ptr res; if (del) { - res = mChatWindow->mMegaChatApi->delReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); + res.reset(mChatWindow->mMegaChatApi->delReaction(mChatId, mMessage->getMsgId(), utfstring.c_str())); } else { - res = mChatWindow->mMegaChatApi->addReaction(mChatId, mMessage->getMsgId(), utfstring.c_str()); + res.reset(mChatWindow->mMegaChatApi->addReaction(mChatId, mMessage->getMsgId(), utfstring.c_str())); } if (res->getErrorCode() != MegaChatError::ERROR_OK) diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index 8daf0e0d3..e24dbf796 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -4,7 +4,7 @@ #include "ui_reaction.h" Reaction::Reaction(ChatMessage *parent, const char *reactionString, int count) : - static_cast(parent), + QWidget(static_cast(parent)), ui(new Ui::Reaction) { mChatMessage = parent; @@ -85,8 +85,8 @@ void Reaction::onRemoveReact() { QMessageBox msg; msg.setParent(nullptr); - msg.setIcon(QMessageBox::Error); - msg.setText(res->toErrorString()); + msg.setIcon(QMessageBox::Warning); + msg.setText(res->getErrorString()); msg.exec(); } } diff --git a/src/chatd.cpp b/src/chatd.cpp index c275186de..1b012cac6 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1821,10 +1821,9 @@ Idx Chat::getHistoryFromDb(unsigned count) // Load msg reactions from cache ::mega::multimap reactions; CALL_DB(getMessageReactions, msg->id(), reactions); - ::mega::multimap::iterator it; - for (it = reactions.begin(); it != reactions.end(); it++) + for (auto &it : reactions) { - msg->addReaction(it->first, it->second); + msg->addReaction(it.first, it.second); } msgIncoming(false, msg, true); //increments mLastHistFetch/DecryptCount, may reset mHasMoreHistoryInDb if this msgid == mLastKnownMsgid From a684626ffeba763f0f95dd51f2c65a3127cda80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 16 Sep 2019 17:47:54 +0200 Subject: [PATCH 054/100] Minor adjustments --- src/chatd.cpp | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 1b012cac6..3c678e8a5 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4160,18 +4160,10 @@ void Chat::handleTruncate(const Message& msg, Idx idx) deleteMessagesBefore(idx); removePendingRichLinks(idx); - // clean reactions for truncate message - Message *truncatemsg = (idx != CHATD_IDX_INVALID) ? findOrNull(idx) : NULL; - if (truncatemsg) - { - truncatemsg->cleanReactions(); - } - - // clean all reactions for this chat in DB - if (!previewMode()) - { - CALL_DB(cleanReactions); - } + // clean reactions for truncate message and for all message in this chat (DB) + at(idx).cleanReactions(); + // TODO: if reactions consider a foreign key with delete on cascade, we can save the line below + CALL_DB(cleanReactions); // update last-seen pointer if (mLastSeenIdx != CHATD_IDX_INVALID) @@ -4885,7 +4877,7 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) } else { - CHATID_LOG_DEBUG("onAddReaction: Failed to find the message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); + CHATID_LOG_DEBUG("onAddReaction: failed to find message. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); } } @@ -4933,7 +4925,7 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) } else { - CHATID_LOG_DEBUG("onDelReaction: Failed to find message by index, being index retrieved from message id (index: %d, id: %d)", messageIdx, msgId); + CHATID_LOG_DEBUG("ondELReaction: failed to find message by index. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); } } From afbaf41d9dc136043d5262948ba64d5b77958f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 16 Sep 2019 17:49:07 +0200 Subject: [PATCH 055/100] Adjust getter to use STL iterators --- src/chatd.cpp | 8 ++---- src/chatdMsg.h | 53 ++++++++++++++++++++++++++-------------- src/megachatapi_impl.cpp | 6 ++--- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 3c678e8a5..f709266d0 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4866,9 +4866,7 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) CALL_DB(addReaction, message->mId, userId, reaction.c_str()); } - std::vector *users = message->getReactionUsers(reaction); - int count = users ? users->size() : 0; - CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), count); + CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), message->getReactionCount(reaction)); }) .fail([this](const ::promise::Error& err) { @@ -4914,9 +4912,7 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) CALL_DB(delReaction, message->mId, userId, reaction.c_str()); } - std::vector *users = message->getReactionUsers(reaction); - int count = users ? users->size() : 0; - CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), count); + CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), message->getReactionCount(reaction)); }) .fail([this](const ::promise::Error& err) { diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 77c758c4c..bc97ea583 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -548,14 +548,16 @@ class Message: public Buffer } /** @brief Returns the userId index in case that exists. Otherwise returns -1 **/ - int userIndex(karere::Id userId) + int userIndex(karere::Id userId) const { - for (size_t i = 0; i < mUsers.size(); i++) + int i = 0; + for (auto &it : mUsers) { - if (mUsers.at(i) == userId) + if (it == userId) { return i; } + i++; } return -1; } @@ -775,51 +777,66 @@ class Message: public Buffer } /** @brief Returns a vector with all the reactions of the message **/ - std::vector getReactions() + std::vector getReactions() const { std::vector reactions; - for (size_t i = 0; i < mReactions.size(); i++) + for (auto &it : mReactions) { - reactions.push_back(mReactions.at(i).mReaction); + reactions.push_back(it.mReaction); } return reactions; } /** @brief Returns true if the user has reacted to this message with the specified reaction **/ - bool hasReacted(std::string reaction, karere::Id uh) + bool hasReacted(std::string reaction, karere::Id uh) const { - for (size_t i = 0; i < mReactions.size(); i++) + for (auto &it : mReactions) { - if (mReactions.at(i).mReaction.compare(reaction) == 0) + if (it.mReaction == reaction) { - return (mReactions.at(i).userIndex(uh) >= 0); + return it.userIndex(uh) >= 0; } } return false; } /** @brief Returns a vector with the userid's associated to an specific reaction **/ - std::vector* getReactionUsers(std::string reaction) + const std::vector* getReactionUsers(std::string reaction) const { - for (size_t i = 0; i < mReactions.size(); i++) + for (auto &it : mReactions) { - if (mReactions.at(i).mReaction.compare(reaction) == 0) + if (it.mReaction == reaction) { - return &(mReactions.at(i).mUsers); + return &(it.mUsers); } } - return NULL; + return nullptr; + } + + /** @brief Returns the number of users for an specific reaction **/ + size_t getReactionCount(std::string reaction) const + { + for (auto const &it : mReactions) + { + if (it.mReaction == reaction) + { + return it.mUsers.size(); + } + } + return 0; } /** @brief Returns the reaction index in case that exists. Otherwise returns -1 **/ - int getReactionIndex(std::string reaction) + int getReactionIndex(std::string reaction) const { - for (int i = 0; i < mReactions.size(); i++) + int i = 0; + for (auto &it : mReactions) { - if (mReactions.at(i).mReaction.compare(reaction) == 0) + if (it.mReaction == reaction) { return i; } + i++; } return -1; } diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 0b3555bd2..b41177e06 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4331,13 +4331,13 @@ MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaCha Message *msg = findMessage(chatid, msgid); if (msg) { - std::vector*users = msg->getReactionUsers(std::string(reaction)); + const std::vector *users = msg->getReactionUsers(std::string(reaction)); if (users) { userList = new MegaHandleListPrivate(); - for (int i = 0; i < users->size(); ++i) + for (auto &userid : *users) { - userList->addMegaHandle(users->at(i)); + userList->addMegaHandle(userid); } } } From 3fe3d943c178e7c62780adb1cf423865caf7ecb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 16 Sep 2019 18:05:45 +0200 Subject: [PATCH 056/100] Adjust log messages --- src/chatd.cpp | 20 ++++++++++---------- src/chatdMsg.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index f709266d0..11bd54bee 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4841,13 +4841,13 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) { if (reaction.empty()) { - CHATID_LOG_DEBUG("onAddReaction: Error, reaction received is empty"); + CHATID_LOG_ERROR("onAddReaction: reaction received is empty. msgid: %s", ID_CSTR(msgId)); return; } if (message->isManagementMessage()) { - CHATID_LOG_DEBUG("onAddReaction: Error, reaction received for a management message with id(%d)", msgId); + CHATID_LOG_ERROR("onAddReaction: reaction received for a management message with msgid: %s", ID_CSTR(msgId)); return; } @@ -4868,14 +4868,14 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), message->getReactionCount(reaction)); }) - .fail([this](const ::promise::Error& err) + .fail([this, msgId](const ::promise::Error& err) { - CHATID_LOG_DEBUG("onAddReaction: Error decrypting reaction: %s", err.what()); + CHATID_LOG_ERROR("onAddReaction: failed to decrypt reaction. msgid: %s, error: %s", ID_CSTR(msgId), err.what()); }); } else { - CHATID_LOG_DEBUG("onAddReaction: failed to find message. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); + CHATID_LOG_ERROR("onAddReaction: failed to find message. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); } } @@ -4887,13 +4887,13 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) { if (reaction.empty()) { - CHATID_LOG_DEBUG("onDelReaction: Error, reaction received is empty"); + CHATID_LOG_ERROR("onDelReaction: reaction received is empty. msgid: %s", ID_CSTR(msgId)); return; } if (message->isManagementMessage()) { - CHATID_LOG_DEBUG("onDelReaction: Error, reaction received for a management message with id(%d)", msgId); + CHATID_LOG_WARNING("onDelReaction: reaction received for a management message with msgid: %s", ID_CSTR(msgId)); return; } @@ -4914,14 +4914,14 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), message->getReactionCount(reaction)); }) - .fail([this](const ::promise::Error& err) + .fail([this, msgId](const ::promise::Error& err) { - CHATID_LOG_DEBUG("onDelReaction: Error decrypting reaction: %s", err.what()); + CHATID_LOG_ERROR("onDelReaction: failed to decryp reaction. msgid: %s, error: %s", ID_CSTR(msgId), err.what()); }); } else { - CHATID_LOG_DEBUG("ondELReaction: failed to find message by index. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); + CHATID_LOG_ERROR("onDelReaction: failed to find message by index. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); } } diff --git a/src/chatdMsg.h b/src/chatdMsg.h index bc97ea583..f9c2c266d 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -814,13 +814,13 @@ class Message: public Buffer } /** @brief Returns the number of users for an specific reaction **/ - size_t getReactionCount(std::string reaction) const + int getReactionCount(std::string reaction) const { for (auto const &it : mReactions) { if (it.mReaction == reaction) { - return it.mUsers.size(); + return static_cast(it.mUsers.size()); } } return 0; From d3cf00452b6990d79ab200acee365326bb0eea3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 16 Sep 2019 18:08:38 +0200 Subject: [PATCH 057/100] Send reaction sn earlier during login Also, set reaction sn for preview mode --- src/chatd.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 11bd54bee..bd0f525cc 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -475,6 +475,8 @@ void Chat::login() mDbInterface->getHistoryInfo(info); mOldestKnownMsgId = info.oldestDbId; + sendReactionSn(); + if (previewMode()) { if (mOldestKnownMsgId) //if we have local history @@ -4928,10 +4930,7 @@ void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) void Chat::onReactionSn(Id rsn) { mReactionSn = rsn; - if (!previewMode()) - { - CALL_DB(setReactionSn, mReactionSn.toString()); - } + CALL_DB(setReactionSn, mReactionSn.toString()); } void Chat::onPreviewersUpdate(uint32_t numPrev) @@ -4989,9 +4988,6 @@ void Chat::setOnlineState(ChatState state) if (state == kChatStateOnline) { - // Send REACTIONSN after a reconnection - sendReactionSn(); - if (mChatdClient.areAllChatsLoggedIn(connection().shardNo())) { mChatdClient.mKarereClient->initStats().shardEnd(InitStats::kStatsLoginChatd, connection().shardNo()); From 925d883d94ee85102770771286470039228c929f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 16 Sep 2019 18:19:19 +0200 Subject: [PATCH 058/100] Adjust constness --- src/chatd.cpp | 4 ++-- src/chatd.h | 4 ++-- src/chatdICrypto.h | 6 ++---- src/strongvelope/strongvelope.cpp | 4 ++-- src/strongvelope/strongvelope.h | 7 ++----- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index bd0f525cc..e221a2002 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2563,7 +2563,7 @@ void Chat::sendSync() } -void Chat::addReaction(Message *message, std::string reaction) +void Chat::addReaction(const Message *message, std::string reaction) { auto wptr = weakHandle(); marshallCall([wptr, this, message, reaction]() @@ -2587,7 +2587,7 @@ void Chat::addReaction(Message *message, std::string reaction) }, mChatdClient.mKarereClient->appCtx); } -void Chat::delReaction(Message *message, std::string reaction) +void Chat::delReaction(const Message *message, std::string reaction) { auto wptr = weakHandle(); marshallCall([wptr, this, message, reaction]() diff --git a/src/chatd.h b/src/chatd.h index 5f4491303..7eaa2a53f 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1295,8 +1295,8 @@ class Chat: public karere::DeleteTrackable uint32_t getNumPreviewers() const; void clearHistory(); void sendSync(); - void addReaction(Message *message, std::string reaction); - void delReaction(Message *message, std::string reaction); + void addReaction(const Message *message, std::string reaction); + void delReaction(const Message *message, std::string reaction); void sendReactionSn(); void setPublicHandle(uint64_t ph); uint64_t getPublicHandle() const; diff --git a/src/chatdICrypto.h b/src/chatdICrypto.h index 1be6a1746..76123dcba 100644 --- a/src/chatdICrypto.h +++ b/src/chatdICrypto.h @@ -163,16 +163,14 @@ class ICrypto * @param msg The message associated to the reaction. * @param reaction An UTF-8 string. */ - virtual promise::Promise> - reactionEncrypt(Message *msg, std::string reaction) = 0; + virtual promise::Promise> reactionEncrypt(const Message *msg, std::string reaction) = 0; /** * @brief Decrypts a reaction with xxtea. * @param msg The message associated to the reaction. * @param reaction The encrypted reaction. */ - virtual promise::Promise> - reactionDecrypt(Message *msg, std::string reaction) = 0; + virtual promise::Promise> reactionDecrypt(const Message *msg, std::string reaction) = 0; /** * @brief The crypto module is destroyed when that chatid is left or the client is destroyed diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index c2c651b17..0b84a86e5 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -625,7 +625,7 @@ ProtocolHandler::ProtocolHandler(karere::Id ownHandle, } promise::Promise> -ProtocolHandler::reactionEncrypt(Message *msg, std::string reaction) +ProtocolHandler::reactionEncrypt(const Message *msg, std::string reaction) { promise::Promise> symPms; if (isPublicChat()) @@ -691,7 +691,7 @@ ProtocolHandler::reactionEncrypt(Message *msg, std::string reaction) } promise::Promise> -ProtocolHandler::reactionDecrypt(Message *msg, std::string reaction) +ProtocolHandler::reactionDecrypt(const Message *msg, std::string reaction) { promise::Promise> symPms; if (isPublicChat()) diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index 9b330ce7a..abbfbf809 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -455,11 +455,8 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable virtual uint64_t getPublicHandle() const; virtual void setPublicHandle(const uint64_t ph); - virtual promise::Promise> - reactionEncrypt(chatd::Message *msg, std::string reaction); - - virtual promise::Promise> - reactionDecrypt(chatd::Message *msg, std::string reaction); + virtual promise::Promise> reactionEncrypt(const chatd::Message *msg, std::string reaction); + virtual promise::Promise> reactionDecrypt(const chatd::Message *msg, std::string reaction); }; } namespace chatd From 2538791f67e8e86099bb7af9340d6c7b34d186ef Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 17 Sep 2019 11:09:40 +0200 Subject: [PATCH 059/100] Minor adjustments --- bindings/qt/QTMegaChatEvent.h | 2 +- bindings/qt/QTMegaChatRoomListener.cpp | 13 +++--------- examples/qtmegachatapi/chatItemWidget.cpp | 5 ----- examples/qtmegachatapi/chatMessage.cpp | 2 +- examples/qtmegachatapi/chatMessage.h | 2 +- examples/qtmegachatapi/chatWindow.cpp | 6 ++---- examples/qtmegachatapi/reaction.cpp | 25 ++++++++--------------- src/chatClient.cpp | 2 +- 8 files changed, 17 insertions(+), 40 deletions(-) diff --git a/bindings/qt/QTMegaChatEvent.h b/bindings/qt/QTMegaChatEvent.h index 1ef519988..be76469be 100644 --- a/bindings/qt/QTMegaChatEvent.h +++ b/bindings/qt/QTMegaChatEvent.h @@ -34,7 +34,7 @@ class QTMegaChatEvent: public QEvent OnAttachmentReceived, OnAttachmentDeleted, OnAttachmentTruncated, - onReactionUpdated + OnReactionUpdated, }; QTMegaChatEvent(MegaChatApi *megaChatApi, Type type); diff --git a/bindings/qt/QTMegaChatRoomListener.cpp b/bindings/qt/QTMegaChatRoomListener.cpp index d3aaed61a..4cb3e0630 100644 --- a/bindings/qt/QTMegaChatRoomListener.cpp +++ b/bindings/qt/QTMegaChatRoomListener.cpp @@ -44,17 +44,10 @@ void QTMegaChatRoomListener::onMessageReceived(MegaChatApi *api, MegaChatMessage void QTMegaChatRoomListener::onReactionUpdate(MegaChatApi *api, MegaChatHandle msgid, const char *reaction, int count) { - QTMegaChatEvent *event = new QTMegaChatEvent(api, (QEvent::Type)QTMegaChatEvent::onReactionUpdated); + QTMegaChatEvent *event = new QTMegaChatEvent(api, (QEvent::Type)QTMegaChatEvent::OnReactionUpdated); event->setChatHandle(msgid); event->setWidth(count); - if (reaction) - { - size_t size = strlen(reaction) + 1; - char *buf = new char[size]; - memcpy(buf, reaction, size); - event->setBuffer(buf); - } - + event->setBuffer(::mega::MegaApi::strdup(reaction)); QCoreApplication::postEvent(this, event, INT_MIN); } @@ -92,7 +85,7 @@ void QTMegaChatRoomListener::customEvent(QEvent *e) case QTMegaChatEvent::OnHistoryReloaded: if (listener) listener->onHistoryReloaded(event->getMegaChatApi(), event->getChatRoom()); break; - case QTMegaChatEvent::onReactionUpdated: + case QTMegaChatEvent::OnReactionUpdated: if (listener) listener->onReactionUpdate(event->getMegaChatApi(), event->getChatHandle(), event->getBuffer(), event->getWidth()); break; default: diff --git a/examples/qtmegachatapi/chatItemWidget.cpp b/examples/qtmegachatapi/chatItemWidget.cpp index 99b0ce3bb..86ed479b6 100644 --- a/examples/qtmegachatapi/chatItemWidget.cpp +++ b/examples/qtmegachatapi/chatItemWidget.cpp @@ -85,11 +85,6 @@ ChatItemWidget::ChatItemWidget(MainWindow *mainWindow, const megachat::MegaChatL void ChatItemWidget::updateToolTip(const megachat::MegaChatListItem *item, const char *author) { megachat::MegaChatRoom *chatRoom = mMegaChatApi->getChatRoom(mChatId); - if (!chatRoom) - { - return; - } - QString text = NULL; std::string senderHandle; megachat::MegaChatHandle lastMessageId = item->getLastMessageId(); diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 49d4de7de..9b26572ae 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -636,7 +636,7 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) } std::string utfstring = reaction.toUtf8().toStdString(); - std::unique_ptr res; + mega::unique_ptr res; if (del) { res.reset(mChatWindow->mMegaChatApi->delReaction(mChatId, mMessage->getMsgId(), utfstring.c_str())); diff --git a/examples/qtmegachatapi/chatMessage.h b/examples/qtmegachatapi/chatMessage.h index 481deeb3d..4f0ca3d26 100644 --- a/examples/qtmegachatapi/chatMessage.h +++ b/examples/qtmegachatapi/chatMessage.h @@ -66,7 +66,7 @@ class ChatMessage: public QWidget void onMessageCtxMenu(const QPoint& point); void onMessageDelAction(); void onMessageEditAction(); - void onManageReaction(bool del, const char *reactionStr = NULL); + void onManageReaction(bool del, const char *reactionStr = nullptr); void onMessageRemoveLinkAction(); void onNodeDownloadOrImport(mega::MegaNode *node, bool import); void onNodePlay(::mega::MegaNode *node); diff --git a/examples/qtmegachatapi/chatWindow.cpp b/examples/qtmegachatapi/chatWindow.cpp index 2ee0ab57d..33edb27de 100644 --- a/examples/qtmegachatapi/chatWindow.cpp +++ b/examples/qtmegachatapi/chatWindow.cpp @@ -507,10 +507,8 @@ void ChatWindow::onHistoryReloaded(megachat::MegaChatApi *, megachat::MegaChatRo void ChatWindow::onReactionUpdate(megachat::MegaChatApi *, megachat::MegaChatHandle msgid, const char *reaction, int count) { ChatMessage *msg = findChatMessage(msgid); - if (msg) - { - msg->updateReaction(reaction, count); - } + assert(msg); + msg->updateReaction(reaction, count); } void ChatWindow::onAttachmentLoaded(MegaChatApi */*api*/, MegaChatMessage *msg) diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index e24dbf796..440230af8 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -71,16 +71,11 @@ void Reaction::onCopyReact() void Reaction::onRemoveReact() { ChatWindow *chatwindow = mChatMessage->getChatWindow(); - if (!chatwindow) - { - return; - } - MegaChatHandle chatid = mChatMessage->getChatId(); MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); const char *reaction = mReactionString.c_str(); - std::unique_ptr res(chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction)); + mega::unique_ptr res(chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction)); if (res->getErrorCode() != MegaChatError::ERROR_OK) { QMessageBox msg; @@ -118,26 +113,22 @@ void Reaction::onAddReact() void Reaction::enterEvent(QEvent *event) { megachat::MegaChatApi *megachatApi = mChatMessage->getMegaChatApi(); - std::unique_ptr <::mega::MegaHandleList> users(megachatApi->getReactionUsers(mChatMessage->getChatId(), mChatMessage->getMessage()->getMsgId(), mReactionString.c_str())); - std::unique_ptr chatRoom(megachatApi->getChatRoom(mChatMessage->getChatId())); - if (!megachatApi || !users || !chatRoom) + mega::unique_ptr <::mega::MegaHandleList> users(megachatApi->getReactionUsers(mChatMessage->getChatId(), mChatMessage->getMessage()->getMsgId(), mReactionString.c_str())); + mega::unique_ptr chatRoom(megachatApi->getChatRoom(mChatMessage->getChatId())); + if (!users || !chatRoom) { return; } QString text; + mega::unique_ptr autorizationToken(chatRoom->getAuthorizationToken()); for (unsigned int i = 0; i < users->size(); i++) - { - const char *autorizationToken = chatRoom->getAuthorizationToken(); - const char *firstName = mChatMessage->getChatWindow()->getMainWin()->getApp()->getFirstname(users->get(i), autorizationToken); - + { + mega::unique_ptrfirstName(mChatMessage->getChatWindow()->getMainWin()->getApp()->getFirstname(users->get(i), autorizationToken.get())); if (firstName) { - text.append(firstName).append("\n"); + text.append(firstName.get()).append("\n"); } - - delete [] autorizationToken; - delete [] firstName; } ui->mReaction->setToolTip(text); } diff --git a/src/chatClient.cpp b/src/chatClient.cpp index 9dc55acfc..801b7a308 100644 --- a/src/chatClient.cpp +++ b/src/chatClient.cpp @@ -274,7 +274,7 @@ bool Client::openDb(const std::string& sid) { // no chats --> only update cache schema KR_LOG_WARNING("Updating schema of MEGAchat cache..."); - db.query("ALTER TABLE `chats` ADD mode tinyint default 0"); + db.query("ALTER TABLE `chats` ADD mode tinyint"); db.query("ALTER TABLE `chats` ADD unified_key blob"); db.query("update vars set value = ? where name = 'schema_version'", currentVersion); db.commit(); From 8acf7b405ae009aa1cf55d41b8d65ea41d810ed6 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 17 Sep 2019 13:15:42 +0200 Subject: [PATCH 060/100] Avoid return NULL in getMessageReactions and getReactionUsers. --- src/megachatapi.h | 4 +--- src/megachatapi_impl.cpp | 33 +++++++++++++++------------------ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/megachatapi.h b/src/megachatapi.h index d4c240919..c3ffddc91 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4638,8 +4638,7 @@ class MegaChatApi * * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message - * @return return a list with the reactions associated to a message. If there's no reactions - * associated to the message return NULL. + * @return return a list with the reactions associated to a message. */ mega::MegaStringList* getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid); @@ -4652,7 +4651,6 @@ class MegaChatApi * @param reaction UTF-8 NULL terminated string that represents the reaction * * @return return a list with the users that reacted to a message with a specific reaction. - * If the reaction doesn't exists for this message return NULL. */ mega::MegaHandleList* getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index b41177e06..5c3b1c4a8 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4286,43 +4286,41 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) { - MegaStringList *reacts = NULL; + MegaStringList *reactionList = NULL; sdkMutex.lock(); + int numReactions = 0; + ::mega::unique_ptr reactArray = nullptr; ChatRoom *chatroom = findChatRoom(chatid); if (chatroom) { - Chat &chat = chatroom->chat(); Message *msg = findMessage(chatid, msgid); if (msg) { std::vector reactions = msg->getReactions(); - char **reactArray = NULL; - if (reactions.size()) + if (!reactions.empty()) { - reactArray = new char*[reactions.size()]; - for (int i = 0; i < reactions.size(); ++i) + numReactions = static_cast(reactions.size()); + reactArray.reset(new char*[numReactions]); + + size_t i = 0; + for (auto &it : reactions) { - char *reaction = MegaApi::strdup(reactions[i].c_str()); - reactArray[i] = reaction; + reactArray[i] = MegaApi::strdup(it.c_str()); + i++; } - reacts = new MegaStringListPrivate(reactArray, reactions.size()); - delete [] reactArray; } } } + + reactionList = new MegaStringListPrivate(reactArray.get(), numReactions); sdkMutex.unlock(); - return reacts; + return reactionList; } MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { - if (!reaction) - { - return NULL; - } - - MegaHandleListPrivate *userList = NULL; + MegaHandleListPrivate *userList = new MegaHandleListPrivate(); sdkMutex.lock(); ChatRoom *chatroom = findChatRoom(chatid); @@ -4334,7 +4332,6 @@ MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaCha const std::vector *users = msg->getReactionUsers(std::string(reaction)); if (users) { - userList = new MegaHandleListPrivate(); for (auto &userid : *users) { userList->addMegaHandle(userid); From db685a15554026084f95532a6ed5e45706b6bc8a Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 17 Sep 2019 13:24:15 +0200 Subject: [PATCH 061/100] Adjust usages of getMessageReactions and getReactionUsers in QtApp and automatic tests --- examples/qtmegachatapi/chatMessage.cpp | 46 +++++++++++++------------- tests/sdk_test/sdk_test.cpp | 8 ++--- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 9b26572ae..cc704108c 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -36,17 +36,14 @@ ChatMessage::ChatMessage(ChatWindow *parent, megachat::MegaChatApi *mChatApi, me delete chatRoom; updateContent(); - std::unique_ptr<::mega::MegaStringList> reactions(mChatWindow->mMegaChatApi->getMessageReactions(mChatId, mMessage->getMsgId())); - if (reactions) + mega::unique_ptr<::mega::MegaStringList> reactions(mChatWindow->mMegaChatApi->getMessageReactions(mChatId, mMessage->getMsgId())); + for (int i = 0; i < reactions->size(); i++) { - for (int i = 0; i < reactions->size(); i++) - { - std::unique_ptr<::mega::MegaHandleList> users(megaChatApi->getReactionUsers(mChatId, mMessage->getMsgId(), reactions->get(i))); - int count = users ? users->size() : 0; - Reaction *reaction = new Reaction(this, reactions->get(i), count); - ui->mReactions->layout()->addWidget(reaction); - mReactions.emplace_back(std::shared_ptr(reaction)); - } + mega::unique_ptr<::mega::MegaHandleList> users(megaChatApi->getReactionUsers(mChatId, mMessage->getMsgId(), reactions->get(i))); + int count = users ? static_cast(users->size()) : 0; + Reaction *reaction = new Reaction(this, reactions->get(i), count); + ui->mReactions->layout()->addWidget(reaction); + mReactions.emplace_back(std::shared_ptr(reaction)); } connect(ui->mMsgDisplay, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onMessageCtxMenu(const QPoint&))); @@ -524,24 +521,27 @@ void ChatMessage::setAuthor(const char *author) } else { - megachat::MegaChatRoom *chatRoom = megaChatApi->getChatRoom(mChatId); - const char *msgAuthor = chatRoom->getPeerFirstnameByHandle(mMessage->getUserHandle()); - const char *autorizationToken = chatRoom->getAuthorizationToken(); - if (msgAuthor && strlen(msgAuthor) > 0) - { - ui->mAuthorDisplay->setText(tr(msgAuthor)); - } - else if ((msgAuthor = mChatWindow->mMainWin->mApp->getFirstname(uh, autorizationToken))) + mega::unique_ptr chatRoom(megaChatApi->getChatRoom(mChatId)); + const char *firstName = chatRoom->getPeerFirstnameByHandle(mMessage->getUserHandle()); + mega::unique_ptr msgAuthor(::mega::MegaApi::strdup(firstName)); + mega::unique_ptr autorizationToken(chatRoom->getAuthorizationToken()); + + if (msgAuthor && strlen(msgAuthor.get()) > 0) { - ui->mAuthorDisplay->setText(tr(msgAuthor)); - delete [] msgAuthor; + ui->mAuthorDisplay->setText(tr(msgAuthor.get())); } else { - ui->mAuthorDisplay->setText(tr("Loading firstname...")); + msgAuthor.reset(mChatWindow->mMainWin->mApp->getFirstname(uh, autorizationToken.get())); + if (msgAuthor) + { + ui->mAuthorDisplay->setText(tr(msgAuthor.get())); + } + else + { + ui->mAuthorDisplay->setText(tr("Loading firstname...")); + } } - delete chatRoom; - delete []autorizationToken; } } diff --git a/tests/sdk_test/sdk_test.cpp b/tests/sdk_test/sdk_test.cpp index 5b5071dbf..fa3abf338 100644 --- a/tests/sdk_test/sdk_test.cpp +++ b/tests/sdk_test/sdk_test.cpp @@ -1775,10 +1775,10 @@ void MegaChatApiTest::TEST_Reactions(unsigned int a1, unsigned int a2) // Check reactions for the message sent above (It shouldn't exist any reaction) ::mega::unique_ptr reactionsList; reactionsList.reset(megaChatApi[a1]->getMessageReactions(chatid, msgId)); - ASSERT_CHAT_TEST(!reactionsList, "getMessageReactions Error: The message shouldn't have reactions"); + ASSERT_CHAT_TEST(!reactionsList->size(), "getMessageReactions Error: The message shouldn't have reactions"); ::mega::unique_ptr userList; userList.reset(megaChatApi[a1]->getReactionUsers(chatid, msgId, "😰")); - ASSERT_CHAT_TEST(!userList, "getReactionUsers Error: The reaction shouldn't exist"); + ASSERT_CHAT_TEST(!userList->size(), "getReactionUsers Error: The reaction shouldn't exist"); // Add reaction ::mega::unique_ptr res; @@ -1799,9 +1799,9 @@ void MegaChatApiTest::TEST_Reactions(unsigned int a1, unsigned int a2) // Check reactions reactionsList.reset(megaChatApi[a1]->getMessageReactions(chatid, msgId)); - ASSERT_CHAT_TEST(reactionsList, "getMessageReactions Error: The message doesn't have reactions"); + ASSERT_CHAT_TEST(reactionsList->size(), "getMessageReactions Error: The message doesn't have reactions"); userList.reset(megaChatApi[a1]->getReactionUsers(chatid, msgId, "😰")); - ASSERT_CHAT_TEST(userList, "getReactionUsers Error: The reaction doesn't exists"); + ASSERT_CHAT_TEST(userList->size(), "getReactionUsers Error: The reaction doesn't exists"); // Del reaction res.reset(megaChatApi[a1]->delReaction(chatid, msgId, NULL)); From e40437a90c349fb36e56b27c1c3e66ec7791ccab Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 17 Sep 2019 14:40:30 +0200 Subject: [PATCH 062/100] Add method getMessageReactionCount to get the number of users that reacted to a message with a specific reaction. - Improve ChatMessage ctor by using iterators --- examples/qtmegachatapi/chatMessage.cpp | 13 +++++++------ src/megachatapi.cpp | 5 +++++ src/megachatapi.h | 11 +++++++++++ src/megachatapi_impl.cpp | 17 +++++++++++++++++ src/megachatapi_impl.h | 1 + tests/sdk_test/sdk_test.cpp | 9 ++++----- 6 files changed, 45 insertions(+), 11 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index cc704108c..c0d7fece1 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -39,8 +39,7 @@ ChatMessage::ChatMessage(ChatWindow *parent, megachat::MegaChatApi *mChatApi, me mega::unique_ptr<::mega::MegaStringList> reactions(mChatWindow->mMegaChatApi->getMessageReactions(mChatId, mMessage->getMsgId())); for (int i = 0; i < reactions->size(); i++) { - mega::unique_ptr<::mega::MegaHandleList> users(megaChatApi->getReactionUsers(mChatId, mMessage->getMsgId(), reactions->get(i))); - int count = users ? static_cast(users->size()) : 0; + int count = megaChatApi->getMessageReactionCount(mChatId, mMessage->getMsgId(), reactions->get(i)); Reaction *reaction = new Reaction(this, reactions->get(i), count); ui->mReactions->layout()->addWidget(reaction); mReactions.emplace_back(std::shared_ptr(reaction)); @@ -61,21 +60,23 @@ ChatMessage::~ChatMessage() void ChatMessage::updateReaction(const char *reaction, int count) { bool found = false; - for (int i = 0; i < mReactions.size(); i++) + for (auto it = mReactions.begin(); it != mReactions.end(); it++) { - std::shared_ptr r = mReactions.at(i); + std::shared_ptr r = *it; if (r->getReactionString().compare(reaction) == 0) { found = true; if (count == 0) { - QLayoutItem *item = ui->mReactions->layout()->takeAt(i); + int index = static_cast(distance(mReactions.begin(), it)); + QLayoutItem *item = ui->mReactions->layout()->takeAt(index); if (item) { item->widget()->deleteLater(); delete item; } - mReactions.erase(mReactions.begin() + i); + auto auxit = it; + mReactions.erase(auxit); } r->updateReactionCount(count); break; diff --git a/src/megachatapi.cpp b/src/megachatapi.cpp index 9913c075f..ad6137be9 100644 --- a/src/megachatapi.cpp +++ b/src/megachatapi.cpp @@ -1021,6 +1021,11 @@ MegaChatError *MegaChatApi::delReaction(MegaChatHandle chatid, MegaChatHandle ms return pImpl->delReaction(chatid, msgid, reaction); } +int MegaChatApi::getMessageReactionCount(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) const +{ + return pImpl->getMessageReactionCount(chatid, msgid, reaction); +} + MegaStringList* MegaChatApi::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) { return pImpl->getMessageReactions(chatid, msgid); diff --git a/src/megachatapi.h b/src/megachatapi.h index c3ffddc91..c88bb6e31 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4631,6 +4631,17 @@ class MegaChatApi */ MegaChatError *delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + /** + * @brief Returns the number of users that reacted to a message with a specific reaction. + * + * @param chatid MegaChatHandle that identifies the chatroom + * @param msgid MegaChatHandle that identifies the message + * @param reaction UTF-8 NULL terminated string that represents the reaction + * + * @return return the number of users that reacted to a message with a specific reaction. + */ + int getMessageReactionCount(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) const; + /** * @brief Gets a list of reactions associated to a message * diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 5c3b1c4a8..05dd2b5e1 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4284,6 +4284,23 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh return megaChatError; } +int MegaChatApiImpl::getMessageReactionCount(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) +{ + int count = 0; + sdkMutex.lock(); + ChatRoom *chatroom = findChatRoom(chatid); + if (chatroom) + { + Message *msg = findMessage(chatid, msgid); + if (msg) + { + count = msg->getReactionCount(reaction); + } + } + sdkMutex.unlock(); + return count; +} + MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) { MegaStringList *reactionList = NULL; diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index d07dee7c2..391d07a1b 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -1001,6 +1001,7 @@ class MegaChatApiImpl : void removeChatListener(MegaChatListener *listener); void removeChatRoomListener(MegaChatHandle chatid, MegaChatRoomListener *listener); void removeChatNotificationListener(MegaChatNotificationListener *listener); + int getMessageReactionCount(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); mega::MegaStringList* getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid); mega::MegaHandleList* getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); #ifndef KARERE_DISABLE_WEBRTC diff --git a/tests/sdk_test/sdk_test.cpp b/tests/sdk_test/sdk_test.cpp index fa3abf338..20548c75a 100644 --- a/tests/sdk_test/sdk_test.cpp +++ b/tests/sdk_test/sdk_test.cpp @@ -1776,9 +1776,8 @@ void MegaChatApiTest::TEST_Reactions(unsigned int a1, unsigned int a2) ::mega::unique_ptr reactionsList; reactionsList.reset(megaChatApi[a1]->getMessageReactions(chatid, msgId)); ASSERT_CHAT_TEST(!reactionsList->size(), "getMessageReactions Error: The message shouldn't have reactions"); - ::mega::unique_ptr userList; - userList.reset(megaChatApi[a1]->getReactionUsers(chatid, msgId, "😰")); - ASSERT_CHAT_TEST(!userList->size(), "getReactionUsers Error: The reaction shouldn't exist"); + int userCount = megaChatApi[a1]->getMessageReactionCount(chatid, msgId, "😰"); + ASSERT_CHAT_TEST(!userCount, "getReactionUsers Error: The reaction shouldn't exist"); // Add reaction ::mega::unique_ptr res; @@ -1800,8 +1799,8 @@ void MegaChatApiTest::TEST_Reactions(unsigned int a1, unsigned int a2) // Check reactions reactionsList.reset(megaChatApi[a1]->getMessageReactions(chatid, msgId)); ASSERT_CHAT_TEST(reactionsList->size(), "getMessageReactions Error: The message doesn't have reactions"); - userList.reset(megaChatApi[a1]->getReactionUsers(chatid, msgId, "😰")); - ASSERT_CHAT_TEST(userList->size(), "getReactionUsers Error: The reaction doesn't exists"); + userCount = megaChatApi[a1]->getMessageReactionCount(chatid, msgId, "😰"); + ASSERT_CHAT_TEST(userCount, "getReactionUsers Error: The reaction doesn't exists"); // Del reaction res.reset(megaChatApi[a1]->delReaction(chatid, msgId, NULL)); From ab2873cbfc30c97c59816a16322e7c6add39bc0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Tue, 17 Sep 2019 18:17:30 +0200 Subject: [PATCH 063/100] Remove unneeded vector with reaction widgets --- examples/qtmegachatapi/chatMessage.cpp | 45 ++++++++++++-------------- examples/qtmegachatapi/chatMessage.h | 1 - 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index c0d7fece1..90b0eec27 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -41,8 +41,7 @@ ChatMessage::ChatMessage(ChatWindow *parent, megachat::MegaChatApi *mChatApi, me { int count = megaChatApi->getMessageReactionCount(mChatId, mMessage->getMsgId(), reactions->get(i)); Reaction *reaction = new Reaction(this, reactions->get(i), count); - ui->mReactions->layout()->addWidget(reaction); - mReactions.emplace_back(std::shared_ptr(reaction)); + ui->mReactions->layout()->addWidget(reaction); // takes ownership } connect(ui->mMsgDisplay, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onMessageCtxMenu(const QPoint&))); @@ -57,37 +56,34 @@ ChatMessage::~ChatMessage() delete ui; } -void ChatMessage::updateReaction(const char *reaction, int count) +void ChatMessage::updateReaction(const char *reactionString, int count) { bool found = false; - for (auto it = mReactions.begin(); it != mReactions.end(); it++) + int size = ui->mReactions->layout()->count(); + for (int i = 0; i < size; i++) { - std::shared_ptr r = *it; - if (r->getReactionString().compare(reaction) == 0) + QLayoutItem *item = ui->mReactions->layout()->itemAt(i); + Reaction *reaction = static_cast(item->widget()); + if (reaction->getReactionString() == reactionString) { - found = true; - if (count == 0) - { - int index = static_cast(distance(mReactions.begin(), it)); - QLayoutItem *item = ui->mReactions->layout()->takeAt(index); - if (item) - { - item->widget()->deleteLater(); - delete item; - } - auto auxit = it; - mReactions.erase(auxit); - } - r->updateReactionCount(count); - break; + found = true; + if (count == 0) + { + item->widget()->deleteLater(); + delete ui->mReactions->layout()->takeAt(i); + } + else + { + reaction->updateReactionCount(count); + } + break; } } if (!found && count) { - Reaction *r = new Reaction(this, reaction, count); - ui->mReactions->layout()->addWidget(r); - mReactions.emplace_back(std::shared_ptr(r)); + Reaction *reaction = new Reaction(this, reactionString, count); + ui->mReactions->layout()->addWidget(reaction); } } @@ -266,7 +262,6 @@ void ChatMessage::clearReactions() item->widget()->deleteLater(); delete item; } - mReactions.clear(); } void ChatMessage::updateContent() diff --git a/examples/qtmegachatapi/chatMessage.h b/examples/qtmegachatapi/chatMessage.h index 4f0ca3d26..1ae09b804 100644 --- a/examples/qtmegachatapi/chatMessage.h +++ b/examples/qtmegachatapi/chatMessage.h @@ -30,7 +30,6 @@ class ChatMessage: public QWidget QListWidgetItem *mListWidgetItem; ChatWindow *mChatWindow; friend class ChatWindow; - std::vector > mReactions; public: ChatMessage(ChatWindow *window, megachat::MegaChatApi *mChatApi, megachat::MegaChatHandle mChatId, megachat::MegaChatMessage *msg); From b24ff3c75025f1296a5e17b356d0ebb85392fb50 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 18 Sep 2019 16:28:02 +0200 Subject: [PATCH 064/100] Add foreign key in chat_reactions table - Enable foreign key support --- src/chatd.cpp | 8 +++----- src/chatdDb.h | 3 +++ src/chatdMsg.h | 3 +++ src/db.h | 8 ++++++++ src/dbSchema.sql | 4 ++-- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index e221a2002..6b3f90686 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4151,6 +4151,9 @@ void Chat::handleTruncate(const Message& msg, Idx idx) // avoid the whole replay (even the idempotent part), and just bail out. CHATID_LOG_DEBUG("Truncating chat history before msgid %s, idx %d, fwdStart %d", ID_CSTR(msg.id()), idx, mForwardStart); + /* clean reactions in RAM, reactions in cache will be cleared in cascade except for truncate message + that will be cleared in DBInterface method truncateHistory*/ + at(idx).cleanReactions(); CALL_CRYPTO(resetSendKey); // discard current key, if any CALL_DB(truncateHistory, msg); if (idx != CHATD_IDX_INVALID) // message is loaded in RAM @@ -4162,11 +4165,6 @@ void Chat::handleTruncate(const Message& msg, Idx idx) deleteMessagesBefore(idx); removePendingRichLinks(idx); - // clean reactions for truncate message and for all message in this chat (DB) - at(idx).cleanReactions(); - // TODO: if reactions consider a foreign key with delete on cascade, we can save the line below - CALL_DB(cleanReactions); - // update last-seen pointer if (mLastSeenIdx != CHATD_IDX_INVALID) { diff --git a/src/chatdDb.h b/src/chatdDb.h index 9e63e59f1..c6f093ac1 100644 --- a/src/chatdDb.h +++ b/src/chatdDb.h @@ -338,6 +338,9 @@ class ChatdSqliteDb: public chatd::DbInterface throw std::runtime_error("dbInterface::truncateHistory: msgid "+msg.id().toString()+" does not exist in db"); mDb.query("delete from history where chatid = ? and idx < ?", mChat.chatId(), idx); + // Clean reactions for the truncate message + mDb.query("delete from chat_reactions where chatid = ?", mChat.chatId()); + #ifndef NDEBUG SqliteStmt stmt(mDb, "select type from history where chatid=? and msgid=?"); stmt << mChat.chatId() << msg.id(); diff --git a/src/chatdMsg.h b/src/chatdMsg.h index f9c2c266d..a69975334 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -634,6 +634,9 @@ class Message: public Buffer mutable void* userp; mutable uint8_t userFlags = 0; bool richLinkRemoved = 0; + + /* Reactions must be ordered in the same order as they were added, + so we need a sequence container */ std::vector mReactions; karere::Id id() const { return mId; } diff --git a/src/db.h b/src/db.h index 298a769ae..50158009b 100644 --- a/src/db.h +++ b/src/db.h @@ -57,6 +57,14 @@ class SqliteDb mDb = nullptr; return false; } + + if (sqlite3_exec(mDb, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr) != SQLITE_OK) + { + sqlite3_close(mDb); + mDb = nullptr; + return false; + } + mCommitEach = commitEach; if (!mCommitEach) { diff --git a/src/dbSchema.sql b/src/dbSchema.sql index ae2a1165f..ee01a53b4 100644 --- a/src/dbSchema.sql +++ b/src/dbSchema.sql @@ -39,5 +39,5 @@ CREATE TABLE node_history(idx int not null, chatid int64 not null, msgid int64 n userid int64, keyid int not null, type tinyint, updated smallint, ts int, is_encrypted tinyint, data blob, backrefid int64 not null, UNIQUE(chatid,msgid), UNIQUE(chatid,idx)); -CREATE TABLE chat_reactions(chatid int64 not null, msgid int64 not null, userid int64 not null, - reaction text, UNIQUE(chatid, msgid, userid, reaction)); +CREATE TABLE chat_reactions(chatid int64 not null, msgid int64 not null, userid int64 not null, reaction text, + UNIQUE(chatid, msgid, userid, reaction), FOREIGN KEY(chatid, msgid) REFERENCES history(chatid, msgid) ON DELETE CASCADE); From c03e91c0dfad35d80ac2f82443b3eb533da4a94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 20 Sep 2019 10:07:27 +0200 Subject: [PATCH 065/100] Finish the call correctly after failure in call reconnection --- src/megachatapi_impl.cpp | 9 +++++++-- src/megachatapi_impl.h | 2 ++ src/rtcModule/webrtc.cpp | 2 ++ src/rtcModule/webrtc.h | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 3ef024c20..069785f9f 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -7720,14 +7720,14 @@ void MegaChatCallHandler::onDestroy(rtcModule::TermCode reason, bool /*byPeer*/, clientidParticipants->get(0) == megaChatApi->getMyClientidHandle(chatid)); if (peeridParticipants && peeridParticipants->size() > 0 && !uniqueParticipant && chatRoom->isGroup()) { - if (chatCall->getStatus() != MegaChatCall::CALL_STATUS_RECONNECTING) + if (chatCall->getStatus() != MegaChatCall::CALL_STATUS_RECONNECTING || mReconnectionFailed) { chatCall->setStatus(MegaChatCall::CALL_STATUS_USER_NO_PRESENT); megaChatApi->fireOnChatCallUpdate(chatCall); } } else if (chatCall->getStatus() != MegaChatCall::CALL_STATUS_RECONNECTING - || reason != rtcModule::TermCode::kErrPeerOffline) + || reason != rtcModule::TermCode::kErrPeerOffline || mReconnectionFailed) { chatCall->setStatus(MegaChatCall::CALL_STATUS_DESTROYED); megaChatApi->fireOnChatCallUpdate(chatCall); @@ -7930,6 +7930,11 @@ void MegaChatCallHandler::onReconnectingState(bool start) megaChatApi->fireOnChatCallUpdate(chatCall); } +void MegaChatCallHandler::setReconnectionFailed() +{ + mReconnectionFailed = true; +} + rtcModule::ICall *MegaChatCallHandler::getCall() { return call; diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index 51dbfcea6..f33ff5dcd 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -594,6 +594,7 @@ class MegaChatCallHandler : public rtcModule::ICallHandler virtual int64_t getInitialTimeStamp(); virtual bool hasBeenNotifiedRinging() const; virtual void onReconnectingState(bool start); + virtual void setReconnectionFailed(); virtual rtcModule::ICall *getCall(); MegaChatCallPrivate *getMegaChatCall(); @@ -603,6 +604,7 @@ class MegaChatCallHandler : public rtcModule::ICallHandler rtcModule::ICall *call = NULL; MegaChatCallPrivate *chatCall = NULL; bool mHasBeenNotifiedRinging = false; + bool mReconnectionFailed = false; rtcModule::IVideoRenderer *localVideoReceiver = NULL; }; diff --git a/src/rtcModule/webrtc.cpp b/src/rtcModule/webrtc.cpp index 4d95cf710..bf7eb37ca 100644 --- a/src/rtcModule/webrtc.cpp +++ b/src/rtcModule/webrtc.cpp @@ -657,6 +657,7 @@ void RtcModule::launchCallRetry(Id chatid, AvFlags av, bool isActiveRetry) mRetryCall.erase(chatid); auto itHandler = mCallHandlers.find(chatid); assert(itHandler != mCallHandlers.end()); + itHandler->second->setReconnectionFailed(); removeCallWithoutParticipants(chatid); }, kRetryCallTimeout, mKarereClient.appCtx); @@ -2082,6 +2083,7 @@ void Call::destroyIfNoSessionsOrRetries(TermCode reason) mManager.mRetryCallTimers.erase(chatid); SUB_LOG_DEBUG("Everybody left, terminating call- After reconnection"); + mHandler->setReconnectionFailed(); destroy(reason, false, "Everybody left - After reconnection"); }, RtcModule::kRetryCallTimeout, mManager.mKarereClient.appCtx); diff --git a/src/rtcModule/webrtc.h b/src/rtcModule/webrtc.h index cb6750e81..fdfb101a8 100644 --- a/src/rtcModule/webrtc.h +++ b/src/rtcModule/webrtc.h @@ -221,6 +221,7 @@ class ICallHandler virtual bool hasBeenNotifiedRinging() const = 0; virtual void onReconnectingState(bool start) = 0; + virtual void setReconnectionFailed() = 0; }; class IGlobalHandler { From c2bbab82f3cc460ca4f98a94d131fc0f65e605de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 20 Sep 2019 11:07:47 +0200 Subject: [PATCH 066/100] Set termcode always that call is terminating --- src/megachatapi_impl.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 069785f9f..63a289d14 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -5066,7 +5066,6 @@ MegaChatCallPrivate::MegaChatCallPrivate(const MegaChatCallPrivate &call) this->participants = call.participants; - this->termCode = call.termCode; this->localTermCode = call.localTermCode; this->ringing = call.ringing; } @@ -7671,6 +7670,7 @@ void MegaChatCallHandler::onStateChange(uint8_t newState) break; case rtcModule::ICall::kStateTerminating: { + chatCall->setTermCode(call->termCode()); if (chatCall->getStatus() == MegaChatCall::CALL_STATUS_RECONNECTING) { // if reconnecting skip terminating state, if reconnection not successful finisht notify call destroyed @@ -7679,7 +7679,6 @@ void MegaChatCallHandler::onStateChange(uint8_t newState) chatCall->setIsRinging(false); state = MegaChatCall::CALL_STATUS_TERMINATING_USER_PARTICIPATION; - chatCall->setTermCode(call->termCode()); API_LOG_INFO("Terminating call. ChatId: %s, callid: %s, termCode: %s , isLocal: %d, duration: %d (s)", karere::Id(chatCall->getChatid()).toString().c_str(), karere::Id(chatCall->getId()).toString().c_str(), From 06283f988f2dd95ad83530938e311f47b3f2bf86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Fri, 20 Sep 2019 11:53:29 +0200 Subject: [PATCH 067/100] Improve behaviour at hang up during call reconnection --- src/rtcModule/webrtc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rtcModule/webrtc.cpp b/src/rtcModule/webrtc.cpp index c87bc34a6..9cf3d1c31 100644 --- a/src/rtcModule/webrtc.cpp +++ b/src/rtcModule/webrtc.cpp @@ -2265,6 +2265,8 @@ bool Call::answer(AvFlags av) void Call::hangup(TermCode reason) { + mManager.removeCallRetry(mChat.chatId()); + switch (mState) { case kStateReqSent: From 5afeea2995cf7e015cbfc080289a5b7f0049cf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Fri, 20 Sep 2019 13:03:25 +0200 Subject: [PATCH 068/100] Improve management of add/del reactions in QtApp --- examples/qtmegachatapi/chatMessage.cpp | 2 +- examples/qtmegachatapi/reaction.cpp | 68 ++++++-------------------- 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 90b0eec27..3cd0b975e 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -645,7 +645,7 @@ void ChatMessage::onManageReaction(bool del, const char *reactionStr) if (res->getErrorCode() != MegaChatError::ERROR_OK) { QMessageBox msg; - msg.setIcon(QMessageBox::Information); + msg.setIcon(QMessageBox::Warning); msg.setText(res->toString()); msg.exec(); } diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index 440230af8..848afb0cb 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -9,14 +9,13 @@ Reaction::Reaction(ChatMessage *parent, const char *reactionString, int count) : { mChatMessage = parent; ui->setupUi(this); - mCount = count; - mReactionString = reactionString ? reactionString : std::string(); - - QString text(mReactionString.c_str()); - text.append(" ") - .append(std::to_string(count).c_str()); + mCount = count; + if (reactionString) + { + mReactionString = reactionString; + } - ui->mReaction->setText(text); + ui->mReaction->setText((mReactionString + " " + std::to_string(count)).c_str()); setAttribute(::Qt::WA_Hover, true); } @@ -49,65 +48,24 @@ std::string Reaction::getReactionString() const void Reaction::updateReactionCount(int count) { - if (!count) - { - return; - } - + assert(count); // it should not be called with count == 0 mCount = count; - QString text(mReactionString.c_str()); - text.append(" ") - .append(std::to_string(count).c_str()); - - ui->mReaction->setText(text.toStdString().c_str()); + ui->mReaction->setText((mReactionString + " " + std::to_string(count)).c_str()); } void Reaction::onCopyReact() { - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(mReactionString.c_str()); + QApplication::clipboard()->setText(mReactionString.c_str()); } void Reaction::onRemoveReact() { - ChatWindow *chatwindow = mChatMessage->getChatWindow(); - MegaChatHandle chatid = mChatMessage->getChatId(); - MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); - const char *reaction = mReactionString.c_str(); - - mega::unique_ptr res(chatwindow->getMegaChatApi()->delReaction(chatid, msgid, reaction)); - if (res->getErrorCode() != MegaChatError::ERROR_OK) - { - QMessageBox msg; - msg.setParent(nullptr); - msg.setIcon(QMessageBox::Warning); - msg.setText(res->getErrorString()); - msg.exec(); - } + mChatMessage->onManageReaction(true, mReactionString.c_str()); } void Reaction::onAddReact() { - ChatWindow *chatwindow = mChatMessage->getChatWindow(); - if (!chatwindow) - { - return; - } - - MegaChatHandle chatid = mChatMessage->getChatId(); - MegaChatHandle msgid = mChatMessage->getMessage()->getMsgId(); - const char *reaction = mReactionString.c_str(); - - MegaChatError *res = chatwindow->getMegaChatApi()->addReaction(chatid, msgid, reaction); - if (res->getErrorCode() != MegaChatError::ERROR_OK) - { - QMessageBox msg; - msg.setParent(nullptr); - msg.setIcon(QMessageBox::Information); - msg.setText(res->toString()); - msg.exec(); - } - delete res; + mChatMessage->onManageReaction(false, mReactionString.c_str()); } void Reaction::enterEvent(QEvent *event) @@ -125,10 +83,12 @@ void Reaction::enterEvent(QEvent *event) for (unsigned int i = 0; i < users->size(); i++) { mega::unique_ptrfirstName(mChatMessage->getChatWindow()->getMainWin()->getApp()->getFirstname(users->get(i), autorizationToken.get())); + mega::unique_ptrb64handle(::mega::MegaApi::userHandleToBase64(users->get(i))); if (firstName) { - text.append(firstName.get()).append("\n"); + text.append(firstName.get()).append(" "); } + text.append("(").append(b64handle.get()).append(")\n"); } ui->mReaction->setToolTip(text); } From 12ead967e3e8875e4aabaa88c7327f1db15e95b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Fri, 20 Sep 2019 14:44:22 +0200 Subject: [PATCH 069/100] Minor adjustments --- src/chatd.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 6b3f90686..b7d86669a 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -1758,7 +1758,10 @@ Chat::Chat(Connection& conn, Id chatid, Listener* listener, mLastSeenIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastSeenId); mLastReceivedIdx = mDbInterface->getIdxOfMsgidFromHistory(mLastReceivedId); std::string reactionSn = mDbInterface->getReactionSn(); - mReactionSn = !reactionSn.empty() ? Id(reactionSn.data(), reactionSn.size()) : Id::inval(); + if (!reactionSn.empty()) + { + mReactionSn = Id(reactionSn.data(), reactionSn.size()); + } if ((mHaveAllHistory = mDbInterface->chatVar("have_all_history"))) { @@ -2232,15 +2235,15 @@ void Connection::execCommand(const StaticBuffer& buf) READ_ID(userid, 8); READ_ID(msgid, 16); READ_8(payloadLen, 24); - std::string reaction (buf.readPtr(pos, payloadLen), payloadLen); + std::string reaction(buf.readPtr(pos, payloadLen), payloadLen); pos += payloadLen; CHATDS_LOG_DEBUG("%s: recv ADDREACTION from user %s to message %s reaction %s", ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), base64urlencode(reaction.data(), reaction.size()).c_str()); - auto& chat = mChatdClient.chats(chatid); - chat.onAddReaction(msgid, userid, reaction); + auto& chat = mChatdClient.chats(chatid); + chat.onAddReaction(msgid, userid, std::move(reaction)); break; } case OP_DELREACTION: @@ -2249,15 +2252,15 @@ void Connection::execCommand(const StaticBuffer& buf) READ_ID(userid, 8); READ_ID(msgid, 16); READ_8(payloadLen, 24); - std::string reaction (buf.readPtr(pos, payloadLen), payloadLen); + std::string reaction(buf.readPtr(pos, payloadLen), payloadLen); pos += payloadLen; CHATDS_LOG_DEBUG("%s: recv DELREACTION from user %s to message %s reaction %s", ID_CSTR(chatid), ID_CSTR(userid), ID_CSTR(msgid), base64urlencode(reaction.data(), reaction.size()).c_str()); - auto& chat = mChatdClient.chats(chatid); - chat.onDelReaction(msgid, userid, reaction); + auto& chat = mChatdClient.chats(chatid); + chat.onDelReaction(msgid, userid, std::move(reaction)); break; } case OP_REACTIONSN: @@ -2265,7 +2268,7 @@ void Connection::execCommand(const StaticBuffer& buf) READ_CHATID(0); READ_ID(rsn, 8); CHATDS_LOG_DEBUG("%s: recv REACTIONSN rsn %s", ID_CSTR(chatid), ID_CSTR(rsn)); - auto& chat = mChatdClient.chats(chatid); + auto& chat = mChatdClient.chats(chatid); chat.onReactionSn(rsn); break; } @@ -2577,8 +2580,7 @@ void Chat::addReaction(const Message *message, std::string reaction) if (wptr.deleted()) return; - std::string encReaction (data->buf(), data->bufSize()); - sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); + sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + data->buf()); }) .fail([this](const ::promise::Error& err) { @@ -2601,8 +2603,7 @@ void Chat::delReaction(const Message *message, std::string reaction) if (wptr.deleted()) return; - std::string encReaction (data->buf(), data->bufSize()); - sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); + sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + data->buf()); }) .fail([this](const ::promise::Error& err) { @@ -4836,7 +4837,7 @@ void Chat::onUserLeave(Id userid) void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) { Idx messageIdx = msgIndexFromId(msgId); - Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : NULL; + Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : nullptr; if (message) { if (reaction.empty()) From 914dd3fef23827f96c41f555e6c74f9c33173ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Fri, 20 Sep 2019 14:44:44 +0200 Subject: [PATCH 070/100] Add reactions to cache in preview mode since the chatroom can be upgraded to full mode. --- src/chatd.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index b7d86669a..a90439f76 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4859,13 +4859,9 @@ void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) if (wptr.deleted()) return; - std::string reaction (data->buf(), data->bufSize()); - message->addReaction(reaction, userId); - - if (!previewMode()) - { - CALL_DB(addReaction, message->mId, userId, reaction.c_str()); - } + std::string reaction(data->buf(), data->bufSize()); + message->addReaction(reaction, userId); + CALL_DB(addReaction, message->mId, userId, reaction.c_str()); CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), message->getReactionCount(reaction)); }) From 4be59ba56b6e0a70382d714860ff29f744afa4ef Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Tue, 24 Sep 2019 17:21:22 +0200 Subject: [PATCH 071/100] Add FOREIGN key to chat_reactions if we need to update cache --- src/chatClient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chatClient.cpp b/src/chatClient.cpp index 801b7a308..a51f69db3 100644 --- a/src/chatClient.cpp +++ b/src/chatClient.cpp @@ -300,7 +300,8 @@ bool Client::openDb(const std::string& sid) // Create new table for chat reactions db.simpleQuery("CREATE TABLE chat_reactions(chatid int64 not null, msgid int64 not null," " userid int64 not null, reaction text," - " UNIQUE(chatid, msgid, userid, reaction))"); + " UNIQUE(chatid, msgid, userid, reaction)," + " FOREIGN KEY(chatid, msgid) REFERENCES history(chatid, msgid) ON DELETE CASCADE)"); db.query("update vars set value = ? where name = 'schema_version'", currentVersion); db.commit(); From 8350026581e8a33d96bf76d1e7197a4cb43c64e6 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 25 Sep 2019 12:02:58 +0200 Subject: [PATCH 072/100] Remove unnecesary functions in QtApp --- examples/qtmegachatapi/reaction.cpp | 14 ++------------ examples/qtmegachatapi/reaction.h | 2 -- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/examples/qtmegachatapi/reaction.cpp b/examples/qtmegachatapi/reaction.cpp index 848afb0cb..1a4a71f84 100644 --- a/examples/qtmegachatapi/reaction.cpp +++ b/examples/qtmegachatapi/reaction.cpp @@ -28,9 +28,9 @@ void Reaction::contextMenuEvent(QContextMenuEvent *event) { QMenu menu(this); auto actAdd = menu.addAction(tr("React to this message")); - connect(actAdd, SIGNAL(triggered()), this, SLOT(onAddReact())); + connect(actAdd, &QAction::triggered, this, [=](){mChatMessage->onManageReaction(false, mReactionString.c_str());}); auto actRemove = menu.addAction(tr("Del reaction")); - connect(actRemove, SIGNAL(triggered()), this, SLOT(onRemoveReact())); + connect(actRemove, &QAction::triggered, this, [=](){mChatMessage->onManageReaction(true, mReactionString.c_str());}); auto actCopy = menu.addAction(tr("Copy UTF-8")); connect(actCopy, SIGNAL(triggered()), this, SLOT(onCopyReact())); @@ -58,16 +58,6 @@ void Reaction::onCopyReact() QApplication::clipboard()->setText(mReactionString.c_str()); } -void Reaction::onRemoveReact() -{ - mChatMessage->onManageReaction(true, mReactionString.c_str()); -} - -void Reaction::onAddReact() -{ - mChatMessage->onManageReaction(false, mReactionString.c_str()); -} - void Reaction::enterEvent(QEvent *event) { megachat::MegaChatApi *megachatApi = mChatMessage->getMegaChatApi(); diff --git a/examples/qtmegachatapi/reaction.h b/examples/qtmegachatapi/reaction.h index 6d4c72bda..b8b24584f 100644 --- a/examples/qtmegachatapi/reaction.h +++ b/examples/qtmegachatapi/reaction.h @@ -29,8 +29,6 @@ class Reaction : public QWidget public slots: void onCopyReact(); - void onRemoveReact(); - void onAddReact(); }; #endif // REACTION_H From 5289f1382c29d83d3d32942f2cc6d9e6918592c8 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Wed, 25 Sep 2019 12:15:27 +0200 Subject: [PATCH 073/100] Fix ADD/DEL REACTION command construction To construct the command we need to specify the reaction length to avoid a buffer overflow. --- src/chatd.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index a90439f76..ac64a11d1 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2580,7 +2580,8 @@ void Chat::addReaction(const Message *message, std::string reaction) if (wptr.deleted()) return; - sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + data->buf()); + std::string encReaction (data->buf(), data->bufSize()); + sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + std::move(encReaction)); }) .fail([this](const ::promise::Error& err) { @@ -2603,7 +2604,8 @@ void Chat::delReaction(const Message *message, std::string reaction) if (wptr.deleted()) return; - sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + data->buf()); + std::string encReaction (data->buf(), data->bufSize()); + sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + std::move(encReaction)); }) .fail([this](const ::promise::Error& err) { From 3aa983e8cae828db2f884dea98311e58095e62e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 14:03:47 +0200 Subject: [PATCH 074/100] Adjust errorcodes for add/delReaction() --- src/chatd.cpp | 4 ++-- src/megachatapi_impl.cpp | 48 ++++++++++++++-------------------------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index ac64a11d1..4c0e2a939 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2580,7 +2580,7 @@ void Chat::addReaction(const Message *message, std::string reaction) if (wptr.deleted()) return; - std::string encReaction (data->buf(), data->bufSize()); + std::string encReaction (data->buf(), data->bufSize()); // lenght must be only 1 byte. passing the buffer uses 4 bytes for size sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + std::move(encReaction)); }) .fail([this](const ::promise::Error& err) @@ -2604,7 +2604,7 @@ void Chat::delReaction(const Message *message, std::string reaction) if (wptr.deleted()) return; - std::string encReaction (data->buf(), data->bufSize()); + std::string encReaction (data->buf(), data->bufSize()); // lenght must be only 1 byte. passing the buffer uses 4 bytes for size sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + std::move(encReaction)); }) .fail([this](const ::promise::Error& err) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 05dd2b5e1..d415501bf 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4194,26 +4194,19 @@ MegaChatErrorPrivate *MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaCh } else { - Message *msg = chat.findOrNull(index); - if (!msg) + const Message &msg = chat.at(index); + if (msg.isManagementMessage()) { - errorCode = MegaChatError::ERROR_NOENT; + errorCode = MegaChatError::ERROR_ARGS; + } + else if (msg.hasReacted(reaction, mClient->myHandle())) + { + errorCode = MegaChatError::ERROR_EXIST; } else { - if (msg->isManagementMessage()) - { - errorCode = MegaChatError::ERROR_NOENT; - } - else if (msg->hasReacted(reaction, mClient->myHandle())) - { - errorCode = MegaChatError::ERROR_EXIST; - } - else - { - std::string reactionString(reaction, strlen(reaction)); - chat.addReaction(msg, reactionString); - } + std::string reactionString(reaction); + chat.addReaction(&msg, reactionString); } } } @@ -4255,26 +4248,19 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh } else { - Message *msg = chat.findOrNull(index); - if (!msg) + const Message &msg = chat.at(index); + if (msg.isManagementMessage()) + { + errorCode = MegaChatError::ERROR_ARGS; + } + else if (!msg.hasReacted(reaction, mClient->myHandle())) { errorCode = MegaChatError::ERROR_NOENT; } else { - if (msg->isManagementMessage()) - { - errorCode = MegaChatError::ERROR_NOENT; - } - else if (!msg->hasReacted(reaction, mClient->myHandle())) - { - errorCode = MegaChatError::ERROR_EXIST; - } - else - { - std::string reactionString(reaction, strlen(reaction)); - chat.delReaction(msg, reactionString); - } + std::string reactionString(reaction); + chat.delReaction(&msg, reactionString); } } } From a3006dae89a9c3d97b9c8fdc808fe167de952ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 14:03:59 +0200 Subject: [PATCH 075/100] Remove obsolete code from WebRTC --- src/rtcModule/webrtc.cpp | 10 ---------- src/rtcModule/webrtcPrivate.h | 1 - 2 files changed, 11 deletions(-) diff --git a/src/rtcModule/webrtc.cpp b/src/rtcModule/webrtc.cpp index 4d95cf710..30f8b365e 100644 --- a/src/rtcModule/webrtc.cpp +++ b/src/rtcModule/webrtc.cpp @@ -3042,16 +3042,6 @@ bool Session::cmd(uint8_t type, Args... args) } return true; } -void Session::asyncDestroy(TermCode code, const std::string& msg) -{ - auto wptr = weakHandle(); - marshallCall([this, wptr, code, msg]() - { - if (wptr.deleted()) - return; - destroy(code, msg); - }, mManager.mKarereClient.appCtx); -} Promise Session::terminateAndDestroy(TermCode code, const std::string& msg) { diff --git a/src/rtcModule/webrtcPrivate.h b/src/rtcModule/webrtcPrivate.h index ed487acdd..387401c19 100644 --- a/src/rtcModule/webrtcPrivate.h +++ b/src/rtcModule/webrtcPrivate.h @@ -79,7 +79,6 @@ class Session: public ISession template bool cmd(uint8_t type, Args... args); void destroy(TermCode code, const std::string& msg=""); - void asyncDestroy(TermCode code, const std::string& msg=""); promise::Promise terminateAndDestroy(TermCode code, const std::string& msg=""); webrtc::FakeConstraints* pcConstraints(); int calculateNetworkQuality(const stats::Sample *sample); From 66137862e4bf15d4d5e983155b4ee88d0a0d43f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 14:54:10 +0200 Subject: [PATCH 076/100] Revamp `Message::hasReactions()` --- src/chatdMsg.h | 12 ++++++++---- src/megachatapi_impl.cpp | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/chatdMsg.h b/src/chatdMsg.h index a69975334..9759e93fc 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -620,6 +620,10 @@ class Message: public Buffer karere::Id mId; bool mIdIsXid = false; + /* Reactions must be ordered in the same order as they were added, + so we need a sequence container */ + std::vector mReactions; + protected: uint8_t mIsEncrypted = kNotEncrypted; @@ -635,10 +639,6 @@ class Message: public Buffer mutable uint8_t userFlags = 0; bool richLinkRemoved = 0; - /* Reactions must be ordered in the same order as they were added, - so we need a sequence container */ - std::vector mReactions; - karere::Id id() const { return mId; } void setId(karere::Id aId, bool isXid) { mId = aId; mIdIsXid = isXid; } bool isSending() const { return mIdIsXid; } @@ -849,6 +849,10 @@ class Message: public Buffer { mReactions.clear(); } + bool hasReactions() const + { + return !mReactions.empty(); + } /** @brief Add a reaction for an specific userid **/ void addReaction(std::string reaction, karere::Id userId) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index d415501bf..c139c6de9 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -7388,7 +7388,7 @@ MegaChatMessagePrivate::MegaChatMessagePrivate(const Message &msg, Message::Stat this->tempId = msg.isSending() ? (MegaChatHandle) msg.id() : MEGACHAT_INVALID_HANDLE; this->rowId = MEGACHAT_INVALID_HANDLE; this->type = msg.type; - this->mHasReactions = msg.mReactions.size() ? true : false; + this->mHasReactions = msg.hasReactions(); this->ts = msg.ts; this->status = status; this->index = index; From dcc3d630881f37e5b939554e3a1d9a749f65a09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 14:55:48 +0200 Subject: [PATCH 077/100] Code improvements --- examples/qtmegachatapi/chatMessage.cpp | 42 ++++++++++++-------------- src/chatd.cpp | 4 +-- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/examples/qtmegachatapi/chatMessage.cpp b/examples/qtmegachatapi/chatMessage.cpp index 3cd0b975e..a22c94c61 100644 --- a/examples/qtmegachatapi/chatMessage.cpp +++ b/examples/qtmegachatapi/chatMessage.cpp @@ -522,16 +522,16 @@ void ChatMessage::setAuthor(const char *author) mega::unique_ptr msgAuthor(::mega::MegaApi::strdup(firstName)); mega::unique_ptr autorizationToken(chatRoom->getAuthorizationToken()); - if (msgAuthor && strlen(msgAuthor.get()) > 0) + if (msgAuthor && msgAuthor[0] != '\0') { - ui->mAuthorDisplay->setText(tr(msgAuthor.get())); + ui->mAuthorDisplay->setText(msgAuthor.get()); } else { msgAuthor.reset(mChatWindow->mMainWin->mApp->getFirstname(uh, autorizationToken.get())); if (msgAuthor) { - ui->mAuthorDisplay->setText(tr(msgAuthor.get())); + ui->mAuthorDisplay->setText(msgAuthor.get()); } else { @@ -555,28 +555,26 @@ void ChatMessage::markAsEdited() void ChatMessage::onMessageCtxMenu(const QPoint& point) { QMenu *menu = ui->mMsgDisplay->createStandardContextMenu(point); - if (!mMessage->isManagementMessage()) + + QMenu *addReactMenu = menu->addMenu("React to this message"); + for (int i = 0; i < utf8reactionsList.size(); i++) { - QMenu *addReactMenu = menu->addMenu("React to this message"); - for (int i = 0; i < utf8reactionsList.size(); i++) - { - std::string react = utf8reactionsList.at(i).toStdString(); - auto actReact = addReactMenu->addAction(tr(react.c_str())); - connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false, react.c_str());}); - } - auto actReact = addReactMenu->addAction(tr("Add reaction (CUSTOM)")); - connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false);}); + std::string react = utf8reactionsList.at(i).toStdString(); + auto actReact = addReactMenu->addAction(react.c_str()); + connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false, react.c_str());}); + } + auto actReact = addReactMenu->addAction(tr("Add reaction (CUSTOM)")); + connect(actReact, &QAction::triggered, this, [=](){onManageReaction(false);}); - QMenu *delReactMenu = menu->addMenu("Del reaction"); - for (int i = 0; i < utf8reactionsList.size(); i++) - { - std::string react = utf8reactionsList.at(i).toStdString(); - auto delReact = delReactMenu->addAction(tr(react.c_str())); - connect(delReact, &QAction::triggered, this, [=](){onManageReaction(true, react.c_str());}); - } - auto delReact = delReactMenu->addAction(tr("Del reaction (CUSTOM)")); - connect(delReact, &QAction::triggered, this, [=](){onManageReaction(true);}); + QMenu *delReactMenu = menu->addMenu("Del reaction"); + for (int i = 0; i < utf8reactionsList.size(); i++) + { + std::string react = utf8reactionsList.at(i).toStdString(); + auto delReact = delReactMenu->addAction(react.c_str()); + connect(delReact, &QAction::triggered, this, [=](){onManageReaction(true, react.c_str());}); } + auto delReact = delReactMenu->addAction(tr("Del reaction (CUSTOM)")); + connect(delReact, &QAction::triggered, this, [=](){onManageReaction(true);}); if (isMine() && !mMessage->isManagementMessage()) { diff --git a/src/chatd.cpp b/src/chatd.cpp index 4c0e2a939..c872b1c1b 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2581,7 +2581,7 @@ void Chat::addReaction(const Message *message, std::string reaction) return; std::string encReaction (data->buf(), data->bufSize()); // lenght must be only 1 byte. passing the buffer uses 4 bytes for size - sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + std::move(encReaction)); + sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); }) .fail([this](const ::promise::Error& err) { @@ -2605,7 +2605,7 @@ void Chat::delReaction(const Message *message, std::string reaction) return; std::string encReaction (data->buf(), data->bufSize()); // lenght must be only 1 byte. passing the buffer uses 4 bytes for size - sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + std::move(encReaction)); + sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); }) .fail([this](const ::promise::Error& err) { From 3ddd5b6bb686183580473470c3bad0025fcf62e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 14:59:05 +0200 Subject: [PATCH 078/100] Improve truncate for reactions History can be truncated at any point, not only at the end of the history. Hence, the newer reactions should be preserved. Only older reactions and the one for the truncate message should be removed --- src/chatd.cpp | 15 ++++++++++++--- src/chatd.h | 1 + src/chatdDb.h | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index c872b1c1b..086d9384d 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2888,6 +2888,17 @@ void Chat::removePendingRichLinks(Idx idx) } } +void Chat::removeMessageReactions(Idx idx) +{ + Message *msg = findOrNull(idx); + if (msg) + { + msg->cleanReactions(); + // reactions in DB are removed along with messages (FK delete on cascade) + } + // TODO: clear any pending reaction in the queue for older messages than `idx` (see removePendingRichLinks(idx)) +} + void Chat::manageRichLinkMessage(Message &message) { std::string url; @@ -4154,9 +4165,6 @@ void Chat::handleTruncate(const Message& msg, Idx idx) // avoid the whole replay (even the idempotent part), and just bail out. CHATID_LOG_DEBUG("Truncating chat history before msgid %s, idx %d, fwdStart %d", ID_CSTR(msg.id()), idx, mForwardStart); - /* clean reactions in RAM, reactions in cache will be cleared in cascade except for truncate message - that will be cleared in DBInterface method truncateHistory*/ - at(idx).cleanReactions(); CALL_CRYPTO(resetSendKey); // discard current key, if any CALL_DB(truncateHistory, msg); if (idx != CHATD_IDX_INVALID) // message is loaded in RAM @@ -4167,6 +4175,7 @@ void Chat::handleTruncate(const Message& msg, Idx idx) deleteMessagesBefore(idx); removePendingRichLinks(idx); + removeMessageReactions(idx); // update last-seen pointer if (mLastSeenIdx != CHATD_IDX_INVALID) diff --git a/src/chatd.h b/src/chatd.h index 7eaa2a53f..5ade1d049 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -903,6 +903,7 @@ class Chat: public karere::DeleteTrackable void requestPendingRichLinks(); void removePendingRichLinks(); void removePendingRichLinks(Idx idx); + void removeMessageReactions(Idx idx); void manageRichLinkMessage(Message &message); void attachmentHistDone(); friend class Connection; diff --git a/src/chatdDb.h b/src/chatdDb.h index c6f093ac1..4f5ab0847 100644 --- a/src/chatdDb.h +++ b/src/chatdDb.h @@ -339,7 +339,7 @@ class ChatdSqliteDb: public chatd::DbInterface mDb.query("delete from history where chatid = ? and idx < ?", mChat.chatId(), idx); // Clean reactions for the truncate message - mDb.query("delete from chat_reactions where chatid = ?", mChat.chatId()); + mDb.query("delete from chat_reactions where chatid = ? and msgid = ?", mChat.chatId(), msg.id()); #ifndef NDEBUG SqliteStmt stmt(mDb, "select type from history where chatid=? and msgid=?"); From 3fdd03b62f5281a43da58fec98bf2cd2c1776eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 17:34:15 +0200 Subject: [PATCH 079/100] Improve management of strings and constness Also allow to decrypt multi-character emojis (fix for offset at reading bytes). --- src/chatd.cpp | 134 +++++++++++++++--------------- src/chatd.h | 4 +- src/chatdICrypto.h | 6 +- src/chatdMsg.h | 26 +++--- src/megachatapi_impl.cpp | 4 +- src/strongvelope/strongvelope.cpp | 75 +++++++---------- src/strongvelope/strongvelope.h | 6 +- 7 files changed, 118 insertions(+), 137 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 086d9384d..6be21761a 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2566,7 +2566,7 @@ void Chat::sendSync() } -void Chat::addReaction(const Message *message, std::string reaction) +void Chat::addReaction(const Message &message, std::string reaction) { auto wptr = weakHandle(); marshallCall([wptr, this, message, reaction]() @@ -2581,7 +2581,7 @@ void Chat::addReaction(const Message *message, std::string reaction) return; std::string encReaction (data->buf(), data->bufSize()); // lenght must be only 1 byte. passing the buffer uses 4 bytes for size - sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); + sendCommand(Command(OP_ADDREACTION) + mChatId + client().myHandle() + message.id() + (int8_t)data->bufSize() + encReaction); }) .fail([this](const ::promise::Error& err) { @@ -2590,7 +2590,7 @@ void Chat::addReaction(const Message *message, std::string reaction) }, mChatdClient.mKarereClient->appCtx); } -void Chat::delReaction(const Message *message, std::string reaction) +void Chat::delReaction(const Message &message, std::string reaction) { auto wptr = weakHandle(); marshallCall([wptr, this, message, reaction]() @@ -2605,7 +2605,7 @@ void Chat::delReaction(const Message *message, std::string reaction) return; std::string encReaction (data->buf(), data->bufSize()); // lenght must be only 1 byte. passing the buffer uses 4 bytes for size - sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message->id() + (int8_t)data->bufSize() + encReaction); + sendCommand(Command(OP_DELREACTION) + mChatId + client().myHandle() + message.id() + (int8_t)data->bufSize() + encReaction); }) .fail([this](const ::promise::Error& err) { @@ -4848,89 +4848,87 @@ void Chat::onUserLeave(Id userid) void Chat::onAddReaction(Id msgId, Id userId, std::string reaction) { Idx messageIdx = msgIndexFromId(msgId); - Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : nullptr; - if (message) + if (messageIdx == CHATD_IDX_INVALID) { - if (reaction.empty()) - { - CHATID_LOG_ERROR("onAddReaction: reaction received is empty. msgid: %s", ID_CSTR(msgId)); - return; - } + CHATID_LOG_WARNING("onAddReaction: message id not found. msgid: %s", ID_CSTR(msgId)); + return; + } - if (message->isManagementMessage()) - { - CHATID_LOG_ERROR("onAddReaction: reaction received for a management message with msgid: %s", ID_CSTR(msgId)); - return; - } + if (reaction.empty()) + { + CHATID_LOG_ERROR("onAddReaction: reaction received is empty. msgid: %s", ID_CSTR(msgId)); + return; + } - auto wptr = weakHandle(); - mCrypto->reactionDecrypt(message, reaction) - .then([this, wptr, message, userId](std::shared_ptr data) - { - if (wptr.deleted()) - return; + Message &message = at(messageIdx); + if (message.isManagementMessage()) + { + CHATID_LOG_ERROR("onAddReaction: reaction received for a management message with msgid: %s", ID_CSTR(msgId)); + return; + } - std::string reaction(data->buf(), data->bufSize()); - message->addReaction(reaction, userId); - CALL_DB(addReaction, message->mId, userId, reaction.c_str()); + auto wptr = weakHandle(); + mCrypto->reactionDecrypt(message, reaction) + .then([this, wptr, &message, userId](std::shared_ptr data) // data is the UTF-8 string (the emoji) + { + if (wptr.deleted()) + return; - CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), message->getReactionCount(reaction)); - }) - .fail([this, msgId](const ::promise::Error& err) - { - CHATID_LOG_ERROR("onAddReaction: failed to decrypt reaction. msgid: %s, error: %s", ID_CSTR(msgId), err.what()); - }); - } - else + const std::string reaction(data->buf(), data->size()); + message.addReaction(reaction, userId); + CALL_DB(addReaction, message.mId, userId, reaction.c_str()); + + CALL_LISTENER(onReactionUpdate, message.mId, reaction.c_str(), message.getReactionCount(reaction)); + }) + .fail([this, msgId](const ::promise::Error& err) { - CHATID_LOG_ERROR("onAddReaction: failed to find message. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); - } + CHATID_LOG_ERROR("onAddReaction: failed to decrypt reaction. msgid: %s, error: %s", ID_CSTR(msgId), err.what()); + }); } void Chat::onDelReaction(Id msgId, Id userId, std::string reaction) { Idx messageIdx = msgIndexFromId(msgId); - Message *message = (messageIdx != CHATD_IDX_INVALID) ? findOrNull(messageIdx) : NULL; - if (message) + if (messageIdx == CHATD_IDX_INVALID) { - if (reaction.empty()) - { - CHATID_LOG_ERROR("onDelReaction: reaction received is empty. msgid: %s", ID_CSTR(msgId)); - return; - } + CHATID_LOG_WARNING("onDelReaction: message id not found. msgid: %s)", ID_CSTR(msgId)); + return; + } - if (message->isManagementMessage()) - { - CHATID_LOG_WARNING("onDelReaction: reaction received for a management message with msgid: %s", ID_CSTR(msgId)); - return; - } + if (reaction.empty()) + { + CHATID_LOG_ERROR("onDelReaction: reaction received is empty. msgid: %s", ID_CSTR(msgId)); + return; + } - auto wptr = weakHandle(); - mCrypto->reactionDecrypt(message, reaction) - .then([this, wptr, message, userId](std::shared_ptr data) - { - if (wptr.deleted()) - return; + Message &message = at(messageIdx); + if (message.isManagementMessage()) + { + CHATID_LOG_WARNING("onDelReaction: reaction received for a management message with msgid: %s", ID_CSTR(msgId)); + return; + } - std::string reaction (data->buf(), data->bufSize()); - message->delReaction(reaction, userId); + auto wptr = weakHandle(); + mCrypto->reactionDecrypt(message, reaction) + .then([this, wptr, &message, userId](std::shared_ptr data) + { + if (wptr.deleted()) + return; - if (!previewMode()) - { - CALL_DB(delReaction, message->mId, userId, reaction.c_str()); - } + const std::string reaction(data->buf(), data->bufSize()); + message.delReaction(reaction, userId); - CALL_LISTENER(onReactionUpdate, message->mId, reaction.c_str(), message->getReactionCount(reaction)); - }) - .fail([this, msgId](const ::promise::Error& err) + if (!previewMode()) { - CHATID_LOG_ERROR("onDelReaction: failed to decryp reaction. msgid: %s, error: %s", ID_CSTR(msgId), err.what()); - }); - } - else + CALL_DB(delReaction, message.mId, userId, reaction.c_str()); + } + + CALL_LISTENER(onReactionUpdate, message.mId, reaction.c_str(), message.getReactionCount(reaction)); + }) + .fail([this, msgId](const ::promise::Error& err) { - CHATID_LOG_ERROR("onDelReaction: failed to find message by index. idx: %d, msgid: %s)", messageIdx, ID_CSTR(msgId)); - } + CHATID_LOG_ERROR("onDelReaction: failed to decryp reaction. msgid: %s, error: %s", ID_CSTR(msgId), err.what()); + }); } void Chat::onReactionSn(Id rsn) diff --git a/src/chatd.h b/src/chatd.h index 5ade1d049..8602f5a03 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1296,8 +1296,8 @@ class Chat: public karere::DeleteTrackable uint32_t getNumPreviewers() const; void clearHistory(); void sendSync(); - void addReaction(const Message *message, std::string reaction); - void delReaction(const Message *message, std::string reaction); + void addReaction(const Message &message, std::string reaction); + void delReaction(const Message &message, std::string reaction); void sendReactionSn(); void setPublicHandle(uint64_t ph); uint64_t getPublicHandle() const; diff --git a/src/chatdICrypto.h b/src/chatdICrypto.h index 76123dcba..6353c2653 100644 --- a/src/chatdICrypto.h +++ b/src/chatdICrypto.h @@ -148,7 +148,7 @@ class ICrypto virtual bool previewMode() = 0; /** Returns true if chat is in public/open mode */ - virtual bool isPublicChat() = 0; + virtual bool isPublicChat() const = 0; virtual void setPrivateChatMode() = 0; @@ -163,14 +163,14 @@ class ICrypto * @param msg The message associated to the reaction. * @param reaction An UTF-8 string. */ - virtual promise::Promise> reactionEncrypt(const Message *msg, std::string reaction) = 0; + virtual promise::Promise> reactionEncrypt(const Message &msg, std::string reaction) = 0; /** * @brief Decrypts a reaction with xxtea. * @param msg The message associated to the reaction. * @param reaction The encrypted reaction. */ - virtual promise::Promise> reactionDecrypt(const Message *msg, std::string reaction) = 0; + virtual promise::Promise> reactionDecrypt(const Message &msg, std::string reaction) = 0; /** * @brief The crypto module is destroyed when that chatid is left or the client is destroyed diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 9759e93fc..74b09dbdd 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -817,7 +817,7 @@ class Message: public Buffer } /** @brief Returns the number of users for an specific reaction **/ - int getReactionCount(std::string reaction) const + int getReactionCount(const std::string &reaction) const { for (auto const &it : mReactions) { @@ -830,7 +830,7 @@ class Message: public Buffer } /** @brief Returns the reaction index in case that exists. Otherwise returns -1 **/ - int getReactionIndex(std::string reaction) const + int getReactionIndex(const std::string &reaction) const { int i = 0; for (auto &it : mReactions) @@ -855,7 +855,7 @@ class Message: public Buffer } /** @brief Add a reaction for an specific userid **/ - void addReaction(std::string reaction, karere::Id userId) + void addReaction(const std::string &reaction, karere::Id userId) { Reaction *r = NULL; int reactIndex = getReactionIndex(reaction); @@ -863,15 +863,12 @@ class Message: public Buffer { r = &mReactions.at(reactIndex); } - else + else // not found, add { - Reaction auxr = Reaction(reaction); - mReactions.emplace_back(auxr); - reactIndex = getReactionIndex(reaction); - r = &mReactions.at(reactIndex); + mReactions.emplace_back(reaction); + r = &mReactions.back(); } - assert(r); int userIndex = r->userIndex(userId); if (userIndex < 0) { @@ -880,19 +877,18 @@ class Message: public Buffer } /** @brief Delete a reaction for an specific userid **/ - void delReaction(std::string reaction, karere::Id userId) + void delReaction(const std::string &reaction, karere::Id userId) { int reactIndex = getReactionIndex(reaction); if (reactIndex >= 0) { - Reaction *r = &mReactions.at(reactIndex); - assert(r); + Reaction &r = mReactions.at(reactIndex); - int userIndex = r->userIndex(userId); + int userIndex = r.userIndex(userId); if (userIndex >= 0) { - r->mUsers.erase(r->mUsers.begin() + userIndex); - if (r->mUsers.size() == 0) + r.mUsers.erase(r.mUsers.begin() + userIndex); + if (r.mUsers.empty()) { mReactions.erase(mReactions.begin() + reactIndex); } diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index c139c6de9..e091a0c6f 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4206,7 +4206,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaCh else { std::string reactionString(reaction); - chat.addReaction(&msg, reactionString); + chat.addReaction(msg, reactionString); } } } @@ -4260,7 +4260,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh else { std::string reactionString(reaction); - chat.delReaction(&msg, reactionString); + chat.delReaction(msg, reactionString); } } } diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 0b84a86e5..f820813d2 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -514,7 +514,7 @@ void ParsedMessage::parsePayload(const StaticBuffer &data, Message &msg) } } -bool ProtocolHandler::isPublicChat() +bool ProtocolHandler::isPublicChat() const { return (mChatMode == CHAT_MODE_PUBLIC); } @@ -625,7 +625,7 @@ ProtocolHandler::ProtocolHandler(karere::Id ownHandle, } promise::Promise> -ProtocolHandler::reactionEncrypt(const Message *msg, std::string reaction) +ProtocolHandler::reactionEncrypt(const Message &msg, std::string reaction) { promise::Promise> symPms; if (isPublicChat()) @@ -634,14 +634,14 @@ ProtocolHandler::reactionEncrypt(const Message *msg, std::string reaction) } else { - symPms = getKey(UserKeyId(msg->userid, msg->keyid)); + symPms = getKey(UserKeyId(msg.userid, msg.keyid)); } auto wptr = weakHandle(); return symPms.then([wptr, msg, &reaction](const std::shared_ptr& data) { wptr.throwIfDeleted(); - std::string msgId = msg->id().toString(); + std::string msgId = msg.id().toString(); std::string keyBin (data->buf(), data->dataSize()); // Inside this function str_to_a32 and a32_to_str calls must be done with type = @@ -650,39 +650,33 @@ ProtocolHandler::reactionEncrypt(const Message *msg, std::string reaction) // key32 XOR msgId32 --> Cypherkey to encrypt reaction std::vector cypherKey(key32.size()); - for (int i = 0; i < key32.size(); i++) + for (size_t i = 0; i < key32.size(); i++) { cypherKey[i] = key32[i] ^ msgId32[i % msgId32.size()]; } // Add padding to reaction - size_t roundSize = ceil(static_cast(reaction.size()) / 4) * 4; - size_t diff = roundSize - reaction.size(); - if (diff > 0) + size_t emojiLenWithPadding = ceil(static_cast(reaction.size()) / 4) * 4; + size_t paddingSize = emojiLenWithPadding - reaction.size(); + for (size_t i = 0; i < paddingSize; i++) { - for (int i = 0; i < diff; i++) - { - reaction.insert(reaction.begin(), '\0'); - } + reaction.insert(reaction.begin(), '\0'); } - // Concat msgid[0..4] with emoji (previously padded) - size_t emojiLen = roundSize + 4; - char plaintext [emojiLen]; - memcpy(plaintext, msgId.data(), 4); - memcpy(plaintext + 4, reaction.data(), roundSize); + // Concat msgid[0..3] with emoji (previously padded) + std::string buf(msgId.data(), 4); + buf.append(reaction); + + // Convert into a unit32 array --> emoji32 + std::vector emoji32 = ::mega::Utils::str_to_a32(buf); - // emoji32 - std::vector emoji32 = ::mega::Utils::str_to_a32(std::string(plaintext, emojiLen)); + // Encrypt reaction + ::mega::xxteaEncrypt(&emoji32[0], emoji32.size(), cypherKey.data(), false); - // Encrypt reaction - ::mega::xxteaEncrypt(&emoji32[0], emoji32.size(), &cypherKey[0], false); + // Convert encrypted reaction to uint32 array + std::string result = ::mega::Utils::a32_to_str(emoji32); - // Convert encrypted reaction to uint32 array - std::string result = ::mega::Utils::a32_to_str(emoji32); - std::shared_ptrbuf; - buf.reset(new Buffer(result.data(), result.size())); - return buf; + return std::make_shared(result.data(), result.size()); }) .fail([](const ::promise::Error& err) { @@ -691,7 +685,7 @@ ProtocolHandler::reactionEncrypt(const Message *msg, std::string reaction) } promise::Promise> -ProtocolHandler::reactionDecrypt(const Message *msg, std::string reaction) +ProtocolHandler::reactionDecrypt(const Message &msg, std::string reaction) { promise::Promise> symPms; if (isPublicChat()) @@ -700,14 +694,14 @@ ProtocolHandler::reactionDecrypt(const Message *msg, std::string reaction) } else { - symPms = getKey(UserKeyId(msg->userid, msg->keyid)); + symPms = getKey(UserKeyId(msg.userid, msg.keyid)); } auto wptr = weakHandle(); return symPms.then([wptr, msg, reaction](const std::shared_ptr& data) { wptr.throwIfDeleted(); - std::string msgId = msg->id().toString(); + std::string msgId = msg.id().toString(); std::string keyBin (data->buf(), data->dataSize()); // Inside this function str_to_a32 and a32_to_str calls must be done with type = @@ -716,31 +710,24 @@ ProtocolHandler::reactionDecrypt(const Message *msg, std::string reaction) // key32 XOR msgId32 --> Cypherkey to encrypt reaction std::vector cypherKey(key32.size()); - for (int i = 0; i < key32.size(); i++) + for (size_t i = 0; i < key32.size(); i++) { cypherKey[i] = key32[i] ^ msgId32[i % msgId32.size()]; } std::vector reaction32 = ::mega::Utils::str_to_a32(reaction); - ::mega::xxteaDecrypt(&reaction32[0], reaction32.size(), &cypherKey[0], false); + ::mega::xxteaDecrypt(reaction32.data(), reaction32.size(), cypherKey.data(), false); std::string decrypted = ::mega::Utils::a32_to_str(reaction32); - int count = 0; - for (int i = 4; i < decrypted.size(); ++i) + // skip the msgid's part (4 most significat bytes) and the left-padding (if any) + size_t pos = 4; + while (pos < decrypted.size() && decrypted[pos] == '\0') { - if (decrypted[i] != '\0') - { - count ++; - } + pos++; } + assert(pos <= 4 + 3); // maximum left-padding should not be greater than 3 bytes - char *resultEmoji = new char[count]; - memcpy(resultEmoji, (char *) (decrypted.data() + 4 + (4-count)), count); - std::string aux(resultEmoji, count); - - std::shared_ptrbuf; - buf.reset(new Buffer(aux.data(), aux.size())); - return buf; + return std::make_shared(decrypted.data() + pos, decrypted.size() - pos); }) .fail([](const ::promise::Error& err) { diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index abbfbf809..f0505bf29 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -449,14 +449,14 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable static Buffer* createUnifiedKey(); virtual promise::Promise > getUnifiedKey(); virtual bool previewMode(); - virtual bool isPublicChat(); virtual void setPrivateChatMode(); virtual void onHistoryReload(); virtual uint64_t getPublicHandle() const; virtual void setPublicHandle(const uint64_t ph); + bool isPublicChat() const override; - virtual promise::Promise> reactionEncrypt(const chatd::Message *msg, std::string reaction); - virtual promise::Promise> reactionDecrypt(const chatd::Message *msg, std::string reaction); + promise::Promise> reactionEncrypt(const chatd::Message &msg, std::string reaction) override; + promise::Promise> reactionDecrypt(const chatd::Message &msg, std::string reaction) override; }; } namespace chatd From ffc7df3be334e5482211f91729b255ee84c37d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 17:34:27 +0200 Subject: [PATCH 080/100] Add override to strongvelope --- src/strongvelope/strongvelope.h | 50 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index f0505bf29..1fc14ac95 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -427,33 +427,33 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable public: //chatd::ICrypto interface promise::Promise> - msgEncrypt(chatd::Message *message, const karere::SetOfIds &recipients, chatd::MsgCommand* msgCmd); - virtual promise::Promise msgDecrypt(chatd::Message* message); - virtual void onKeyReceived(chatd::KeyId keyid, karere::Id sender, - karere::Id receiver, const char* data, uint16_t dataLen); - virtual void onKeyConfirmed(chatd::KeyId localkeyid, chatd::KeyId keyid); - virtual void onKeyRejected(); - virtual void setUsers(karere::SetOfIds* users); - virtual void onUserJoin(karere::Id userid); - virtual void onUserLeave(karere::Id userid); - virtual void resetSendKey(); - virtual bool handleLegacyKeys(chatd::Message& msg); - virtual void randomBytes(void* buf, size_t bufsize) const; - virtual promise::Promise> encryptChatTitle(const std::string& data, uint64_t extraUser = 0, bool encryptAsPrivate = false); - virtual promise::Promise encryptUnifiedKeyForAllParticipants(uint64_t extraUser = 0); - - virtual promise::Promise decryptChatTitleFromApi(const Buffer& data); - - virtual promise::Promise - decryptUnifiedKey(std::shared_ptr& key, uint64_t sender, uint64_t receiver); + msgEncrypt(chatd::Message *message, const karere::SetOfIds &recipients, chatd::MsgCommand* msgCmd) override; + promise::Promise msgDecrypt(chatd::Message* message) override; + void onKeyReceived(chatd::KeyId keyid, karere::Id sender, + karere::Id receiver, const char* data, uint16_t dataLen) override; + void onKeyConfirmed(chatd::KeyId localkeyid, chatd::KeyId keyid) override; + void onKeyRejected() override; + void setUsers(karere::SetOfIds* users) override; + void onUserJoin(karere::Id userid) override; + void onUserLeave(karere::Id userid) override; + void resetSendKey() override; + bool handleLegacyKeys(chatd::Message& msg) override; + void randomBytes(void* buf, size_t bufsize) const override; + promise::Promise> encryptChatTitle(const std::string& data, uint64_t extraUser = 0, bool encryptAsPrivate = false) override; + promise::Promise encryptUnifiedKeyForAllParticipants(uint64_t extraUser = 0) override; + + promise::Promise decryptChatTitleFromApi(const Buffer& data) override; + + promise::Promise + decryptUnifiedKey(std::shared_ptr& key, uint64_t sender, uint64_t receiver) override; static Buffer* createUnifiedKey(); - virtual promise::Promise > getUnifiedKey(); - virtual bool previewMode(); - virtual void setPrivateChatMode(); - virtual void onHistoryReload(); - virtual uint64_t getPublicHandle() const; - virtual void setPublicHandle(const uint64_t ph); + promise::Promise > getUnifiedKey() override; + bool previewMode() override; bool isPublicChat() const override; + void setPrivateChatMode() override; + void onHistoryReload() override; + uint64_t getPublicHandle() const override; + void setPublicHandle(const uint64_t ph) override; promise::Promise> reactionEncrypt(const chatd::Message &msg, std::string reaction) override; promise::Promise> reactionDecrypt(const chatd::Message &msg, std::string reaction) override; From 0582ba1d4e2752d59bc46a82b2bb90fad0e8602e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Mon, 30 Sep 2019 18:04:29 +0200 Subject: [PATCH 081/100] Adjust constness --- src/chatd.cpp | 10 +++++----- src/chatd.h | 4 ++-- src/chatdICrypto.h | 4 ++-- src/megachatapi_impl.cpp | 6 ++---- src/strongvelope/strongvelope.cpp | 15 ++++++--------- src/strongvelope/strongvelope.h | 4 ++-- 6 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 6be21761a..15f90d734 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -2566,7 +2566,7 @@ void Chat::sendSync() } -void Chat::addReaction(const Message &message, std::string reaction) +void Chat::addReaction(const Message &message, const std::string &reaction) { auto wptr = weakHandle(); marshallCall([wptr, this, message, reaction]() @@ -2575,7 +2575,7 @@ void Chat::addReaction(const Message &message, std::string reaction) return; mCrypto->reactionEncrypt(message, reaction) - .then([this, wptr, message](std::shared_ptr data) + .then([this, wptr, &message](std::shared_ptr data) { if (wptr.deleted()) return; @@ -2590,16 +2590,16 @@ void Chat::addReaction(const Message &message, std::string reaction) }, mChatdClient.mKarereClient->appCtx); } -void Chat::delReaction(const Message &message, std::string reaction) +void Chat::delReaction(const Message &message, const std::string &reaction) { auto wptr = weakHandle(); - marshallCall([wptr, this, message, reaction]() + marshallCall([wptr, this, &message, reaction]() { if (wptr.deleted()) return; mCrypto->reactionEncrypt(message, reaction) - .then([this, wptr, message](std::shared_ptr data) + .then([this, wptr, &message](std::shared_ptr data) { if (wptr.deleted()) return; diff --git a/src/chatd.h b/src/chatd.h index 8602f5a03..62250b254 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1296,8 +1296,8 @@ class Chat: public karere::DeleteTrackable uint32_t getNumPreviewers() const; void clearHistory(); void sendSync(); - void addReaction(const Message &message, std::string reaction); - void delReaction(const Message &message, std::string reaction); + void addReaction(const Message &message, const std::string &reaction); + void delReaction(const Message &message, const std::string &reaction); void sendReactionSn(); void setPublicHandle(uint64_t ph); uint64_t getPublicHandle() const; diff --git a/src/chatdICrypto.h b/src/chatdICrypto.h index 6353c2653..5a8908884 100644 --- a/src/chatdICrypto.h +++ b/src/chatdICrypto.h @@ -163,14 +163,14 @@ class ICrypto * @param msg The message associated to the reaction. * @param reaction An UTF-8 string. */ - virtual promise::Promise> reactionEncrypt(const Message &msg, std::string reaction) = 0; + virtual promise::Promise> reactionEncrypt(const Message &msg, const std::string &reaction) = 0; /** * @brief Decrypts a reaction with xxtea. * @param msg The message associated to the reaction. * @param reaction The encrypted reaction. */ - virtual promise::Promise> reactionDecrypt(const Message &msg, std::string reaction) = 0; + virtual promise::Promise> reactionDecrypt(const Message &msg,const std::string &reaction) = 0; /** * @brief The crypto module is destroyed when that chatid is left or the client is destroyed diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index e091a0c6f..45c68e855 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4205,8 +4205,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaCh } else { - std::string reactionString(reaction); - chat.addReaction(msg, reactionString); + chat.addReaction(msg, reaction); } } } @@ -4259,8 +4258,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh } else { - std::string reactionString(reaction); - chat.delReaction(msg, reactionString); + chat.delReaction(msg, reaction); } } } diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index f820813d2..6243cd912 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -625,7 +625,7 @@ ProtocolHandler::ProtocolHandler(karere::Id ownHandle, } promise::Promise> -ProtocolHandler::reactionEncrypt(const Message &msg, std::string reaction) +ProtocolHandler::reactionEncrypt(const Message &msg, const std::string &reaction) { promise::Promise> symPms; if (isPublicChat()) @@ -638,7 +638,7 @@ ProtocolHandler::reactionEncrypt(const Message &msg, std::string reaction) } auto wptr = weakHandle(); - return symPms.then([wptr, msg, &reaction](const std::shared_ptr& data) + return symPms.then([wptr, &msg, &reaction](const std::shared_ptr& data) { wptr.throwIfDeleted(); std::string msgId = msg.id().toString(); @@ -658,13 +658,10 @@ ProtocolHandler::reactionEncrypt(const Message &msg, std::string reaction) // Add padding to reaction size_t emojiLenWithPadding = ceil(static_cast(reaction.size()) / 4) * 4; size_t paddingSize = emojiLenWithPadding - reaction.size(); - for (size_t i = 0; i < paddingSize; i++) - { - reaction.insert(reaction.begin(), '\0'); - } - // Concat msgid[0..3] with emoji (previously padded) + // Concat msgid[0..3] with emoji and padding std::string buf(msgId.data(), 4); + buf.append(paddingSize, '\0'); buf.append(reaction); // Convert into a unit32 array --> emoji32 @@ -685,7 +682,7 @@ ProtocolHandler::reactionEncrypt(const Message &msg, std::string reaction) } promise::Promise> -ProtocolHandler::reactionDecrypt(const Message &msg, std::string reaction) +ProtocolHandler::reactionDecrypt(const Message &msg, const std::string &reaction) { promise::Promise> symPms; if (isPublicChat()) @@ -698,7 +695,7 @@ ProtocolHandler::reactionDecrypt(const Message &msg, std::string reaction) } auto wptr = weakHandle(); - return symPms.then([wptr, msg, reaction](const std::shared_ptr& data) + return symPms.then([wptr, &msg, &reaction](const std::shared_ptr& data) { wptr.throwIfDeleted(); std::string msgId = msg.id().toString(); diff --git a/src/strongvelope/strongvelope.h b/src/strongvelope/strongvelope.h index 1fc14ac95..9e5929642 100644 --- a/src/strongvelope/strongvelope.h +++ b/src/strongvelope/strongvelope.h @@ -455,8 +455,8 @@ class ProtocolHandler: public chatd::ICrypto, public karere::DeleteTrackable uint64_t getPublicHandle() const override; void setPublicHandle(const uint64_t ph) override; - promise::Promise> reactionEncrypt(const chatd::Message &msg, std::string reaction) override; - promise::Promise> reactionDecrypt(const chatd::Message &msg, std::string reaction) override; + promise::Promise> reactionEncrypt(const chatd::Message &msg, const std::string &reaction) override; + promise::Promise> reactionDecrypt(const chatd::Message &msg, const std::string &reaction) override; }; } namespace chatd From f2e11a73fd2c92b45741ded94121ea0f7b5ba27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Tue, 1 Oct 2019 19:24:45 +0200 Subject: [PATCH 082/100] Adjust constness and override --- src/chatd.h | 2 +- src/chatdDb.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/chatd.h b/src/chatd.h index 62250b254..aee415d36 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1584,7 +1584,7 @@ class DbInterface // <<<--- Reaction methods --->>> virtual std::string getReactionSn() = 0; - virtual void setReactionSn(std::string rsn) = 0; + virtual void setReactionSn(const std::string &rsn) = 0; virtual void cleanReactions() = 0; virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; virtual void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; diff --git a/src/chatdDb.h b/src/chatdDb.h index 4f5ab0847..1fbd88b53 100644 --- a/src/chatdDb.h +++ b/src/chatdDb.h @@ -536,7 +536,7 @@ class ChatdSqliteDb: public chatd::DbInterface } } - virtual std::string getReactionSn() + std::string getReactionSn() override { SqliteStmt stmt(mDb, "select rsn from chats where chatid = ?"); stmt << mChat.chatId(); @@ -544,30 +544,30 @@ class ChatdSqliteDb: public chatd::DbInterface return stmt.stringCol(0); } - virtual void setReactionSn(std::string rsn) + void setReactionSn(const std::string &rsn) override { mDb.query("update chats set rsn = ? where chatid = ?", rsn, mChat.chatId()); assertAffectedRowCount(1); } - virtual void cleanReactions() + void cleanReactions() override { mDb.query("delete from chat_reactions where chatid = ?", mChat.chatId()); } - virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) + void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) override { mDb.query("insert into chat_reactions(chatid, msgid, userid, reaction)" "values(?,?,?,?)", mChat.chatId(), msgId, userId, reaction); } - virtual void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) + void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) override { mDb.query("delete from chat_reactions where chatid = ? and msgid = ? and userid = ? and reaction = ?", mChat.chatId(), msgId, userId, reaction); } - virtual void getMessageReactions(karere::Id msgId, ::mega::multimap& reactions) + void getMessageReactions(karere::Id msgId, ::mega::multimap& reactions) override { SqliteStmt stmt(mDb, "select reaction, userid from chat_reactions where chatid = ? and msgid = ?"); stmt << mChat.chatId(); From 38cc871e1fa0a234570000b80800fda93e16f31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 14:18:59 +0200 Subject: [PATCH 083/100] Create convenience method `Reaction::hasReacted(userid)` --- src/chatdMsg.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/chatdMsg.h b/src/chatdMsg.h index 74b09dbdd..ea9156fde 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -561,6 +561,10 @@ class Message: public Buffer } return -1; } + bool hasReacted(karere::Id userId) const + { + return userIndex(userId) != -1; + } }; class CallEndedInfo @@ -797,7 +801,7 @@ class Message: public Buffer { if (it.mReaction == reaction) { - return it.userIndex(uh) >= 0; + return it.hasReacted(uh); } } return false; @@ -869,8 +873,7 @@ class Message: public Buffer r = &mReactions.back(); } - int userIndex = r->userIndex(userId); - if (userIndex < 0) + if (!r->hasReacted(userId)) { r->mUsers.emplace_back(userId); } From f22099ca4071e6aeea26cd442209d4d4d0f0753b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 14:19:38 +0200 Subject: [PATCH 084/100] Fix text + Update doc The error code for unexisting reaction is now `ENOENT` --- src/megachatapi.h | 12 ++++++------ tests/sdk_test/sdk_test.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/megachatapi.h b/src/megachatapi.h index c88bb6e31..6db440192 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -3291,7 +3291,8 @@ class MegaChatApi * all reactions associated to the message are wiped and must be cleared by applications. * * You can expect a call to \c MegaChatRoomListener::onMessageUpdate where the message - * will have no content and it will be of type \c MegaChatMessage::TYPE_TRUNCATE. + * will have no content and it will be of type \c MegaChatMessage::TYPE_TRUNCATE. Any + * reactions associated to the original message will be cleared. * * The associated request type with this request is MegaChatRequest::TYPE_TRUNCATE_HISTORY * Valid data in the MegaChatRequest object received on callbacks: @@ -3310,14 +3311,13 @@ class MegaChatApi void truncateChat(MegaChatHandle chatid, MegaChatHandle messageid, MegaChatRequestListener *listener = NULL); /** - * @brief Allows a logged in operator/moderator to clear the entire chat history up - * to a certain message. All earlier messages are wiped, but this specific message - * will be overwritten by a management message. In addition all reactions associated - * to the message are wiped and must be cleared by applications. + * @brief Allows a logged in operator/moderator to clear the entire chat history * + * If the history is not already empty, the latest message will be overwritten by * You can expect a call to \c MegaChatRoomListener::onMessageUpdate * where the message will have no content and it will be of type - * \c MegaChatMessage::TYPE_TRUNCATE. + * \c MegaChatMessage::TYPE_TRUNCATE. Any reactions associated to the original + * message will be cleared. * * The associated request type with this request is MegaChatRequest::TYPE_TRUNCATE_HISTORY * Valid data in the MegaChatRequest object received on callbacks: diff --git a/tests/sdk_test/sdk_test.cpp b/tests/sdk_test/sdk_test.cpp index 20548c75a..1fbb13cec 100644 --- a/tests/sdk_test/sdk_test.cpp +++ b/tests/sdk_test/sdk_test.cpp @@ -1816,7 +1816,7 @@ void MegaChatApiTest::TEST_Reactions(unsigned int a1, unsigned int a2) ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_OK, "delReaction: failed to remove a reaction. Error:" + std::string(res->getErrorString())); ASSERT_CHAT_TEST(waitForResponse(reactionReceived), "Expired timeout for remove reaction"); res.reset(megaChatApi[a1]->delReaction(chatid, msgId, "😰")); - ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_EXIST, "delReaction: Unexpected error for unexisting reaction. Error:" + std::string(res->getErrorString())); + ASSERT_CHAT_TEST(res->getErrorCode() == MegaChatError::ERROR_NOENT, "delReaction: Unexpected error for unexisting reaction. Error:" + std::string(res->getErrorString())); // Close chatroom megaChatApi[a1]->closeChatRoom(chatid, chatroomListener); From 26db5bbd8673c00f9b6c87f715d7bd0612e2a46f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 14:35:52 +0200 Subject: [PATCH 085/100] Update doc Error codes, style and namespaces --- src/megachatapi.h | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/megachatapi.h b/src/megachatapi.h index 6db440192..dddb0987b 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4578,61 +4578,60 @@ class MegaChatApi void removeChatNotificationListener(MegaChatNotificationListener* listener); /** - * @brief Adds a reaction for a message in a chatroom. + * @brief Adds a reaction for a message in a chatroom + * * The reactions updates will be notified one by one through the MegaChatRoomListener * specified at MegaChatApi::openChatRoom (and through any other listener you may have - * registered by calling MegaChatApi::addChatRoomListener). + * registered by calling MegaChatApi::addChatRoomListener). The corresponding callback + * is MegaChatRoomListener::onReactionUpdate. * * You take the ownership of the returned value. * - * The corresponding callback is MegaChatRoomListener::onReactionUpdate. * Possible error codes associated to MegaChatError can be: - * - MegaChatError::ERROR_OK - If no errors occurred. - * - MegaChatError::ERROR_ARGS - If reaction is NULL - * - MegaChatError::ERROR_NOENT - If the chatroom or message - * doesn't exists or if the message it's a management message - * - MegaChatError::ERROR_ACCESS if our own privilege is different than - * MegaChatPeerList::PRIV_STANDARD or MegaChatPeerList::PRIV_MODERATOR - * - MegaChatError::API_EEXIST if our own user has reacted previously with this reaction + * - MegaChatError::ERROR_OK: if no errors occurred. + * - MegaChatError::ERROR_ARGS: if reaction is NULL or the msgid references a management message. + * - MegaChatError::ERROR_NOENT: if the chatroom/message doesn't exists + * - MegaChatError::ERROR_ACCESS: if our own privilege is different than + * MegaChatPeerList::PRIV_STANDARD or MegaChatPeerList::PRIV_MODERATOR. + * - MegaChatError::API_EEXIST: if our own user has reacted previously with this reaction * for this message * * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message - * @param reaction UTF-8 NULL terminated string that represents the reaction + * @param reaction UTF-8 NULL-terminated string that represents the reaction * * @return returns MegaChatError with an error code associated. */ MegaChatError *addReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); /** - * @brief Removes a reaction for a message in a chatroom. + * @brief Removes a reaction for a message in a chatroom + * * The reactions updates will be notified one by one through the MegaChatRoomListener * specified at MegaChatApi::openChatRoom (and through any other listener you may have - * registered by calling MegaChatApi::addChatRoomListener). + * registered by calling MegaChatApi::addChatRoomListener). The corresponding callback + * is MegaChatRoomListener::onReactionUpdate. * * You take the ownership of the returned value. * - * The corresponding callback is MegaChatRoomListener::onReactionUpdate * Possible error codes associated to MegaChatError can be: - * - MegaChatError::ERROR_OK - If no errors occurred. - * - MegaChatError::ERROR_ARGS - If reaction is NULL - * - MegaChatError::ERROR_NOENT - If the chatroom or message - * doesn't exists or if the message it's a management message - * - MegaChatError::ERROR_ACCESS if our own privilege is different than + * - MegaChatError::ERROR_OK: if no errors occurred. + * - MegaChatError::ERROR_ARGS: if reaction is NULL or the msgid references a management message. + * - MegaChatError::ERROR_NOENT: if the chatroom/message doesn't exists, or if your own user has + * not reacted to the message with the specified reaction. + * - MegaChatError::ERROR_ACCESS: if our own privilege is different than * MegaChatPeerList::PRIV_STANDARD or MegaChatPeerList::PRIV_MODERATOR - * - MegaChatError::API_EEXIST if our own user has not reacted previously with this reaction - * for this message * * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message - * @param reaction UTF-8 NULL terminated string that represents the reaction + * @param reaction UTF-8 NULL-terminated string that represents the reaction * * @return returns MegaChatError with an error code associated. */ MegaChatError *delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); /** - * @brief Returns the number of users that reacted to a message with a specific reaction. + * @brief Returns the number of users that reacted to a message with a specific reaction * * @param chatid MegaChatHandle that identifies the chatroom * @param msgid MegaChatHandle that identifies the message @@ -4651,10 +4650,11 @@ class MegaChatApi * @param msgid MegaChatHandle that identifies the message * @return return a list with the reactions associated to a message. */ - mega::MegaStringList* getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid); + ::mega::MegaStringList* getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid); /** * @brief Gets a list of users that reacted to a message with a specific reaction + * * You take the ownership of the returned value. * * @param chatid MegaChatHandle that identifies the chatroom @@ -4663,7 +4663,7 @@ class MegaChatApi * * @return return a list with the users that reacted to a message with a specific reaction. */ - mega::MegaHandleList* getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); + ::mega::MegaHandleList* getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction); #ifndef KARERE_DISABLE_WEBRTC /** From 06e355f4f094b9832e47c16c828d9b7e43f781d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 17:18:03 +0200 Subject: [PATCH 086/100] Fix memory leak at getMessageReactions() Additionally, add the SdkMutexGuard to MEGAchat --- src/megachatapi.h | 12 +++++++- src/megachatapi_impl.cpp | 59 ++++++++++++++++------------------------ src/megachatapi_impl.h | 1 + 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/megachatapi.h b/src/megachatapi.h index dddb0987b..b32954d8c 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -5568,7 +5568,17 @@ class MegaChatRoomListener * @param chat MegaChatRoom whose local history is about to be discarded */ virtual void onHistoryReloaded(MegaChatApi* api, MegaChatRoom *chat); - virtual void onReactionUpdate(MegaChatApi* /*api*/, MegaChatHandle /*msgid*/, const char* /*reaction*/, int /*count*/); + + + /** + * @brief This function is called when a message has been reacted (or an existing reaction has been removed) + * + * @param api MegaChatApi connected to the account + * @param msgid MegaChatHandle that identifies the message + * @param reaction UTF-8 NULL-terminated string that represents the reaction + * @param count Number of users who have reacted to this message with the same reaction + */ + virtual void onReactionUpdate(MegaChatApi* api, MegaChatHandle msgid, const char* reaction, int count); }; /** diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 45c68e855..56a8e140f 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4172,7 +4172,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaCh return megaChatError; } - sdkMutex.lock(); + SdkMutexGuard g(sdkMutex); ChatRoom *chatroom = findChatRoom(chatid); if (!chatroom) { @@ -4180,7 +4180,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaCh } else { - if (chatroom->ownPriv() < MegaChatPeerList::PRIV_STANDARD) + if (chatroom->ownPriv() < static_cast(MegaChatPeerList::PRIV_STANDARD)) { errorCode = MegaChatError::ERROR_ACCESS; } @@ -4210,9 +4210,8 @@ MegaChatErrorPrivate *MegaChatApiImpl::addReaction(MegaChatHandle chatid, MegaCh } } } - sdkMutex.unlock(); - megaChatError = new MegaChatErrorPrivate(errorCode); - return megaChatError; + + return new MegaChatErrorPrivate(errorCode); } MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) @@ -4225,7 +4224,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh return megaChatError; } - sdkMutex.lock(); + SdkMutexGuard g(sdkMutex); ChatRoom *chatroom = findChatRoom(chatid); if (!chatroom) { @@ -4233,7 +4232,7 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh } else { - if (chatroom->ownPriv() < MegaChatPeerList::PRIV_STANDARD) + if (chatroom->ownPriv() < static_cast(MegaChatPeerList::PRIV_STANDARD)) { errorCode = MegaChatError::ERROR_ACCESS; } @@ -4263,15 +4262,16 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh } } } - sdkMutex.unlock(); - megaChatError = new MegaChatErrorPrivate(errorCode); - return megaChatError; + + return new MegaChatErrorPrivate(errorCode); } int MegaChatApiImpl::getMessageReactionCount(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { int count = 0; - sdkMutex.lock(); + + SdkMutexGuard g(sdkMutex); + ChatRoom *chatroom = findChatRoom(chatid); if (chatroom) { @@ -4281,56 +4281,45 @@ int MegaChatApiImpl::getMessageReactionCount(MegaChatHandle chatid, MegaChatHand count = msg->getReactionCount(reaction); } } - sdkMutex.unlock(); + return count; } MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) -{ - MegaStringList *reactionList = NULL; - sdkMutex.lock(); +{ + SdkMutexGuard g(sdkMutex); - int numReactions = 0; - ::mega::unique_ptr reactArray = nullptr; + vector reactArray; ChatRoom *chatroom = findChatRoom(chatid); if (chatroom) { Message *msg = findMessage(chatid, msgid); if (msg) { - std::vector reactions = msg->getReactions(); - if (!reactions.empty()) + std::vector reactions(msg->getReactions()); + for (auto &it : reactions) { - numReactions = static_cast(reactions.size()); - reactArray.reset(new char*[numReactions]); - - size_t i = 0; - for (auto &it : reactions) - { - reactArray[i] = MegaApi::strdup(it.c_str()); - i++; - } + reactArray.push_back(MegaApi::strdup(it.c_str())); } } } - reactionList = new MegaStringListPrivate(reactArray.get(), numReactions); - sdkMutex.unlock(); - return reactionList; + return new MegaStringListPrivate(reactArray.data(), static_cast(reactArray.size())); } MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { MegaHandleListPrivate *userList = new MegaHandleListPrivate(); - sdkMutex.lock(); + + SdkMutexGuard g(sdkMutex); ChatRoom *chatroom = findChatRoom(chatid); - if (chatroom) + if (chatroom && reaction) { Message *msg = findMessage(chatid, msgid); if (msg) { - const std::vector *users = msg->getReactionUsers(std::string(reaction)); + const std::vector *users = msg->getReactionUsers(reaction); if (users) { for (auto &userid : *users) @@ -4340,7 +4329,7 @@ MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaCha } } } - sdkMutex.unlock(); + return userList; } diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index 391d07a1b..f5a468190 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -905,6 +905,7 @@ class MegaChatApiImpl : MegaChatApiImpl(MegaChatApi *chatApi, mega::MegaApi *megaApi); virtual ~MegaChatApiImpl(); + using SdkMutexGuard = std::unique_lock; // (equivalent to typedef) std::recursive_mutex sdkMutex; std::recursive_mutex videoMutex; mega::Waiter *waiter; From 1d2de4f7e76220d0b39c45c21733795e4738314c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 17:33:19 +0200 Subject: [PATCH 087/100] Unify the usage of `MegaStringListPrivate` ctor --- src/megachatapi_impl.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 56a8e140f..c29269519 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4376,23 +4376,13 @@ rtcModule::ICallHandler *MegaChatApiImpl::onGroupCallActive(Id chatid, Id callid MegaStringList *MegaChatApiImpl::getChatInDevices(const std::vector &devicesVector) { - int devicesNumber = devicesVector.size(); - char **devicesArray = NULL; - if (devicesNumber > 0) + vector devicesArray; + for (auto &device : devicesVector) { - devicesArray = new char*[devicesNumber]; - for (int i = 0; i < devicesNumber; ++i) - { - char *device = MegaApi::strdup(devicesVector[i].c_str()); - devicesArray[i] = device; - } + devicesArray.push_back(::mega::MegaApi::strdup(device.c_str())); } - MegaStringList *devices = new MegaStringListPrivate(devicesArray, devicesNumber); - delete [] devicesArray; - - return devices; - + return new MegaStringListPrivate(devicesArray.data(), static_cast(devicesArray.size())); } void MegaChatApiImpl::cleanCallHandlerMap() From aff8e8c76b6df22589619c78022a62624c3e7cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 18:18:37 +0200 Subject: [PATCH 088/100] Improve getMessageReactions() and getMessageReactionCount() Add error messages for things going wrong --- src/megachatapi.h | 3 ++- src/megachatapi_impl.cpp | 44 +++++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/megachatapi.h b/src/megachatapi.h index b32954d8c..ea3240674 100644 --- a/src/megachatapi.h +++ b/src/megachatapi.h @@ -4637,7 +4637,8 @@ class MegaChatApi * @param msgid MegaChatHandle that identifies the message * @param reaction UTF-8 NULL terminated string that represents the reaction * - * @return return the number of users that reacted to a message with a specific reaction. + * @return return the number of users that reacted to a message with a specific reaction, + * or -1 if the chatroom or message is not found. */ int getMessageReactionCount(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) const; diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index c29269519..9dcf1e582 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -4268,21 +4268,16 @@ MegaChatErrorPrivate *MegaChatApiImpl::delReaction(MegaChatHandle chatid, MegaCh int MegaChatApiImpl::getMessageReactionCount(MegaChatHandle chatid, MegaChatHandle msgid, const char *reaction) { - int count = 0; - SdkMutexGuard g(sdkMutex); - ChatRoom *chatroom = findChatRoom(chatid); - if (chatroom) + Message *msg = findMessage(chatid, msgid); + if (!msg) { - Message *msg = findMessage(chatid, msgid); - if (msg) - { - count = msg->getReactionCount(reaction); - } + API_LOG_ERROR("Chatroom or message not found"); + return -1; } - return count; + return msg->getReactionCount(reaction); } MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, MegaChatHandle msgid) @@ -4290,19 +4285,19 @@ MegaStringList* MegaChatApiImpl::getMessageReactions(MegaChatHandle chatid, Mega SdkMutexGuard g(sdkMutex); vector reactArray; - ChatRoom *chatroom = findChatRoom(chatid); - if (chatroom) + Message *msg = findMessage(chatid, msgid); + if (msg) { - Message *msg = findMessage(chatid, msgid); - if (msg) + std::vector reactions(msg->getReactions()); + for (auto &it : reactions) { - std::vector reactions(msg->getReactions()); - for (auto &it : reactions) - { - reactArray.push_back(MegaApi::strdup(it.c_str())); - } + reactArray.push_back(MegaApi::strdup(it.c_str())); } } + else + { + API_LOG_ERROR("Chatroom or message not found"); + } return new MegaStringListPrivate(reactArray.data(), static_cast(reactArray.size())); } @@ -4313,8 +4308,7 @@ MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaCha SdkMutexGuard g(sdkMutex); - ChatRoom *chatroom = findChatRoom(chatid); - if (chatroom && reaction) + if (reaction && reaction[0] != '\0') { Message *msg = findMessage(chatid, msgid); if (msg) @@ -4328,6 +4322,14 @@ MegaHandleList* MegaChatApiImpl::getReactionUsers(MegaChatHandle chatid, MegaCha } } } + else + { + API_LOG_ERROR("Chatroom or message not found"); + } + } + else + { + API_LOG_ERROR("Empty reaction"); } return userList; From 710af1f56a72ebeffffa0faccd1359ef1c1a4565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 18:34:09 +0200 Subject: [PATCH 089/100] Protect against JSON parsing errors for attachments/voiceclips --- src/megachatapi_impl.cpp | 42 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 9dcf1e582..c2cc2f0c5 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -5908,19 +5908,18 @@ void MegaChatRoomHandler::handleHistoryMessage(MegaChatMessage *message) if (message->getType() == MegaChatMessage::TYPE_NODE_ATTACHMENT) { MegaNodeList *nodeList = message->getMegaNodeList(); - if (!nodeList) + if (nodeList) { - return; - } - for (int i = 0; i < nodeList->size(); i++) - { - MegaChatHandle h = nodeList->get(i)->getHandle(); - auto itAccess = attachmentsAccess.find(h); - if (itAccess == attachmentsAccess.end()) + for (int i = 0; i < nodeList->size(); i++) { - attachmentsAccess[h] = true; + MegaChatHandle h = nodeList->get(i)->getHandle(); + auto itAccess = attachmentsAccess.find(h); + if (itAccess == attachmentsAccess.end()) + { + attachmentsAccess[h] = true; + } + attachmentsIds[h].insert(message->getMsgId()); } - attachmentsIds[h].insert(message->getMsgId()); } } else if (message->getType() == MegaChatMessage::TYPE_REVOKE_NODE_ATTACHMENT) @@ -5942,21 +5941,24 @@ std::set *MegaChatRoomHandler::handleNewMessage(MegaChatMessage if (message->getType() == MegaChatMessage::TYPE_NODE_ATTACHMENT) { MegaNodeList *nodeList = message->getMegaNodeList(); - for (int i = 0; i < nodeList->size(); i++) + if (nodeList) { - MegaChatHandle h = nodeList->get(i)->getHandle(); - auto itAccess = attachmentsAccess.find(h); - if (itAccess != attachmentsAccess.end() && !itAccess->second) + for (int i = 0; i < nodeList->size(); i++) { - // access changed from revoked to granted --> update attachment messages - if (!msgToUpdate) + MegaChatHandle h = nodeList->get(i)->getHandle(); + auto itAccess = attachmentsAccess.find(h); + if (itAccess != attachmentsAccess.end() && !itAccess->second) { - msgToUpdate = new set ; + // access changed from revoked to granted --> update attachment messages + if (!msgToUpdate) + { + msgToUpdate = new set ; + } + msgToUpdate->insert(attachmentsIds[h].begin(), attachmentsIds[h].end()); } - msgToUpdate->insert(attachmentsIds[h].begin(), attachmentsIds[h].end()); + attachmentsAccess[h] = true; + attachmentsIds[h].insert(message->getMsgId()); } - attachmentsAccess[h] = true; - attachmentsIds[h].insert(message->getMsgId()); } } else if (message->getType() == MegaChatMessage::TYPE_REVOKE_NODE_ATTACHMENT) From de96e8985e828e20a39aa7604f46a7bca726a35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Wed, 2 Oct 2019 19:02:26 +0200 Subject: [PATCH 090/100] Adjustments to reactionEncrypt/reactionDecrypt Mostly cosmetic ones. Nothing relevant --- src/strongvelope/strongvelope.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/strongvelope/strongvelope.cpp b/src/strongvelope/strongvelope.cpp index 6243cd912..cb6f49982 100644 --- a/src/strongvelope/strongvelope.cpp +++ b/src/strongvelope/strongvelope.cpp @@ -641,18 +641,21 @@ ProtocolHandler::reactionEncrypt(const Message &msg, const std::string &reaction return symPms.then([wptr, &msg, &reaction](const std::shared_ptr& data) { wptr.throwIfDeleted(); - std::string msgId = msg.id().toString(); - std::string keyBin (data->buf(), data->dataSize()); // Inside this function str_to_a32 and a32_to_str calls must be done with type = + std::string keyBin(data->buf(), data->dataSize()); std::vector key32 = ::mega::Utils::str_to_a32(keyBin); + size_t key32Len = key32.size(); + + std::string msgId(msg.id().toString()); std::vector msgId32 = ::mega::Utils::str_to_a32(msgId); + size_t msgId32Len = msgId32.size(); // key32 XOR msgId32 --> Cypherkey to encrypt reaction - std::vector cypherKey(key32.size()); - for (size_t i = 0; i < key32.size(); i++) + std::vector cypherKey(key32Len); + for (size_t i = 0; i < key32Len; i++) { - cypherKey[i] = key32[i] ^ msgId32[i % msgId32.size()]; + cypherKey[i] = key32[i] ^ msgId32[i % msgId32Len]; } // Add padding to reaction @@ -668,7 +671,7 @@ ProtocolHandler::reactionEncrypt(const Message &msg, const std::string &reaction std::vector emoji32 = ::mega::Utils::str_to_a32(buf); // Encrypt reaction - ::mega::xxteaEncrypt(&emoji32[0], emoji32.size(), cypherKey.data(), false); + ::mega::xxteaEncrypt(emoji32.data(), emoji32.size(), cypherKey.data(), false); // Convert encrypted reaction to uint32 array std::string result = ::mega::Utils::a32_to_str(emoji32); @@ -698,18 +701,21 @@ ProtocolHandler::reactionDecrypt(const Message &msg, const std::string &reaction return symPms.then([wptr, &msg, &reaction](const std::shared_ptr& data) { wptr.throwIfDeleted(); - std::string msgId = msg.id().toString(); - std::string keyBin (data->buf(), data->dataSize()); // Inside this function str_to_a32 and a32_to_str calls must be done with type = + std::string keyBin (data->buf(), data->dataSize()); std::vector key32 = ::mega::Utils::str_to_a32(keyBin); + size_t key32Len = key32.size(); + + std::string msgId = msg.id().toString(); std::vector msgId32 = ::mega::Utils::str_to_a32(msgId); + size_t msgId32Len = msgId32.size(); // key32 XOR msgId32 --> Cypherkey to encrypt reaction - std::vector cypherKey(key32.size()); - for (size_t i = 0; i < key32.size(); i++) + std::vector cypherKey(key32Len); + for (size_t i = 0; i < key32Len; i++) { - cypherKey[i] = key32[i] ^ msgId32[i % msgId32.size()]; + cypherKey[i] = key32[i] ^ msgId32[i % msgId32Len]; } std::vector reaction32 = ::mega::Utils::str_to_a32(reaction); From 3885a2d215dd9e17f6c2715d5bfaa7ff8aa6d0b7 Mon Sep 17 00:00:00 2001 From: Matt Weir Date: Thu, 3 Oct 2019 16:29:56 +1300 Subject: [PATCH 091/100] Added getcontacts command for testing --- examples/megaclc/megaclc.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/megaclc/megaclc.cpp b/examples/megaclc/megaclc.cpp index 96e44e77a..2560316fc 100644 --- a/examples/megaclc/megaclc.cpp +++ b/examples/megaclc/megaclc.cpp @@ -3275,6 +3275,21 @@ void exec_getCameraUploadsFolder(ac::ACState& s) } +void exec_getContact(ac::ACState& s) +{ + + unique_ptr user(g_megaApi->getContact(s.words[1].s.c_str())); + if (user) + { + conlock(cout) << "found with handle: " << ch_s(user->getHandle()) << " timestamp: " << user->getTimestamp() << endl; + } + else + { + conlock(cout) << "No user found with that email" << endl; + } +} + + ac::ACN autocompleteSyntax() { using namespace ac; @@ -3430,6 +3445,7 @@ ac::ACN autocompleteSyntax() p->Add(exec_setCameraUploadsFolder, sequence(text("setcamerauploadsfolder"), param("remotedst"))); p->Add(exec_getCameraUploadsFolder, sequence(text("getcamerauploadsfolder"))); + p->Add(exec_getContact, sequence(text("getcontact"), param("email"))); return p; } From 6c2baa166c1a4317342f96b10634b8072cae7dc5 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 3 Oct 2019 10:19:42 +0200 Subject: [PATCH 092/100] Clean reactions upon message deletion - Adjust documentation in Reaction struct --- src/chatd.cpp | 4 ++++ src/chatdMsg.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 15f90d734..421e055a8 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4090,6 +4090,10 @@ void Chat::onMsgUpdated(Message* cipherMsg) { mAttachmentNodes->deleteMessage(*msg); } + + // Clean message reactions + removeMessageReactions(idx); + CALL_DB(cleanReactions); } if (msg->type == Message::kMsgTruncate) diff --git a/src/chatdMsg.h b/src/chatdMsg.h index ea9156fde..dd149fa79 100644 --- a/src/chatdMsg.h +++ b/src/chatdMsg.h @@ -535,10 +535,10 @@ class Message: public Buffer Priv privilege = PRIV_INVALID; }; + /** @brief Contains a UTF-8 string that represents the reaction + * and a vector of userid's associated to that reaction. */ struct Reaction { - /** @brief Contains a UTF-8 string that represents the reaction - * and a vector of userid's associated to that reaction. */ std::string mReaction; std::vector mUsers; From b44ea534472a9f8d959956d87f8b7a43302a7339 Mon Sep 17 00:00:00 2001 From: Javier Gonzalez Andres Date: Thu, 3 Oct 2019 10:37:18 +0200 Subject: [PATCH 093/100] Fix error cleaning reactions upon message deletion --- src/chatd.cpp | 4 ++-- src/chatd.h | 2 +- src/chatdDb.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index 421e055a8..a1d00a8d3 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -4092,8 +4092,8 @@ void Chat::onMsgUpdated(Message* cipherMsg) } // Clean message reactions - removeMessageReactions(idx); - CALL_DB(cleanReactions); + msg->cleanReactions(); + CALL_DB(cleanReactions, msg->id()); } if (msg->type == Message::kMsgTruncate) diff --git a/src/chatd.h b/src/chatd.h index aee415d36..fd7f44961 100644 --- a/src/chatd.h +++ b/src/chatd.h @@ -1585,7 +1585,7 @@ class DbInterface // <<<--- Reaction methods --->>> virtual std::string getReactionSn() = 0; virtual void setReactionSn(const std::string &rsn) = 0; - virtual void cleanReactions() = 0; + virtual void cleanReactions(karere::Id msgId) = 0; virtual void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; virtual void delReaction(karere::Id msgId, karere::Id userId, const char *reaction) = 0; virtual void getMessageReactions(karere::Id msgId, ::mega::multimap& reactions) = 0; diff --git a/src/chatdDb.h b/src/chatdDb.h index 1fbd88b53..a0f906e4c 100644 --- a/src/chatdDb.h +++ b/src/chatdDb.h @@ -550,9 +550,9 @@ class ChatdSqliteDb: public chatd::DbInterface assertAffectedRowCount(1); } - void cleanReactions() override + void cleanReactions(karere::Id msgId) override { - mDb.query("delete from chat_reactions where chatid = ?", mChat.chatId()); + mDb.query("delete from chat_reactions where chatid = ? and msgId = ?", mChat.chatId(), msgId); } void addReaction(karere::Id msgId, karere::Id userId, const char *reaction) override From d0d1b4b6166b0a7006d1f14a6ba72c2f51538f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Fri, 4 Oct 2019 11:25:27 +0200 Subject: [PATCH 094/100] Add logs and setRinging() upon terminating call --- src/megachatapi_impl.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 63a289d14..433066b2c 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -7671,19 +7671,22 @@ void MegaChatCallHandler::onStateChange(uint8_t newState) case rtcModule::ICall::kStateTerminating: { chatCall->setTermCode(call->termCode()); - if (chatCall->getStatus() == MegaChatCall::CALL_STATUS_RECONNECTING) - { - // if reconnecting skip terminating state, if reconnection not successful finisht notify call destroyed - return; - } - chatCall->setIsRinging(false); - state = MegaChatCall::CALL_STATUS_TERMINATING_USER_PARTICIPATION; + API_LOG_INFO("Terminating call. ChatId: %s, callid: %s, termCode: %s , isLocal: %d, duration: %d (s)", karere::Id(chatCall->getChatid()).toString().c_str(), karere::Id(chatCall->getId()).toString().c_str(), rtcModule::termCodeToStr(call->termCode() & (~rtcModule::TermCode::kPeer)), chatCall->isLocalTermCode(), chatCall->getDuration()); + + if (chatCall->getStatus() == MegaChatCall::CALL_STATUS_RECONNECTING) + { + // if reconnecting, then skip notify terminating state. If reconnection fails, call's destruction will be notified later + API_LOG_INFO("Skip notification of termination due to reconnection in progress"); + return; + } + + state = MegaChatCall::CALL_STATUS_TERMINATING_USER_PARTICIPATION; } break; case rtcModule::ICall::kStateDestroyed: From abc37fe22f00fc263b9725182e8ee66484f76836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Fri, 4 Oct 2019 11:25:43 +0200 Subject: [PATCH 095/100] Refactoring --- src/megachatapi_impl.cpp | 14 +++----------- src/megachatapi_impl.h | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/megachatapi_impl.cpp b/src/megachatapi_impl.cpp index 433066b2c..b9ed15211 100644 --- a/src/megachatapi_impl.cpp +++ b/src/megachatapi_impl.cpp @@ -5065,9 +5065,6 @@ MegaChatCallPrivate::MegaChatCallPrivate(const MegaChatCallPrivate &call) } this->participants = call.participants; - - this->localTermCode = call.localTermCode; - this->ringing = call.ringing; } MegaChatCallPrivate::~MegaChatCallPrivate() @@ -7691,7 +7688,6 @@ void MegaChatCallHandler::onStateChange(uint8_t newState) break; case rtcModule::ICall::kStateDestroyed: return; - break; default: state = newState; } @@ -7713,10 +7709,10 @@ void MegaChatCallHandler::onDestroy(rtcModule::TermCode reason, bool /*byPeer*/, if (chatCall != NULL) { chatid = chatCall->getChatid(); - MegaChatRoom *chatRoom = megaChatApi->getChatRoom(chatid); + unique_ptr chatRoom(megaChatApi->getChatRoom(chatid)); assert(chatRoom); - MegaHandleList *peeridParticipants = chatCall->getPeeridParticipants(); - MegaHandleList *clientidParticipants = chatCall->getClientidParticipants(); + unique_ptr peeridParticipants(chatCall->getPeeridParticipants()); + unique_ptr clientidParticipants(chatCall->getClientidParticipants()); bool uniqueParticipant = (peeridParticipants && peeridParticipants->size() == 1 && peeridParticipants->get(0) == megaChatApi->getMyUserHandle() && clientidParticipants->get(0) == megaChatApi->getMyClientidHandle(chatid)); @@ -7735,10 +7731,6 @@ void MegaChatCallHandler::onDestroy(rtcModule::TermCode reason, bool /*byPeer*/, megaChatApi->fireOnChatCallUpdate(chatCall); megaChatApi->removeCall(chatid); } - - delete chatRoom; - delete peeridParticipants; - delete clientidParticipants; } else { diff --git a/src/megachatapi_impl.h b/src/megachatapi_impl.h index f33ff5dcd..14a5822c4 100644 --- a/src/megachatapi_impl.h +++ b/src/megachatapi_impl.h @@ -594,7 +594,7 @@ class MegaChatCallHandler : public rtcModule::ICallHandler virtual int64_t getInitialTimeStamp(); virtual bool hasBeenNotifiedRinging() const; virtual void onReconnectingState(bool start); - virtual void setReconnectionFailed(); + virtual void setReconnectionFailed() override; virtual rtcModule::ICall *getCall(); MegaChatCallPrivate *getMegaChatCall(); From cb6e967d1fa7ebd16f936705d71ce0071f835c34 Mon Sep 17 00:00:00 2001 From: Matt Weir Date: Tue, 8 Oct 2019 17:19:14 +1300 Subject: [PATCH 096/100] Add -order parameter for exec_ls Needs the branch of the same name in the SDK --- examples/megaclc/megaclc.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/megaclc/megaclc.cpp b/examples/megaclc/megaclc.cpp index 2560316fc..62eeca030 100644 --- a/examples/megaclc/megaclc.cpp +++ b/examples/megaclc/megaclc.cpp @@ -2988,6 +2988,7 @@ struct ls_flags bool mtime = false; bool size = false; bool versions = false; + int order = 1; }; @@ -3041,7 +3042,7 @@ void ls(m::MegaNode* node, const string& basepath, const ls_flags& flags, int de if (show && depth > 0) cout << endl; if (flags.recursive || depth == 0) { - unique_ptr children(g_megaApi->getChildren(node)); + unique_ptr children(g_megaApi->getChildren(node, flags.order)); if (children) for (int i = 0; i < children->size(); ++i) { ls(children->get(i), basepath, flags, depth + 1); @@ -3053,14 +3054,19 @@ void ls(m::MegaNode* node, const string& basepath, const ls_flags& flags, int de void exec_ls(ac::ACState& s) { + string orderstring; ls_flags flags; - flags.recursive = extractflag("-recursive", s.words); - flags.regexfilter = extractflagparam("-refilter", flags.regexfilterstring, s.words); - flags.handle = extractflag("-handles", s.words); - flags.ctime = extractflag("-ctime", s.words); - flags.mtime = extractflag("-mtime", s.words); - flags.size = extractflag("-size", s.words); - flags.versions = extractflag("-versions", s.words); + flags.recursive = s.extractflag("-recursive"); + flags.regexfilter = s.extractflagparam("-refilter", flags.regexfilterstring); + flags.handle = s.extractflag("-handles"); + flags.ctime = s.extractflag("-ctime"); + flags.mtime = s.extractflag("-mtime"); + flags.size = s.extractflag("-size"); + flags.versions = s.extractflag("-versions"); + if (s.extractflagparam("-order", orderstring)) + { + flags.order = std::stoi(orderstring); + } if (flags.regexfilter) { @@ -3434,7 +3440,7 @@ ac::ACN autocompleteSyntax() p->Add(exec_createpreview, sequence(text("createpreview"), localFSFile(), localFSFile())); p->Add(exec_testAllocation, sequence(text("testAllocation"), param("count"), param("size"))); p->Add(exec_getnodebypath, sequence(text("getnodebypath"), param("remotepath"))); - p->Add(exec_ls, sequence(text("ls"), repeat(either(flag("-recursive"), flag("-handles"), flag("-ctime"), flag("-mtime"), flag("-size"), flag("-versions"), sequence(flag("-refilter"), param("regex")))), param("path"))); + p->Add(exec_ls, sequence(text("ls"), repeat(either(flag("-recursive"), flag("-handles"), flag("-ctime"), flag("-mtime"), flag("-size"), flag("-versions"), sequence(flag("-order"), param("order")), sequence(flag("-refilter"), param("regex")))), param("path"))); p->Add(exec_renamenode, sequence(text("renamenode"), param("remotepath"), param("newname"))); p->Add(exec_pushreceived, sequence(text("pushreceived"), opt(flag("-beep")), opt(param("chatid")))); From 702ade1bd353bbd1cd64de3cf7fdf8b0a832a1db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Thu, 10 Oct 2019 13:00:35 +0200 Subject: [PATCH 097/100] Avoid send messages witout being logged in --- src/chatd.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/chatd.cpp b/src/chatd.cpp index 1a72b85db..e401eb379 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -3558,6 +3558,9 @@ int Chat::unreadMsgCount() const void Chat::flushOutputQueue(bool fromStart) { + if (!isLoggedIn()) + return; + if (fromStart) mNextUnsent = mSending.begin(); From 70552b1ff7b461b048efac2508ab2f0700db37ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 14 Oct 2019 11:04:51 +0200 Subject: [PATCH 098/100] Improve url detector --- src/chatd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chatd.cpp b/src/chatd.cpp index e401eb379..9f799fdbb 100644 --- a/src/chatd.cpp +++ b/src/chatd.cpp @@ -5354,13 +5354,13 @@ bool Message::parseUrl(const std::string &url) } } - std::regex megaUrlExpression("^((WWW.|www.)?mega.+(nz/|co.nz/)).*((#F!|#!|C!|chat/|file/|folder/)[a-z0-9A-Z-._~:\/?#!$&'()*+,;=\-@]+)$"); + std::regex megaUrlExpression("((WWW.|www.)?mega.+(nz/|co.nz/)).*((#F!|#!|C!|chat/|file/|folder/)[a-z0-9A-Z-._~:/?#!$&'()*+,;= \\-@]+)$"); if (regex_match(urlToParse, megaUrlExpression)) { return false; } - std::regex regularExpresion("^(WWW.|www.)?[a-z0-9A-Z-._~:/?#@!$&'()*+,;=]+[.][a-zA-Z]{2,5}(:[0-9]{1,5})?([a-z0-9A-Z-._~:/?#@!$&'()*+,;=]*)?$"); + std::regex regularExpresion("((^([0-9]{1,3}[.]{1}[0-9]{1,3}[.]{1}[0-9]{1,3}[.]{1}[0-9]{1,3}))|((^(WWW.|www.))?([a-z0-9A-Z]+)([a-z0-9A-Z-._~?#!$&'()*+,;=])*([a-z0-9A-Z]+)([.]{1}[a-zA-Z]{2,5}){1,2}))([:]{1}[0-9]{1,5})?([/]{1}[a-z0-9A-Z-._~:?#/@!$&'()*+,;=]*)?$"); return regex_match(urlToParse, regularExpresion); } From 9f00f3a13f8e103ed7ebb94226b4c221fc6bd22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Rodr=C3=ADguez?= Date: Mon, 14 Oct 2019 11:08:21 +0200 Subject: [PATCH 099/100] Modify url parser unitary tests --- tests/sdk_test/sdk_test.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/tests/sdk_test/sdk_test.cpp b/tests/sdk_test/sdk_test.cpp index b7086e794..de65e5ab0 100644 --- a/tests/sdk_test/sdk_test.cpp +++ b/tests/sdk_test/sdk_test.cpp @@ -4622,7 +4622,7 @@ bool MegaChatApiUnitaryTest::UNITARYTEST_ParseUrl() checkUrls["esto es un prueba www.mega. nz"] = 1; checkUrls["ftp://www.googl.com"] = 0; checkUrls["www.googl .com"] = 1; - checkUrls[" www.sfdsadfasfdsfsdf "] = 1; + checkUrls[" www.sfdsadfasfdsfsdf "] = 0; checkUrls["example.com/products?id=1&page=2"] = 1; checkUrls["www.example.com/products?iddfdsfdsfsfsdfa=1&page=2"] = 1; checkUrls["https://mega.co.nz/#!p2QnF89I!Kf-m03Lwmyut-eF7RnJjSv1PRYYtYHg7oodFrW1waEQ"] = 0; @@ -4657,17 +4657,18 @@ bool MegaChatApiUnitaryTest::UNITARYTEST_ParseUrl() checkUrls["http://www.example.com/wpstyle/?p=364"] = 1; checkUrls["https://www.example.com/foo/?bar=baz&inga=42&quux"] = 1; checkUrls["http://odf.ws/123"] = 1; - checkUrls["http://userid:password@example.com:8080)"] = 1; - checkUrls["http://userid:password@example.com:8080/"] = 1; - checkUrls["http://userid@example.com"] = 1; - checkUrls["http://userid@example.com/"] = 1; - checkUrls["http://userid@example.com:8080"] = 1; - checkUrls["http://userid@example.com:8080/"] = 1; - checkUrls["http://userid:password@example.com"] = 1; - checkUrls["http://userid:password@example.com/"] = 1; + checkUrls["http://userid:password@example.com:8080)"] = 0; + checkUrls["http://userid:password@example.com:8080/"] = 0; + checkUrls["http://userid@example.com"] = 0; + checkUrls["http://userid@example.com/"] = 0; + checkUrls["http://userid@example.com:8080"] = 0; + checkUrls["http://userid@example.com:8080/"] = 0; + checkUrls["http://userid:password@example.com"] = 0; + checkUrls["http://userid:password@example.com/"] = 0; checkUrls["http://foo.com/blah_(wikipedia)#cite-1"] = 1; checkUrls["http://foo.com/unicode_(✪)_in_parens"] = 1; checkUrls["http://code.google.com/events/#&product=browser"] = 1; + checkUrls["www.code.google.com/events/#&product=browser"] = 1; checkUrls["http://1337.net"] = 1; checkUrls["http://a.b-c.de"] = 1; checkUrls["https://foo_bar.example.com/"] = 1; @@ -4679,14 +4680,15 @@ bool MegaChatApiUnitaryTest::UNITARYTEST_ParseUrl() checkUrls["http://??"] = 0; checkUrls["http://??/"] = 0; checkUrls["http://#"] = 0; - checkUrls["http://foo.bar?q=Spaces should be encoded"] = 1; + checkUrls["http://foo.bar?q=Spaces should be encoded"] = 0; checkUrls["///a"] = 0; checkUrls["http:// shouldfail.com"] = 1; checkUrls["http://foo.bar/foo(bar)baz quux"] = 1; - checkUrls["http://10.1.1.0"] = 0; + checkUrls["http://10.1.1.0"] = 1; checkUrls["http://3628126748"] = 0; checkUrls["http://123.123.123"] = 0; - checkUrls["http://.www.foo.bar./"] = 1; + checkUrls["http://123.123..123"] = 0; + checkUrls["http://.www.foo.bar./"] = 0; checkUrls["Test ..www.google.es..."] = 1; checkUrls["Test ..test..."] = 0; checkUrls[":// should fail"] = 0; @@ -4694,6 +4696,11 @@ bool MegaChatApiUnitaryTest::UNITARYTEST_ParseUrl() checkUrls["prueba!!"] = 0; checkUrls["prueba.com!!"] = 1; checkUrls["pepitoPerez@gmail.com"] = 0; + checkUrls["hi..dsdd"] = 0; + checkUrls["hidsfdf..ddsfsdsdd"] = 0; + checkUrls["hidsfdf..com"] = 0; + checkUrls["hidsfdf.d.ddsfsdsdd"] = 0; + checkUrls["122.123.122.123/jjkkk"] = 1; std::cout << " TEST - Message::parseUrl()" << std::endl; bool succesful = true; From 5fe874a55616d3eae261bcf56c4b506d1b740d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Hern=C3=A1ndez?= Date: Thu, 17 Oct 2019 14:33:42 +0200 Subject: [PATCH 100/100] Protect against calls without audio track --- src/rtcModule/webrtc.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/rtcModule/webrtc.cpp b/src/rtcModule/webrtc.cpp index d516c5a7f..bb05a6e8f 100644 --- a/src/rtcModule/webrtc.cpp +++ b/src/rtcModule/webrtc.cpp @@ -2861,7 +2861,11 @@ void Session::onAddStream(artc::tspMediaStream stream) }); mRemotePlayer->attachToStream(stream); mRemotePlayer->enableVideo(mPeerAv.video()); - mRemotePlayer->getAudioTrack()->AddSink(mAudioLevelMonitor.get()); + + if (mRemotePlayer->isAudioAttached()) + { + mRemotePlayer->getAudioTrack()->AddSink(mAudioLevelMonitor.get()); + } } void Session::onRemoveStream(artc::tspMediaStream stream) { @@ -2872,7 +2876,10 @@ void Session::onRemoveStream(artc::tspMediaStream stream) } if(mRemotePlayer) { - mRemotePlayer->getAudioTrack()->RemoveSink(mAudioLevelMonitor.get()); + if (mRemotePlayer->isAudioAttached()) + { + mRemotePlayer->getAudioTrack()->RemoveSink(mAudioLevelMonitor.get()); + } mRemotePlayer->detachFromStream(); mRemotePlayer.reset(); }