From 31576722f7a8fd5c9719852242a2b4e9749830d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20P=C3=B6sel?= Date: Tue, 15 Jul 2014 15:35:50 +0000 Subject: Facebook: First phase of chat refactoring - It loads list of users, their "roles" (myself, friend, user) with friend's names - Fixed some memory leak git-svn-id: http://svn.miranda-ng.org/main/trunk@9809 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/FacebookRM/src/chat.cpp | 57 +++++++------ protocols/FacebookRM/src/client.h | 3 +- protocols/FacebookRM/src/communication.cpp | 9 ++ protocols/FacebookRM/src/connection.cpp | 1 + protocols/FacebookRM/src/contacts.cpp | 106 ++++++++++++++++++++++- protocols/FacebookRM/src/entities.h | 4 +- protocols/FacebookRM/src/json.cpp | 130 ++++++++++++++++------------- protocols/FacebookRM/src/json.h | 1 + protocols/FacebookRM/src/process.cpp | 66 +++++++++++---- protocols/FacebookRM/src/proto.h | 4 +- 10 files changed, 274 insertions(+), 107 deletions(-) diff --git a/protocols/FacebookRM/src/chat.cpp b/protocols/FacebookRM/src/chat.cpp index 323c36428d..2293592aa4 100644 --- a/protocols/FacebookRM/src/chat.cpp +++ b/protocols/FacebookRM/src/chat.cpp @@ -41,8 +41,9 @@ void FacebookProto::UpdateChat(const TCHAR *tchat_id, const char *id, const char gce.ptszUID = tid; CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); - std::map::iterator chatroom = facy.chat_rooms.find(tchat_id); - chatroom->second.message_readers = ""; + // TODO: keep it here or move it somewhere else? + std::map::iterator chatroom = facy.chat_rooms.find(tchat_id); + chatroom->second->message_readers = ""; } void FacebookProto::RenameChat(const char *chat_id, const char *name) @@ -152,37 +153,36 @@ void FacebookProto::AddChatContact(const TCHAR *tchat_id, const char *id, const gce.time = ::time(NULL); gce.bIsMe = !strcmp(id, facy.self_.user_id.c_str()); - if (gce.bIsMe) - gce.ptszStatus = _T("Admin"); - else - gce.ptszStatus = _T("Normal"); - - std::map::iterator room = facy.chat_rooms.find(tchat_id); - if(room != facy.chat_rooms.end()) - room->second.participants.insert(std::make_pair(id, name)); + if (gce.bIsMe) { + gce.ptszStatus = _T("Myself"); + } else { + MCONTACT hContact = ContactIDToHContact(id); + if (hContact == NULL || getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE) != CONTACT_FRIEND) + gce.ptszStatus = _T("User"); + else { + gce.ptszStatus = _T("Friend"); + } + } - CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); + CallServiceSync(MS_GC_EVENT, 0, reinterpret_cast(&gce)); } - -void FacebookProto::RemoveChatContact(const TCHAR *tchat_id, const char *id) +void FacebookProto::RemoveChatContact(const TCHAR *tchat_id, const char *id, const char *name) { // We dont want to remove our self-contact from chat. Ever. if (!strcmp(id, facy.self_.user_id.c_str())) return; + ptrT tnick(mir_a2t_cp(name, CP_UTF8)); ptrT tid( mir_a2t(id)); GCDEST gcd = { m_szModuleName, tchat_id, GC_EVENT_PART }; GCEVENT gce = { sizeof(gce), &gcd }; gce.dwFlags = GCEF_ADDTOLOG; - gce.ptszUID = gce.ptszNick = tid; + gce.ptszNick = tnick; + gce.ptszUID = tid; gce.time = ::time(NULL); - gce.bIsMe = false;//!strcmp(id, facy.self_.user_id.c_str()); - - std::map::iterator room = facy.chat_rooms.find(tchat_id); - if (room != facy.chat_rooms.end()) - room->second.participants.erase(id); + gce.bIsMe = false; CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); } @@ -223,9 +223,11 @@ void FacebookProto::AddChat(const TCHAR *tid, const TCHAR *tname) GCEVENT gce = { sizeof(gce), &gcd }; // Create a user statuses - gce.ptszStatus = _T("Admin"); + gce.ptszStatus = _T("User"); + CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast(&gce)); + gce.ptszStatus = _T("Friend"); CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast(&gce)); - gce.ptszStatus = _T("Normal"); + gce.ptszStatus = _T("Myself"); CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast(&gce)); // Finish initialization @@ -233,12 +235,8 @@ void FacebookProto::AddChat(const TCHAR *tid, const TCHAR *tname) gce.time = ::time(NULL); gce.pDest = &gcd; - facebook_chatroom chatroom; - chatroom.chat_name = tname; - facy.chat_rooms.insert(std::make_pair(tid, chatroom)); - // Add self contact - AddChatContact(tid, facy.self_.user_id.c_str(), facy.self_.real_name.c_str()); + ////AddChatContact(tid, facy.self_.user_id.c_str(), facy.self_.real_name.c_str()); CallServiceSync(MS_GC_EVENT,SESSION_INITDONE,reinterpret_cast(&gce)); CallServiceSync(MS_GC_EVENT,SESSION_ONLINE, reinterpret_cast(&gce)); } @@ -268,10 +266,11 @@ INT_PTR FacebookProto::OnJoinChat(WPARAM hContact, LPARAM suppress) // Create a group GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_ADDGROUP }; GCEVENT gce = { sizeof(gce), &gcd }; - gce.ptszStatus = _T("Admin"); + gce.ptszStatus = _T("Myself"); CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast(&gce)); - - gce.ptszStatus = _T("Normal"); + gce.ptszStatus = _T("Friend"); + CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast(&gce)); + gce.ptszStatus = _T("User"); CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast(&gce)); SetTopic("Omegle is a great way of meeting new friends!"); diff --git a/protocols/FacebookRM/src/client.h b/protocols/FacebookRM/src/client.h index 29b2ba0f95..4b3d23f112 100644 --- a/protocols/FacebookRM/src/client.h +++ b/protocols/FacebookRM/src/client.h @@ -97,7 +97,7 @@ public: std::map cookies; std::map pages; - std::map chat_rooms; + std::map chat_rooms; std::map notifications; std::string get_newsfeed_type(); @@ -112,6 +112,7 @@ public: void store_headers(http::response* resp, NETLIBHTTPHEADER* headers, int headers_count); void clear_cookies(); void clear_notifications(); + void clear_chatrooms(); //////////////////////////////////////////////////////////// diff --git a/protocols/FacebookRM/src/communication.cpp b/protocols/FacebookRM/src/communication.cpp index 3faf8da535..8c72bd9be6 100644 --- a/protocols/FacebookRM/src/communication.cpp +++ b/protocols/FacebookRM/src/communication.cpp @@ -705,6 +705,15 @@ void facebook_client::clear_notifications() notifications.clear(); } +void facebook_client::clear_chatrooms() +{ + for (std::map::iterator it = chat_rooms.begin(); it != chat_rooms.end();) { + delete it->second; + it = chat_rooms.erase(it); + } + chat_rooms.clear(); +} + void loginError(FacebookProto *proto, std::string error_str) { error_str = utils::text::trim( utils::text::special_expressions_decode( diff --git a/protocols/FacebookRM/src/connection.cpp b/protocols/FacebookRM/src/connection.cpp index 56673fe6df..b234928fc4 100644 --- a/protocols/FacebookRM/src/connection.cpp +++ b/protocols/FacebookRM/src/connection.cpp @@ -52,6 +52,7 @@ void FacebookProto::ChangeStatus(void*) facy.clear_cookies(); facy.clear_notifications(); + facy.clear_chatrooms(); facy.buddies.clear(); facy.messages_ignore.clear(); facy.pages.clear(); diff --git a/protocols/FacebookRM/src/contacts.cpp b/protocols/FacebookRM/src/contacts.cpp index a4834d6237..ec84cbabb4 100644 --- a/protocols/FacebookRM/src/contacts.cpp +++ b/protocols/FacebookRM/src/contacts.cpp @@ -165,16 +165,118 @@ void FacebookProto::LoadContactInfo(facebook_user* fbu) p->parse_user_info(&resp.data, fbu); delete p; - debugLogA("***** Thread info processed"); + debugLogA("***** Contact thread info processed"); CODE_BLOCK_CATCH - debugLogA("***** Error processing thread info: %s", e.what()); + debugLogA("***** Error processing contact thread info: %s", e.what()); CODE_BLOCK_END } } +void FacebookProto::LoadParticipantsNames(facebook_chatroom *fbc) +{ + for (std::map::iterator it = fbc->participants.begin(); it != fbc->participants.end(); ++it) { + if (it->second.empty()) { + if (!strcmp(it->first.c_str(), facy.self_.user_id.c_str())) + it->second = facy.self_.real_name; + else { + MCONTACT hContact = ContactIDToHContact(it->first.c_str()); + if (hContact != NULL) { + DBVARIANT dbv; + if (!getStringUtf(hContact, FACEBOOK_KEY_NICK, &dbv)) { + it->second = dbv.pszVal; + db_free(&dbv); + } + // TODO: set correct role (friend/user) for this contact here - need rework participants map to + } + + // TODO: load unknown contact's names from server + if (it->second.empty()) + it->second = it->first; + } + } + } +} + +void FacebookProto::LoadChatInfo(facebook_chatroom *fbc) +{ + std::string data = "client=mercury"; + data += "&__user=" + facy.self_.user_id; + data += "&fb_dtsg=" + (!facy.dtsg_.empty() ? facy.dtsg_ : "0"); + data += "&__a=1&__dyn=&__req=&ttstamp=0"; + + std::string thread_id = utils::url::encode(std::string(_T2A(fbc->thread_id.c_str()))); + + // request info about thread + data += "&threads[thread_ids][0]=" + thread_id; + + http::response resp = facy.flap(REQUEST_THREAD_INFO, &data); + + if (resp.code == HTTP_CODE_OK) { + + CODE_BLOCK_TRY + + facebook_json_parser* p = new facebook_json_parser(this); + p->parse_chat_info(&resp.data, fbc); + delete p; + + // Load missing participants names + LoadParticipantsNames(fbc); + + // If chat has no name, create name from participants list + if (fbc->chat_name.empty()) { + unsigned int namesCount = 3; // how many names should be in room name; max. 5 + + for (std::map::iterator it = fbc->participants.begin(); it != fbc->participants.end(); ++it) { + if (it->second.empty()) + continue; + + if (!fbc->chat_name.empty()) + fbc->chat_name += _T(", "); + + std::string name; + std::string::size_type pos; + if ((pos = it->second.find(" ")) != std::string::npos) { + name = it->second.substr(0, pos); + } + else { + name = it->second; + } + + fbc->chat_name += _A2T(name.c_str()); + } + + if (fbc->participants.size() > namesCount) { + TCHAR more[200]; + mir_sntprintf(more, SIZEOF(more), TranslateT("%s and more (%d)"), fbc->chat_name.c_str(), fbc->participants.size() - namesCount); + fbc->chat_name = more; + } + + // If there are no participants to create a name from, use just thread_id + if (fbc->chat_name.empty()) + fbc->chat_name = fbc->thread_id; // TODO: is this needed? Isn't it showed automatically as id if there is no name? + } + + //ReceiveMessages(messages, local_timestamp, true); // don't let it fall into infinite cycle, solve it somehow... + + debugLogA("***** Chat thread info processed"); + + CODE_BLOCK_CATCH + + debugLogA("***** Error processing chat thread info: %s", e.what()); + + CODE_BLOCK_END + + facy.handle_success("LoadChatInfo"); + } + else { + facy.handle_error("LoadChatInfo"); + } + +} + MCONTACT FacebookProto::AddToContactList(facebook_user* fbu, ContactType type, bool force_add) { // First, check if this contact exists (and if does, just return it) diff --git a/protocols/FacebookRM/src/entities.h b/protocols/FacebookRM/src/entities.h index 977b9b635d..0be3d2d396 100644 --- a/protocols/FacebookRM/src/entities.h +++ b/protocols/FacebookRM/src/entities.h @@ -88,8 +88,10 @@ struct facebook_user struct facebook_chatroom { - std::tstring chat_name; + facebook_chatroom(std::tstring thread_id) : thread_id(thread_id) {} + std::tstring thread_id; + std::tstring chat_name; std::map participants; std::string message_readers; diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp index 7e2993e5e8..b12fe32378 100644 --- a/protocols/FacebookRM/src/json.cpp +++ b/protocols/FacebookRM/src/json.cpp @@ -429,24 +429,25 @@ int facebook_json_parser::parse_messages(void* data, std::vector< facebook_messa std::tstring tid = json_as_string(threadid); std::string reader_id = json_as_pstring(reader); - std::map::iterator chatroom = proto->facy.chat_rooms.find(tid); + std::map::iterator chatroom = proto->facy.chat_rooms.find(tid); if (chatroom != proto->facy.chat_rooms.end()) { - std::map::const_iterator participant = chatroom->second.participants.find(reader_id); - if (participant == chatroom->second.participants.end()) { + std::map::const_iterator participant = chatroom->second->participants.find(reader_id); + if (participant == chatroom->second->participants.end()) { // TODO: load name of this participant std::string name = reader_id; + chatroom->second->participants.insert(std::make_pair(reader_id, name)); proto->AddChatContact(tid.c_str(), reader_id.c_str(), name.c_str()); } - participant = chatroom->second.participants.find(reader_id); - if (participant != chatroom->second.participants.end()) { + participant = chatroom->second->participants.find(reader_id); + if (participant != chatroom->second->participants.end()) { MCONTACT hChatContact = proto->ChatIDToHContact(tid); - if (!chatroom->second.message_readers.empty()) - chatroom->second.message_readers += ", "; - chatroom->second.message_readers += participant->second; + if (!chatroom->second->message_readers.empty()) + chatroom->second->message_readers += ", "; + chatroom->second->message_readers += participant->second; - ptrT readers(mir_utf8decodeT(chatroom->second.message_readers.c_str())); + ptrT readers(mir_utf8decodeT(chatroom->second->message_readers.c_str())); StatusTextData st = { 0 }; st.cbSize = sizeof(st); @@ -594,17 +595,17 @@ int facebook_json_parser::parse_messages(void* data, std::vector< facebook_messa std::tstring tid = json_as_string(thread_); std::string from_id = json_as_pstring(from_); - std::map::iterator chatroom = proto->facy.chat_rooms.find(tid); + std::map::iterator chatroom = proto->facy.chat_rooms.find(tid); if (chatroom != proto->facy.chat_rooms.end()) { - std::map::const_iterator participant = chatroom->second.participants.find(from_id); - if (participant == chatroom->second.participants.end()) { + std::map::const_iterator participant = chatroom->second->participants.find(from_id); + if (participant == chatroom->second->participants.end()) { // TODO: load name of this participant std::string name = from_id; proto->AddChatContact(tid.c_str(), from_id.c_str(), name.c_str()); } - participant = chatroom->second.participants.find(from_id); - if (participant != chatroom->second.participants.end()) { + participant = chatroom->second->participants.find(from_id); + if (participant != chatroom->second->participants.end()) { MCONTACT hChatContact = proto->ChatIDToHContact(tid); ptrT name(mir_utf8decodeT(participant->second.c_str())); @@ -779,9 +780,7 @@ int facebook_json_parser::parse_thread_messages(void* data, std::vector< faceboo // Ignore "wrong" (duplicit) identifiers - these that doesn't begin with "id." if (id.substr(0, 3) == _T("id.")) { - facebook_chatroom *room = new facebook_chatroom(); - room->thread_id = id; - + facebook_chatroom *room = new facebook_chatroom(id); chatrooms->insert(std::make_pair((char*)_T2A(room->thread_id.c_str()), room)); } } @@ -987,61 +986,74 @@ int facebook_json_parser::parse_user_info(void* data, facebook_user* fbu) return EXIT_SUCCESS; } -/* TODO: implement this somehow -int facebook_json_parser::parse_chat_info(void* data, facebook_chat* fbu) { - // This is a recent 5 person listing of participants. - JSONNODE *participants_ids = json_get(gthreadinfo, "participant_ids"); - JSONNODE *participants_names = json_get(gthreadinfo, "participant_names"); +int facebook_json_parser::parse_chat_info(void* data, facebook_chatroom* fbc) +{ + std::string jsonData = static_cast< std::string* >(data)->substr(9); - JSONNODE *thread_name_ = json_get(gthreadinfo, "name"); - std::tstring name = json_as_string(thread_name_); + JSONNODE *root = json_parse(jsonData.c_str()); + if (root == NULL) + return EXIT_FAILURE; - // if there is no name for this room, set own name - if (name.empty()) { - unsigned int namesCount = 3; // how many names should be in room name; max. 5 + JSONNODE *payload = json_get(root, "payload"); + if (payload == NULL) { + json_delete(root); + return EXIT_FAILURE; + } + + //JSONNODE *actions = json_get(payload, "actions"); + JSONNODE *threads = json_get(payload, "threads"); + if (/*actions == NULL || */threads == NULL) { + json_delete(root); + return EXIT_FAILURE; + } - for (unsigned int n = 0; n < json_size(participants_names) && n < namesCount; n++) { - JSONNODE *nameItr = json_at(participants_names, n); + /*JSONNODE *roger = json_get(payload, "roger"); + if (roger != NULL) { + for (unsigned int i = 0; i < json_size(roger); i++) { + JSONNODE *it = json_at(roger, i); + std::tstring id = _A2T(json_name(it)); - if (!name.empty()) - name += _T(", "); + // Ignore "wrong" (duplicit) identifiers - these that doesn't begin with "id." + if (id.substr(0, 3) == _T("id.")) { + facebook_chatroom *room = new facebook_chatroom(); + room->thread_id = id; - name += json_as_string(nameItr); + chatrooms->insert(std::make_pair((char*)_T2A(room->thread_id.c_str()), room)); + } } - JSONNODE *count_ = json_get(gthreadinfo, "participant_total_count"); - unsigned int count = json_as_int(count_); + }*/ - if (count > namesCount) { - TCHAR more[200]; - mir_sntprintf(more, SIZEOF(more), TranslateT("%s and more (%d)"), name.c_str(), count - namesCount); - name = more; - } - } + std::map thread_ids; + for (unsigned int i = 0; i < json_size(threads); i++) { + JSONNODE *it = json_at(threads, i); - if (name.empty()) - name = thread_id; + JSONNODE *is_canonical_user_ = json_get(it, "is_canonical_user"); + JSONNODE *thread_id_ = json_get(it, "thread_id"); + JSONNODE *name_ = json_get(it, "name"); + //JSONNODE *message_count_ = json_get(it, "message_count"); + JSONNODE *unread_count_ = json_get(it, "unread_count"); // TODO: use it to check against number of loaded messages... but how? + JSONNODE *folder_ = json_get(it, "folder"); - for (unsigned int n = 0; n < json_size(participants_ids); n++) { - JSONNODE *idItr = json_at(participants_ids, n); - std::string pId = json_as_pstring(idItr); + if (thread_id_ == NULL || is_canonical_user_ == NULL || json_as_bool(is_canonical_user_)) + continue; - JSONNODE *nameItr = json_at(participants_names, n); - std::string pName = json_as_pstring(nameItr); + std::tstring tid = json_as_string(thread_id_); - if (!proto->IsChatContact(thread_id.c_str(), pId.c_str())) { - proto->AddChatContact(thread_id.c_str(), pId.c_str(), pName.c_str()); + // TODO: allow more users to parse at once + if (fbc->thread_id != tid) { + continue; } - } - std::string senderName = json_as_pstring(sender_name); - std::string::size_type pos; - if ((pos = senderName.find(" ")) != std::string::npos) { - senderName = senderName.substr(0, pos); - } + JSONNODE *participants = json_get(it, "participants"); + for (unsigned int j = 0; j < json_size(participants); j++) { + JSONNODE *jt = json_at(participants, j); + std::string user_id = json_as_pstring(jt); + fbc->participants.insert(std::make_pair(user_id.substr(5), "")); + } - // Last fall-back for adding this sender (in case he was not in the participants) - is this even needed? - if (!proto->IsChatContact(thread_id.c_str(), id.c_str())) { - proto->AddChatContact(thread_id.c_str(), id.c_str(), senderName.c_str()); + fbc->chat_name = json_as_string(name_); } + + json_delete(root); + return EXIT_SUCCESS; } -*/ \ No newline at end of file diff --git a/protocols/FacebookRM/src/json.h b/protocols/FacebookRM/src/json.h index 70001e4a31..d1e8f2e44d 100644 --- a/protocols/FacebookRM/src/json.h +++ b/protocols/FacebookRM/src/json.h @@ -38,6 +38,7 @@ public: int parse_thread_messages(void*, std::vector< facebook_message* >*, std::map< std::string, facebook_chatroom* >*, bool unreadOnly, bool inboxOnly, int limit); int parse_thread_info(void* data, std::string* user_id); int parse_user_info(void* data, facebook_user* fbu); + int parse_chat_info(void* data, facebook_chatroom* fbc); facebook_json_parser(FacebookProto* proto) { diff --git a/protocols/FacebookRM/src/process.cpp b/protocols/FacebookRM/src/process.cpp index 2f13369f5a..0d87147a58 100644 --- a/protocols/FacebookRM/src/process.cpp +++ b/protocols/FacebookRM/src/process.cpp @@ -380,9 +380,12 @@ void FacebookProto::ProcessUnreadMessage(void *p) for (std::map::iterator it = chatrooms.begin(); it != chatrooms.end(); ) { - facebook_chatroom *room = it->second; + // TODO: refactor this too! + // TODO: have all chatrooms in facy, in memory, and then handle them as needed... somehow think about it... + /* facebook_chatroom *room = it->second; MCONTACT hChatContact = NULL; - if (GetChatUsers(room->thread_id.c_str()) == NULL) { + ptrA users(GetChatUsers(room->thread_id.c_str())); + if (users == NULL) { AddChat(room->thread_id.c_str(), room->chat_name.c_str()); hChatContact = ChatIDToHContact(room->thread_id); // Set thread id (TID) for later @@ -397,7 +400,7 @@ void FacebookProto::ProcessUnreadMessage(void *p) if (!hChatContact) hChatContact = ChatIDToHContact(room->thread_id); - ForkThread(&FacebookProto::ReadMessageWorker, (void*)hChatContact); + ForkThread(&FacebookProto::ReadMessageWorker, (void*)hChatContact);*/ delete it->second; it = chatrooms.erase(it); @@ -485,11 +488,13 @@ CODE_BLOCK_TRY p->parse_thread_messages(&resp.data, &messages, &chatrooms, false, false, 20); delete p; - for (std::map::iterator it = chatrooms.begin(); it != chatrooms.end();) { + // TODO: do something with this, chat is loading somewhere else... (in receiveMessages method right now) + /*for (std::map::iterator it = chatrooms.begin(); it != chatrooms.end();) { facebook_chatroom *room = it->second; MCONTACT hChatContact = NULL; - if (GetChatUsers(room->thread_id.c_str()) == NULL) { + ptrA users(GetChatUsers(room->thread_id.c_str())); + if (users == NULL) { AddChat(room->thread_id.c_str(), room->chat_name.c_str()); hChatContact = ChatIDToHContact(room->thread_id); // Set thread id (TID) for later @@ -509,7 +514,7 @@ CODE_BLOCK_TRY delete it->second; it = chatrooms.erase(it); } - chatrooms.clear(); + chatrooms.clear();*/ bool local_timestamp = getBool(FACEBOOK_KEY_LOCAL_TIMESTAMP_UNREAD, 0); ReceiveMessages(messages, local_timestamp, true); @@ -584,25 +589,51 @@ void FacebookProto::ReceiveMessages(std::vector messages, boo // Multi-user message debugLogA(" Got chat message: %s", messages[i]->message_text.c_str()); + facebook_chatroom *fbc; std::tstring tthread_id = _A2T(messages[i]->thread_id.c_str()); - // RM TODO: better use check if chatroom exists/is in db/is online... no? - // like: if (ChatIDToHContact(tthread_id) == NULL) { - if (GetChatUsers(tthread_id.c_str()) == NULL) { + std::map::iterator it = facy.chat_rooms.find(tthread_id); + if (it != facy.chat_rooms.end()) { + fbc = it->second; + } else { // In Naseem's spam mode we ignore outgoing messages sent from other instances if (naseemsSpamMode && !messages[i]->isIncoming) { delete messages[i]; continue; } - // TODO: We don't have this chat, lets load info about it (name, list of users, last messages, etc.) - //LoadChatInfo(&fbu); // In this method use json's parse_chat_info - std::tstring tthread_name = tthread_id; // TODO: use correct name for chat, not thread_id + // We don't have this chat loaded in memory yet, lets load some info (name, list of users) + fbc = new facebook_chatroom(tthread_id); + LoadChatInfo(fbc); + facy.chat_rooms.insert(std::make_pair(tthread_id, fbc)); + } - AddChat(tthread_id.c_str(), tthread_name.c_str()); + MCONTACT hChatContact; + // RM TODO: better use check if chatroom exists/is in db/is online... no? + // like: if (ChatIDToHContact(tthread_id) == NULL) { + ptrA users(GetChatUsers(tthread_id.c_str())); + if (users == NULL) { + AddChat(fbc->thread_id.c_str(), fbc->chat_name.c_str()); + hChatContact = ChatIDToHContact(fbc->thread_id); + // Set thread id (TID) for later + setTString(hChatContact, FACEBOOK_KEY_TID, fbc->thread_id.c_str()); + + for (std::map::iterator jt = fbc->participants.begin(); jt != fbc->participants.end(); ++jt) { + // If this contact isn't already in chat, add it + if (!IsChatContact(fbc->thread_id.c_str(), jt->first.c_str())) // TODO: is this needed? + AddChatContact(fbc->thread_id.c_str(), jt->first.c_str(), jt->second.c_str()); + } } - MCONTACT hChatContact = ChatIDToHContact(tthread_id); + if (!hChatContact) + hChatContact = ChatIDToHContact(fbc->thread_id); + + if (!hChatContact) { + // hopefully shouldn't happen, but who knows? + debugLog(_T("! ! ! No hChatContact for %s"), fbc->thread_id.c_str()); + delete messages[i]; + continue; + } // Save last (this) message ID setString(hChatContact, FACEBOOK_KEY_MESSAGE_ID, messages[i]->message_id.c_str()); @@ -642,6 +673,13 @@ void FacebookProto::ReceiveMessages(std::vector messages, boo hContact = AddToContactList(&fbu, CONTACT_NONE); } + if (!hContact) { + // hopefully shouldn't happen, but who knows? + debugLogA("! ! ! No hContact for %s", messages[i]->user_id); + delete messages[i]; + continue; + } + // Save last (this) message ID setString(hContact, FACEBOOK_KEY_MESSAGE_ID, messages[i]->message_id.c_str()); diff --git a/protocols/FacebookRM/src/proto.h b/protocols/FacebookRM/src/proto.h index 7a1b208707..8fd911ed63 100644 --- a/protocols/FacebookRM/src/proto.h +++ b/protocols/FacebookRM/src/proto.h @@ -210,10 +210,12 @@ public: void RenameChat(const char *chat_id, const char *name); bool IsChatContact(const TCHAR *chat_id, const char *id); void AddChatContact(const TCHAR *chat_id, const char *id, const char *name); - void RemoveChatContact(const TCHAR *chat_id, const char *id); + void RemoveChatContact(const TCHAR *chat_id, const char *id, const char *name); void SetChatStatus(const char *chat_id, int status); char *GetChatUsers(const TCHAR *chat_id); void ReceiveMessages(std::vector messages, bool local_timestamp, bool check_duplicates = false); + void LoadChatInfo(facebook_chatroom* fbc); + void LoadParticipantsNames(facebook_chatroom *fbc); // Connection client facebook_client facy; // TODO: Refactor to "client" and make dynamic -- cgit v1.2.3