diff options
Diffstat (limited to 'protocols/FacebookRM/src/json.cpp')
-rw-r--r-- | protocols/FacebookRM/src/json.cpp | 243 |
1 files changed, 138 insertions, 105 deletions
diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp index af232b9bd6..1ffd30b203 100644 --- a/protocols/FacebookRM/src/json.cpp +++ b/protocols/FacebookRM/src/json.cpp @@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "stdafx.h" +#include <regex> LRESULT CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -1165,127 +1166,159 @@ int FacebookProto::ParseUnreadThreads(std::string *data, std::vector< std::strin int FacebookProto::ParseThreadMessages(std::string *data, std::vector< facebook_message >* messages, bool unreadOnly) { - std::string jsonData = data->substr(9); + /*size_t len = data->find("\r\n"); + if (len != data->npos) + data->erase(len);*/ + + // since it could loop over multiple queries not all can be valid + // so return EXIT_FAILURE only if none is processed + bool hasResult = false; + + // pattern for one query + std::regex r("\\{\"o\\d\":\\{\"data\":\\{\"message_thread\":\\{.+\\}{4,5}"); // (\\{|$) + std::sregex_iterator i = std::sregex_iterator(data->begin(), data->end(), r); + std::sregex_iterator end; + // loop over queries + for (; i != end; ++i) { + + std::smatch m = *i; + std::string match = m.str(); + + JSONNode root = JSONNode::parse(match.c_str()); + if (!root) + //return EXIT_FAILURE; + continue; - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; + // query number "o0", "o1", .. but they are not ordered + std::string oX = std::string("o") + std::string(1, match.at(3)); - const JSONNode &payload = root["payload"]; - if (!payload) - return EXIT_FAILURE; + const JSONNode &thread = root[oX.c_str()]["data"]["message_thread"]; + if (!thread) + //return EXIT_FAILURE; + continue; - const JSONNode &actions = payload["actions"]; - const JSONNode &threads = payload["threads"]; - if (!actions || !threads) - return EXIT_FAILURE; + const JSONNode &nodes = thread["messages"]["nodes"]; + if (!nodes) + //return EXIT_FAILURE; + continue; - for (auto &it : actions) { - const JSONNode &author_ = it["author"]; - const JSONNode &other_user_fbid_ = it["other_user_fbid"]; - const JSONNode &body_ = it["body"]; - const JSONNode &thread_id_ = it["thread_id"]; - const JSONNode &thread_fbid_ = it["thread_fbid"]; - const JSONNode &mid_ = it["message_id"]; - const JSONNode ×tamp_ = it["timestamp"]; - const JSONNode &filtered_ = it["is_filtered_content"]; - const JSONNode &is_unread_ = it["is_unread"]; + // TODO! process commented sections and better pair json (this is just quick attempt, + I do not know what everything means yet) - // Either there is "body" (for classic messages), or "log_message_type" and "log_message_body" (for log messages) - const JSONNode &log_type_ = it["log_message_type"]; - const JSONNode &log_body_ = it["log_message_body"]; - const JSONNode &log_data_ = it["log_message_data"]; // additional data for this log message + const JSONNode &other_user_fbid_ = thread["thread_key"]["other_user_id"]; + const JSONNode &thread_fbid_ = thread["thread_key"]["thread_fbid"]; - if (!author_ || (!body_ && !log_body_) || !mid_ || (!thread_fbid_ && !thread_id_) || !timestamp_) { - debugLogA("ParseThreadMessages: ignoring message (%s) - missing attribute", mid_.as_string().c_str()); - continue; - } + for (auto it = nodes.begin(); it != nodes.end(); ++it) { + const JSONNode &author_ = (*it)["message_sender"]["id"]; + const JSONNode &body_ = (*it)["message"]["text"]; + const JSONNode &thread_id_ = (*it)["offline_threading_id"]; + const JSONNode &mid_ = (*it)["message_id"]; + const JSONNode ×tamp_ = (*it)["timestamp_precise"]; + // const JSONNode &filtered_ = (*it)["is_filtered_content"]; + const JSONNode &is_unread_ = (*it)["unread"]; - std::string thread_id = thread_id_.as_string(); - std::string thread_fbid = thread_fbid_.as_string(); - std::string message_id = mid_.as_string(); - std::string message_text = body_ ? body_.as_string() : log_body_.as_string(); - std::string author_id = author_.as_string(); - std::string other_user_fbid = other_user_fbid_ ? other_user_fbid_.as_string() : ""; - std::string::size_type pos = author_id.find(":"); // strip "fbid:" prefix - if (pos != std::string::npos) - author_id = author_id.substr(pos + 1); + // Either there is "body" (for classic messages), or "log_message_type" and "log_message_body" (for log messages) + const JSONNode &log_type_ = (*it)["log_message_type"]; + const JSONNode &log_body_ = (*it)["log_message_body"]; + const JSONNode &log_data_ = (*it)["log_message_data"]; // additional data for this log message - // Process attachements and stickers - ParseAttachments(message_text, it, other_user_fbid, true); + if (!author_ || (!body_ && !log_body_) || !mid_ || (!thread_fbid_ && !thread_id_) || !timestamp_) { + debugLogA("ParseThreadMessages: ignoring message (%s) - missing attribute", mid_.as_string().c_str()); + continue; + } - if (filtered_.as_bool() && message_text.empty()) - message_text = Translate("This message is no longer available, because it was marked as abusive or spam."); + std::string thread_id = thread_id_.as_string(); + std::string thread_fbid = thread_fbid_.as_string(); + std::string message_id = mid_.as_string(); + std::string message_text = body_ ? body_.as_string() : log_body_.as_string(); + std::string author_id = author_.as_string(); + std::string other_user_fbid = other_user_fbid_ ? other_user_fbid_.as_string() : ""; + std::string::size_type pos = author_id.find(":"); // strip "fbid:" prefix + if (pos != std::string::npos) + author_id = author_id.substr(pos + 1); + + // Process attachements and stickers + ParseAttachments(message_text, (*it), other_user_fbid, true); + + //if (filtered_.as_bool() && message_text.empty()) + // message_text = Translate("This message is no longer available, because it was marked as abusive or spam."); + + message_text = utils::text::trim(utils::text::slashu_to_utf8(message_text), true); + if (message_text.empty()) { + debugLogA("ParseThreadMessages: ignoring message (%s) - empty message text", mid_.as_string().c_str()); + continue; + } - message_text = utils::text::trim(utils::text::slashu_to_utf8(message_text), true); - if (message_text.empty()) { - debugLogA("ParseThreadMessages: ignoring message (%s) - empty message text", mid_.as_string().c_str()); - continue; - } + bool isUnread = is_unread_.as_bool(); - bool isUnread = is_unread_.as_bool(); + // Ignore read messages if we want only unread messages + if (unreadOnly && !isUnread) + continue; - // Ignore read messages if we want only unread messages - if (unreadOnly && !isUnread) - continue; + facebook_message message; + message.message_text = message_text; + message.time = utils::time::from_string(timestamp_.as_string()); + message.message_id = message_id; + message.isIncoming = (author_id != facy.self_.user_id); + message.isUnread = isUnread; + + message.isChat = other_user_fbid.empty(); + if (message.isChat) { + message.user_id = author_id; + message.thread_id = "id." + thread_fbid; + } + else { + message.user_id = other_user_fbid; + message.thread_id = thread_id; + } - facebook_message message; - message.message_text = message_text; - message.time = utils::time::from_string(timestamp_.as_string()); - message.message_id = message_id; - message.isIncoming = (author_id != facy.self_.user_id); - message.isUnread = isUnread; + ParseMessageType(message, log_type_, log_body_, log_data_); - message.isChat = other_user_fbid.empty(); - if (message.isChat) { - message.user_id = author_id; - message.thread_id = "id." + thread_fbid; + messages->push_back(message); + hasResult = true; } - else { - message.user_id = other_user_fbid; - message.thread_id = thread_id; - } - - ParseMessageType(message, log_type_, log_body_, log_data_); - - messages->push_back(message); } - return EXIT_SUCCESS; + return hasResult ? EXIT_SUCCESS : EXIT_FAILURE; } -int FacebookProto::ParseHistory(std::string *data, std::vector< facebook_message >* messages, std::string *firstTimestamp) +int FacebookProto::ParseHistory(std::string *data, std::vector< facebook_message > *messages, std::string* firstTimestamp) { - std::string jsonData = data->substr(9); + size_t len = data->find("\r\n"); + if (len != data->npos) + data->erase(len); - JSONNode root = JSONNode::parse(jsonData.c_str()); + JSONNode root = JSONNode::parse(data->c_str()); if (!root) return EXIT_FAILURE; - const JSONNode &payload = root["payload"]; - if (!payload) + const JSONNode &thread = root["o0"]["data"]["message_thread"]; + if (!thread) return EXIT_FAILURE; - const JSONNode &actions = payload["actions"]; - if (!actions) + const JSONNode &nodes = thread["messages"]["nodes"]; + if (!nodes) return EXIT_FAILURE; + // TODO! process commented sections and better pair json (this is just quick attempt, + I do not know what everything means yet) + bool first = true; - for (auto &it : actions) { - const JSONNode &author = it["author"]; - const JSONNode &other_user_fbid = it["other_user_fbid"]; - const JSONNode &body = it["body"]; - const JSONNode &tid = it["thread_id"]; - const JSONNode &mid = it["message_id"]; - const JSONNode ×tamp = it["timestamp"]; - const JSONNode &filtered = it["is_filtered_content"]; - const JSONNode &is_unread = it["is_unread"]; + const JSONNode &other_user_fbid_ = thread["thread_key"]["other_user_id"]; + const JSONNode &thread_fbid_ = thread["thread_key"]["thread_fbid"]; + + for (auto it = nodes.begin(); it != nodes.end(); ++it) { + const JSONNode &author = (*it)["message_sender"]["id"]; + const JSONNode &body = (*it)["message"]["text"]; + const JSONNode &tid = (*it)["offline_threading_id"]; + const JSONNode &mid = (*it)["message_id"]; + const JSONNode ×tamp = (*it)["timestamp_precise"]; + // const JSONNode &filtered = (*it)["is_filtered_content"]; + const JSONNode &is_unread = (*it)["unread"]; // Either there is "body" (for classic messages), or "log_message_type" and "log_message_body" (for log messages) - const JSONNode &log_type_ = it["log_message_type"]; - const JSONNode &log_body_ = it["log_message_body"]; - const JSONNode &log_data_ = it["log_message_data"]; + const JSONNode &log_type_ = (*it)["log_message_type"]; + const JSONNode &log_body_ = (*it)["log_message_body"]; + const JSONNode &log_data_ = (*it)["log_message_data"]; if (!author || (!body && !log_body_) || !mid || !tid || !timestamp) { debugLogA("ParseHistory: ignoring message (%s) - missing attribute", mid.as_string().c_str()); @@ -1301,16 +1334,16 @@ int FacebookProto::ParseHistory(std::string *data, std::vector< facebook_message std::string message_id = mid.as_string(); std::string message_text = body ? body.as_string() : log_body_.as_string(); std::string author_id = author.as_string(); - std::string other_user_id = other_user_fbid ? other_user_fbid.as_string() : ""; + std::string other_user_id = other_user_fbid_ ? other_user_fbid_.as_string() : ""; std::string::size_type pos = author_id.find(":"); // strip "fbid:" prefix if (pos != std::string::npos) author_id = author_id.substr(pos + 1); // Process attachements and stickers - ParseAttachments(message_text, it, other_user_id, true); + ParseAttachments(message_text, (*it), other_user_id, true); - if (filtered.as_bool() && message_text.empty()) - message_text = Translate("This message is no longer available, because it was marked as abusive or spam."); + //if (filtered.as_bool() && message_text.empty()) + // message_text = Translate("This message is no longer available, because it was marked as abusive or spam."); message_text = utils::text::trim(utils::text::slashu_to_utf8(message_text), true); if (message_text.empty()) { @@ -1395,26 +1428,26 @@ int FacebookProto::ParseUserInfo(std::string *data, facebook_user* fbu) int FacebookProto::ParseMessagesCount(std::string *data, int *messagesCount, int *unreadCount) { - std::string jsonData = data->substr(9); + size_t len = data->find("\r\n"); + if (len != data->npos) + data->erase(len); - JSONNode root = JSONNode::parse(jsonData.c_str()); + JSONNode root = JSONNode::parse(data->c_str()); if (!root) return EXIT_FAILURE; - const JSONNode &threads = root["payload"].at("threads"); - if (!threads) + const JSONNode &thread = root["o0"]["data"]["message_thread"]; + if (!thread) return EXIT_FAILURE; - for (auto &it : threads) { - const JSONNode &message_count_ = it["message_count"]; - const JSONNode &unread_count_ = it["unread_count"]; + const JSONNode &message_count_ = thread["messages_count"]; + const JSONNode &unread_count_ = thread["unread_count"]; - if (!message_count_ || !unread_count_) - return EXIT_FAILURE; + if (!message_count_ || !unread_count_) + return EXIT_FAILURE; - *messagesCount = message_count_.as_int(); - *unreadCount = unread_count_.as_int(); - } + *messagesCount = message_count_.as_int(); + *unreadCount = unread_count_.as_int(); return EXIT_SUCCESS; } |