From e94c705bb01c662d934c0096480bc9a732d0e1ec Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 19 Jan 2012 12:21:27 +0000 Subject: FacebookRM: Version bump Version 0.0.7.0 + Support for group chats (EXPERIMENTAL!) - enable it in options ! Fixed loading contact list ! Fixed potential freeze. Total downloads: (None or statistics not available yet) Version 0.0.6.1a Reuploaded. Total downloads: (None or statistics not available yet) Version 0.0.6.1 + Returned option to close chat windows (on website) + New option to map non-standard statuses to Invisible (insetad of Online) + New option to load contacts, which have "On the Phone" status ! Fixed changing chat visibility ! Very long messages are no longer received duplicitely ! Changes and fixes related to multiuser messages and messages from people, which are not in server-list Total downloads: (None or statistics not available yet) git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@261 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- FacebookRM/build.h | 2 +- FacebookRM/chat.cpp | 328 +++++++++++++++++++++++++++++++++ FacebookRM/client.h | 9 +- FacebookRM/common.h | 2 +- FacebookRM/communication.cpp | 205 ++++++++++++--------- FacebookRM/connection.cpp | 10 +- FacebookRM/constants.h | 15 +- FacebookRM/contacts.cpp | 55 +++++- FacebookRM/db.h | 6 +- FacebookRM/dialogs.cpp | 17 +- FacebookRM/entities.h | 35 +++- FacebookRM/facebook.rc | 46 +++-- FacebookRM/facebook.vcproj | 20 +- FacebookRM/facebook_10.sln | 3 +- FacebookRM/facebook_10.vcxproj | 18 +- FacebookRM/facebook_10.vcxproj.filters | 3 + FacebookRM/icons/addFriend.ico | Bin 0 -> 2550 bytes FacebookRM/icons/removeFriend.ico | Bin 0 -> 2550 bytes FacebookRM/json.cpp | 248 ++++++++++++++++++++----- FacebookRM/json.h | 1 + FacebookRM/messages.cpp | 35 ++-- FacebookRM/process.cpp | 108 +++++++++-- FacebookRM/proto.cpp | 117 +++++++++--- FacebookRM/proto.h | 23 ++- FacebookRM/resource.h | 21 +-- FacebookRM/theme.cpp | 48 ++++- FacebookRM/theme.h | 2 +- FacebookRM/utils.cpp | 18 ++ FacebookRM/utils.h | 1 + 29 files changed, 1113 insertions(+), 283 deletions(-) create mode 100644 FacebookRM/chat.cpp create mode 100644 FacebookRM/icons/addFriend.ico create mode 100644 FacebookRM/icons/removeFriend.ico diff --git a/FacebookRM/build.h b/FacebookRM/build.h index 81c7985..e409157 100644 --- a/FacebookRM/build.h +++ b/FacebookRM/build.h @@ -1 +1 @@ -#define __BUILD 1874 +#define __BUILD 2068 diff --git a/FacebookRM/chat.cpp b/FacebookRM/chat.cpp new file mode 100644 index 0000000..8e0e007 --- /dev/null +++ b/FacebookRM/chat.cpp @@ -0,0 +1,328 @@ +/* + +Facebook plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2011 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "common.h" + +void FacebookProto::UpdateChat(const char *chat_id, const char *id, const char *name, const char *message) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = mir_a2t(chat_id); + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.ptszText = mir_a2t_cp(message,CP_UTF8); + gce.time = ::time(NULL); + gce.dwFlags = GC_TCHAR; + gcd.iType = GC_EVENT_MESSAGE; + gce.bIsMe = !strcmp(id,facy.self_.user_id.c_str()); + gce.dwFlags |= GCEF_ADDTOLOG; + + gce.ptszNick = mir_a2t_cp(name,CP_UTF8); + gce.ptszUID = mir_a2t(id); + + CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); + + mir_free(const_cast(gce.ptszUID)); + mir_free(const_cast(gce.ptszNick)); + mir_free(const_cast(gce.ptszText)); + mir_free(const_cast(gcd.ptszID)); + + + // Close chat window, if set + ForkThread( &FacebookProto::MessagingWorker, this, new send_messaging(chat_id, FACEBOOK_SEND_MESSAGE ) ); +} + +int FacebookProto::OnChatOutgoing(WPARAM wParam,LPARAM lParam) +{ + GCHOOK *hook = reinterpret_cast(lParam); + char *text; + char *id; + + if (strcmp(hook->pDest->pszModule,m_szModuleName)) + return 0; + + switch(hook->pDest->iType) + { + case GC_USER_MESSAGE: + { + text = mir_t2a_cp(hook->ptszText,CP_UTF8); + std::string msg = text; + + id = mir_t2a_cp(hook->pDest->ptszID,CP_UTF8); + std::string chat_id = id; + + mir_free(text); + mir_free(id); + + if (isOnline()) { + LOG("**Chat - Outgoing message: %s", text); + ForkThread(&FacebookProto::SendChatMsgWorker, this, new send_chat(chat_id, msg) ); + } + + break; + } + + case GC_USER_LEAVE: + case GC_SESSION_TERMINATE: + { + break; + } + } + + return 0; +} + +void FacebookProto::AddChatContact(const char *chat_id, const char *id, const char *name) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = mir_a2t(chat_id); + gcd.iType = GC_EVENT_JOIN; + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; + gce.ptszNick = mir_a2t_cp(name, CP_UTF8); + gce.ptszUID = mir_a2t(id); + 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"); + + CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); + + mir_free(const_cast(gce.ptszNick)); + mir_free(const_cast(gce.ptszUID)); + mir_free(const_cast(gcd.ptszID)); +} + + +void FacebookProto::RemoveChatContact(const char *chat_id, const char *id) +{ + // We dont want to remove our self-contact from chat. Ever. + if (!strcmp(id, facy.self_.user_id.c_str())) + return; + + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = mir_a2t(chat_id); + gcd.iType = GC_EVENT_PART; + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG; + //gce.ptszNick = mir_a2t_cp(name, CP_UTF8); + gce.ptszUID = mir_a2t(id); + gce.ptszNick = gce.ptszUID; + gce.time = ::time(NULL); + gce.bIsMe = false;//!strcmp(id, facy.self_.user_id.c_str()); + + CallServiceSync(MS_GC_EVENT,0,reinterpret_cast(&gce)); + + mir_free(const_cast(gcd.ptszID)); + mir_free(const_cast(gce.ptszNick)); + mir_free(const_cast(gce.ptszUID)); +} + +char *FacebookProto::GetChatUsers(const char *chat_id) +{ + GC_INFO gci = {0}; + gci.Flags = USERS; + gci.pszModule = m_szModuleName; + gci.pszID = mir_a2t(chat_id); + CallService(MS_GC_GETINFO, 0, (LPARAM)(GC_INFO *) &gci); + + LOG("**Chat - Users in chat %s: %s", chat_id, gci.pszUsers); + + mir_free(gci.pszID); + + // mir_free(gci.pszUsers); + return gci.pszUsers; +} + +bool FacebookProto::IsChatContact(const char *chat_id, const char *id) +{ + char *users = GetChatUsers(chat_id); + bool found = false; + + if (users != NULL && strstr(users, id) != NULL) + found = true; + + mir_free(users); + return found; +} + +void FacebookProto::AddChat(const char *id, const char *name) +{ + GCSESSION gcw = {sizeof(gcw)}; + + // Create the group chat session + gcw.dwFlags = GC_TCHAR; + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.ptszName = mir_a2t_cp(name, CP_UTF8); + gcw.ptszID = mir_a2t(id); + CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); + + mir_free(const_cast(gcw.ptszName)); + mir_free(const_cast(gcw.ptszID)); + + // Send setting events + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = mir_a2t(id); + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + + // Create a user statuses + gcd.iType = GC_EVENT_ADDGROUP; + gce.ptszStatus = _T("Admin"); + CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast(&gce) ); + gce.ptszStatus = _T("Normal"); + CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast(&gce) ); + + // Finish initialization + gcd.iType = GC_EVENT_CONTROL; + gce.time = ::time(NULL); + gce.pDest = &gcd; + + // Add self contact + AddChatContact(id, 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)); + + mir_free(const_cast(gcd.ptszID)); +} + + +int FacebookProto::OnJoinChat(WPARAM,LPARAM suppress) +{ +/* GCSESSION gcw = {sizeof(gcw)}; + + // Create the group chat session + gcw.dwFlags = GC_TCHAR; + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.ptszName = m_tszUserName; + gcw.ptszID = m_tszUserName; + CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); + + if(m_iStatus != ID_STATUS_ONLINE) + return 0; + + // Create a group + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast(m_tszUserName); + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + + gcd.iType = GC_EVENT_ADDGROUP; + + gce.ptszStatus = _T("Admin"); + CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast(&gce) ); + + gce.ptszStatus = _T("Normal"); + CallServiceSync( MS_GC_EVENT, NULL, reinterpret_cast(&gce) ); + + SetTopic("Omegle is a great way of meeting new friends!"); + + // Note: Initialization will finish up in SetChatStatus, called separately + if(!suppress) + SetChatStatus(m_iStatus); +*/ + return 0; +} + +/*void FacebookProto::SetTopic(const char *topic) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast(m_tszUserName); + gcd.iType = GC_EVENT_TOPIC; + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + gce.time = ::time(NULL); + + std::string top = Translate(topic); + gce.ptszText = mir_a2t(top.c_str()); + CallServiceSync(MS_GC_EVENT,0, reinterpret_cast(&gce)); +} +*/ +int FacebookProto::OnLeaveChat(WPARAM,LPARAM) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = NULL; + gcd.iType = GC_EVENT_CONTROL; + + GCEVENT gce = {sizeof(gce)}; + gce.dwFlags = GC_TCHAR; + gce.time = ::time(NULL); + gce.pDest = &gcd; + + CallServiceSync(MS_GC_EVENT,SESSION_OFFLINE, reinterpret_cast(&gce)); + CallServiceSync(MS_GC_EVENT,SESSION_TERMINATE,reinterpret_cast(&gce)); + + return 0; +} +/* +void FacebookProto::SetChatStatus(int status) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast(m_tszUserName); + gcd.iType = GC_EVENT_CONTROL; + + GCEVENT gce = {sizeof(gce)}; + gce.dwFlags = GC_TCHAR; + gce.time = ::time(NULL); + gce.pDest = &gcd; + + if(status == ID_STATUS_ONLINE) + { + // Add self contact + AddChatContact(facy.nick_.c_str()); + + CallServiceSync(MS_GC_EVENT,SESSION_INITDONE,reinterpret_cast(&gce)); + CallServiceSync(MS_GC_EVENT,SESSION_ONLINE, reinterpret_cast(&gce)); + } + else + { + CallServiceSync(MS_GC_EVENT,SESSION_OFFLINE,reinterpret_cast(&gce)); + } +} +/* +void FacebookProto::ClearChat() +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast(m_tszUserName); + gcd.iType = GC_EVENT_CONTROL; + + GCEVENT gce = {sizeof(gce)}; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + + CallServiceSync(MS_GC_EVENT,WINDOW_CLEARLOG,reinterpret_cast(&gce)); +} +*/ \ No newline at end of file diff --git a/FacebookRM/client.h b/FacebookRM/client.h index 39b3c17..cff5c09 100644 --- a/FacebookRM/client.h +++ b/FacebookRM/client.h @@ -44,9 +44,7 @@ public: chat_sequence_num_ = chat_channel_host_ = chat_channel_partition_ = chat_channel_jslogger_ = \ logout_hash_ = ""; - msgid_ = error_count_ = last_feeds_update_ = \ - last_notification_time_ = /*last_message_time_ =*/ \ - last_grpmessage_time_ = /*last_close_chat_time_ =*/ 0; + msgid_ = error_count_ = last_feeds_update_ = last_notification_time_ = 0; invisible_ = is_typing_ = false; @@ -83,9 +81,6 @@ public: bool is_typing_; time_t last_feeds_update_; unsigned __int64 last_notification_time_; - //unsigned __int64 last_message_time_; - time_t last_grpmessage_time_; - //time_t last_close_chat_time_; int msgid_; //////////////////////////////////////////////////////////// @@ -150,9 +145,9 @@ public: HANDLE send_message_lock_; bool buddy_list( ); + bool facepiles( ); bool load_friends( ); bool feeds( ); - void delete_friends( ); //////////////////////////////////////////////////////////// diff --git a/FacebookRM/common.h b/FacebookRM/common.h index c544d13..ce4e572 100644 --- a/FacebookRM/common.h +++ b/FacebookRM/common.h @@ -108,4 +108,4 @@ class FacebookProto; extern HINSTANCE g_hInstance; extern std::string g_strUserAgent; -extern DWORD g_mirandaVersion; +extern DWORD g_mirandaVersion; \ No newline at end of file diff --git a/FacebookRM/communication.cpp b/FacebookRM/communication.cpp index 174c084..3b8da48 100644 --- a/FacebookRM/communication.cpp +++ b/FacebookRM/communication.cpp @@ -224,15 +224,17 @@ DWORD facebook_client::choose_security_level( int request_type ) // case FACEBOOK_REQUEST_LOGOUT: // case FACEBOOK_REQUEST_HOME: // case FACEBOOK_REQUEST_BUDDY_LIST: +// case FACEBOOK_REQUEST_FACEPILES: // case FACEBOOK_REQUEST_LOAD_FRIENDS: // case FACEBOOK_REQUEST_DELETE_FRIEND: +// case FACEBOOK_REQUEST_ADD_FRIEND: // case FACEBOOK_REQUEST_FEEDS: // case FACEBOOK_REQUEST_NOTIFICATIONS: // case FACEBOOK_REQUEST_RECONNECT: // case FACEBOOK_REQUEST_STATUS_SET: // case FACEBOOK_REQUEST_MESSAGE_SEND: // case FACEBOOK_REQUEST_MESSAGES_RECEIVE: -// case FACEBOOK_REQUEST_SETTINGS: +// case FACEBOOK_REQUEST_VISIBILITY: // case FACEBOOK_REQUEST_TABS: // case FACEBOOK_REQUEST_ASYNC: // case FACEBOOK_REQUEST_ASYNC_GET: @@ -249,14 +251,16 @@ int facebook_client::choose_method( int request_type ) case FACEBOOK_REQUEST_LOGIN: case FACEBOOK_REQUEST_SETUP_MACHINE: case FACEBOOK_REQUEST_BUDDY_LIST: + case FACEBOOK_REQUEST_FACEPILES: case FACEBOOK_REQUEST_STATUS_SET: case FACEBOOK_REQUEST_MESSAGE_SEND: - case FACEBOOK_REQUEST_SETTINGS: + case FACEBOOK_REQUEST_VISIBILITY: case FACEBOOK_REQUEST_TABS: case FACEBOOK_REQUEST_ASYNC: case FACEBOOK_REQUEST_TYPING_SEND: case FACEBOOK_REQUEST_LOGOUT: case FACEBOOK_REQUEST_DELETE_FRIEND: + case FACEBOOK_REQUEST_ADD_FRIEND: return REQUEST_POST; // case FACEBOOK_REQUEST_HOME: @@ -287,16 +291,18 @@ std::string facebook_client::choose_proto( int request_type ) // case FACEBOOK_REQUEST_NOTIFICATIONS: // case FACEBOOK_REQUEST_RECONNECT: // case FACEBOOK_REQUEST_BUDDY_LIST: +// case FACEBOOK_REQUEST_FACEPILES: // case FACEBOOK_REQUEST_LOAD_FRIENDS: // case FACEBOOK_REQUEST_STATUS_SET: // case FACEBOOK_REQUEST_MESSAGE_SEND: // case FACEBOOK_REQUEST_MESSAGES_RECEIVE: -// case FACEBOOK_REQUEST_SETTINGS: +// case FACEBOOK_REQUEST_VISIBILITY: // case FACEBOOK_REQUEST_TABS: // case FACEBOOK_REQUEST_ASYNC: // case FACEBOOK_REQUEST_ASYNC_GET: // case FACEBOOK_REQUEST_TYPING_SEND: // case FACEBOOK_REQUEST_DELETE_FRIEND: +// case FACEBOOK_REQUEST_ADD_FRIEND: default: return HTTP_PROTO_REGULAR; @@ -327,19 +333,21 @@ std::string facebook_client::choose_server( int request_type, std::string* data // case FACEBOOK_REQUEST_LOGOUT: // case FACEBOOK_REQUEST_HOME: // case FACEBOOK_REQUEST_BUDDY_LIST: +// case FACEBOOK_REQUEST_FACEPILES: // case FACEBOOK_REQUEST_LOAD_FRIENDS: // case FACEBOOK_REQUEST_FEEDS: // case FACEBOOK_REQUEST_NOTIFICATIONS: // case FACEBOOK_REQUEST_RECONNECT: // case FACEBOOK_REQUEST_STATUS_SET: // case FACEBOOK_REQUEST_MESSAGE_SEND: -// case FACEBOOK_REQUEST_SETTINGS: +// case FACEBOOK_REQUEST_VISIBILITY: // case FACEBOOK_REQUEST_TABS: // case FACEBOOK_REQUEST_ASYNC: // case FACEBOOK_REQUEST_ASYNC_GET: // case FACEBOOK_REQUEST_TYPING_SEND: // case FACEBOOK_REQUEST_SETUP_MACHINE: // case FACEBOOK_REQUEST_DELETE_FRIEND: +// case FACEBOOK_REQUEST_ADD_FRIEND: default: return FACEBOOK_SERVER_REGULAR; } @@ -359,11 +367,14 @@ std::string facebook_client::choose_action( int request_type, std::string* data return "/logout.php"; case FACEBOOK_REQUEST_HOME: - return "/home.php"; + return "/home.php?_fb_noscript=1"; case FACEBOOK_REQUEST_BUDDY_LIST: return "/ajax/chat/buddy_list.php?__a=1"; + case FACEBOOK_REQUEST_FACEPILES: + return "/ajax/groups/chat/update_facepiles.php?__a=1"; + case FACEBOOK_REQUEST_LOAD_FRIENDS: { std::string action = "/ajax/chat/user_info_all.php?__a=1&viewer=%s"; @@ -376,6 +387,11 @@ std::string facebook_client::choose_action( int request_type, std::string* data return "/ajax/profile/removefriend.php?__a=1"; } + case FACEBOOK_REQUEST_ADD_FRIEND: + { + return "/ajax/add_friend/action.php?__a=1"; + } + case FACEBOOK_REQUEST_FEEDS: { std::string action = "/ajax/intent.php?filter="; @@ -426,8 +442,8 @@ std::string facebook_client::choose_action( int request_type, std::string* data return action; } - case FACEBOOK_REQUEST_SETTINGS: - return "/ajax/chat/settings.php?__a=1"; + case FACEBOOK_REQUEST_VISIBILITY: + return "/ajax/chat/visibility.php?__a=1"; case FACEBOOK_REQUEST_TABS: return "/ajax/chat/tabs.php?__a=1"; @@ -446,7 +462,7 @@ std::string facebook_client::choose_action( int request_type, std::string* data return "/ajax/messaging/typ.php?__a=1"; default: - return "/"; + return "/?_fb_noscript=1"; } } @@ -465,15 +481,17 @@ NETLIBHTTPHEADER* facebook_client::get_request_headers( int request_type, int* h case FACEBOOK_REQUEST_LOGIN: case FACEBOOK_REQUEST_SETUP_MACHINE: case FACEBOOK_REQUEST_BUDDY_LIST: + case FACEBOOK_REQUEST_FACEPILES: case FACEBOOK_REQUEST_LOAD_FRIENDS: case FACEBOOK_REQUEST_STATUS_SET: case FACEBOOK_REQUEST_MESSAGE_SEND: - case FACEBOOK_REQUEST_SETTINGS: + case FACEBOOK_REQUEST_VISIBILITY: case FACEBOOK_REQUEST_TABS: case FACEBOOK_REQUEST_ASYNC: case FACEBOOK_REQUEST_ASYNC_GET: case FACEBOOK_REQUEST_TYPING_SEND: case FACEBOOK_REQUEST_DELETE_FRIEND: + case FACEBOOK_REQUEST_ADD_FRIEND: *headers_count = 5; break; @@ -494,15 +512,17 @@ NETLIBHTTPHEADER* facebook_client::get_request_headers( int request_type, int* h case FACEBOOK_REQUEST_LOGIN: case FACEBOOK_REQUEST_SETUP_MACHINE: case FACEBOOK_REQUEST_BUDDY_LIST: + case FACEBOOK_REQUEST_FACEPILES: case FACEBOOK_REQUEST_LOAD_FRIENDS: case FACEBOOK_REQUEST_STATUS_SET: case FACEBOOK_REQUEST_MESSAGE_SEND: - case FACEBOOK_REQUEST_SETTINGS: + case FACEBOOK_REQUEST_VISIBILITY: case FACEBOOK_REQUEST_TABS: case FACEBOOK_REQUEST_ASYNC: case FACEBOOK_REQUEST_ASYNC_GET: case FACEBOOK_REQUEST_TYPING_SEND: case FACEBOOK_REQUEST_DELETE_FRIEND: + case FACEBOOK_REQUEST_ADD_FRIEND: headers[4].szName = "Content-Type"; headers[4].szValue = "application/x-www-form-urlencoded; charset=utf-8"; @@ -574,7 +594,7 @@ void facebook_client::store_headers( http::response* resp, NETLIBHTTPHEADER* hea } else { // TODO RM: (un)comment - parent->Log("----- Got header '%s': %s", header_name.c_str(), header_value.c_str() ); + //parent->Log("----- Got header '%s': %s", header_name.c_str(), header_value.c_str() ); resp->headers[header_name] = header_value; } } @@ -768,13 +788,13 @@ bool facebook_client::home( ) // Get real_name this->self_.real_name = utils::text::remove_html( utils::text::special_expressions_decode( utils::text::source_get_value( &resp.data, 2, " id=\"navAccountName\">", "m_szModuleName,FACEBOOK_KEY_NAME,this->self_.real_name.c_str()); - DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,"Nick",this->self_.real_name.c_str()); + DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NICK,this->self_.real_name.c_str()); parent->Log(" Got self real name: %s", this->self_.real_name.c_str()); } else if ( resp.data.find("id=\"pageNav\"") != std::string::npos ) { // Get real_name this->self_.real_name = utils::text::remove_html( utils::text::special_expressions_decode( utils::text::source_get_value( &resp.data, 3, " class=\"headerTinymanName\"", ">", "m_szModuleName,FACEBOOK_KEY_NAME,this->self_.real_name.c_str()); - DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,"Nick",this->self_.real_name.c_str()); + DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NICK,this->self_.real_name.c_str()); parent->Log(" Got self real name: %s", this->self_.real_name.c_str()); } else { client_notify(TranslateT("Something happened to Facebook. Maybe there was some major update so you should wait for an update.")); @@ -791,11 +811,11 @@ bool facebook_client::home( ) parent->CheckAvatarChange(NULL, this->self_.image_url); // Get post_form_id - this->post_form_id_ = utils::text::source_get_value( &resp.data, 2, "post_form_id:\"", "\"" ); + this->post_form_id_ = utils::text::source_get_value( &resp.data, 3, "name=\"post_form_id\"", "value=\"", "\"" ); parent->Log(" Got self post form id: %s", this->post_form_id_.c_str()); // Get dtsg - this->dtsg_ = utils::text::source_get_value( &resp.data, 2, "fb_dtsg:\"", "\"" ); + this->dtsg_ = utils::text::source_get_value( &resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"" ); parent->Log(" Got self dtsg: %s", this->dtsg_.c_str()); // Get logout hash @@ -836,35 +856,28 @@ bool facebook_client::home( ) ForkThread( &FacebookProto::ProcessNotifications, this->parent, NULL ); } - // TODO RM: if enabled groupchats support - // Get group chats -/* std::string chat_ids = utils::text::source_get_value( &resp.data, 2, "HomeNavController.initGroupCounts([","]" ); - if ( chat_ids.length() ) - { + // TODO RM: if enabled groupchats support - // split by comma to ids, find names in source, inicialize groups in contactlist - // maybe check which groupchats user wants - // add to list? start worker for parse and add contacts to groupchat - // add "," to end for better parsing - chat_ids += ","; - std::string::size_type oldpos = 0, pos = 0; - - while ( ( pos = chat_ids.find(",", oldpos) ) != std::string::npos ) - { - std::string id = chat_ids.substr(oldpos, pos-oldpos); - std::string name = utils::text::trim( - utils::text::special_expressions_decode( - utils::text::remove_html( - utils::text::edit_html( - utils::text::source_get_value( &resp.data, 5, "HomeNavController.initGroupCounts", "home.php?sk=group_", id.c_str(), "input title=\\\"", "\\\" " ) ) ) ) ); - - parent->Log(" Got groupchat id: %s, name: %s", id.c_str(), name.c_str()); - oldpos = pos+1; - - parent->AddChat(id.c_str(), name.c_str()); - } - }*/ + if (DBGetContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS)) { + // Get group chats + std::string favorites = utils::text::source_get_value( &resp.data, 2, "
", pos) - pos); + std::string id = item.substr(0, item.find("/")); + + if (!id.empty()) { + std::string name = utils::text::source_get_value( &item, 3, "class=\"linkWrap", ">", "
" ); + name = utils::text::special_expressions_decode(utils::text::slashu_to_utf8( name ) ); + parent->Log(" Got new group chat: %s (id: %s)", name.c_str(), id.c_str()); + if (!name.empty()) + parent->AddChat(id.c_str(), name.c_str()); + } + } + } return handle_success( "home" ); @@ -891,7 +904,7 @@ bool facebook_client::chat_state( bool online ) data += "&post_form_id_source=AsyncRequest"; data += "&fb_dtsg=" + this->dtsg_; data += "&lsd="; - http::response resp = flap( FACEBOOK_REQUEST_SETTINGS, &data ); + http::response resp = flap( FACEBOOK_REQUEST_VISIBILITY, &data ); return handle_success( "chat_state" ); } @@ -942,16 +955,16 @@ bool facebook_client::buddy_list( ) handle_entry( "buddy_list" ); // Prepare update data - std::string data = "user=" + this->self_.user_id + "&force_render=true&fetch_mobile=true&post_form_id=" + this->post_form_id_ + "&fb_dtsg=" + this->dtsg_ + "&lsd=&post_form_id_source=AsyncRequest&__user=" + this->self_.user_id; + std::string data = "user=" + this->self_.user_id + "&fetch_mobile=true&post_form_id=" + this->post_form_id_ + "&fb_dtsg=" + this->dtsg_ + "&lsd=&post_form_id_source=AsyncRequest&__user=" + this->self_.user_id; { ScopedLock s(buddies_lock_); int counter = 0; - for (List::Item< facebook_user >* i = buddies.begin(); i != NULL; i = i->next ) + for (List::Item< facebook_user >* i = buddies.begin(); i != NULL; i = i->next, counter++ ) { data += "&available_user_info_ids["; - data += counter++; + data += utils::conversion::to_string(&counter, UTILS_CONV_UNSIGNED_NUMBER); data += "]="; data += i->data->user_id; } @@ -966,12 +979,11 @@ bool facebook_client::buddy_list( ) switch ( resp.code ) { case HTTP_CODE_OK: - if ( resp.data.find( "\"listChanged\":true" ) != std::string::npos ) - { - std::string* response_data = new std::string( resp.data ); - ForkThread( &FacebookProto::ProcessBuddyList, this->parent, ( void* )response_data ); - } + { + std::string* response_data = new std::string( resp.data ); + ForkThread( &FacebookProto::ProcessBuddyList, this->parent, ( void* )response_data ); return handle_success( "buddy_list" ); + } case HTTP_CODE_FAKE_ERROR: case HTTP_CODE_FAKE_DISCONNECTED: @@ -980,6 +992,51 @@ bool facebook_client::buddy_list( ) } } +bool facebook_client::facepiles( ) +{ + handle_entry( "facepiles" ); + + int count = (int)CallServiceSync(MS_GC_GETSESSIONCOUNT, 0, (LPARAM)parent->m_szModuleName); + for ( int i = 0; i < count; i++ ) { + GC_INFO gci = {0}; + gci.Flags = BYINDEX | TYPE | ID; + gci.iItem = i; + gci.pszModule = parent->m_szModuleName; + if ( !CallServiceSync( MS_GC_GETINFO, 0, (LPARAM)&gci ) && gci.iType == GCW_CHATROOM ) { + char *id = mir_t2a(gci.pszID); + + // Prepare data + std::string data = "id="; + data += id; + data += "&post_form_id=" + this->post_form_id_ + "&fb_dtsg=" + this->dtsg_ + "&lsd=&post_form_id_source=AsyncRequest&__user=" + this->self_.user_id + "&phstamp=0"; + + // Get facepiles + http::response resp = flap( FACEBOOK_REQUEST_FACEPILES, &data ); + + // Process result data + validate_response(&resp); + + std::string chat_id = id; + mir_free(id); + + switch ( resp.code ) + { + case HTTP_CODE_OK: + ForkThread( &FacebookProto::ProcessFacepiles, this->parent, new send_chat(chat_id, resp.data) ); + break; + + case HTTP_CODE_FAKE_ERROR: + case HTTP_CODE_FAKE_DISCONNECTED: + default: + return handle_error( "facepiles" ); + } + + } + } + + return handle_success( "facepiles" ); +} + bool facebook_client::load_friends( ) { handle_entry( "load_friends" ); @@ -1037,42 +1094,6 @@ bool facebook_client::feeds( ) } } -void facebook_client::delete_friends( ) -{ - handle_entry( "delete_friends" ); - - // Check and update old contacts - for(HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); - hContact; - hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0) ) - { - if(!parent->IsMyContact(hContact)) - continue; - - if( !DBGetContactSettingByte(hContact,parent->m_szModuleName,FACEBOOK_KEY_DELETE_NEXT,0) ) { - DBVARIANT dbv; - if( !DBGetContactSettingString(hContact,parent->m_szModuleName,FACEBOOK_KEY_ID,&dbv) ) { - std::string* id = new std::string(dbv.pszVal); - DBFreeVariant(&dbv); - - if( !DBGetContactSettingString(hContact,parent->m_szModuleName,FACEBOOK_KEY_NAME,&dbv) ) { - - TCHAR* szTitle = mir_a2t_cp(dbv.pszVal, CP_UTF8); - parent->NotifyEvent(szTitle, TranslateT("Contact was deleted."), hContact, FACEBOOK_EVENT_CLIENT, NULL); - mir_free( szTitle ); - DBFreeVariant(&dbv); - - CallService(MS_DB_CONTACT_DELETE,(WPARAM)hContact,0); - - ForkThread( &FacebookProto::DeleteContactFromServer, this->parent, ( void* )id ); - } - } - } - } - - handle_success( "delete_friends" ); -} - bool facebook_client::channel( ) { handle_entry( "channel" ); @@ -1131,6 +1152,12 @@ bool facebook_client::channel( ) case HTTP_CODE_FAKE_DISCONNECTED: case HTTP_CODE_FAKE_ERROR: default: + // Testing workaround for channel change + if (!this->chat_channel_jslogger_.empty()) + this->chat_channel_jslogger_ = "_"; + else + this->chat_channel_jslogger_.clear(); + return handle_error( "channel" ); } } @@ -1191,7 +1218,8 @@ bool facebook_client::send_message( std::string message_recipient, std::string m case 1356003: // Contact is offline { HANDLE hContact = parent->ContactIDToHContact( message_recipient ); - DBWriteContactSettingWord(hContact,parent->m_szModuleName,"Status",ID_STATUS_OFFLINE); + if (hContact != NULL) + DBWriteContactSettingWord(hContact,parent->m_szModuleName,"Status",ID_STATUS_OFFLINE); return false; } break; @@ -1225,6 +1253,7 @@ bool facebook_client::send_message( std::string message_recipient, std::string m case HTTP_CODE_FAKE_DISCONNECTED: default: *error_text = Translate("Timeout when sending message."); + handle_error( "send_message" ); return false; } diff --git a/FacebookRM/connection.cpp b/FacebookRM/connection.cpp index b546e79..d871ee1 100644 --- a/FacebookRM/connection.cpp +++ b/FacebookRM/connection.cpp @@ -55,6 +55,8 @@ void FacebookProto::ChangeStatus(void*) ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); + OnLeaveChat(NULL, NULL); + SetAllContactStatuses( ID_STATUS_OFFLINE ); ToggleStatusMenuItems(false); @@ -83,7 +85,6 @@ void FacebookProto::ChangeStatus(void*) facy.home(); facy.reconnect(); - facy.delete_friends(); facy.load_friends(); setDword( "LogonTS", (DWORD)time(NULL) ); @@ -118,6 +119,7 @@ void FacebookProto::ChangeStatus(void*) facy.chat_state( m_iDesiredStatus != ID_STATUS_INVISIBLE ); facy.buddy_list( ); + facy.facepiles( ); m_iStatus = facy.self_.status_id = m_iDesiredStatus; ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); @@ -179,10 +181,14 @@ void FacebookProto::UpdateLoop(void *) for ( int i = -1; !isOffline(); i = ++i % 6 ) { - if ( i != -1 ) + if ( i != -1 ) { if ( !facy.invisible_ ) if ( !facy.buddy_list( ) ) break; + if ( getByte( FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS) ) + if ( !facy.facepiles( ) ) + break; + } if ( i == 2 && getByte( FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE ) ) if ( !facy.feeds( ) ) break; diff --git a/FacebookRM/constants.h b/FacebookRM/constants.h index 7c5171c..a9a7844 100644 --- a/FacebookRM/constants.h +++ b/FacebookRM/constants.h @@ -29,13 +29,13 @@ Last change on : $Date$ // Version management #include "build.h" -#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 6, 0) +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 7, 0) #define __PRODUCT_DWORD PLUGIN_MAKE_VERSION(0, 9, 14, 0) -#define __VERSION_STRING "0.0.6.0" +#define __VERSION_STRING "0.0.7.0" #define __PRODUCT_STRING "0.9.14.0" -#define __VERSION_VS_FILE 0,0,6,0 +#define __VERSION_VS_FILE 0,0,7,0 #define __VERSION_VS_PROD 0,9,14,0 -#define __VERSION_VS_FILE_STRING "0, 0, 6, 0" +#define __VERSION_VS_FILE_STRING "0, 0, 7, 0" #define __VERSION_VS_PROD_STRING "0, 9, 14, 0" // Product management @@ -77,6 +77,9 @@ Last change on : $Date$ #define DEFAULT_BIG_AVATARS 0 #define DEFAULT_DISCONNECT_CHAT 0 #define DEFAULT_PARSE_MESSAGES 0 +#define DEFAULT_MAP_STATUSES 0 +#define DEFAULT_LOAD_MOBILE 0 +#define DEFAULT_ENABLE_GROUPCHATS 0 #define DEFAULT_EVENT_NOTIFICATIONS_ENABLE 1 #define DEFAULT_EVENT_FEEDS_ENABLE 1 @@ -101,6 +104,8 @@ Last change on : $Date$ #define FACEBOOK_REQUEST_BUDDY_LIST 120 // getting regular updates (friends online, ...) #define FACEBOOK_REQUEST_LOAD_FRIENDS 121 // getting list of all friends #define FACEBOOK_REQUEST_DELETE_FRIEND 122 // deleting friends +#define FACEBOOK_REQUEST_ADD_FRIEND 123 // adding friends +#define FACEBOOK_REQUEST_FACEPILES 124 // getting list of contacts in chat #define FACEBOOK_REQUEST_FEEDS 125 // getting feeds #define FACEBOOK_REQUEST_NOTIFICATIONS 126 // getting notifications #define FACEBOOK_REQUEST_RECONNECT 130 // getting __sequence_num__ and __channel_id__ @@ -108,7 +113,7 @@ Last change on : $Date$ #define FACEBOOK_REQUEST_MESSAGE_SEND 300 // sending message #define FACEBOOK_REQUEST_MESSAGES_RECEIVE 301 // receiving messages #define FACEBOOK_REQUEST_TYPING_SEND 304 // sending typing notification -#define FACEBOOK_REQUEST_SETTINGS 305 // setting chat visibility +#define FACEBOOK_REQUEST_VISIBILITY 305 // setting chat visibility #define FACEBOOK_REQUEST_TABS 306 // closing message window, setting chat visibility #define FACEBOOK_REQUEST_ASYNC 307 // marking messages read and getting other things #define FACEBOOK_REQUEST_ASYNC_GET 308 // GET version of async request diff --git a/FacebookRM/contacts.cpp b/FacebookRM/contacts.cpp index de01800..1f0a007 100644 --- a/FacebookRM/contacts.cpp +++ b/FacebookRM/contacts.cpp @@ -68,7 +68,7 @@ HANDLE FacebookProto::ContactIDToHContact(std::string user_id) return 0; } -HANDLE FacebookProto::AddToContactList(facebook_user* fbu, bool dont_check) +HANDLE FacebookProto::AddToContactList(facebook_user* fbu, bool dont_check, const char *new_name) { HANDLE hContact; @@ -98,7 +98,13 @@ HANDLE FacebookProto::AddToContactList(facebook_user* fbu, bool dont_check) DBWriteContactSettingTString(hContact,"CList","Group",dbv.ptszVal); DBFreeVariant(&dbv); } - + + if (strlen(new_name) > 0) { + DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, new_name); + DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NICK, new_name); + DBWriteContactSettingByte(hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 1); // We suppose he is not on server list + } + if (getByte(FACEBOOK_KEY_DISABLE_STATUS_NOTIFY, 0)) CallService(MS_IGNORE_IGNORE, (WPARAM)hContact, (LPARAM)IGNOREEVENT_USERONLINE); @@ -154,10 +160,46 @@ void FacebookProto::DeleteContactFromServer(void *data) if (resp.code != HTTP_CODE_OK) { facy.handle_error( "DeleteContactFromServer" ); } + + NotifyEvent(TranslateT("Deleting contact"), TranslateT("Contact was sucessfully removed from server."), NULL, FACEBOOK_EVENT_OTHER, NULL); + + delete data; +} + +void FacebookProto::AddContactToServer(void *data) +{ + facy.handle_entry( "AddContactToServer" ); + + if ( data == NULL ) + return; + + std::string *id = (std::string*)data; + std::string query = "action=add_friend&how_found=profile_button&ref_param=ts&outgoing_id=&unwanted=&logging_location=&no_flyout_on_click=false&ego_log_data=&post_form_id_source=AsyncRequest&lsd=&fb_dtsg="; + query += facy.dtsg_; + query += "&post_form_id="; + query += facy.post_form_id_; + query += "&to_friend="; + query += *id; + query += "&__user="; + query += facy.self_.user_id; + + // Get unread inbox threads + http::response resp = facy.flap( FACEBOOK_REQUEST_ADD_FRIEND, &query ); + + // Process result data + facy.validate_response(&resp); + + if (resp.code != HTTP_CODE_OK || resp.data.find("\"success\":true") == std::string::npos) { + facy.handle_error( "AddContactToServer" ); + } +// RM TODO: better notify... + NotifyEvent(TranslateT("Adding contact"), TranslateT("Request for friendship was sent successfully."), NULL, FACEBOOK_EVENT_OTHER, NULL); + delete data; } + HANDLE FacebookProto::GetAwayMsg(HANDLE hContact) { return 0; // Status messages are disabled @@ -169,7 +211,7 @@ int FacebookProto::OnContactDeleted(WPARAM wparam,LPARAM) if (IsMyContact(hContact)) { - if (!DBGetContactSettingByte(hContact,m_szModuleName,FACEBOOK_KEY_DELETE_NEXT,0)) { +// if (!DBGetContactSettingByte(hContact,m_szModuleName,FACEBOOK_KEY_DELETE_NEXT,0)) { if (MessageBox( 0, TranslateT("Do you want to delete this contact also from server list?"), m_tszUserName, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 ) == IDYES) { DBVARIANT dbv; if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) ) @@ -179,16 +221,17 @@ int FacebookProto::OnContactDeleted(WPARAM wparam,LPARAM) ForkThread( &FacebookProto::DeleteContactFromServer, this, ( void* )id ); DBFreeVariant(&dbv); } else { - facebook_user fbu; +/* facebook_user fbu; fbu.user_id = dbv.pszVal; hContact = AddToContactList(&fbu); DBWriteContactSettingByte(hContact,m_szModuleName,FACEBOOK_KEY_DELETE_NEXT,1); - facy.client_notify(TranslateT("Contact will be deleted at next login.")); + facy.client_notify(TranslateT("Contact will be deleted at next login."));*/ + NotifyEvent(TranslateT("Deleting contact"), TranslateT("Contact wasn't deleted, because you are not connected."), NULL, FACEBOOK_EVENT_OTHER, NULL); } } } - } +// } ScopedLock s(facy.buddies_lock_); diff --git a/FacebookRM/db.h b/FacebookRM/db.h index 8278889..4c8afcf 100644 --- a/FacebookRM/db.h +++ b/FacebookRM/db.h @@ -46,12 +46,13 @@ Last change on : $Date: 2011-01-08 11:10:34 +0100 (so, 08 1 2011) $ #define FACEBOOK_KEY_LOGIN "Email" #define FACEBOOK_KEY_ID "ID" #define FACEBOOK_KEY_NAME "RealName" +#define FACEBOOK_KEY_NICK "Nick" #define FACEBOOK_KEY_PASS "Password" #define FACEBOOK_KEY_UPD_NAMES "UpdateNames" #define FACEBOOK_KEY_DEVICE_ID "DeviceID" #define FACEBOOK_KEY_AV_URL "AvatarURL" #define FACEBOOK_KEY_DELETED "Deleted" -#define FACEBOOK_KEY_DELETE_NEXT "DeleteNext" +#define FACEBOOK_KEY_CONTACT_TYPE "ContactType" #define FACEBOOK_KEY_DEF_GROUP "DefaultGroup" #define FACEBOOK_KEY_FORCE_HTTPS "ForceHTTPS" @@ -64,6 +65,9 @@ Last change on : $Date: 2011-01-08 11:10:34 +0100 (so, 08 1 2011) $ #define FACEBOOK_KEY_PARSE_MESSAGES "ParseUnreadMessages" #define FACEBOOK_KEY_BIG_AVATARS "UseBigAvatars" #define FACEBOOK_KEY_DISCONNECT_CHAT "DisconnectChatEnable" +#define FACEBOOK_KEY_MAP_STATUSES "MapStatuses" +#define FACEBOOK_KEY_LOAD_MOBILE "LoadMobile" +#define FACEBOOK_KEY_ENABLE_GROUPCHATS "GroupchatsEnable" #define FACEBOOK_KEY_POLL_RATE "PollRate" // [HIDDEN] #define FACEBOOK_KEY_TIMEOUTS_LIMIT "TimeoutsLimit" // [HIDDEN] diff --git a/FacebookRM/dialogs.cpp b/FacebookRM/dialogs.cpp index aa58ff3..309bbad 100644 --- a/FacebookRM/dialogs.cpp +++ b/FacebookRM/dialogs.cpp @@ -227,15 +227,19 @@ INT_PTR CALLBACK FBOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM l DBFreeVariant(&dbv); } - LoadDBCheckState(proto, hwnd, IDC_SECURE, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS); + LoadDBCheckState(proto, hwnd, IDC_SECURE, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS); LoadDBCheckState(proto, hwnd, IDC_SECURE_CHANNEL, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL, DEFAULT_FORCE_HTTPS_CHANNEL); LoadDBCheckState(proto, hwnd, IDC_SET_IGNORE_STATUS, FACEBOOK_KEY_DISABLE_STATUS_NOTIFY, DEFAULT_DISABLE_STATUS_NOTIFY); LoadDBCheckState(proto, hwnd, IDC_BIGGER_AVATARS, FACEBOOK_KEY_BIG_AVATARS, DEFAULT_BIG_AVATARS); LoadDBCheckState(proto, hwnd, IDC_DISCONNECT_CHAT, FACEBOOK_KEY_DISCONNECT_CHAT, DEFAULT_DISCONNECT_CHAT); - LoadDBCheckState(proto, hwnd, IDC_PARSE_UNREAD, FACEBOOK_KEY_PARSE_MESSAGES, DEFAULT_PARSE_MESSAGES); + LoadDBCheckState(proto, hwnd, IDC_PARSE_UNREAD, FACEBOOK_KEY_PARSE_MESSAGES, DEFAULT_PARSE_MESSAGES); LoadDBCheckState(proto, hwnd, IDC_CLOSE_WINDOWS, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE, DEFAULT_CLOSE_WINDOWS_ENABLE); LoadDBCheckState(proto, hwnd, IDC_SET_STATUS, FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS); - LoadDBCheckState(proto, hwnd, IDC_LOGGING, FACEBOOK_KEY_LOGGING_ENABLE, DEFAULT_LOGGING_ENABLE); + LoadDBCheckState(proto, hwnd, IDC_LOGGING, FACEBOOK_KEY_LOGGING_ENABLE, DEFAULT_LOGGING_ENABLE); + LoadDBCheckState(proto, hwnd, IDC_MAP_STATUSES, FACEBOOK_KEY_MAP_STATUSES, DEFAULT_MAP_STATUSES); + LoadDBCheckState(proto, hwnd, IDC_LOAD_MOBILE, FACEBOOK_KEY_LOAD_MOBILE, DEFAULT_LOAD_MOBILE); + LoadDBCheckState(proto, hwnd, IDC_GROUPCHATS, FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS); + EnableWindow(GetDlgItem(hwnd, IDC_SECURE_CHANNEL), IsDlgButtonChecked(hwnd, IDC_SECURE)); @@ -287,12 +291,15 @@ INT_PTR CALLBACK FBOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM l StoreDBCheckState(proto, hwnd, IDC_SECURE, FACEBOOK_KEY_FORCE_HTTPS); StoreDBCheckState(proto, hwnd, IDC_CLOSE_WINDOWS, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE); - StoreDBCheckState(proto, hwnd, IDC_LOGGING, FACEBOOK_KEY_LOGGING_ENABLE); + StoreDBCheckState(proto, hwnd, IDC_LOGGING, FACEBOOK_KEY_LOGGING_ENABLE); StoreDBCheckState(proto, hwnd, IDC_SECURE_CHANNEL, FACEBOOK_KEY_FORCE_HTTPS_CHANNEL); StoreDBCheckState(proto, hwnd, IDC_SET_IGNORE_STATUS, FACEBOOK_KEY_DISABLE_STATUS_NOTIFY); StoreDBCheckState(proto, hwnd, IDC_BIGGER_AVATARS, FACEBOOK_KEY_BIG_AVATARS); StoreDBCheckState(proto, hwnd, IDC_DISCONNECT_CHAT, FACEBOOK_KEY_DISCONNECT_CHAT); StoreDBCheckState(proto, hwnd, IDC_PARSE_UNREAD, FACEBOOK_KEY_PARSE_MESSAGES); + StoreDBCheckState(proto, hwnd, IDC_MAP_STATUSES, FACEBOOK_KEY_MAP_STATUSES); + StoreDBCheckState(proto, hwnd, IDC_LOAD_MOBILE, FACEBOOK_KEY_LOAD_MOBILE); + StoreDBCheckState(proto, hwnd, IDC_GROUPCHATS, FACEBOOK_KEY_ENABLE_GROUPCHATS); BOOL setStatus = IsDlgButtonChecked(hwnd, IDC_SET_STATUS); BOOL setStatusOld = DBGetContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS); @@ -406,8 +413,6 @@ INT_PTR CALLBACK FBEventsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lp { if ( reinterpret_cast(lparam)->code == PSN_APPLY ) { - DBWriteContactSettingByte(NULL, proto->m_szModuleName, FACEBOOK_KEY_FEED_TYPE, SendDlgItemMessage(hwnd, IDC_FEEDS_TYPE, CB_GETCURSEL, 0, 0)); - StoreDBCheckState(proto, hwnd, IDC_SYSTRAY_NOTIFY, FACEBOOK_KEY_SYSTRAY_NOTIFY); StoreDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_ENABLE, FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE); diff --git a/FacebookRM/entities.h b/FacebookRM/entities.h index 432af9f..c09c20d 100644 --- a/FacebookRM/entities.h +++ b/FacebookRM/entities.h @@ -63,11 +63,12 @@ struct facebook_message { std::string user_id; std::string message_text; + std::string sender_name; time_t time; facebook_message( ) { - this->user_id = this->message_text = ""; + this->user_id = this->message_text = this->sender_name = ""; this->time = 0; } @@ -75,6 +76,7 @@ struct facebook_message { this->user_id = msg.user_id; this->message_text = msg.message_text; + this->sender_name = msg.sender_name; this->time = msg.time; } }; @@ -103,3 +105,34 @@ struct facebook_newsfeed this->user_id = this->title = this->text = this->link = ""; } }; + + +struct send_chat +{ + send_chat(const std::string &chat_id,const std::string &msg) : chat_id(chat_id), msg(msg) {} + std::string chat_id; + std::string msg; +}; + + +struct send_direct +{ + send_direct(HANDLE hContact,const std::string &msg, HANDLE msgid) : hContact(hContact), msg(msg), msgid(msgid) {} + HANDLE hContact; + std::string msg; + HANDLE msgid; +}; + +struct send_typing +{ + send_typing(HANDLE hContact,const int status) : hContact(hContact), status(status) {} + HANDLE hContact; + int status; +}; + +struct send_messaging +{ + send_messaging(const std::string &user_id, const int type) : user_id(user_id), type(type) {} + std::string user_id; + int type; +}; diff --git a/FacebookRM/facebook.rc b/FacebookRM/facebook.rc index 6516e4a..be34e49 100644 --- a/FacebookRM/facebook.rc +++ b/FacebookRM/facebook.rc @@ -55,6 +55,8 @@ END // remains consistent on all systems. IDI_FACEBOOK ICON "icons/facebook.ico" IDI_MIND ICON "icons/mind.ico" +IDI_ADDFRIEND ICON "icons/addFriend.ico" +IDI_REMOVEFRIEND ICON "icons/removeFriend.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -91,30 +93,38 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - GROUPBOX "User Details",IDC_STATIC,50,7,224,58 - LTEXT "E-mail:",IDC_STATIC,59,19,60,8 - EDITTEXT IDC_UN,123,17,144,13,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,59,34,60,8 - EDITTEXT IDC_PW,123,32,144,13,ES_PASSWORD | ES_AUTOHSCROLL + GROUPBOX "User Details",IDC_STATIC,50,7,224,52 + LTEXT "E-mail:",IDC_STATIC,59,17,60,8 + EDITTEXT IDC_UN,123,15,144,13,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,59,30,60,8 + EDITTEXT IDC_PW,123,28,144,13,ES_PASSWORD | ES_AUTOHSCROLL CONTROL "Create a new Facebook account",IDC_NEWACCOUNTLINK, - "Hyperlink",WS_TABSTOP,123,50,144,10 - LTEXT "Default group:",IDC_STATIC,59,84,60,8 - EDITTEXT IDC_GROUP,123,84,144,13,ES_AUTOHSCROLL + "Hyperlink",WS_TABSTOP,123,44,144,10 + LTEXT "Default group:",IDC_STATIC,59,75,60,8 + EDITTEXT IDC_GROUP,123,75,144,13,ES_AUTOHSCROLL CONTROL "Automatically set 'Ignore status change' flag",IDC_SET_IGNORE_STATUS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,100,208,10 - GROUPBOX "Contacts Settings",IDC_STATIC,50,71,224,57 - CONTROL "Use bigger avatars",IDC_BIGGER_AVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,113,208,10 - GROUPBOX "Advanced Settings",IDC_STATIC,50,135,224,98 - CONTROL "Force secure (HTTPS) connection",IDC_SECURE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,159,208,10 - CONTROL "Post Miranda statuses to Wall",IDC_SET_STATUS,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,59,188,208,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,90,208,10 + GROUPBOX "Contacts Settings",IDC_STATIC,50,62,224,64 + CONTROL "Use bigger avatars",IDC_BIGGER_AVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,101,208,10 + GROUPBOX "Advanced Settings",IDC_STATIC,50,128,224,117 + CONTROL "Force secure (HTTPS) connection",IDC_SECURE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,149,208,10 + CONTROL "Post Miranda statuses to Wall",IDC_SET_STATUS,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,59,172,208,10 CONTROL "Enable logging for debugging purposes",IDC_LOGGING, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,146,208,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,138,208,10 CONTROL "Use secure connection also for channel requests",IDC_SECURE_CHANNEL, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,69,172,198,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,69,160,198,10 CONTROL "Also disconnect chat when going to offline",IDC_DISCONNECT_CHAT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,202,208,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,184,208,10 CONTROL "Get unread messages on login (EXPERIMENTAL)",IDC_PARSE_UNREAD, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,215,208,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,220,208,10 + CONTROL "Automatically close chat windows (on website)",IDC_CLOSE_WINDOWS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,196,208,10 + CONTROL "Map non-standard statuses to Invisible (instead of Online)",IDC_MAP_STATUSES, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,208,208,10 + CONTROL "Load contacts with 'On the Mobile' status",IDC_LOAD_MOBILE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,112,208,10 + CONTROL "Enable groupchats support (EXPERIMENTAL)",IDC_GROUPCHATS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,59,232,208,10 END IDD_OPTIONS_EVENTS DIALOGEX 0, 0, 305, 217 diff --git a/FacebookRM/facebook.vcproj b/FacebookRM/facebook.vcproj index c467ae1..4d3aebe 100644 --- a/FacebookRM/facebook.vcproj +++ b/FacebookRM/facebook.vcproj @@ -47,7 +47,7 @@ Name="VCCLCompilerTool" Optimization="0" WholeProgramOptimization="false" - AdditionalIncludeDirectories="../../include;../ExternalAPI" + AdditionalIncludeDirectories="../../include;." PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX" MinimalRebuild="false" RuntimeLibrary="3" @@ -133,7 +133,7 @@ Name="VCCLCompilerTool" Optimization="0" WholeProgramOptimization="false" - AdditionalIncludeDirectories="../../include;../ExternalAPI" + AdditionalIncludeDirectories="../../include;." PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_WIN64" RuntimeLibrary="3" EnableFunctionLevelLinking="false" @@ -217,7 +217,7 @@ Optimization="1" EnableIntrinsicFunctions="true" FavorSizeOrSpeed="2" - AdditionalIncludeDirectories="../../include;../ExternalAPI" + AdditionalIncludeDirectories="../../include;." PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX" StringPooling="true" RuntimeLibrary="2" @@ -303,7 +303,7 @@ Optimization="1" EnableIntrinsicFunctions="true" FavorSizeOrSpeed="2" - AdditionalIncludeDirectories="../../include;../ExternalAPI" + AdditionalIncludeDirectories="../../include;." PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;FACEBOOK_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_WIN64" StringPooling="true" RuntimeLibrary="2" @@ -372,6 +372,10 @@ RelativePath=".\avatars.cpp" > + + @@ -564,6 +568,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + @@ -576,6 +584,10 @@ RelativePath=".\icons\mind.ico" > + + diff --git a/FacebookRM/facebook_10.sln b/FacebookRM/facebook_10.sln index fc98ae0..e473e17 100644 --- a/FacebookRM/facebook_10.sln +++ b/FacebookRM/facebook_10.sln @@ -1,5 +1,6 @@ + Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual C++ Express 2010 +# Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "facebook", "facebook_10.vcxproj", "{DADE9455-DC28-465A-9604-2CA28052B9FB}" EndProject Global diff --git a/FacebookRM/facebook_10.vcxproj b/FacebookRM/facebook_10.vcxproj index 5f2ad60..0f98c4a 100644 --- a/FacebookRM/facebook_10.vcxproj +++ b/FacebookRM/facebook_10.vcxproj @@ -73,10 +73,8 @@ true $(SolutionDir)$(Configuration)/Plugins\ $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ - false $(SolutionDir)\$(Configuration) $(Platform)/Plugins\ $(SolutionDir)\$(Configuration) $(Platform)/Obj/$(ProjectName)\ - true AllRules.ruleset @@ -109,11 +107,11 @@ _UNICODE;UNICODE;_DEBUG;%(PreprocessorDefinitions) - ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) true true + $(TargetDir)$(TargetName).map Windows @@ -123,6 +121,7 @@ false MachineX86 + $(IntDir)$(TargetName).lib @@ -146,10 +145,8 @@ _UNICODE;UNICODE;_DEBUG;%(PreprocessorDefinitions) - ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) - Build\$(Platform) $(Configuration)\plugins\$(ProjectName).dll true true $(TargetDir)$(TargetName).map @@ -162,6 +159,7 @@ false MachineX64 + $(IntDir)$(TargetName).lib @@ -188,18 +186,20 @@ _UNICODE;UNICODE;%(PreprocessorDefinitions) - ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + ../../include/msapi/ $(OutDir)$(TargetName)$(TargetExt) true false + $(TargetDir)$(TargetName).map Windows true true false MachineX86 uuid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(IntDir)$(TargetName).lib @@ -223,14 +223,13 @@ common.h Level3 ProgramDatabase - StreamingSIMDExtensions2 Strict false false _UNICODE;UNICODE;%(PreprocessorDefinitions) - ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + ../../include/msapi/ $(OutDir)$(TargetName)$(TargetExt) @@ -241,10 +240,13 @@ true false MachineX64 + $(IntDir)$(TargetName).lib + uuid.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + diff --git a/FacebookRM/facebook_10.vcxproj.filters b/FacebookRM/facebook_10.vcxproj.filters index 462a553..b3b2a03 100644 --- a/FacebookRM/facebook_10.vcxproj.filters +++ b/FacebookRM/facebook_10.vcxproj.filters @@ -63,6 +63,9 @@ Source Files + + Source Files + diff --git a/FacebookRM/icons/addFriend.ico b/FacebookRM/icons/addFriend.ico new file mode 100644 index 0000000..d8879d1 Binary files /dev/null and b/FacebookRM/icons/addFriend.ico differ diff --git a/FacebookRM/icons/removeFriend.ico b/FacebookRM/icons/removeFriend.ico new file mode 100644 index 0000000..9639a9c Binary files /dev/null and b/FacebookRM/icons/removeFriend.ico differ diff --git a/FacebookRM/json.cpp b/FacebookRM/json.cpp index 1c57f00..bd69c75 100644 --- a/FacebookRM/json.cpp +++ b/FacebookRM/json.cpp @@ -62,8 +62,32 @@ int facebook_json_parser::parse_buddy_list( void* data, List::List< facebook_use i->data->status_id = ID_STATUS_OFFLINE; } - const Object& nowAvailableList = objRoot["payload"]["buddy_list"]["nowAvailableList"]; + // Find mobile friends + if (DBGetContactSettingByte(NULL,proto->m_szModuleName,FACEBOOK_KEY_LOAD_MOBILE, DEFAULT_LOAD_MOBILE)) { + const Array& mobileFriends = objRoot["payload"]["buddy_list"]["mobile_friends"]; + + for ( Array::const_iterator buddy( mobileFriends.Begin() ); buddy != mobileFriends.End(); ++buddy) { + const Number& member = *buddy; + char was_id[32]; + lltoa( member.Value(), was_id, 10 ); + + std::string id = was_id; + if (!id.empty()) { + current = buddy_list->find( id ); + + if ( current == NULL) { + buddy_list->insert( std::make_pair( id, new facebook_user( ) ) ); + current = buddy_list->find( id ); + current->user_id = id; + } + + current->status_id = ID_STATUS_ONTHEPHONE; + } + } + } + const Object& nowAvailableList = objRoot["payload"]["buddy_list"]["nowAvailableList"]; + // Find now awailable contacts for (Object::const_iterator itAvailable(nowAvailableList.Begin()); itAvailable != nowAvailableList.End(); ++itAvailable) { @@ -78,13 +102,13 @@ int facebook_json_parser::parse_buddy_list( void* data, List::List< facebook_use buddy_list->insert( std::make_pair( member.name, new facebook_user( ) ) ); current = buddy_list->find( member.name ); current->user_id = current->real_name = member.name; - } + } current->status_id = (idle ? ID_STATUS_OFFLINE : ID_STATUS_ONLINE); } const Object& userInfosList = objRoot["payload"]["buddy_list"]["userInfos"]; - + // Get aditional informations about contacts (if available) for (Object::const_iterator itUserInfo(userInfosList.Begin()); itUserInfo != userInfosList.End(); ++itUserInfo) { @@ -121,6 +145,83 @@ int facebook_json_parser::parse_buddy_list( void* data, List::List< facebook_use return EXIT_SUCCESS; } +int facebook_json_parser::parse_facepiles( void* data, std::map< std::string, std::string > *facepiles ) +{ + using namespace json; + + try + { + std::string buddyData = static_cast< std::string* >( data )->substr( 9 ); + std::istringstream sDocument( buddyData ); + Object objDocument; + Reader::Read(objDocument, sDocument); + std::map< std::string, std::string >::iterator it; + + const Object& objRoot = objDocument; +/* const Array& infos = objRoot["payload"]["facepile_click_info"]; + + for ( Array::const_iterator info( infos.Begin() ); + info != infos.End(); ++info) + { + const Object& objMember = *info; + + if (objMember.Find("uid") != objMember.End()) { + const Number& id = objMember["uid"]; + char was_id[32]; + lltoa( id.Value(), was_id, 10 ); + + const String& name = objMember["name"]; + std::string user_name = utils::text::slashu_to_utf8( + utils::text::special_expressions_decode( name.Value() ) ); + + it = facepiles->find( std::string( was_id ) ); + if ( it == facepiles->end() ) { + facepiles->insert( std::make_pair( was_id, user_name ) ); + } + } + } */ + + // Contacts in chat are getting by parsing html response. Don't know if it will work also for many people in chat room. + const String& response_html = objRoot["payload"]["response_html"]; + std::string contacts = utils::text::slashu_to_utf8( utils::text::special_expressions_decode( response_html.Value( ) ) ); + + std::string::size_type pos = 0; + while ((pos = contacts.find("") - pos); + + std::string status = utils::text::source_get_value2( &row, "chat", "\" " ); // "Online" or "Idle" + std::string name = utils::text::source_get_value( &row, 2, "title=\"", "\"" ); + std::string id = utils::text::source_get_value( &row, 3, "href=\"", "/profile.php?id=", "\"" ); + if (id.empty()) + id = utils::text::source_get_value( &row, 3, "href=\"", "facebook.com/", "\"" ); + + it = facepiles->find( id ); + if ( it == facepiles->end() ) { + facepiles->insert( std::make_pair( id, name ) ); + } + + pos++; + } + + } + catch (Reader::ParseException& e) + { + proto->Log( "!!!!! Caught json::ParseException: %s", e.what() ); + proto->Log( " Line/offset: %d/%d", e.m_locTokenBegin.m_nLine + 1, e.m_locTokenBegin.m_nLineOffset + 1 ); + } + catch (const Exception& e) + { + proto->Log( "!!!!! Caught json::Exception: %s", e.what() ); + } + catch (const std::exception& e) + { + proto->Log( "!!!!! Caught std::exception: %s", e.what() ); + } + + return EXIT_SUCCESS; +} + + int facebook_json_parser::parse_friends( void* data, std::map< std::string, facebook_user* >* friends ) { using namespace json; @@ -256,7 +357,7 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess const String& type = objMember["type"]; - if ( type.Value( ) == "msg" ) // chat message + if ( type.Value( ) == "msg" || type.Value() == "offline_msg" ) // direct message { const Number& from = objMember["from"]; char was_id[32]; @@ -264,20 +365,22 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess const Object& messageContent = objMember["msg"]; const String& text = messageContent["text"]; + //"tab_type":"friend", objMember["tab_type"] //const Number& time_sent = messageContent["time"]; - // proto->Log("????? Checking time %15.2f > %15.2f", time_sent.Value(), proto->facy.last_message_time_); - if (last_msg != text.Value()) -/* if (time_sent.Value() > proto->facy.last_message_time_ - || (time_sent.Value() < 0 && proto->facy.last_message_time_ >= 0)) // Check agains duplicit messages*/ - { + if ((messageContent.Find("truncated") != messageContent.End()) + && (((const Number &)messageContent["truncated"]).Value() == 1)) { + // If we got truncated message, we can ignore it, because we should get it again as "messaging" type + std::string msg = "????? We got truncated message so we ignore it\n"; + msg += utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value())); + proto->Log(msg.c_str()); + } else if (last_msg != text.Value()) { last_msg = text.Value(); - //proto->facy.last_message_time_ = time_sent.Value(); facebook_message* message = new facebook_message( ); - message->message_text= utils::text::special_expressions_decode( + message->message_text = utils::text::special_expressions_decode( utils::text::slashu_to_utf8( text.Value( ) ) ); message->time = ::time( NULL ); message->user_id = was_id; @@ -289,7 +392,7 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess proto->Log(msg.c_str()); } } - else if ( type.Value( ) == "messaging" ) // inbox message + else if ( type.Value( ) == "messaging" ) // inbox message (multiuser or direct) { const String& type = objMember["event"]; @@ -299,32 +402,69 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess const Number& from = messageContent["sender_fbid"]; char was_id[32]; lltoa( from.Value(), was_id, 10 ); + + + // Ignore if message is from self user + if (was_id == proto->facy.self_.user_id) + continue; + const String& text = messageContent["body"]; + //std::string tid = ((const String&)messageContent["tid"]).Value(); + + const String& sender_name = messageContent["sender_name"]; - // TODO RM: include sender name - // const String& name = messageContent["sender_name"]; + std::string row = ((const String &)objMember["thread_row"]).Value(); //const Number& time_sent = messageContent["timestamp"]; //proto->Log("????? Checking time %15.2f > %15.2f", time_sent.Value(), proto->facy.last_message_time_); - if (last_msg != text.Value()) -/* if (time_sent.Value() > proto->facy.last_message_time_ - || (time_sent.Value() < 0 && proto->facy.last_message_time_ >= 0)) // Check agains duplicit messages*/ - { + if (last_msg != text.Value()) { last_msg = text.Value(); - //proto->facy.last_message_time_ = time_sent.Value(); facebook_message* message = new facebook_message( ); - message->message_text= utils::text::special_expressions_decode( + message->message_text = utils::text::special_expressions_decode( utils::text::slashu_to_utf8( text.Value( ) ) ); - message->time = ::time( NULL ); + message->sender_name = utils::text::special_expressions_decode( + utils::text::slashu_to_utf8( sender_name.Value( ) ) ); + + message->time = ::time( NULL ); + message->user_id = was_id; // TODO: Check if we have contact with this ID in friendlist and then do something different? - message->user_id = was_id; + if (row.find("uiSplitPic",0) != std::string::npos) { + // This is multiuser message + + std::string authors = utils::text::special_expressions_decode( + utils::text::slashu_to_utf8( row ) ); + authors = utils::text::source_get_value(&authors, 2, "", "<"); - messages->push_back( message ); + const String& to_id = messageContent["tid"]; + + std::string popup_text = message->sender_name; + popup_text += ": "; + popup_text += message->message_text; + + std::string title = Translate("Multichat"); + title += ": "; + title += authors; + + std::string url = "/?action=read&sk=inbox&page&query&tid="; + url += to_id.Value(); + + proto->Log(" Got multichat message"); + + TCHAR* szTitle = mir_a2t_cp(title.c_str(), CP_UTF8); + TCHAR* szText = mir_a2t_cp(popup_text.c_str(), CP_UTF8); + TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8); + proto->NotifyEvent(szTitle,szText,NULL,FACEBOOK_EVENT_OTHER, szUrl); + mir_free(szTitle); + mir_free(szText); + + } else { + messages->push_back( message ); + } } else { std::string msg = "????? Got duplicit inbox message?\n"; msg += utils::text::special_expressions_decode(utils::text::slashu_to_utf8(text.Value())); @@ -334,13 +474,10 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess } else if ( type.Value( ) == "group_msg" ) // chat message { - if ( (::time(NULL) - proto->facy.last_grpmessage_time_) < 15 ) // TODO RM: remove dont notify more than once every 15 secs + if (!DBGetContactSettingByte(NULL,proto->m_szModuleName,FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS)) continue; - - proto->facy.last_grpmessage_time_ = ::time(NULL); - + const String& from_name = objMember["from_name"]; - const String& group_name = objMember["to_name"]; const Number& to = objMember["to"]; char group_id[32]; @@ -350,6 +487,32 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess char was_id[32]; lltoa( from.Value(), was_id, 10 ); + const Object& messageContent = objMember["msg"]; + const String& text = messageContent["text"]; + + std::string msg = utils::text::special_expressions_decode( + utils::text::slashu_to_utf8( text.Value( ) ) ); + + std::string name = utils::text::special_expressions_decode( + utils::text::slashu_to_utf8( from_name.Value( ) ) ); + + // Add contact into chat, if isn't there already + if (!proto->IsChatContact(group_id, was_id)) + proto->AddChatContact(group_id, was_id, name.c_str()); + + // Add message into chat + proto->UpdateChat(group_id, was_id, name.c_str(), msg.c_str()); + } + else if ( type.Value( ) == "thread_msg" ) // multiuser message + { + const String& from_name = objMember["from_name"]; + const String& to_name = objMember["to_name"]["__html"]; + const String& to_id = objMember["to"]; + + const Number& from = objMember["from"]; + char was_id[32]; + lltoa( from.Value(), was_id, 10 ); + // Ignore if message is from self user if (was_id == proto->facy.self_.user_id) continue; @@ -357,24 +520,25 @@ int facebook_json_parser::parse_messages( void* data, std::vector< facebook_mess const Object& messageContent = objMember["msg"]; const String& text = messageContent["text"]; - std::string popup_text = utils::text::remove_html( - utils::text::special_expressions_decode( - utils::text::slashu_to_utf8( from_name.Value( ) ) ) ); + + last_msg = text.Value(); + + + std::string popup_text = utils::text::special_expressions_decode( + utils::text::slashu_to_utf8( from_name.Value( ) ) ); popup_text += ": "; - popup_text += utils::text::remove_html( - utils::text::special_expressions_decode( - utils::text::slashu_to_utf8( text.Value( ) ) ) ); + popup_text += utils::text::special_expressions_decode( + utils::text::slashu_to_utf8( text.Value( ) ) ); - std::string title = Translate("Groupchat"); + std::string title = Translate("Multichat"); title += ": "; - title += utils::text::remove_html( - utils::text::special_expressions_decode( - utils::text::slashu_to_utf8( group_name.Value( ) ) ) ); - - std::string url = "/home.php?sk=group_"; - url += group_id; + title += utils::text::special_expressions_decode( + utils::text::slashu_to_utf8( to_name.Value( ) ) ); + + std::string url = "/?action=read&sk=inbox&page&query&tid="; + url += to_id.Value(); - proto->Log(" Got groupchat message"); + proto->Log(" Got multichat message"); TCHAR* szTitle = mir_a2t_cp(title.c_str(), CP_UTF8); TCHAR* szText = mir_a2t_cp(popup_text.c_str(), CP_UTF8); diff --git a/FacebookRM/json.h b/FacebookRM/json.h index 19105b3..6227c78 100644 --- a/FacebookRM/json.h +++ b/FacebookRM/json.h @@ -36,6 +36,7 @@ class facebook_json_parser public: FacebookProto* proto; int parse_buddy_list( void*, List::List< facebook_user >* ); + int parse_facepiles( void*, std::map< std::string, std::string >* ); 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* >* ); diff --git a/FacebookRM/messages.cpp b/FacebookRM/messages.cpp index 7091e77..7578550 100644 --- a/FacebookRM/messages.cpp +++ b/FacebookRM/messages.cpp @@ -27,28 +27,6 @@ Last change on : $Date: 2011-02-07 18:19:39 +0100 (po, 07 2 2011) $ #include "common.h" -struct send_direct -{ - send_direct(HANDLE hContact,const std::string &msg, HANDLE msgid) : hContact(hContact), msg(msg), msgid(msgid) {} - HANDLE hContact; - std::string msg; - HANDLE msgid; -}; - -struct send_typing -{ - send_typing(HANDLE hContact,const int status) : hContact(hContact), status(status) {} - HANDLE hContact; - int status; -}; - -struct send_messaging -{ - send_messaging(const std::string &user_id, const int type) : user_id(user_id), type(type) {} - std::string user_id; - int type; -}; - int FacebookProto::RecvMsg(HANDLE hContact, PROTORECVEVENT *pre) { DBVARIANT dbv; @@ -102,6 +80,19 @@ void FacebookProto::SendMsgWorker(void *p) delete data; } +void FacebookProto::SendChatMsgWorker(void *p) +{ + if(p == NULL) + return; + + send_chat *data = static_cast(p); + std::string err_message = ""; + + facy.send_message(data->chat_id, data->msg, &err_message, false ); + + delete data; +} + int FacebookProto::SendMsg(HANDLE hContact, int flags, const char *msg) { // TODO: msg comes as Unicode (retyped wchar_t*), why should we convert it as ANSI to UTF-8? o_O diff --git a/FacebookRM/process.cpp b/FacebookRM/process.cpp index e6c965c..48430df 100644 --- a/FacebookRM/process.cpp +++ b/FacebookRM/process.cpp @@ -70,14 +70,32 @@ void FacebookProto::ProcessBuddyList( void* data ) if (!fbu->handle) { // just been added fbu->handle = AddToContactList(fbu); - DBWriteContactSettingUTF8String(fbu->handle,m_szModuleName,FACEBOOK_KEY_NAME,fbu->real_name.c_str()); - DBWriteContactSettingUTF8String(fbu->handle,m_szModuleName,"Nick",fbu->real_name.c_str()); + if (!fbu->real_name.empty()) { + DBWriteContactSettingUTF8String(fbu->handle,m_szModuleName,FACEBOOK_KEY_NAME,fbu->real_name.c_str()); + DBWriteContactSettingUTF8String(fbu->handle,m_szModuleName,FACEBOOK_KEY_NICK,fbu->real_name.c_str()); + } + } + + if (DBGetContactSettingWord(fbu->handle,m_szModuleName,"Status", 0) != fbu->status_id ) { + DBWriteContactSettingWord(fbu->handle,m_szModuleName,"Status", fbu->status_id ); } - if (DBGetContactSettingWord(fbu->handle,m_szModuleName,"Status", 0) != ID_STATUS_ONLINE) { - DBWriteContactSettingWord(fbu->handle,m_szModuleName,"Status", ID_STATUS_ONLINE ); + if (DBGetContactSettingByte(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE, 0)) { + DBDeleteContactSetting(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE); // Set type "on server-list" contact } + // Wasn't contact removed from "server-list" someday? + if ( DBGetContactSettingDword(fbu->handle, m_szModuleName, FACEBOOK_KEY_DELETED, 0) ) { + DBDeleteContactSetting(fbu->handle, m_szModuleName, FACEBOOK_KEY_DELETED); + + std::string url = FACEBOOK_URL_PROFILE + fbu->user_id; + + TCHAR* szTitle = mir_a2t_cp(fbu->real_name.c_str(), CP_UTF8); + TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8); + NotifyEvent(szTitle, TranslateT("Contact is back on server-list."), fbu->handle, FACEBOOK_EVENT_OTHER, szUrl); + mir_free( szTitle ); + // mir_free( szUrl ); // url is free'd in popup procedure + } // Check avatar change CheckAvatarChange(fbu->handle, fbu->image_url); @@ -96,6 +114,66 @@ exit: delete resp; } +void FacebookProto::ProcessFacepiles( void* data ) +{ + if ( data == NULL ) + return; + + send_chat *resp = static_cast(data); + + if ( isOffline() ) + goto exit; + + LOG("***** Starting processing facepiles"); + + CODE_BLOCK_TRY + + std::map< std::string, std::string > facepiles; + + facebook_json_parser* p = new facebook_json_parser( this ); + p->parse_facepiles( &(resp->msg), &facepiles ); + delete p; + + std::map< std::string, std::string >::iterator iter; + + char *chat_users = this->GetChatUsers(resp->chat_id.c_str()); + std::string users = chat_users; + mir_free(chat_users); + + std::vector users_list; + utils::text::explode(users, " ", &users_list); + + for( std::vector::size_type i=0; iRemoveChatContact(resp->chat_id.c_str(), users_list[i].c_str()); + LOG(" Now offline facepile (%s): [%s]", resp->chat_id.c_str(), users_list[i].c_str()); + } else { + facepiles.erase(iter); + } + } + + for ( iter = facepiles.begin( ); iter != facepiles.end(); ++iter ) + { + // These contacts are newly online, add them... + this->AddChatContact(resp->chat_id.c_str(), iter->first.c_str(), iter->second.c_str()); + LOG(" Now online facepile (%s): [%s] %s", resp->chat_id.c_str(), iter->first.c_str(), iter->second.c_str()); + } + + LOG("***** Facepiles processed"); + + CODE_BLOCK_CATCH + + LOG("***** Error processing facepiles: %s", e.what()); + + CODE_BLOCK_END + +exit: + delete resp; +} + + void FacebookProto::ProcessFriendList( void* data ) { if ( data == NULL ) @@ -151,7 +229,11 @@ void FacebookProto::ProcessFriendList( void* data ) if ( update_required ) { DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, fbu->real_name.c_str()); - DBWriteContactSettingUTF8String(hContact, m_szModuleName, "Nick", fbu->real_name.c_str()); + DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NICK, fbu->real_name.c_str()); + } + + if (DBGetContactSettingByte(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE, 0)) { + DBDeleteContactSetting(fbu->handle,m_szModuleName,FACEBOOK_KEY_CONTACT_TYPE); // Has type "on server-list" contact } // Wasn't contact removed from "server-list" someday? @@ -162,7 +244,7 @@ void FacebookProto::ProcessFriendList( void* data ) TCHAR* szTitle = mir_a2t_cp(fbu->real_name.c_str(), CP_UTF8); TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8); - NotifyEvent(szTitle, TranslateT("Contact is back on server-list."), hContact, FACEBOOK_EVENT_CLIENT, szUrl); + NotifyEvent(szTitle, TranslateT("Contact is back on server-list."), hContact, FACEBOOK_EVENT_OTHER, szUrl); mir_free( szTitle ); // mir_free( szUrl ); // url is free'd in popup procedure } @@ -176,7 +258,9 @@ void FacebookProto::ProcessFriendList( void* data ) // Contact was removed from "server-list", notify it // Wasnt we already been notified about this contact? - if ( !DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0) ) { + if ( !DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0) + && !DBGetContactSettingByte(hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 0) ) { // And is this contact "on-server" contact? + DBWriteContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, ::time(NULL)); std::string contactname = id; @@ -189,7 +273,7 @@ void FacebookProto::ProcessFriendList( void* data ) TCHAR* szTitle = mir_a2t_cp(contactname.c_str(), CP_UTF8); TCHAR* szUrl = mir_a2t_cp(url.c_str(), CP_UTF8); - NotifyEvent(szTitle, TranslateT("Contact is no longer on server-list."), hContact, FACEBOOK_EVENT_CLIENT, szUrl); + NotifyEvent(szTitle, TranslateT("Contact is no longer on server-list."), hContact, FACEBOOK_EVENT_OTHER, szUrl); mir_free( szTitle ); // mir_free( szUrl ); // url is free'd in popup procedure } @@ -206,7 +290,7 @@ void FacebookProto::ProcessFriendList( void* data ) DBWriteContactSettingByte(hContact, m_szModuleName, "Gender", fbu->gender ); DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NAME, fbu->real_name.c_str()); - DBWriteContactSettingUTF8String(hContact, m_szModuleName, "Nick", fbu->real_name.c_str()); + DBWriteContactSettingUTF8String(hContact, m_szModuleName, FACEBOOK_KEY_NICK, fbu->real_name.c_str()); DBWriteContactSettingString(hContact, m_szModuleName, FACEBOOK_KEY_AV_URL, fbu->image_url.c_str()); // DBWriteContactSettingWord(hContact, m_szModuleName, "Status", ID_STATUS_OFFLINE ); } @@ -266,7 +350,7 @@ void FacebookProto::ProcessUnreadMessages( void* ) std::string user_id = utils::text::source_get_value( &messageslist, 2, "single_thread_id\":", "," ); if (user_id.empty()) { - LOG(" !! !! Thread id is empty - this is groupchat message."); // todo remove as this is not such 'error' + LOG(" !! !! Thread id is empty - this is groupchat message."); // TODO: remove as this is not such 'error' continue; } @@ -336,8 +420,8 @@ void FacebookProto::ProcessMessages( void* data ) facebook_user fbu; fbu.user_id = messages[i]->user_id; - HANDLE hContact = AddToContactList(&fbu); - + HANDLE hContact = AddToContactList(&fbu, false, messages[i]->sender_name.c_str()); + PROTORECVEVENT recv = {0}; CCSDATA ccs = {0}; diff --git a/FacebookRM/proto.cpp b/FacebookRM/proto.cpp index 5a88c40..f54ceee 100644 --- a/FacebookRM/proto.cpp +++ b/FacebookRM/proto.cpp @@ -51,14 +51,16 @@ FacebookProto::FacebookProto(const char* proto_name,const TCHAR* username) CreateProtoService(m_szModuleName, PS_GETAVATARCAPS, &FacebookProto::GetAvatarCaps, this); // TODO RM: group chats -/* CreateProtoService(m_szModuleName,PS_JOINCHAT, &FacebookProto::OnJoinChat, this); - CreateProtoService(m_szModuleName,PS_LEAVECHAT,&FacebookProto::OnLeaveChat,this);*/ + CreateProtoService(m_szModuleName, PS_JOINCHAT, &FacebookProto::OnJoinChat, this); + CreateProtoService(m_szModuleName, PS_LEAVECHAT, &FacebookProto::OnLeaveChat, this); + if(g_mirandaVersion < PLUGIN_MAKE_VERSION(0, 10, 0, 2)) { HookProtoEvent(ME_DB_CONTACT_DELETED, &FacebookProto::OnContactDeleted, this); } - HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &FacebookProto::OnBuildStatusMenu, this); - HookProtoEvent(ME_OPT_INITIALISE, &FacebookProto::OnOptionsInit, this); + HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &FacebookProto::OnBuildStatusMenu, this); + HookProtoEvent(ME_OPT_INITIALISE, &FacebookProto::OnOptionsInit, this); + HookProtoEvent(ME_GC_EVENT, &FacebookProto::OnChatOutgoing, this); // Create standard network connection TCHAR descr[512]; @@ -127,7 +129,7 @@ DWORD_PTR FacebookProto::GetCaps( int type, HANDLE hContact ) else return PF1_IM | PF1_MODEMSGRECV; case PFLAGNUM_2: - return PF2_ONLINE | PF2_INVISIBLE; // | PF2_IDLE | PF2_SHORTAWAY; + return PF2_ONLINE | PF2_INVISIBLE | PF2_ONTHEPHONE; // | PF2_IDLE | PF2_SHORTAWAY; case PFLAGNUM_3: if ( getByte( FACEBOOK_KEY_SET_MIRANDA_STATUS, 0 ) ) return PF2_ONLINE; // | PF2_SHORTAWAY; @@ -135,6 +137,8 @@ DWORD_PTR FacebookProto::GetCaps( int type, HANDLE hContact ) return 0; case PFLAGNUM_4: return PF4_FORCEAUTH | PF4_NOCUSTOMAUTH /*| PF4_SUPPORTIDLE*/ | PF4_IMSENDUTF | PF4_AVATARS | PF4_SUPPORTTYPING | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE; + case PFLAGNUM_5: + return PF2_ONTHEPHONE; case PFLAG_MAXLENOFMESSAGE: return FACEBOOK_MESSAGE_LIMIT; case PFLAG_UNIQUEIDTEXT: @@ -166,7 +170,7 @@ int FacebookProto::SetStatus( int new_status ) switch ( new_status ) { case ID_STATUS_INVISIBLE: - case ID_STATUS_OFFLINE: + case ID_STATUS_OFFLINE: m_iDesiredStatus = new_status; break; @@ -176,6 +180,11 @@ int FacebookProto::SetStatus( int new_status ) break; default: + m_iDesiredStatus = ID_STATUS_INVISIBLE; + if (DBGetContactSettingByte(NULL,m_szModuleName,FACEBOOK_KEY_MAP_STATUSES, DEFAULT_MAP_STATUSES)) + break; + case ID_STATUS_ONLINE: + case ID_STATUS_FREECHAT: m_iDesiredStatus = ID_STATUS_ONLINE; break; } @@ -289,16 +298,14 @@ int FacebookProto::SvcCreateAccMgrUI(WPARAM wParam,LPARAM lParam) int FacebookProto::OnModulesLoaded(WPARAM wParam,LPARAM lParam) { -/* - // RM TODO: group chats // Register group chat GCREGISTER gcr = {sizeof(gcr)}; - gcr.dwFlags = GC_ACKMSG; + //gcr.dwFlags = GC_ACKMSG; gcr.pszModule = m_szModuleName; gcr.pszModuleDispName = m_szModuleName; gcr.iMaxText = FACEBOOK_MESSAGE_LIMIT; CallService(MS_GC_REGISTER,0,reinterpret_cast(&gcr)); -*/ + return 0; } @@ -311,8 +318,11 @@ int FacebookProto::OnPreShutdown(WPARAM wParam,LPARAM lParam) int FacebookProto::OnPrebuildContactMenu(WPARAM wParam,LPARAM lParam) { HANDLE hContact = reinterpret_cast(wParam); - if(IsMyContact(hContact, true)) - ShowContactMenus(true); + if(IsMyContact(hContact/*, true*/)) { + bool hide = (DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0) + || DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 0) ); + ShowContactMenus(true, hide); + } return 0; } @@ -385,7 +395,7 @@ int FacebookProto::OnBuildStatusMenu(WPARAM wParam,LPARAM lParam) mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP; mi.pszName = LPGEN("Visit Profile"); mi.icolibItem = GetIconHandle("homepage"); - // TODO RM: remember and properly free in destructor + // TODO RM: remember and properly free in destructor? /*m_hStatusMind = */reinterpret_cast( CallService( MS_CLIST_ADDPROTOMENUITEM,0,reinterpret_cast(&mi)) ); @@ -415,27 +425,78 @@ int FacebookProto::VisitProfile(WPARAM wParam,LPARAM lParam) { CallService(MS_UTILS_OPENURL,1,reinterpret_cast(dbv.pszVal)); DBFreeVariant(&dbv); - }/* else { - // TODO RM: remove this - std::string key, url; - if (DBGetContactSettingByte(hContact,m_szModuleName,"ChatRoom",0) == 0) - { // usual contact - key = FACEBOOK_KEY_ID; - url = FACEBOOK_URL_PROFILE; + } + + return 0; +} + +int FacebookProto::RemoveFriend(WPARAM wParam,LPARAM lParam) +{ + if (wParam == NULL) + { // self contact + // CallService(MS_UTILS_OPENURL,1,reinterpret_cast(FACEBOOK_URL_PROFILE)); + return 0; + } + + if (isOffline()) + return 0; + + if (MessageBox( 0, TranslateT("Are you sure?"), TranslateT("Delete contact from server list"), MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 ) != IDYES) + return 0; + + HANDLE hContact = reinterpret_cast(wParam); + + DBVARIANT dbv; + if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) ) + { + if (!isOffline()) { + std::string* id = new std::string(dbv.pszVal); + ForkThread( &FacebookProto::DeleteContactFromServer, this, ( void* )id ); + DBFreeVariant(&dbv); + + if ( !DBGetContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, 0) ) + DBWriteContactSettingDword(hContact, m_szModuleName, FACEBOOK_KEY_DELETED, ::time(NULL)); } else { - key = "ChatRoomID"; - url = FACEBOOK_URL_GROUP; +/* facebook_user fbu; + fbu.user_id = dbv.pszVal; + hContact = AddToContactList(&fbu); + + DBWriteContactSettingByte(hContact,m_szModuleName,FACEBOOK_KEY_DELETE_NEXT,1); + facy.client_notify(TranslateT("Contact will be deleted at next login."));*/ + NotifyEvent(TranslateT("Deleting contact"), TranslateT("Contact wasn't deleted, because you are not connected."), NULL, FACEBOOK_EVENT_OTHER, NULL); } + } - if ( !DBGetContactSettingString(hContact,m_szModuleName,key.c_str(),&dbv) ) - { - url += dbv.pszVal; - DBWriteContactSettingString(hContact,m_szModuleName,"Homepage",url.c_str()); + return 0; +} - CallService(MS_UTILS_OPENURL,1,reinterpret_cast(url.c_str())); +int FacebookProto::AddFriend(WPARAM wParam,LPARAM lParam) +{ + if (wParam == NULL) + { // self contact +// CallService(MS_UTILS_OPENURL,1,reinterpret_cast(FACEBOOK_URL_PROFILE)); + return 0; + } + + HANDLE hContact = reinterpret_cast(wParam); + + DBVARIANT dbv; + if( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv) ) + { + if (!isOffline()) { + std::string* id = new std::string(dbv.pszVal); + ForkThread( &FacebookProto::AddContactToServer, this, ( void* )id ); DBFreeVariant(&dbv); + } else { +/* facebook_user fbu; + fbu.user_id = dbv.pszVal; + hContact = AddToContactList(&fbu); + + DBWriteContactSettingByte(hContact,m_szModuleName,FACEBOOK_KEY_DELETE_NEXT,1); + facy.client_notify(TranslateT("Contact will be deleted at next login."));*/ + NotifyEvent(TranslateT("Adding contact"), TranslateT("Contact wasn't added, because you are not connected."), NULL, FACEBOOK_EVENT_OTHER, NULL); } - }*/ + } return 0; } diff --git a/FacebookRM/proto.h b/FacebookRM/proto.h index 7c70a56..b6fd3d8 100644 --- a/FacebookRM/proto.h +++ b/FacebookRM/proto.h @@ -124,6 +124,8 @@ public: int __cdecl GetAvatarInfo(WPARAM, LPARAM ); int __cdecl GetAvatarCaps(WPARAM, LPARAM ); int __cdecl VisitProfile(WPARAM, LPARAM ); + int __cdecl RemoveFriend(WPARAM, LPARAM ); + int __cdecl AddFriend(WPARAM, LPARAM ); // Events int __cdecl OnModulesLoaded(WPARAM, LPARAM); @@ -134,9 +136,9 @@ public: int __cdecl OnPreShutdown(WPARAM,LPARAM); int __cdecl OnPrebuildContactMenu(WPARAM,LPARAM); // TODO RM: Chat handling - /* int __cdecl OnChatOutgoing(WPARAM,LPARAM); + int __cdecl OnChatOutgoing(WPARAM,LPARAM); int __cdecl OnJoinChat(WPARAM,LPARAM); - int __cdecl OnLeaveChat(WPARAM,LPARAM);*/ + int __cdecl OnLeaveChat(WPARAM,LPARAM); // Loops bool NegotiateConnection(); @@ -146,6 +148,7 @@ public: // Processing threads void __cdecl ProcessBuddyList(void*); + void __cdecl ProcessFacepiles(void*); void __cdecl ProcessFriendList(void*); void __cdecl ProcessMessages(void*); void __cdecl ProcessUnreadMessages(void*); @@ -159,22 +162,26 @@ public: void __cdecl SetAwayMsgWorker(void*); void __cdecl UpdateAvatarWorker(void*); void __cdecl SendMsgWorker(void*); + void __cdecl SendChatMsgWorker(void*); void __cdecl SendTypingWorker(void*); void __cdecl MessagingWorker(void*); void __cdecl DeleteContactFromServer(void*); + void __cdecl AddContactToServer(void*); // Contacts handling bool IsMyContact(HANDLE, bool include_chat = false); HANDLE ContactIDToHContact(std::string); - HANDLE AddToContactList(facebook_user*, bool dont_check = false); + HANDLE AddToContactList(facebook_user*, bool dont_check = false, const char *new_name = ""); void SetAllContactStatuses(int); // TODO RM: Chats handling - /*void AddChat(const char *id,const char *name); - void UpdateChat(const facebook_user &update); - void AddChatContact(const char *name,const char *nick=0); - void DeleteChatContact(const char *name); - void SetChatStatus(int);*/ + void AddChat(const char *id, const char *name); + void UpdateChat(const char *chat_id, const char *id, const char *name, const char *message); + bool IsChatContact(const char *chat_id, const char *id); + void AddChatContact(const char *chat_id, const char *id, const char *name); + void RemoveChatContact(const char *chat_id, const char *id); + void SetChatStatus(const char *chat_id, int status); + char *GetChatUsers(const char *chat_id); // Connection client facebook_client facy; // TODO: Refactor to "client" and make dynamic diff --git a/FacebookRM/resource.h b/FacebookRM/resource.h index a9254bf..50a0638 100644 --- a/FacebookRM/resource.h +++ b/FacebookRM/resource.h @@ -4,6 +4,8 @@ // #define IDI_FACEBOOK 101 #define IDI_MIND 102 +#define IDI_ADDFRIEND 103 +#define IDI_REMOVEFRIEND 104 #define IDD_FACEBOOKACCOUNT 111 #define IDD_MIND 112 #define IDD_OPTIONS 113 @@ -11,27 +13,23 @@ #define IDC_UN 1001 #define IDC_PW 1002 #define IDC_NEWACCOUNTLINK 1003 -#define IDC_NAME 1011 #define IDC_MINDMSG 1012 #define IDC_CHARACTERS 1013 #define IDC_GROUP 1021 -#define IDC_AGENT 1022 -#define IDC_POLLRATE 1023 #define IDC_SECURE 1024 -#define IDC_CLOSE_WINDOWS 1025 -#define IDC_IGNORE_STATUS 1025 #define IDC_SET_IGNORE_STATUS 1025 -#define IDC_SECURE2 1026 #define IDC_SECURE_CHANNEL 1026 #define IDC_LOGGING 1027 -#define IDC_COOKIES 1028 -#define IDC_CLOSE_WINDOWS2 1028 #define IDC_DISCONNECT_CHAT 1028 -#define IDC_LOGGING2 1029 -#define IDC_UNREAD_MESSAGES 1029 #define IDC_PARSE_UNREAD 1029 -#define IDC_SET_IGNORE_STATUS2 1030 #define IDC_BIGGER_AVATARS 1030 +#define IDC_CLOSE_CHAT 1031 +#define IDC_CLOSE_WINDOWS 1031 +#define IDC_MAP_STATUSES 1032 +#define IDC_BIGGER_AVATARS2 1033 +#define IDC_LOAD_MOBILE 1033 +#define IDC_PARSE_UNREAD2 1034 +#define IDC_GROUPCHATS 1034 #define IDC_NOTIFICATIONS_ENABLE 1041 #define IDC_FEEDS_ENABLE 1042 #define IDC_OTHER_ENABLE 1043 @@ -59,7 +57,6 @@ #define IDC_SYSTRAY_NOTIFY 1098 #define IDC_PREVIEW 1099 #define IDC_SET_STATUS 1126 -#define IDC_FEEDS_TYPE 1201 #define IDC_FEED_TYPE 1201 // Next default values for new objects diff --git a/FacebookRM/theme.cpp b/FacebookRM/theme.cpp index 30f4513..6e919ae 100644 --- a/FacebookRM/theme.cpp +++ b/FacebookRM/theme.cpp @@ -32,16 +32,18 @@ extern OBJLIST g_Instances; struct { const char* name; - const char* descr; + char* descr; int defIconID; const char* section; } static const icons[] = { - { "facebook", LPGEN("Facebook Icon"), IDI_FACEBOOK }, - { "mind", LPGEN("Mind"), IDI_MIND }, + { "facebook", LPGEN("Facebook Icon"), IDI_FACEBOOK }, + { "mind", LPGEN("Mind"), IDI_MIND }, + { "removeFriend", LPGEN("Remove from server"), IDI_REMOVEFRIEND }, + { "addFriend", LPGEN("Request friendship"), IDI_ADDFRIEND }, - { "homepage", LPGEN("Visit Profile"), 0, "core_main_2" }, + { "homepage", LPGEN("Visit Profile"), 0, "core_main_2" }, }; static HANDLE hIconLibItem[SIZEOF(icons)]; @@ -98,8 +100,18 @@ HANDLE GetIconHandle(const char* name) return 0; } +char *GetIconDescription(const char* name) +{ + for(size_t i=0; iOnPrebuildContactMenu(wParam,lParam) : 0; } -HANDLE hHookPreBuildMenu,sVisitProfile; +HANDLE hHookPreBuildMenu,sVisitProfile,sAddFriend,sRemoveFriend; void InitContactMenus() { hHookPreBuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU,PrebuildContactMenu); @@ -141,11 +153,27 @@ void InitContactMenus() mi.position=-2000006000; mi.icolibItem = GetIconHandle("homepage"); - mi.pszName = LPGEN("Visit Profile"); + mi.pszName = GetIconDescription("homepage"); mi.pszService = "FacebookProto/VisitProfile"; sVisitProfile = CreateServiceFunction(mi.pszService,GlobalService<&FacebookProto::VisitProfile>); g_hMenuItems[1] = reinterpret_cast( CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi) ); + + mi.position=-2000006000; + mi.icolibItem = GetIconHandle("removeFriend"); + mi.pszName = GetIconDescription("removeFriend"); + mi.pszService = "FacebookProto/RemoveFriend"; + sRemoveFriend = CreateServiceFunction(mi.pszService,GlobalService<&FacebookProto::RemoveFriend>); + g_hMenuItems[2] = reinterpret_cast( + CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi) ); + + mi.position=-2000006000; + mi.icolibItem = GetIconHandle("addFriend"); + mi.pszName = GetIconDescription("addFriend"); + mi.pszService = "FacebookProto/AddFriend"; + sAddFriend = CreateServiceFunction(mi.pszService,GlobalService<&FacebookProto::AddFriend>); + g_hMenuItems[3] = reinterpret_cast( + CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi) ); } void UninitContactMenus() @@ -154,15 +182,17 @@ void UninitContactMenus() CallService(MS_CLIST_REMOVECONTACTMENUITEM,(WPARAM)g_hMenuItems[i],0); UnhookEvent(hHookPreBuildMenu); DestroyServiceFunction(sVisitProfile); + DestroyServiceFunction(sRemoveFriend); + DestroyServiceFunction(sAddFriend); } -void ShowContactMenus(bool show) +void ShowContactMenus(bool show, bool deleted) { for(size_t i=0; i(g_hMenuItems[i]), diff --git a/FacebookRM/theme.h b/FacebookRM/theme.h index 87db9d1..5eccc91 100644 --- a/FacebookRM/theme.h +++ b/FacebookRM/theme.h @@ -32,4 +32,4 @@ HANDLE GetIconHandle(const char *name); void InitContactMenus(void); void UninitContactMenus(void); -void ShowContactMenus(bool show); +void ShowContactMenus(bool show, bool deleted = false); diff --git a/FacebookRM/utils.cpp b/FacebookRM/utils.cpp index 096f1fa..5d32091 100644 --- a/FacebookRM/utils.cpp +++ b/FacebookRM/utils.cpp @@ -215,6 +215,9 @@ std::string utils::text::remove_html( std::string data ) if ( data.at(i) == '<' && data.at(i+1) != ' ' ) { i = data.find( ">", i ); + if (i == std::string::npos) + break; + continue; } @@ -269,6 +272,21 @@ std::string utils::text::trim( std::string data ) return (begin != std::string::npos) ? data.substr( begin, end - begin ) : ""; } +void utils::text::explode(std::string str, std::string separator, std::vector* results){ + std::string::size_type pos; + pos = str.find_first_of(separator); + while(pos != std::string::npos){ + if(pos > 0){ + results->push_back(str.substr(0,pos)); + } + str = str.substr(pos+1); + pos = str.find_first_of(separator); + } + if(str.length() > 0){ + results->push_back(str); + } +} + std::string utils::text::source_get_value( std::string* data, unsigned int argument_count, ... ) { va_list arg; diff --git a/FacebookRM/utils.h b/FacebookRM/utils.h index 0978283..f7fe1c8 100644 --- a/FacebookRM/utils.h +++ b/FacebookRM/utils.h @@ -95,6 +95,7 @@ namespace utils std::string trim( std::string data ); std::string source_get_value( std::string* data, unsigned int argument_count, ... ); std::string source_get_value2( std::string* data, const char *term, const char *endings); + void explode(std::string str, std::string separator, std::vector* results); }; namespace conversion -- cgit v1.2.3