From 4c6d7054a9d545c8d8978b6fe1d1f8a89119f2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20P=C3=B6sel?= Date: Tue, 18 Mar 2014 23:42:49 +0000 Subject: Facebook: Load user info when receiving message from someone who isn't in clist yet git-svn-id: http://svn.miranda-ng.org/main/trunk@8655 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/FacebookRM/src/communication.cpp | 13 ++++ protocols/FacebookRM/src/constants.h | 5 +- protocols/FacebookRM/src/contacts.cpp | 24 ++++++ protocols/FacebookRM/src/json.cpp | 95 ++++++++++++++++------- protocols/FacebookRM/src/json.h | 1 + protocols/FacebookRM/src/process.cpp | 119 ++++++++++------------------- protocols/FacebookRM/src/proto.h | 2 + 7 files changed, 153 insertions(+), 106 deletions(-) (limited to 'protocols/FacebookRM/src') diff --git a/protocols/FacebookRM/src/communication.cpp b/protocols/FacebookRM/src/communication.cpp index 5c99482a89..e1facb8016 100644 --- a/protocols/FacebookRM/src/communication.cpp +++ b/protocols/FacebookRM/src/communication.cpp @@ -209,6 +209,7 @@ DWORD facebook_client::choose_security_level(RequestType request_type) // case REQUEST_HOME: // case REQUEST_DTSG: // case REQUEST_BUDDY_LIST: +// case REQUEST_LOAD_FRIEND: // case REQUEST_LOAD_FRIENDS: // case REQUEST_USER_INFO: // case REQUEST_LOAD_REQUESTS: @@ -276,6 +277,7 @@ int facebook_client::choose_method(RequestType request_type) // case REQUEST_PAGES: // case REQUEST_NOTIFICATIONS: // case REQUEST_RECONNECT: +// case REQUEST_LOAD_FRIEND: // case REQUEST_LOAD_FRIENDS: // case REQUEST_USER_INFO: // case REQUEST_LOAD_REQUESTS: @@ -318,6 +320,7 @@ std::string facebook_client::choose_server(RequestType request_type, std::string // case REQUEST_LOGOUT: // case REQUEST_BUDDY_LIST: +// case REQUEST_LOAD_FRIEND: // case REQUEST_LOAD_FRIENDS: // case REQUEST_FEEDS: // case REQUEST_PAGES: @@ -368,6 +371,16 @@ std::string facebook_client::choose_action(RequestType request_type, std::string case REQUEST_BUDDY_LIST: return "/ajax/chat/buddy_list.php?__a=1"; + case REQUEST_LOAD_FRIEND: + { + std::string action = "/ajax/chat/user_info.php?__a=1&viewer=%s&__user=%s"; + utils::text::replace_all(&action, "%s", self_.user_id); + if (get_data != NULL) { + action += "&" + (*get_data); + } + return action; + } + case REQUEST_LOAD_FRIENDS: { std::string action = "/ajax/chat/user_info_all.php?__a=1&viewer=%s&__user=%s"; diff --git a/protocols/FacebookRM/src/constants.h b/protocols/FacebookRM/src/constants.h index 83da81d108..d3b6a3b2d7 100644 --- a/protocols/FacebookRM/src/constants.h +++ b/protocols/FacebookRM/src/constants.h @@ -111,8 +111,9 @@ enum RequestType { REQUEST_NOTIFICATIONS_READ, // marking notifications read REQUEST_BUDDY_LIST, // getting regular updates (friends online, ...) - REQUEST_LOAD_FRIENDS, // getting list of all friends - REQUEST_USER_INFO, // getting info about particular user + REQUEST_LOAD_FRIEND, // getting info about particular friend + REQUEST_LOAD_FRIENDS, // getting info about all friends + REQUEST_USER_INFO, // getting info about particular user (from mobile website) REQUEST_REQUEST_FRIEND, // requesting friendships REQUEST_APPROVE_FRIEND, // approving friendships REQUEST_DELETE_FRIEND, // deleting friendships diff --git a/protocols/FacebookRM/src/contacts.cpp b/protocols/FacebookRM/src/contacts.cpp index d641a775af..1135c3fd6e 100644 --- a/protocols/FacebookRM/src/contacts.cpp +++ b/protocols/FacebookRM/src/contacts.cpp @@ -138,6 +138,30 @@ std::string FacebookProto::ThreadIDToContactID(std::string thread_id) return user_id; } +void FacebookProto::LoadContactInfo(facebook_user* fbu) +{ + // TODO: support for more friends at once + std::string get_query = "&ids[0]=" + utils::url::encode(fbu->user_id); + + http::response resp = facy.flap(REQUEST_LOAD_FRIEND, NULL, &get_query); + + if (resp.code == HTTP_CODE_OK) { + CODE_BLOCK_TRY + + facebook_json_parser* p = new facebook_json_parser(this); + p->parse_user_info(&resp.data, fbu); + delete p; + + debugLogA("***** Thread info processed"); + + CODE_BLOCK_CATCH + + debugLogA("***** Error processing thread info: %s", e.what()); + + CODE_BLOCK_END + } +} + MCONTACT FacebookProto::AddToContactList(facebook_user* fbu, ContactType type, bool dont_check) { MCONTACT hContact; diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp index 0cce660a62..ee2c9abbab 100644 --- a/protocols/FacebookRM/src/json.cpp +++ b/protocols/FacebookRM/src/json.cpp @@ -161,6 +161,35 @@ int facebook_json_parser::parse_buddy_list(void* data, List::List< facebook_user return EXIT_SUCCESS; } +void parseUser(JSONNODE *it, facebook_user *fbu) +{ + fbu->user_id = json_name(it); + + JSONNODE *name = json_get(it, "name"); + JSONNODE *thumbSrc = json_get(it, "thumbSrc"); + JSONNODE *gender = json_get(it, "gender"); + //JSONNODE *vanity = json_get(it, "vanity"); // username + //JSONNODE *uri = json_get(it, "uri"); // profile url + //JSONNODE *is_friend = json_get(it, "is_friend"); // e.g. "True" + //JSONNODE *type = json_get(it, "type"); // e.g. "friend" (classic contact) or "user" (disabled/deleted account) + + + if (name) + fbu->real_name = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_pstring(name))); + if (thumbSrc) + fbu->image_url = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_pstring(thumbSrc))); + + if (gender) + switch (json_as_int(gender)) { + case 1: // female + fbu->gender = 70; + break; + case 2: // male + fbu->gender = 77; + break; + } +} + int facebook_json_parser::parse_friends(void* data, std::map< std::string, facebook_user* >* friends) { std::string jsonData = static_cast< std::string* >(data)->substr(9); @@ -177,35 +206,11 @@ int facebook_json_parser::parse_friends(void* data, std::map< std::string, faceb for (unsigned int i = 0; i < json_size(payload); i++) { JSONNODE *it = json_at(payload, i); - const char *id = json_name(it); - - JSONNODE *name = json_get(it, "name"); - JSONNODE *thumbSrc = json_get(it, "thumbSrc"); - JSONNODE *gender = json_get(it, "gender"); - //JSONNODE *vanity = json_get(it, "vanity"); // username - //JSONNODE *uri = json_get(it, "uri"); // profile url - //JSONNODE *is_friend = json_get(it, "is_friend"); // e.g. "True" - //JSONNODE *type = json_get(it, "type"); // e.g. "friend" (classic contact) or "user" (disabled/deleted account) facebook_user *fbu = new facebook_user(); + parseUser(it, fbu); - fbu->user_id = id; - if (name) - fbu->real_name = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_pstring(name))); - if (thumbSrc) - fbu->image_url = utils::text::slashu_to_utf8(utils::text::special_expressions_decode(json_as_pstring(thumbSrc))); - - if (gender) - switch (json_as_int(gender)) { - case 1: // female - fbu->gender = 70; - break; - case 2: // male - fbu-> gender = 77; - break; - } - - friends->insert(std::make_pair(id, fbu)); + friends->insert(std::make_pair(fbu->user_id, fbu)); } json_delete(root); @@ -963,3 +968,41 @@ int facebook_json_parser::parse_thread_info(void* data, std::string* user_id) json_delete(root); return EXIT_SUCCESS; } + + +int facebook_json_parser::parse_user_info(void* data, facebook_user* fbu) +{ + std::string jsonData = static_cast< std::string* >(data)->substr(9); + + JSONNODE *root = json_parse(jsonData.c_str()); + if (root == NULL) + return EXIT_FAILURE; + + JSONNODE *payload = json_get(root, "payload"); + if (payload == NULL) { + json_delete(root); + return EXIT_FAILURE; + } + + JSONNODE *profiles = json_get(payload, "profiles"); + if (profiles == NULL) { + json_delete(root); + return EXIT_FAILURE; + } + + std::map user_ids; + for (unsigned int i = 0; i < json_size(profiles); i++) { + JSONNODE *it = json_at(profiles, i); + + // TODO: allow more users to parse at once + std::string id = json_name(it); + + if (fbu->user_id == id) { + parseUser(it, fbu); + break; + } + } + + json_delete(root); + return EXIT_SUCCESS; +} diff --git a/protocols/FacebookRM/src/json.h b/protocols/FacebookRM/src/json.h index 6cd89faac0..33f5538559 100644 --- a/protocols/FacebookRM/src/json.h +++ b/protocols/FacebookRM/src/json.h @@ -37,6 +37,7 @@ public: int parse_unread_threads(void*, std::vector< std::string >*, bool inboxOnly); 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); facebook_json_parser(FacebookProto* proto) { diff --git a/protocols/FacebookRM/src/process.cpp b/protocols/FacebookRM/src/process.cpp index b39168849a..43402fcfd7 100644 --- a/protocols/FacebookRM/src/process.cpp +++ b/protocols/FacebookRM/src/process.cpp @@ -385,52 +385,7 @@ void FacebookProto::ProcessUnreadMessage(void *p) } chatrooms.clear(); - - for (std::vector::size_type i = 0; i < messages.size(); i++) { - if (messages[i]->isChat) { - debugLogA(" Got chat message: %s", messages[i]->message_text.c_str()); - UpdateChat(_A2T(messages[i]->thread_id.c_str()), messages[i]->user_id.c_str(), messages[i]->sender_name.c_str(), messages[i]->message_text.c_str(), local_timestamp || !messages[i]->time ? ::time(NULL) : messages[i]->time); - } else if (messages[i]->user_id != facy.self_.user_id) { - debugLogA(" Got message: %s", messages[i]->message_text.c_str()); - facebook_user fbu; - fbu.user_id = messages[i]->user_id; - fbu.real_name = messages[i]->sender_name; - - // TODO: optimize this? - MCONTACT hContact = AddToContactList(&fbu, CONTACT_NONE); - setString(hContact, FACEBOOK_KEY_MESSAGE_ID, messages[i]->message_id.c_str()); - - // Save TID if not exists already - ptrA tid( getStringA(hContact, FACEBOOK_KEY_TID)); - if (!tid || strcmp(tid, messages[i]->thread_id.c_str())) - setString(hContact, FACEBOOK_KEY_TID, messages[i]->thread_id.c_str()); - - // TODO: if contact is newly added, get his user info - // TODO: maybe create new "receiveMsg" function and use it for offline and channel messages? - - ParseSmileys(messages[i]->message_text, hContact); - - if (messages[i]->isIncoming) { - PROTORECVEVENT recv = {0}; - recv.flags = PREF_UTF; - recv.szMessage = const_cast(messages[i]->message_text.c_str()); - recv.timestamp = local_timestamp || !messages[i]->time ? ::time(NULL) : messages[i]->time; - ProtoChainRecvMsg(hContact, &recv); - } else { - DBEVENTINFO dbei = {0}; - dbei.cbSize = sizeof(dbei); - dbei.eventType = EVENTTYPE_MESSAGE; - dbei.flags = DBEF_SENT | DBEF_UTF; - dbei.szModule = m_szModuleName; - dbei.timestamp = local_timestamp || !messages[i]->time ? ::time(NULL) : messages[i]->time; - dbei.cbBlob = (DWORD)messages[i]->message_text.length() + 1; - dbei.pBlob = (PBYTE)messages[i]->message_text.c_str(); - db_event_add(hContact, &dbei); - } - } - delete messages[i]; - } - messages.clear(); + ReceiveMessages(messages, local_timestamp); debugLogA("***** Unread messages processed"); @@ -452,41 +407,22 @@ void FacebookProto::ProcessUnreadMessage(void *p) } } -// TODO: combine processmessages and processunreadmessages? (behavior of showing messages to user should be the same) -void FacebookProto::ProcessMessages(void* data) +void FacebookProto::ReceiveMessages(std::vector messages, bool local_timestamp) { - if (data == NULL) - return; - - std::string* resp = (std::string*)data; - - // receive messages from all folders by default, use hidden setting to receive only inbox messages - bool inboxOnly = getBool(FACEBOOK_KEY_INBOX_ONLY, 0); - - if (isOffline()) - goto exit; - - debugLogA("***** Starting processing messages"); - - CODE_BLOCK_TRY - - std::vector< facebook_message* > messages; - std::vector< facebook_notification* > notifications; - - facebook_json_parser* p = new facebook_json_parser(this); - p->parse_messages(data, &messages, ¬ifications, inboxOnly); - delete p; - - bool local_timestamp = getBool(FACEBOOK_KEY_LOCAL_TIMESTAMP, 0); - - for(std::vector::size_type i=0; i::size_type i = 0; i < messages.size(); i++) { debugLogA(" Got message: %s", messages[i]->message_text.c_str()); facebook_user fbu; fbu.user_id = messages[i]->user_id; fbu.real_name = messages[i]->sender_name; - MCONTACT hContact = AddToContactList(&fbu, CONTACT_NONE); + MCONTACT hContact = ContactIDToHContact(fbu.user_id); + if (hContact == NULL) { + // We don't have this contact, lets load info about him + LoadContactInfo(&fbu); + + hContact = AddToContactList(&fbu, CONTACT_NONE); + } + setString(hContact, FACEBOOK_KEY_MESSAGE_ID, messages[i]->message_id.c_str()); // Save TID if not exists already @@ -494,9 +430,6 @@ void FacebookProto::ProcessMessages(void* data) if (!tid || strcmp(tid, messages[i]->thread_id.c_str())) setString(hContact, FACEBOOK_KEY_TID, messages[i]->thread_id.c_str()); - // TODO: if contact is newly added, get his user info - // TODO: maybe create new "receiveMsg" function and use it for offline and channel messages? - ParseSmileys(messages[i]->message_text, hContact); if (messages[i]->isIncoming) { @@ -519,6 +452,36 @@ void FacebookProto::ProcessMessages(void* data) delete messages[i]; } messages.clear(); +} + +// TODO: combine processmessages and processunreadmessages? (behavior of showing messages to user should be the same) +void FacebookProto::ProcessMessages(void* data) +{ + if (data == NULL) + return; + + std::string* resp = (std::string*)data; + + // receive messages from all folders by default, use hidden setting to receive only inbox messages + bool inboxOnly = getBool(FACEBOOK_KEY_INBOX_ONLY, 0); + + if (isOffline()) + goto exit; + + debugLogA("***** Starting processing messages"); + + CODE_BLOCK_TRY + + std::vector< facebook_message* > messages; + std::vector< facebook_notification* > notifications; + + facebook_json_parser* p = new facebook_json_parser(this); + p->parse_messages(data, &messages, ¬ifications, inboxOnly); + delete p; + + bool local_timestamp = getBool(FACEBOOK_KEY_LOCAL_TIMESTAMP, 0); + + ReceiveMessages(messages, local_timestamp); for(std::vector::size_type i=0; i messages, bool local_timestamp); // Connection client facebook_client facy; // TODO: Refactor to "client" and make dynamic -- cgit v1.2.3