summaryrefslogtreecommitdiff
path: root/protocols/FacebookRM
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2018-01-04 22:06:10 +0300
committerGeorge Hazan <ghazan@miranda.im>2018-01-04 22:06:10 +0300
commit4244ac9aff45e1e723b17f32b192ce4996ac52c0 (patch)
tree5ad42fc6fd841e756e7f697df0f4bedcaea8317d /protocols/FacebookRM
parentb6d0a372771d1fac2a2276841f6d2bbac22e8552 (diff)
Facebook: kinda final fix for groupchats
Diffstat (limited to 'protocols/FacebookRM')
-rw-r--r--protocols/FacebookRM/src/chat.cpp154
-rw-r--r--protocols/FacebookRM/src/contacts.cpp114
-rw-r--r--protocols/FacebookRM/src/json.cpp58
-rw-r--r--protocols/FacebookRM/src/version.h2
4 files changed, 155 insertions, 173 deletions
diff --git a/protocols/FacebookRM/src/chat.cpp b/protocols/FacebookRM/src/chat.cpp
index 7b5a0d7935..bca2ee561b 100644
--- a/protocols/FacebookRM/src/chat.cpp
+++ b/protocols/FacebookRM/src/chat.cpp
@@ -422,3 +422,157 @@ std::string FacebookProto::GenerateChatName(facebook_chatroom *fbc)
return name;
}
+
+void FacebookProto::LoadParticipantsNames(facebook_chatroom *fbc)
+{
+ std::vector<std::string> namelessIds;
+
+ // TODO: We could load all names from server at once by skipping this for cycle and using namelessIds as all in participants list, but we would lost our local names of our contacts. But maybe that's not a problem?
+ for (auto &it : fbc->participants) {
+ const char *id = it.first.c_str();
+ chatroom_participant &user = it.second;
+
+ if (!user.loaded) {
+ if (!mir_strcmp(id, facy.self_.user_id.c_str())) {
+ user.nick = facy.self_.real_name;
+ user.role = ROLE_ME;
+ user.loaded = true;
+ }
+ else {
+ MCONTACT hContact = ContactIDToHContact(id);
+ if (hContact != 0) {
+ DBVARIANT dbv;
+ if (!getStringUtf(hContact, FACEBOOK_KEY_NICK, &dbv)) {
+ user.nick = dbv.pszVal;
+ db_free(&dbv);
+ }
+ if (user.role == ROLE_NONE) {
+ int type = getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE);
+ if (type == CONTACT_FRIEND)
+ user.role = ROLE_FRIEND;
+ else
+ user.role = ROLE_NONE;
+ }
+ user.loaded = true;
+ }
+
+ if (!user.loaded)
+ namelessIds.push_back(id);
+ }
+ }
+ }
+
+ if (!namelessIds.empty()) {
+ // we have some contacts without name, let's load them all from the server
+
+ LIST<char> userIds(1);
+ for (std::string::size_type i = 0; i < namelessIds.size(); i++)
+ userIds.insert(mir_strdup(namelessIds.at(i).c_str()));
+
+ HttpRequest *request = new UserInfoRequest(&facy, userIds);
+ http::response resp = facy.sendRequest(request);
+
+ FreeList(userIds);
+ userIds.destroy();
+
+ if (resp.code == HTTP_CODE_OK) {
+ try {
+ // TODO: We can cache these results and next time (e.g. for different chatroom) we can use that already cached names
+ ParseChatParticipants(&resp.data, &fbc->participants);
+ debugLogA("*** Participant names processed");
+ }
+ catch (const std::exception &e) {
+ debugLogA("*** Error processing participant names: %s", e.what());
+ }
+ }
+ }
+}
+
+void FacebookProto::JoinChatrooms()
+{
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ if (!isChatRoom(hContact))
+ continue;
+
+ // Ignore archived and unsubscribed chats
+ if (getBool(hContact, FACEBOOK_KEY_CHAT_IS_ARCHIVED, false) || !getBool(hContact, FACEBOOK_KEY_CHAT_IS_SUBSCRIBED, true))
+ continue;
+
+ OnJoinChat(hContact, 0);
+ }
+}
+
+void FacebookProto::LoadChatInfo(facebook_chatroom *fbc)
+{
+ if (isOffline())
+ return;
+
+ // request info about chat thread
+ HttpRequest *request = new ThreadInfoRequest(&facy, true, fbc->thread_id.c_str());
+ http::response resp = facy.sendRequest(request);
+
+ if (resp.code != HTTP_CODE_OK) {
+ facy.handle_error("LoadChatInfo");
+ return;
+ }
+
+ try {
+ ParseChatInfo(&resp.data, fbc);
+
+ // Load missing participants names
+ LoadParticipantsNames(fbc);
+
+ // If chat has no name, create name from participants list
+ if (fbc->chat_name.empty()) {
+ std::string newName = GenerateChatName(fbc);
+ fbc->chat_name = _A2T(newName.c_str(), CP_UTF8);
+ }
+
+ debugLogA("*** Chat thread info processed");
+ }
+ catch (const std::exception &e) {
+ debugLogA("*** Error processing chat thread info: %s", e.what());
+ }
+
+ facy.handle_success("LoadChatInfo");
+}
+
+int FacebookProto::ParseChatInfo(std::string *data, facebook_chatroom* fbc)
+{
+ size_t len = data->find("\r\n");
+ if (len != data->npos)
+ data->erase(len);
+
+ JSONNode root = JSONNode::parse(data->c_str());
+ if (!root)
+ return EXIT_FAILURE;
+
+ const JSONNode &thread = root["o0"]["data"]["message_thread"];
+ if (!thread)
+ return EXIT_FAILURE;
+
+ const JSONNode &thread_fbid_ = thread["thread_key"]["thread_fbid"];
+ const JSONNode &name_ = thread["name"];
+ if (!thread_fbid_)
+ return EXIT_FAILURE;
+
+ std::string tid = "id." + thread_fbid_.as_string();
+ if (fbc->thread_id != tid)
+ return EXIT_FAILURE;
+
+ chatroom_participant user;
+ user.is_former = false;
+ user.role = ROLE_NONE;
+ const JSONNode &participants = thread["all_participants"]["nodes"];
+ for (auto &jt : participants) {
+ user.user_id = jt["messaging_actor"]["id"].as_string();
+ fbc->participants.insert(std::make_pair(user.user_id, user));
+ }
+
+ fbc->can_reply = thread["can_reply"].as_bool();
+ fbc->is_archived = thread["has_viewer_archived"].as_bool();
+ fbc->is_subscribed = thread["is_viewer_subscribed"].as_bool();
+ fbc->read_only = thread["read_only"].as_bool();
+ fbc->chat_name = std::wstring(ptrW(mir_utf8decodeW(name_.as_string().c_str())));
+ return EXIT_SUCCESS;
+}
diff --git a/protocols/FacebookRM/src/contacts.cpp b/protocols/FacebookRM/src/contacts.cpp
index 6ae8fb0604..16d9a0bb73 100644
--- a/protocols/FacebookRM/src/contacts.cpp
+++ b/protocols/FacebookRM/src/contacts.cpp
@@ -217,120 +217,6 @@ void FacebookProto::LoadContactInfo(facebook_user* fbu)
}
}
-void FacebookProto::LoadParticipantsNames(facebook_chatroom *fbc)
-{
- std::vector<std::string> namelessIds;
-
- // TODO: We could load all names from server at once by skipping this for cycle and using namelessIds as all in participants list, but we would lost our local names of our contacts. But maybe that's not a problem?
- for (auto &it : fbc->participants) {
- const char *id = it.first.c_str();
- chatroom_participant &user = it.second;
-
- if (!user.loaded) {
- if (!mir_strcmp(id, facy.self_.user_id.c_str())) {
- user.nick = facy.self_.real_name;
- user.role = ROLE_ME;
- user.loaded = true;
- }
- else {
- MCONTACT hContact = ContactIDToHContact(id);
- if (hContact != 0) {
- DBVARIANT dbv;
- if (!getStringUtf(hContact, FACEBOOK_KEY_NICK, &dbv)) {
- user.nick = dbv.pszVal;
- db_free(&dbv);
- }
- if (user.role == ROLE_NONE) {
- int type = getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE);
- if (type == CONTACT_FRIEND)
- user.role = ROLE_FRIEND;
- else
- user.role = ROLE_NONE;
- }
- user.loaded = true;
- }
-
- if (!user.loaded)
- namelessIds.push_back(id);
- }
- }
- }
-
- if (!namelessIds.empty()) {
- // we have some contacts without name, let's load them all from the server
-
- LIST<char> userIds(1);
- for (std::string::size_type i = 0; i < namelessIds.size(); i++)
- userIds.insert(mir_strdup(namelessIds.at(i).c_str()));
-
- HttpRequest *request = new UserInfoRequest(&facy, userIds);
- http::response resp = facy.sendRequest(request);
-
- FreeList(userIds);
- userIds.destroy();
-
- if (resp.code == HTTP_CODE_OK) {
- try {
- // TODO: We can cache these results and next time (e.g. for different chatroom) we can use that already cached names
- ParseChatParticipants(&resp.data, &fbc->participants);
- debugLogA("*** Participant names processed");
- }
- catch (const std::exception &e) {
- debugLogA("*** Error processing participant names: %s", e.what());
- }
- }
- }
-}
-
-void FacebookProto::JoinChatrooms()
-{
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
- if (!isChatRoom(hContact))
- continue;
-
- // Ignore archived and unsubscribed chats
- if (getBool(hContact, FACEBOOK_KEY_CHAT_IS_ARCHIVED, false) || !getBool(hContact, FACEBOOK_KEY_CHAT_IS_SUBSCRIBED, true))
- continue;
-
- OnJoinChat(hContact, 0);
- }
-}
-
-void FacebookProto::LoadChatInfo(facebook_chatroom *fbc)
-{
- if (isOffline())
- return;
-
- // request info about chat thread
- HttpRequest *request = new ThreadInfoRequest(&facy, true, fbc->thread_id.c_str());
- http::response resp = facy.sendRequest(request);
-
- if (resp.code != HTTP_CODE_OK) {
- //!!!!!!! facy.handle_error("LoadChatInfo");
- return;
- }
-
- try {
- ParseChatInfo(&resp.data, fbc);
-
- // Load missing participants names
- LoadParticipantsNames(fbc);
-
- // If chat has no name, create name from participants list
- if (fbc->chat_name.empty()) {
- std::string newName = GenerateChatName(fbc);
- fbc->chat_name = _A2T(newName.c_str(), CP_UTF8);
- }
-
- debugLogA("*** Chat thread info processed");
- }
- catch (const std::exception &e) {
- debugLogA("*** Error processing chat thread info: %s", e.what());
- }
-
- facy.handle_success("LoadChatInfo");
-}
-
MCONTACT FacebookProto::AddToContactList(facebook_user* fbu, bool force_add, bool add_temporarily)
{
// Ignore self user completely
diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp
index 8ed8d5f5b7..69dd1e02fa 100644
--- a/protocols/FacebookRM/src/json.cpp
+++ b/protocols/FacebookRM/src/json.cpp
@@ -1306,64 +1306,6 @@ int FacebookProto::ParseUserInfo(std::string *data, facebook_user* fbu)
return EXIT_SUCCESS;
}
-int FacebookProto::ParseChatInfo(std::string *data, facebook_chatroom* fbc)
-{
- std::string jsonData = data->substr(9);
-
- JSONNode root = JSONNode::parse(jsonData.c_str());
- if (!root)
- return EXIT_FAILURE;
-
- const JSONNode &threads = root["payload"].at("threads");
- if (!threads)
- return EXIT_FAILURE;
-
- for (auto &it : threads) {
- const JSONNode &is_canonical_user_ = it["is_canonical_user"];
- const JSONNode &thread_fbid_ = it["thread_fbid"];
- const JSONNode &name_ = it["name"];
- //const JSONNode &message_count_ = it["message_count");
- //const JSONNode &unread_count_ = it["unread_count"); // TODO: use it to check against number of loaded messages... but how?
-
- if (!thread_fbid_ || !is_canonical_user_ || is_canonical_user_.as_bool())
- continue;
-
- std::string tid = "id." + thread_fbid_.as_string();
-
- // TODO: allow more chats to parse at once
- if (fbc->thread_id != tid)
- continue;
-
- chatroom_participant user;
-
- user.is_former = true;
- const JSONNode &former_participants = it["former_participants"];
- for (auto &jt : former_participants) {
- user.role = jt["is_friend"].as_bool() ? ROLE_FRIEND : ROLE_NONE;
- user.user_id = jt["id"].as_string().substr(5); // strip "fbid:" prefix
- fbc->participants.insert(std::make_pair(user.user_id, user));
- }
-
- user.is_former = false;
- user.role = ROLE_NONE;
- const JSONNode &participants = it["participants"];
- for (auto &jt : participants) {
- user.user_id = jt.as_string().substr(5); // strip "fbid:" prefix
- fbc->participants.insert(std::make_pair(user.user_id, user));
- }
-
- // TODO: don't automatically join unsubscribed or archived chatrooms
-
- fbc->can_reply = it["can_reply"].as_bool();
- fbc->is_archived = it["is_archived"].as_bool();
- fbc->is_subscribed = it["is_subscribed"].as_bool();
- fbc->read_only = it["read_only"].as_bool();
- fbc->chat_name = std::wstring(ptrW(mir_utf8decodeW(name_.as_string().c_str())));
- }
-
- return EXIT_SUCCESS;
-}
-
int FacebookProto::ParseMessagesCount(std::string *data, int *messagesCount, int *unreadCount)
{
std::string jsonData = data->substr(9);
diff --git a/protocols/FacebookRM/src/version.h b/protocols/FacebookRM/src/version.h
index b6de90ab7a..070b2bc311 100644
--- a/protocols/FacebookRM/src/version.h
+++ b/protocols/FacebookRM/src/version.h
@@ -1,7 +1,7 @@
#define __MAJOR_VERSION 0
#define __MINOR_VERSION 4
#define __RELEASE_NUM 0
-#define __BUILD_NUM 2
+#define __BUILD_NUM 3
#include <stdver.h>