From 5e8e5ed54e602e0de3d328098ff828cba441b2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20P=C3=B6sel?= Date: Sat, 5 Apr 2014 09:03:20 +0000 Subject: Facebook: Correct implementation of managing number of unread notifications git-svn-id: http://svn.miranda-ng.org/main/trunk@8858 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/FacebookRM/src/client.h | 7 +++-- protocols/FacebookRM/src/communication.cpp | 13 ++++++++ protocols/FacebookRM/src/connection.cpp | 1 + protocols/FacebookRM/src/entities.h | 4 +++ protocols/FacebookRM/src/events.cpp | 16 +++++----- protocols/FacebookRM/src/json.cpp | 50 ++++++++++++++---------------- protocols/FacebookRM/src/json.h | 4 +-- protocols/FacebookRM/src/process.cpp | 45 +++++++++++---------------- protocols/FacebookRM/src/proto.cpp | 2 +- protocols/FacebookRM/src/proto.h | 3 +- 10 files changed, 77 insertions(+), 68 deletions(-) (limited to 'protocols') diff --git a/protocols/FacebookRM/src/client.h b/protocols/FacebookRM/src/client.h index c2980556c0..bbd7eb45dc 100644 --- a/protocols/FacebookRM/src/client.h +++ b/protocols/FacebookRM/src/client.h @@ -41,7 +41,7 @@ public: chat_sequence_num_ = chat_channel_host_ = chat_channel_partition_ = \ dtsg_ = logout_hash_ = chat_sticky_num_ = chat_conn_num_ = chat_clientid_ = ""; - msgid_ = error_count_ = last_feeds_update_ = last_notification_time_ = notifications_count_ = 0; + msgid_ = error_count_ = last_feeds_update_ = last_notification_time_ = 0; https_ = is_idle_ = invisible_ = is_typing_ = false; @@ -82,7 +82,6 @@ public: bool https_; time_t last_feeds_update_; unsigned __int64 last_notification_time_; - int notifications_count_; int msgid_; //////////////////////////////////////////////////////////// @@ -100,6 +99,7 @@ public: std::map cookies; std::map pages; std::map chat_rooms; + std::map notifications; std::string get_newsfeed_type(); std::string get_server_type(); @@ -107,7 +107,8 @@ public: char* load_cookies(); void store_headers(http::response* resp, NETLIBHTTPHEADER* headers, int headers_count); - void clear_cookies(); + void clear_cookies(); + void clear_notifications(); //////////////////////////////////////////////////////////// diff --git a/protocols/FacebookRM/src/communication.cpp b/protocols/FacebookRM/src/communication.cpp index e1facb8016..901d731074 100644 --- a/protocols/FacebookRM/src/communication.cpp +++ b/protocols/FacebookRM/src/communication.cpp @@ -679,6 +679,19 @@ void facebook_client::clear_cookies() cookies.clear(); } +void facebook_client::clear_notifications() +{ + for (std::map::iterator it = notifications.begin(); it != notifications.end(); ) { + if (it->second->hWndPopup != NULL) + PUDeletePopup(it->second->hWndPopup); // close popup + + delete it->second; + it = notifications.erase(it); + } + + notifications.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 dff3474234..abe78a324a 100644 --- a/protocols/FacebookRM/src/connection.cpp +++ b/protocols/FacebookRM/src/connection.cpp @@ -51,6 +51,7 @@ void FacebookProto::ChangeStatus(void*) facy.logout(); facy.clear_cookies(); + facy.clear_notifications(); facy.buddies.clear(); facy.messages_ignore.clear(); facy.pages.clear(); diff --git a/protocols/FacebookRM/src/entities.h b/protocols/FacebookRM/src/entities.h index 14a62ef0eb..ecb54136bb 100644 --- a/protocols/FacebookRM/src/entities.h +++ b/protocols/FacebookRM/src/entities.h @@ -135,10 +135,14 @@ struct facebook_notification std::string text; std::string link; std::string id; + bool seen; + HWND hWndPopup; facebook_notification() { this->user_id = this->text = this->link = this->id = ""; + this->seen = false; + this->hWndPopup = NULL; } }; diff --git a/protocols/FacebookRM/src/events.cpp b/protocols/FacebookRM/src/events.cpp index 19a9c68701..e1e3ac560f 100644 --- a/protocols/FacebookRM/src/events.cpp +++ b/protocols/FacebookRM/src/events.cpp @@ -22,7 +22,7 @@ along with this program. If not, see . #include "common.h" -void FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWORD flags, std::string *url, std::string *notification_id) +HWND FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWORD flags, std::string *url, std::string *notification_id) { char name[256]; @@ -30,14 +30,14 @@ void FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWO { case FACEBOOK_EVENT_CLIENT: if (!getByte(FACEBOOK_KEY_EVENT_CLIENT_ENABLE, DEFAULT_EVENT_CLIENT_ENABLE)) - return; + return NULL; mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Client"); flags |= NIIF_WARNING; break; case FACEBOOK_EVENT_NEWSFEED: if (!getByte(FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE)) - return; + return NULL; mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Newsfeed"); SkinPlaySound("NewsFeed"); flags |= NIIF_INFO; @@ -45,7 +45,7 @@ void FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWO case FACEBOOK_EVENT_NOTIFICATION: if (!getByte(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE)) - return; + return NULL; mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Notification"); SkinPlaySound("Notification"); flags |= NIIF_INFO; @@ -53,7 +53,7 @@ void FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWO case FACEBOOK_EVENT_OTHER: if (!getByte(FACEBOOK_KEY_EVENT_OTHER_ENABLE, DEFAULT_EVENT_OTHER_ENABLE)) - return; + return NULL; mir_snprintf(name, SIZEOF(name), "%s_%s", m_szModuleName, "Other"); SkinPlaySound("OtherEvent"); flags |= NIIF_INFO; @@ -87,7 +87,7 @@ void FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWO } if (CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&pd) == 0) - return; + return NULL; // TODO: return popup window handle (to allow closing them) } } else { if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) @@ -105,10 +105,12 @@ void FacebookProto::NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWO err.tszInfo = info; err.uTimeout = 10000; if (CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM) & err) == 0) - return; + return NULL; } } if (FLAG_CONTAINS(flags, FACEBOOK_EVENT_CLIENT)) MessageBox(NULL, info, title, MB_OK | MB_ICONINFORMATION); + + return NULL; } diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp index dc824d0cbf..110a82d127 100644 --- a/protocols/FacebookRM/src/json.cpp +++ b/protocols/FacebookRM/src/json.cpp @@ -225,7 +225,7 @@ int facebook_json_parser::parse_friends(void* data, std::map< std::string, faceb } -int facebook_json_parser::parse_notifications(void *data, std::vector< facebook_notification* > *notifications) +int facebook_json_parser::parse_notifications(void *data, std::map< std::string, facebook_notification* > *notifications) { std::string jsonData = static_cast< std::string* >(data)->substr(9); @@ -265,7 +265,10 @@ int facebook_json_parser::parse_notifications(void *data, std::vector< facebook_ notification->link = utils::text::source_get_value(&text, 3, "text = utils::text::remove_html(utils::text::source_get_value(&text, 1, "push_back(notification); + if (notifications->find(notification->id) == notifications->end()) + notifications->insert(std::make_pair(notification->id, notification)); + else + delete notification; } json_delete(root); @@ -365,7 +368,7 @@ void parseAttachments(FacebookProto *proto, std::string *message_text, JSONNODE } } -int facebook_json_parser::parse_messages(void* data, std::vector< facebook_message* >* messages, std::vector< facebook_notification* >* notifications, bool inboxOnly) +int facebook_json_parser::parse_messages(void* data, std::vector< facebook_message* >* messages, std::map< std::string, facebook_notification* >* notifications, bool inboxOnly) { // remove old received messages from map for (std::map::iterator it = proto->facy.messages_ignore.begin(); it != proto->facy.messages_ignore.end();) { @@ -599,20 +602,10 @@ int facebook_json_parser::parse_messages(void* data, std::vector< facebook_messa messages->push_back(message); } } - } else if (t == "notifications_read") { - JSONNODE *alerts = json_get(it, "alert_ids"); - proto->facy.notifications_count_ -= json_size(alerts); - - if (proto->facy.notifications_count_ < 0) - proto->facy.notifications_count_ = 0; } else if (t == "notification_json") { // event notification JSONNODE *nodes = json_get(it, "nodes"); - proto->facy.notifications_count_ += json_size(nodes); - if (!proto->getByte(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE)) - continue; - for (unsigned int j = 0; j < json_size(nodes); j++) { JSONNODE *itNodes = json_at(nodes, j); @@ -645,7 +638,10 @@ int facebook_json_parser::parse_messages(void* data, std::vector< facebook_messa if (pos != std::string::npos) notification->id = notification->id.substr(pos+1); - notifications->push_back(notification); + if (notifications->find(notification->id) == notifications->end()) + notifications->insert(std::make_pair(notification->id, notification)); + else + delete notification; } } } else if (t == "typ") { @@ -706,14 +702,6 @@ int facebook_json_parser::parse_messages(void* data, std::vector< facebook_messa /* if (!text.empty()) { proto->NotifyEvent() }*/ - } else if (t == "inbox") { - // count of unread/unseen messages - pretty useless info for us - /* JSONNODE *unread_ = json_get(it, "unread"); - JSONNODE *unseen_ = json_get(it, "unseen"); - JSONNODE *other_unread_ = json_get(it, "other_unread"); - JSONNODE *other_unseen_ = json_get(it, "other_unseen"); - JSONNODE *seen_timestamp_ = json_get(it, "seen_timestamp"); */ - continue; } else if (t == "mercury") { // rename multi user chat, ... @@ -741,12 +729,20 @@ int facebook_json_parser::parse_messages(void* data, std::vector< facebook_messa proto->UpdateChat(thread_id.c_str(), NULL, NULL, message.c_str()); } } else if (t == "notifications_read") { - // TODO: close popups with these IDs - JSONNODE *alert_ids = json_get(it, "alert_ids"); - for (unsigned int n = 0; n < json_size(alert_ids); n++) { - JSONNODE *idItr = json_at(alert_ids, n); + JSONNODE *alerts = json_get(it, "alert_ids"); - // PUDeletePopup(hWndPopup); + for (unsigned int j = 0; j < json_size(alerts); j++) { + JSONNODE *itAlerts = json_at(alerts, j); + std::string id = json_as_pstring(itAlerts); + + std::map::iterator it = notifications->find(id); + if (it != notifications->end()) { + if (it->second->hWndPopup != NULL) + PUDeletePopup(it->second->hWndPopup); // close popup + + delete it->second; + notifications->erase(it); + } } } else continue; diff --git a/protocols/FacebookRM/src/json.h b/protocols/FacebookRM/src/json.h index 33f5538559..70001e4a31 100644 --- a/protocols/FacebookRM/src/json.h +++ b/protocols/FacebookRM/src/json.h @@ -32,8 +32,8 @@ public: FacebookProto* proto; int parse_buddy_list(void*, List::List< facebook_user >*); int parse_friends(void*, std::map< std::string, facebook_user* >*); - int parse_notifications(void*, std::vector< facebook_notification* >*); - int parse_messages(void*, std::vector< facebook_message* >*, std::vector< facebook_notification* >*, bool inboxOnly); + int parse_notifications(void*, std::map< std::string, facebook_notification* >*); + int parse_messages(void*, std::vector< facebook_message* >*, std::map< std::string, facebook_notification* >*, bool inboxOnly); 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); diff --git a/protocols/FacebookRM/src/process.cpp b/protocols/FacebookRM/src/process.cpp index 0fd44897ce..c8a3fc7d6b 100644 --- a/protocols/FacebookRM/src/process.cpp +++ b/protocols/FacebookRM/src/process.cpp @@ -497,7 +497,6 @@ void FacebookProto::ReceiveMessages(std::vector messages, boo 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) @@ -516,24 +515,16 @@ void FacebookProto::ProcessMessages(void* data) 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); + p->parse_messages(data, &messages, &facy.notifications, inboxOnly); delete p; bool local_timestamp = getBool(FACEBOOK_KEY_LOCAL_TIMESTAMP, 0); ReceiveMessages(messages, local_timestamp); - for(std::vector::size_type i=0; itext.c_str()); - ptrT szText( mir_utf8decodeT(notifications[i]->text.c_str())); - NotifyEvent(m_tszUserName, szText, ContactIDToHContact(notifications[i]->user_id), FACEBOOK_EVENT_NOTIFICATION, ¬ifications[i]->link, ¬ifications[i]->id); - delete notifications[i]; - } - notifications.clear(); + ShowNotifications(); debugLogA("***** Messages processed"); @@ -547,6 +538,20 @@ exit: delete resp; } +void FacebookProto::ShowNotifications() { + if (!getByte(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE)) + return; + + for (std::map::iterator it = facy.notifications.begin(); it != facy.notifications.end(); ++it) { + if (it->second != NULL && !it->second->seen) { + debugLogA(" Got notification: %s", it->second->text.c_str()); + ptrT szText(mir_utf8decodeT(it->second->text.c_str())); + it->second->hWndPopup = NotifyEvent(m_tszUserName, szText, ContactIDToHContact(it->second->user_id), FACEBOOK_EVENT_NOTIFICATION, &it->second->link, &it->second->id); + it->second->seen = true; + } + } +} + void FacebookProto::ProcessNotifications(void*) { if (isOffline()) @@ -568,25 +573,11 @@ void FacebookProto::ProcessNotifications(void*) CODE_BLOCK_TRY - std::vector< facebook_notification* > notifications; - facebook_json_parser* p = new facebook_json_parser(this); - p->parse_notifications(&(resp.data), ¬ifications); + p->parse_notifications(&(resp.data), &facy.notifications); delete p; - facy.notifications_count_ = notifications.size(); - - if (!getByte(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE)) - return; - - for(std::vector::size_type i=0; itext.c_str()); - ptrT szText( mir_utf8decodeT(notifications[i]->text.c_str())); - NotifyEvent(m_tszUserName, szText, ContactIDToHContact(notifications[i]->user_id), FACEBOOK_EVENT_NOTIFICATION, ¬ifications[i]->link, ¬ifications[i]->id); - delete notifications[i]; - } - notifications.clear(); + ShowNotifications(); debugLogA("***** Notifications processed"); diff --git a/protocols/FacebookRM/src/proto.cpp b/protocols/FacebookRM/src/proto.cpp index fc837ffaad..3a5b5d38dd 100644 --- a/protocols/FacebookRM/src/proto.cpp +++ b/protocols/FacebookRM/src/proto.cpp @@ -385,7 +385,7 @@ INT_PTR FacebookProto::GetNotificationsCount(WPARAM wParam, LPARAM lParam) if (isOffline()) return 0; - return facy.notifications_count_; + return facy.notifications.size(); } ////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/FacebookRM/src/proto.h b/protocols/FacebookRM/src/proto.h index 49c9102367..346ece4193 100644 --- a/protocols/FacebookRM/src/proto.h +++ b/protocols/FacebookRM/src/proto.h @@ -235,5 +235,6 @@ public: static void CALLBACK APC_callback(ULONG_PTR p); // Information providing - void NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWORD flags, std::string *url = NULL, std::string *notification_id = NULL); + HWND NotifyEvent(TCHAR* title, TCHAR* info, MCONTACT contact, DWORD flags, std::string *url = NULL, std::string *notification_id = NULL); + void ShowNotifications(); }; -- cgit v1.2.3