diff options
author | George Hazan <ghazan@miranda.im> | 2019-12-28 21:13:56 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-12-28 21:13:56 +0300 |
commit | e768095692677d7095a4dd323295fc8ef595a283 (patch) | |
tree | e75f86be661b4a6dad2c79d19afc3dcfd276ea1c /protocols | |
parent | 8ae951ec9a7690cfe11e35e4d3026635a5ecb9ca (diff) |
FacebookRM deprecated and replaced with Facebook MQTT
Diffstat (limited to 'protocols')
66 files changed, 0 insertions, 11397 deletions
diff --git a/protocols/FacebookRM/CMakeLists.txt b/protocols/FacebookRM/CMakeLists.txt deleted file mode 100644 index 6441c53332..0000000000 --- a/protocols/FacebookRM/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -file(GLOB SOURCES "src/*.h" "src/requests/*.h" "src/*.cpp" "res/*.rc" "${CMAKE_SOURCE_DIR}/utils/std_string_utils.cpp") -set(TARGET Facebook) -include(${CMAKE_SOURCE_DIR}/cmake/plugin.cmake) -target_link_libraries(${TARGET} libjson) -add_subdirectory(proto_facebook)
\ No newline at end of file diff --git a/protocols/FacebookRM/facebook.vcxproj b/protocols/FacebookRM/facebook.vcxproj deleted file mode 100644 index 7abb3a804b..0000000000 --- a/protocols/FacebookRM/facebook.vcxproj +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <ProjectName>Facebook</ProjectName>
- <ProjectGuid>{DADE9455-DC28-465A-9604-2CA28052B9FB}</ProjectGuid>
- </PropertyGroup>
- <ImportGroup Label="PropertySheets">
- <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
- </ImportGroup>
- <ItemGroup>
- <ClCompile Include="..\..\utils\std_string_utils.cpp">
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- </ClCompile>
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\..\libs\libjson\libjson.vcxproj">
- <Project>{f6a9340e-b8d9-4c75-be30-47dc66d0abc7}</Project>
- </ProjectReference>
- </ItemGroup>
-</Project>
\ No newline at end of file diff --git a/protocols/FacebookRM/facebook.vcxproj.filters b/protocols/FacebookRM/facebook.vcxproj.filters deleted file mode 100644 index de5ad9f66c..0000000000 --- a/protocols/FacebookRM/facebook.vcxproj.filters +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
-</Project>
\ No newline at end of file diff --git a/protocols/FacebookRM/proto_facebook/CMakeLists.txt b/protocols/FacebookRM/proto_facebook/CMakeLists.txt deleted file mode 100644 index be5f194172..0000000000 --- a/protocols/FacebookRM/proto_facebook/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -set(TARGET Proto_Facebook) -include(${CMAKE_SOURCE_DIR}/cmake/icons.cmake)
\ No newline at end of file diff --git a/protocols/FacebookRM/proto_facebook/Proto_Facebook.vcxproj b/protocols/FacebookRM/proto_facebook/Proto_Facebook.vcxproj deleted file mode 100644 index efb464373d..0000000000 --- a/protocols/FacebookRM/proto_facebook/Proto_Facebook.vcxproj +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <ProjectName>Proto_Facebook</ProjectName>
- <ProjectGuid>{44298314-7DD4-4EF7-B576-30E503257223}</ProjectGuid>
- </PropertyGroup>
- <ImportGroup Label="PropertySheets">
- <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
- </ImportGroup>
-</Project>
\ No newline at end of file diff --git a/protocols/FacebookRM/proto_facebook/Proto_Facebook.vcxproj.filters b/protocols/FacebookRM/proto_facebook/Proto_Facebook.vcxproj.filters deleted file mode 100644 index e39f86d5d6..0000000000 --- a/protocols/FacebookRM/proto_facebook/Proto_Facebook.vcxproj.filters +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
-</Project>
\ No newline at end of file diff --git a/protocols/FacebookRM/proto_facebook/res/Away.ico b/protocols/FacebookRM/proto_facebook/res/Away.ico Binary files differdeleted file mode 100644 index 4c3987b76c..0000000000 --- a/protocols/FacebookRM/proto_facebook/res/Away.ico +++ /dev/null diff --git a/protocols/FacebookRM/proto_facebook/res/Invisible.ico b/protocols/FacebookRM/proto_facebook/res/Invisible.ico Binary files differdeleted file mode 100644 index caff5b5e3d..0000000000 --- a/protocols/FacebookRM/proto_facebook/res/Invisible.ico +++ /dev/null diff --git a/protocols/FacebookRM/proto_facebook/res/Offline.ico b/protocols/FacebookRM/proto_facebook/res/Offline.ico Binary files differdeleted file mode 100644 index ec0c820259..0000000000 --- a/protocols/FacebookRM/proto_facebook/res/Offline.ico +++ /dev/null diff --git a/protocols/FacebookRM/proto_facebook/res/Online.ico b/protocols/FacebookRM/proto_facebook/res/Online.ico Binary files differdeleted file mode 100644 index 07170ab5be..0000000000 --- a/protocols/FacebookRM/proto_facebook/res/Online.ico +++ /dev/null diff --git a/protocols/FacebookRM/proto_facebook/res/Proto_Facebook.rc b/protocols/FacebookRM/proto_facebook/res/Proto_Facebook.rc deleted file mode 100644 index 05200253dc..0000000000 --- a/protocols/FacebookRM/proto_facebook/res/Proto_Facebook.rc +++ /dev/null @@ -1,73 +0,0 @@ -// Microsoft Visual C++ generated resource script.
-//
-#include "..\src\resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// Russian (Russia) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
-LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "..\\src\\resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_ICON1 ICON "Offline.ico"
-IDI_ICON2 ICON "Online.ico"
-IDI_ICON3 ICON "Away.ico"
-IDI_ICON4 ICON "Invisible.ico"
-
-#endif // Russian (Russia) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/protocols/FacebookRM/proto_facebook/src/resource.h b/protocols/FacebookRM/proto_facebook/src/resource.h deleted file mode 100644 index 9cb62d9a84..0000000000 --- a/protocols/FacebookRM/proto_facebook/src/resource.h +++ /dev/null @@ -1,19 +0,0 @@ -//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Proto_Facebook.rc
-//
-#define IDI_ICON1 105
-#define IDI_ICON2 104
-#define IDI_ICON3 128
-#define IDI_ICON4 130
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 106
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1001
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
diff --git a/protocols/FacebookRM/res/angry.ico b/protocols/FacebookRM/res/angry.ico Binary files differdeleted file mode 100644 index 212b152a68..0000000000 --- a/protocols/FacebookRM/res/angry.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/conversation.ico b/protocols/FacebookRM/res/conversation.ico Binary files differdeleted file mode 100644 index 5542ea51db..0000000000 --- a/protocols/FacebookRM/res/conversation.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/facebook.ico b/protocols/FacebookRM/res/facebook.ico Binary files differdeleted file mode 100644 index 5808707d59..0000000000 --- a/protocols/FacebookRM/res/facebook.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/facebook.rc b/protocols/FacebookRM/res/facebook.rc deleted file mode 100644 index 8b8482f16e..0000000000 --- a/protocols/FacebookRM/res/facebook.rc +++ /dev/null @@ -1,374 +0,0 @@ -// Microsoft Visual C++ generated resource script.
-//
-#include "..\src\resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "winres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (United States) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "..\\src\\resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#include ""winres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_FACEBOOK ICON "facebook.ico"
-
-IDI_MIND ICON "mind.ico"
-
-IDI_POKE ICON "poke.ico"
-
-IDI_NOTIFICATION ICON "notification.ico"
-
-IDI_NEWSFEED ICON "feeds.ico"
-
-IDI_FRIENDS ICON "friends.ico"
-
-IDI_CONVERSATION ICON "conversation.ico"
-
-IDI_READ ICON "read.ico"
-
-IDI_MEMORIES ICON "memories.ico"
-
-IDI_ANGRY ICON "angry.ico"
-
-IDI_HAHA ICON "haha.ico"
-
-IDI_LIKE ICON "like.ico"
-
-IDI_LOVE ICON "love.ico"
-
-IDI_SAD ICON "sad.ico"
-
-IDI_WOW ICON "wow.ico"
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_FACEBOOKACCOUNT DIALOGEX 0, 0, 186, 134
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- LTEXT "E-mail:",IDC_STATIC,6,0,46,12,0,WS_EX_RIGHT
- EDITTEXT IDC_UN,56,0,122,12,ES_AUTOHSCROLL
- LTEXT "Password:",IDC_STATIC,6,16,46,12,0,WS_EX_RIGHT
- EDITTEXT IDC_PW,56,16,122,12,ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Create a new Facebook account",IDC_NEWACCOUNTLINK,
- "Hyperlink",WS_TABSTOP,6,40,172,12
-END
-
-IDD_MIND DIALOGEX 0, 0, 418, 113
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "What's on your mind?"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Wall:",IDC_STATIC,4,7,44,8,0,WS_EX_RIGHT
- COMBOBOX IDC_WALL,53,4,79,14,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Visibility:",IDC_STATIC,140,6,40,8,0,WS_EX_RIGHT
- COMBOBOX IDC_PRIVACY,186,4,77,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Text:",IDC_STATIC,4,23,44,8,0,WS_EX_RIGHT
- EDITTEXT IDC_MINDMSG,53,21,210,36,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
- LTEXT "URL:",IDC_STATIC,4,63,44,8,0,WS_EX_RIGHT
- EDITTEXT IDC_URL,53,60,210,14,ES_AUTOHSCROLL
- LTEXT "Place:",IDC_STATIC,4,80,44,8,0,WS_EX_RIGHT
- EDITTEXT IDC_PLACE,53,77,210,14,ES_AUTOHSCROLL
- PUSHBUTTON "Contacts >>",IDC_EXPAND,202,94,61,15
- GROUPBOX "Attach contacts:",IDC_CCLIST_LABEL,266,4,148,105
- CONTROL "",IDC_CCLIST,"CListControl",WS_TABSTOP | 0x16f,268,17,143,90
- DEFPUSHBUTTON "Share",IDOK,53,94,54,15
- PUSHBUTTON "Cancel",IDCANCEL,110,94,44,15
-END
-
-IDD_OPTIONS DIALOGEX 0, 0, 305, 195
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- GROUPBOX "User details",IDC_STATIC,7,7,291,62
- LTEXT "E-mail:",IDC_STATIC,17,20,61,8,0,WS_EX_RIGHT
- EDITTEXT IDC_UN,84,18,123,13,ES_AUTOHSCROLL
- LTEXT "Password:",IDC_STATIC,17,36,61,8,0,WS_EX_RIGHT
- EDITTEXT IDC_PW,84,34,123,13,ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Create a new Facebook account",IDC_NEWACCOUNTLINK,
- "Hyperlink",WS_TABSTOP,84,53,189,10
- GROUPBOX "Contacts",IDC_STATIC,7,77,291,103
- LTEXT "Default group:",IDC_STATIC,17,91,61,8,0,WS_EX_RIGHT
- EDITTEXT IDC_GROUP,84,89,123,13,ES_AUTOHSCROLL
- CONTROL "Automatically set 'Ignore status change' flag",IDC_SET_IGNORE_STATUS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,107,271,10
- CONTROL "Use bigger avatars",IDC_BIGGER_AVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,120,271,10
- CONTROL "Prefer real names instead of nicknames",IDC_NAME_AS_NICK,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,134,271,10
- CONTROL "Load also Messenger contacts at login (not only Facebook friends)",IDC_LOAD_ALL_CONTACTS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,148,271,10
- CONTROL "Use Invisible status for Facebook Pages (instead of Offline)",IDC_PAGES_ALWAYS_ONLINE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,163,271,10
-END
-
-IDD_OPTIONS_EVENTS DIALOGEX 0, 0, 305, 227
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- GROUPBOX "Popup notifications",IDC_STATIC,6,7,292,118
- CONTROL "Show notifications",IDC_NOTIFICATIONS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,23,272,8
- CONTROL "Show wall posts (news feed) (WARNING: Causes excessive network traffic!)",IDC_FEEDS_ENABLE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,36,272,8
- RTEXT "News feed types to notify:",IDC_STATIC,46,48,137,8
- COMBOBOX IDC_FEED_TYPE,191,46,97,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- CONTROL "Don't show advertising posts",IDC_FILTER_ADS,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_RIGHT | WS_TABSTOP,46,63,242,8
- CONTROL "Show friendships changes (when someone removes/approves you)",IDC_FRIENDSHIP_ENABLE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,79,272,8
- CONTROL "Show real-time friends activity (ticker feed)",IDC_TICKER_ENABLE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,93,272,8
- CONTROL "Show my ""On this day"" posts at login",IDC_ON_THIS_DAY_ENABLE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,108,272,8
- GROUPBOX "Chatroom logging",IDC_STATIC,6,130,292,33
- CONTROL "Log notifications into special chatroom",IDC_NOTIFICATIONS_CHATROOM,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,145,272,8
- GROUPBOX "Extra",IDC_STATIC,6,169,292,46
- CONTROL "Use balloon notifications in system tray instead of popups",IDC_SYSTRAY_NOTIFY,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,183,272,8
- RTEXT "Use this server for opening links:",IDC_STATIC,16,199,167,8
- COMBOBOX IDC_URL_SERVER,191,196,97,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-END
-
-IDD_OPTIONS_STATUSES DIALOGEX 0, 0, 308, 226
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- GROUPBOX "Statuses",IDC_STATIC,7,7,294,73
- CONTROL "Post Miranda statuses to Wall",IDC_SET_STATUS,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,13,21,281,10
- CONTROL "Turn off chat on Facebook when going to offline in Miranda",IDC_DISCONNECT_CHAT,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,281,10
- CONTROL "Map unsupported statuses to Invisible (instead of Away)",IDC_MAP_STATUSES,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,47,281,10
- CONTROL "Allow posting statuses to my pages (may slow down login)",IDC_LOAD_PAGES,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,61,281,10
- GROUPBOX "Advanced",IDC_STATIC,7,85,294,67
- CONTROL "Send typing notifications even when Invisible",IDC_TYPING_WHEN_INVISIBLE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,98,281,10
- LTEXT "Typing is one way how user is determined active. If you don't want to be seen ""active 1 min ago"" on Facebook, uncheck this option and also don't interact with website at all. Sending messages from Miranda should be ok, but don't 100% rely on it either.",IDC_STATIC,32,112,262,39
-END
-
-IDD_CAPTCHAFORM DIALOGEX 0, 0, 258, 224
-STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-CAPTION "Bots challenge test"
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- EDITTEXT IDC_VALUE,4,203,137,14,ES_AUTOHSCROLL
- CONTROL "",IDC_WHITERECT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,0,0,258,25
- LTEXT "Instruction:",IDC_TITLE,7,7,243,8,NOT WS_GROUP
- EDITTEXT IDC_INSTRUCTION,17,16,233,8,ES_MULTILINE | ES_READONLY | NOT WS_BORDER
- CONTROL "",IDC_FRAME1,"Static",SS_ETCHEDHORZ,0,26,258,1
- CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,197,258,1
- DEFPUSHBUTTON "Submit",IDOK,146,203,50,14
- PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14
-END
-
-IDD_OPTIONS_MESSAGING DIALOGEX 0, 0, 308, 226
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 0, 0, 0x1
-BEGIN
- GROUPBOX "Messages",IDC_STATIC,7,7,294,43
- CONTROL "Keep messages as unread on server (don't send ""seen"" info)",IDC_KEEP_UNREAD,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,281,10
- CONTROL "Show stickers as custom smileys (EXPERIMENTAL)",IDC_CUSTOM_SMILEYS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,281,10
- GROUPBOX "Multi user chats",IDC_STATIC,7,56,294,57
- CONTROL "Enable multi user chats support",IDC_ENABLE_CHATS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,69,281,10
- CONTROL "Do not open chat windows on creation",IDC_HIDE_CHATS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,83,281,10
- CONTROL "Automatically join active chats that exist in contact list",IDC_JOIN_EXISTING_CHATS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,97,281,10
- GROUPBOX "History synchronization",IDC_STATIC,7,121,294,44
- CONTROL "Load last messages on opening message window (EXPERIMENTAL)",IDC_MESSAGES_ON_OPEN,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,134,281,10
- RTEXT "Number of messages to load:",IDC_STATIC,13,148,231,8
- EDITTEXT IDC_MESSAGES_COUNT,249,145,34,14,ES_AUTOHSCROLL
- CONTROL "",IDC_MESSAGES_COUNT_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,283,145,11,14
-END
-
-IDD_GUARD DIALOGEX 0, 0, 285, 104
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Facebook Login Approval"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Your security settings requires to input a security code to access your account from unknown browsers.\n\nYou can get the code via Facebook application on your phone or click button below to receive it via SMS.",IDC_STATIC,7,7,264,54
- PUSHBUTTON "Send SMS",IDC_SEND_SMS,7,84,59,15
- EDITTEXT IDC_TEXT,7,65,264,12,ES_AUTOHSCROLL | ES_NUMBER
- DEFPUSHBUTTON "OK",IDOK,159,84,50,14
- PUSHBUTTON "Cancel",IDCANCEL,221,84,50,14
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
-BEGIN
- IDD_FACEBOOKACCOUNT, DIALOG
- BEGIN
- VERTGUIDE, 6
- VERTGUIDE, 52
- VERTGUIDE, 56
- VERTGUIDE, 178
- END
-
- IDD_MIND, DIALOG
- BEGIN
- LEFTMARGIN, 4
- RIGHTMARGIN, 414
- VERTGUIDE, 48
- VERTGUIDE, 53
- VERTGUIDE, 132
- VERTGUIDE, 160
- VERTGUIDE, 210
- VERTGUIDE, 214
- VERTGUIDE, 263
- TOPMARGIN, 4
- BOTTOMMARGIN, 109
- HORZGUIDE, 21
- HORZGUIDE, 40
- HORZGUIDE, 57
- HORZGUIDE, 94
- HORZGUIDE, 109
- END
-
- IDD_OPTIONS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- VERTGUIDE, 17
- VERTGUIDE, 31
- VERTGUIDE, 78
- VERTGUIDE, 84
- VERTGUIDE, 207
- VERTGUIDE, 288
- VERTGUIDE, 298
- TOPMARGIN, 7
- BOTTOMMARGIN, 188
- END
-
- IDD_OPTIONS_EVENTS, DIALOG
- BEGIN
- LEFTMARGIN, 6
- RIGHTMARGIN, 298
- VERTGUIDE, 16
- VERTGUIDE, 46
- VERTGUIDE, 183
- VERTGUIDE, 191
- VERTGUIDE, 288
- TOPMARGIN, 7
- BOTTOMMARGIN, 219
- END
-
- IDD_OPTIONS_STATUSES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 301
- VERTGUIDE, 13
- VERTGUIDE, 32
- VERTGUIDE, 152
- VERTGUIDE, 156
- VERTGUIDE, 294
- TOPMARGIN, 7
- BOTTOMMARGIN, 224
- END
-
- IDD_OPTIONS_MESSAGING, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 301
- VERTGUIDE, 13
- VERTGUIDE, 32
- VERTGUIDE, 152
- VERTGUIDE, 156
- VERTGUIDE, 294
- TOPMARGIN, 7
- BOTTOMMARGIN, 224
- END
-
- IDD_GUARD, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 284
- VERTGUIDE, 271
- TOPMARGIN, 7
- BOTTOMMARGIN, 94
- HORZGUIDE, 84
- END
-END
-#endif // APSTUDIO_INVOKED
-
-//
-// AFX_DIALOG_LAYOUT
-//
-IDD_OPTIONS_STATUSES AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-#endif // English (United States) resources
-/////////////////////////////////////////////////////////////////////////////
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/protocols/FacebookRM/res/feeds.ico b/protocols/FacebookRM/res/feeds.ico Binary files differdeleted file mode 100644 index 99feff90f5..0000000000 --- a/protocols/FacebookRM/res/feeds.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/friends.ico b/protocols/FacebookRM/res/friends.ico Binary files differdeleted file mode 100644 index d883108db7..0000000000 --- a/protocols/FacebookRM/res/friends.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/haha.ico b/protocols/FacebookRM/res/haha.ico Binary files differdeleted file mode 100644 index fca966b859..0000000000 --- a/protocols/FacebookRM/res/haha.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/like.ico b/protocols/FacebookRM/res/like.ico Binary files differdeleted file mode 100644 index bd19c39de2..0000000000 --- a/protocols/FacebookRM/res/like.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/love.ico b/protocols/FacebookRM/res/love.ico Binary files differdeleted file mode 100644 index feea230b45..0000000000 --- a/protocols/FacebookRM/res/love.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/memories.ico b/protocols/FacebookRM/res/memories.ico Binary files differdeleted file mode 100644 index d216611b8a..0000000000 --- a/protocols/FacebookRM/res/memories.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/mind.ico b/protocols/FacebookRM/res/mind.ico Binary files differdeleted file mode 100644 index f158842429..0000000000 --- a/protocols/FacebookRM/res/mind.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/notification.ico b/protocols/FacebookRM/res/notification.ico Binary files differdeleted file mode 100644 index 7f29a97b16..0000000000 --- a/protocols/FacebookRM/res/notification.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/poke.ico b/protocols/FacebookRM/res/poke.ico Binary files differdeleted file mode 100644 index e77400a61f..0000000000 --- a/protocols/FacebookRM/res/poke.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/read.ico b/protocols/FacebookRM/res/read.ico Binary files differdeleted file mode 100644 index 91e9b72370..0000000000 --- a/protocols/FacebookRM/res/read.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/sad.ico b/protocols/FacebookRM/res/sad.ico Binary files differdeleted file mode 100644 index 3584d1f385..0000000000 --- a/protocols/FacebookRM/res/sad.ico +++ /dev/null diff --git a/protocols/FacebookRM/res/version.rc b/protocols/FacebookRM/res/version.rc deleted file mode 100644 index 5a5ddd63ed..0000000000 --- a/protocols/FacebookRM/res/version.rc +++ /dev/null @@ -1,9 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#ifdef APSTUDIO_INVOKED -#error this file is not editable by Microsoft Visual C++ -#endif //APSTUDIO_INVOKED - -#include "..\src\version.h" - -#include "..\..\build\Version.rc" diff --git a/protocols/FacebookRM/res/wow.ico b/protocols/FacebookRM/res/wow.ico Binary files differdeleted file mode 100644 index 8d9052ffd9..0000000000 --- a/protocols/FacebookRM/res/wow.ico +++ /dev/null diff --git a/protocols/FacebookRM/src/avatars.cpp b/protocols/FacebookRM/src/avatars.cpp deleted file mode 100644 index af553cd948..0000000000 --- a/protocols/FacebookRM/src/avatars.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "stdafx.h"
-
-bool FacebookProto::GetDbAvatarInfo(PROTO_AVATAR_INFORMATION &pai, std::string *url)
-{
- ptrA id(getStringA(pai.hContact, FACEBOOK_KEY_ID));
- if (id == nullptr)
- return false;
-
- if (url) {
- *url = FACEBOOK_URL_PICTURE;
- utils::text::replace_first(url, "%s", std::string(id));
- }
-
- std::wstring filename = GetAvatarFolder() + L'\\' + std::wstring(_A2T(id)) + L".jpg";
-
- wcsncpy_s(pai.filename, filename.c_str(), _TRUNCATE);
- pai.format = ProtoGetAvatarFormat(pai.filename);
- return true;
-}
-
-void FacebookProto::CheckAvatarChange(MCONTACT hContact, const std::string &image_url)
-{
- std::wstring::size_type pos = image_url.rfind("/");
-
- // Facebook contacts always have some avatar - keep avatar in database even if we have loaded empty one (e.g. for 'On Mobile' contacts)
- if (image_url.empty() || pos == std::wstring::npos)
- return;
-
- // Get name of image
- std::string image_name = image_url.substr(pos + 1);
-
- // Remove eventual parameters from name
- pos = image_name.rfind("?");
- if (pos != std::wstring::npos)
- image_name = image_name.substr(0, pos);
-
- // Append our parameters to allow comparing for avatar/settings change
- if (getBool(FACEBOOK_KEY_BIG_AVATARS, DEFAULT_BIG_AVATARS))
- image_name += "?big";
-
- // Check for avatar change
- ptrA old_name(getStringA(hContact, FACEBOOK_KEY_AVATAR));
- bool update_required = (old_name == nullptr || image_name.compare(old_name) != 0);
-
- // TODO: Remove this in some newer version
- if (old_name == nullptr) {
- // Remove AvatarURL value, which was used in previous versions of plugin
- delSetting(hContact, "AvatarURL");
- }
-
- if (update_required)
- setString(hContact, FACEBOOK_KEY_AVATAR, image_name.c_str());
-
- if (!hContact) {
- PROTO_AVATAR_INFORMATION ai = { 0 };
- if (GetAvatarInfo(update_required ? GAIF_FORCE : 0, (LPARAM)&ai) != GAIR_WAITFOR)
- ReportSelfAvatarChanged();
- }
- else if (update_required) {
- db_set_b(hContact, "ContactPhoto", "NeedUpdate", 1);
- ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, nullptr);
- }
-}
-
-void FacebookProto::UpdateAvatarWorker(void *)
-{
- HNETLIBCONN nlc = nullptr;
-
- debugLogA("*** UpdateAvatarWorker");
-
- std::string params = getBool(FACEBOOK_KEY_BIG_AVATARS, DEFAULT_BIG_AVATARS) ? "?width=200&height=200" : "?width=80&height=80";
-
- for (;;) {
- std::string url;
- PROTO_AVATAR_INFORMATION ai = { 0 };
- ai.hContact = avatar_queue[0];
-
- if (Miranda_IsTerminated()) {
- debugLogA("*** Terminating avatar update early: %s", url.c_str());
- break;
- }
-
- if (GetDbAvatarInfo(ai, &url)) {
- debugLogA("*** Updating avatar: %s", url.c_str());
- bool success = facy.save_url(url + params, ai.filename, nlc);
-
- if (ai.hContact)
- ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, success ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)&ai);
- else if (success)
- ReportSelfAvatarChanged();
- }
-
- mir_cslock s(avatar_lock_);
- avatar_queue.erase(avatar_queue.begin());
- if (avatar_queue.empty())
- break;
- }
- Netlib_CloseHandle(nlc);
-}
-
-std::wstring FacebookProto::GetAvatarFolder()
-{
- wchar_t path[MAX_PATH];
- mir_snwprintf(path, L"%s\\%s", VARSW(L"%miranda_avatarcache%"), m_tszUserName);
- return path;
-}
-
-INT_PTR FacebookProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
-{
- int res = 0;
-
- switch (wParam) {
- case AF_MAXSIZE:
- ((POINT*)lParam)->x = -1;
- ((POINT*)lParam)->y = -1;
- break;
-
- case AF_FORMATSUPPORTED:
- res = (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF);
- break;
-
- case AF_DELAYAFTERFAIL:
- res = 10 * 60 * 1000;
- break;
-
- case AF_ENABLED:
- case AF_FETCHIFPROTONOTVISIBLE:
- case AF_FETCHIFCONTACTOFFLINE:
- res = 1;
- break;
- }
-
- return res;
-}
-
-INT_PTR FacebookProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam)
-{
- if (!lParam)
- return GAIR_NOAVATAR;
-
- PROTO_AVATAR_INFORMATION* pai = (PROTO_AVATAR_INFORMATION*)lParam;
- if (GetDbAvatarInfo(*pai, nullptr)) {
- bool fileExist = _waccess(pai->filename, 0) == 0;
-
- bool needLoad;
- if (pai->hContact)
- needLoad = (wParam & GAIF_FORCE) && (!fileExist || db_get_b(pai->hContact, "ContactPhoto", "NeedUpdate", 0));
- else
- needLoad = (wParam & GAIF_FORCE) || !fileExist;
-
- if (needLoad) {
- debugLogA("*** Starting avatar request thread for %s", _T2A(pai->filename));
- mir_cslock s(avatar_lock_);
-
- if (std::find(avatar_queue.begin(), avatar_queue.end(), pai->hContact) == avatar_queue.end()) {
- bool is_empty = avatar_queue.empty();
- avatar_queue.push_back(pai->hContact);
- if (is_empty)
- ForkThread(&FacebookProto::UpdateAvatarWorker, nullptr);
- }
- return GAIR_WAITFOR;
- }
- else if (fileExist)
- return GAIR_SUCCESS;
-
- }
- return GAIR_NOAVATAR;
-}
-
-INT_PTR FacebookProto::GetMyAvatar(WPARAM wParam, LPARAM lParam)
-{
- debugLogA("*** GetMyAvatar");
-
- if (!wParam || !lParam)
- return -3;
-
- wchar_t* buf = (wchar_t*)wParam;
- int size = (int)lParam;
-
- PROTO_AVATAR_INFORMATION ai = { 0 };
- switch (GetAvatarInfo(0, (LPARAM)&ai)) {
- case GAIR_SUCCESS:
- wcsncpy(buf, ai.filename, size);
- buf[size - 1] = 0;
- return 0;
-
- case GAIR_WAITFOR:
- return -1;
-
- default:
- return -2;
- }
-}
diff --git a/protocols/FacebookRM/src/captcha.cpp b/protocols/FacebookRM/src/captcha.cpp deleted file mode 100644 index 23226857c4..0000000000 --- a/protocols/FacebookRM/src/captcha.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" -#include "resource.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// Captcha form - -struct CAPTCHA_FORM_PARAMS -{ - HBITMAP bmp; - int w, h; - char Result[100]; -}; - -static INT_PTR CALLBACK CaptchaFormDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CAPTCHA_FORM_PARAMS *params = (CAPTCHA_FORM_PARAMS*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - Window_SetIcon_IcoLib(hwndDlg, Skin_GetIconHandle(SKINICON_OTHER_KEYS)); - params = (CAPTCHA_FORM_PARAMS*)lParam; - - SetDlgItemText(hwndDlg, IDC_INSTRUCTION, TranslateT("Enter the text you see")); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)params); - return TRUE; - - case WM_CTLCOLORSTATIC: - switch (GetWindowLongPtr((HWND)lParam, GWL_ID)) { - case IDC_WHITERECT: - case IDC_INSTRUCTION: - case IDC_TITLE: - return (INT_PTR)GetStockObject(WHITE_BRUSH); - } - return 0; - - case WM_PAINT: - if (params) { - PAINTSTRUCT ps; - HDC hdc, hdcMem; - RECT rc; - - GetClientRect(hwndDlg, &rc); - hdc = BeginPaint(hwndDlg, &ps); - hdcMem = CreateCompatibleDC(hdc); - HGDIOBJ hOld = SelectObject(hdcMem, params->bmp); - - int y = (rc.bottom + rc.top - params->h) / 2; - int x = (rc.right + rc.left - params->w) / 2; - BitBlt(hdc, x, y, params->w, params->h, hdcMem, 0, 0, SRCCOPY); - SelectObject(hdcMem, hOld); - DeleteDC(hdcMem); - - EndPaint(hwndDlg, &ps); - } - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hwndDlg, 0); - return TRUE; - - case IDOK: - GetDlgItemTextA(hwndDlg, IDC_VALUE, params->Result, _countof(params->Result)); - EndDialog(hwndDlg, 1); - return TRUE; - } - break; - - case WM_CLOSE: - EndDialog(hwndDlg, 0); - break; - - case WM_DESTROY: - Window_FreeIcon_IcoLib(hwndDlg); - break; - } - return FALSE; -} - -bool FacebookProto::RunCaptchaForm(std::string captchaUrl, std::string &result) -{ - debugLogA(" RunCaptchaForm: reading picture from %s", captchaUrl.c_str()); - result.clear(); - - NETLIBHTTPREQUEST req = { sizeof(req) }; - req.requestType = REQUEST_GET; - req.szUrl = (char*)captchaUrl.c_str(); - req.flags = NLHRF_NODUMPHEADERS; - - NETLIBHTTPREQUEST *reply = Netlib_HttpTransaction(facy.handle_, &req); - if (reply == nullptr) - return false; - - if (reply->resultCode != HTTP_CODE_OK) { - debugLogA(" RunCaptchaForm: failed with code %d", reply->resultCode); - return false; - } - - CAPTCHA_FORM_PARAMS param = {}; - param.bmp = Image_LoadFromMem(reply->pData, reply->dataLength, FIF_UNKNOWN); - - BITMAP bmp = { 0 }; - GetObject(param.bmp, sizeof(bmp), &bmp); - param.w = bmp.bmWidth; - param.h = bmp.bmHeight; - int res = DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_CAPTCHAFORM), nullptr, CaptchaFormDlgProc, (LPARAM)¶m); - if (res == 0) - return false; - - debugLogA(" RunCaptchaForm: user entered text %s", param.Result); - result = param.Result; - return true; -} diff --git a/protocols/FacebookRM/src/channel.cpp b/protocols/FacebookRM/src/channel.cpp deleted file mode 100644 index ba4a9c21e2..0000000000 --- a/protocols/FacebookRM/src/channel.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// receiving updates, sending activity ping - -HttpRequest* facebook_client::channelRequest(facebook_client::Type type) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FORMAT, FACEBOOK_SERVER_CHAT, - chat_conn_num_.empty() ? "0" : chat_conn_num_.c_str(), - chat_channel_host_.c_str(), - (type == PULL) ? "pull" : "active_ping"); - - if (type == PULL) { - p->timeout = 65 * 1000; - p->Persistent = p->CHANNEL; - } - - bool isPing = (type == PING); - - p << CHAR_PARAM("channel", chat_channel_.empty() ? ("p_" + self_.user_id).c_str() : chat_channel_.c_str()); - if (!isPing) - p << CHAR_PARAM("seq", chat_sequence_num_.empty() ? "0" : chat_sequence_num_.c_str()); - - p << CHAR_PARAM("partition", chat_channel_partition_.empty() ? "0" : chat_channel_partition_.c_str()) - << CHAR_PARAM("clientid", chat_clientid_.c_str()) - << CHAR_PARAM("cb", utils::text::rand_string(4, "0123456789abcdefghijklmnopqrstuvwxyz", &random_).c_str()); - - int idleSeconds = parent->IdleSeconds(); - p << INT_PARAM("idle", idleSeconds); // Browser is sending "idle" always, even if it's "0" - - if (!isPing) { - p << CHAR_PARAM("qp", "y") << CHAR_PARAM("pws", "fresh") << INT_PARAM("isq", 487632); - p << INT_PARAM("msgs_recv", chat_msgs_recv_); - // TODO: sometimes there is &tur=1711 and &qpmade=<some actual timestamp> and &isq=487632 - // Url << "request_batch=1"; // it somehow batches up more responses to one - then response has special "t=batched" type and "batches" array with the data - // Url << "msgr_region=LLA"; // it was here only for first pull, same as request_batch - } - - p << INT_PARAM("cap", 8) // TODO: what's this item? Sometimes it's 0, sometimes 8 - << CHAR_PARAM("uid", self_.user_id.c_str()) - << CHAR_PARAM("viewer_uid", self_.user_id.c_str()); - - if (!chat_sticky_num_.empty() && !chat_sticky_pool_.empty()) { - p << CHAR_PARAM("sticky_token", chat_sticky_num_.c_str()); - p << CHAR_PARAM("sticky_pool", chat_sticky_pool_.c_str()); - } - - if (!isPing && !chat_traceid_.empty()) - p << CHAR_PARAM("traceid", chat_traceid_.c_str()); - - if (parent->isInvisible()) - p << CHAR_PARAM("state", "offline"); - else if (isPing || idleSeconds < 60) - p << CHAR_PARAM("state", "active"); - - return p; -} diff --git a/protocols/FacebookRM/src/chat.cpp b/protocols/FacebookRM/src/chat.cpp deleted file mode 100644 index 2cbc2423d4..0000000000 --- a/protocols/FacebookRM/src/chat.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" -#include <m_history.h> -#include <m_userinfo.h> - -enum ChatMenuItems -{ - IDM_INVITE = 10, IDM_EXIT, IDM_DESTROY, - - IDM_DETAILS = 20, IDM_HISTORY -}; - -static const struct gc_item LogMenuItems[] = -{ - { LPGENW("&Invite user..."), IDM_INVITE, MENU_ITEM, FALSE }, - { LPGENW("E&xit chat session"), IDM_EXIT, MENU_ITEM, FALSE }, - { LPGENW("&Destroy chat session"), IDM_DESTROY, MENU_ITEM, FALSE }, -}; - -static const struct gc_item NickMenuItems[] = -{ - { LPGENW("User &details"), IDM_DETAILS, MENU_ITEM, FALSE }, - { LPGENW("User &history"), IDM_HISTORY, MENU_ITEM, FALSE }, -}; - -void FacebookProto::UpdateChat(const char *chat_id, const char *id, const char *name, const char *message, DWORD timestamp, bool is_old) -{ - // replace % to %% to not interfere with chat color codes - std::string smessage = message; - utils::text::replace_all(&smessage, "%", "%%"); - - GCEVENT gce = { m_szModuleName, chat_id, GC_EVENT_MESSAGE }; - gce.pszText.a = smessage.c_str(); - gce.time = timestamp ? timestamp : ::time(0); - if (id != nullptr) - gce.bIsMe = !mir_strcmp(id, facy.self_.user_id.c_str()); - gce.dwFlags = GCEF_ADDTOLOG | GCEF_UTF8; - if (is_old) { - gce.dwFlags |= GCEF_NOTNOTIFY; - gce.dwFlags &= ~GCEF_ADDTOLOG; - } - gce.pszNick.a = name; - gce.pszUID.a = id; - Chat_Event(&gce); - - facy.erase_reader(ChatIDToHContact(chat_id)); -} - -void FacebookProto::RenameChat(const char *chat_id, const char *name) -{ - Chat_ChangeSessionName(m_szModuleName, _A2T(chat_id), Utf2T(name)); -} - -int FacebookProto::OnGCEvent(WPARAM, LPARAM lParam) -{ - GCHOOK *hook = reinterpret_cast<GCHOOK*>(lParam); - if (mir_strcmp(hook->pszModule, m_szModuleName)) - return 0; - - // Ignore for special chatrooms - if (!mir_wstrcmp(hook->ptszID, _A2W(FACEBOOK_NOTIFICATIONS_CHATROOM))) - return 0; - - switch (hook->iType) { - case GC_USER_MESSAGE: - if (isOnline()) { - debugLogA(" > Chat - Outgoing message"); - std::string msg = _T2A(hook->ptszText, CP_UTF8); - std::string chat_id = _T2A(hook->ptszID, CP_UTF8); - ForkThread(&FacebookProto::SendChatMsgWorker, new send_chat(chat_id, msg)); - } - break; - - case GC_USER_PRIVMESS: - { - facebook_user fbu; - fbu.user_id = _T2A(hook->ptszUID, CP_UTF8); - - // Find this contact in list or add new temporary contact - MCONTACT hContact = AddToContactList(&fbu, false, true); - if (!hContact) - break; - - CallService(MS_MSG_SENDMESSAGEW, hContact); - } - break; - - case GC_USER_LOGMENU: - switch (hook->dwData) { - case IDM_INVITE: - break; - - case IDM_EXIT: - { - std::string thread_id = _T2A(hook->ptszID, CP_UTF8); - auto it = facy.chat_rooms.find(thread_id); - if (it != facy.chat_rooms.end()) - facy.sendRequest(facy.exitThreadRequest(it->second)); - } - break; - - case IDM_DESTROY: - { - std::string thread_id = _T2A(hook->ptszID, CP_UTF8); - auto it = facy.chat_rooms.find(thread_id); - if (it != facy.chat_rooms.end()) - if (IDOK == MessageBoxW(nullptr, TranslateT("Delete conversation"), TranslateT("This will permanently delete the conversation history"), MB_OKCANCEL)) - facy.sendRequest(facy.destroyThreadRequest(it->second)); - } - } - break; - - case GC_USER_NICKLISTMENU: - MCONTACT hContact = 0; - if (hook->dwData == 10 || hook->dwData == 20) { - facebook_user fbu; - fbu.user_id = _T2A(hook->ptszUID, CP_UTF8); - - // Find this contact in list or add new temporary contact - hContact = AddToContactList(&fbu, false, true); - if (!hContact) - break; - } - - switch (hook->dwData) { - case IDM_DETAILS: - CallService(MS_USERINFO_SHOWDIALOG, hContact); - break; - - case IDM_HISTORY: - CallService(MS_HISTORY_SHOWCONTACTHISTORY, hContact); - break; - } - - break; - } - - return 0; -} - -void FacebookProto::AddChatContact(const char *chat_id, const chatroom_participant &user, bool addToLog) -{ - // Don't add user if it's already there - if (IsChatContact(chat_id, user.user_id.c_str())) - return; - - GCEVENT gce = { m_szModuleName, chat_id, GC_EVENT_JOIN }; - gce.dwFlags = GCEF_UTF8 + (addToLog ? GCEF_ADDTOLOG : 0); - gce.pszNick.a = user.nick.c_str(); - gce.pszUID.a = user.user_id.c_str(); - gce.time = ::time(0); - gce.bIsMe = (user.role == ROLE_ME); - - if (user.is_former) { - gce.pszStatus.a = TranslateU("Former"); - } - else { - switch (user.role) { - case ROLE_ME: - gce.pszStatus.a = TranslateU("Myself"); - break; - case ROLE_FRIEND: - gce.pszStatus.a = TranslateU("Friend"); - break; - case ROLE_NONE: - gce.pszStatus.a = TranslateU("User"); - break; - } - } - - Chat_Event(&gce); -} - -void FacebookProto::RemoveChatContact(const char *chat_id, const char *id, const char *name) -{ - GCEVENT gce = { m_szModuleName, chat_id, GC_EVENT_PART }; - gce.dwFlags = GCEF_UTF8 + GCEF_ADDTOLOG; - gce.pszNick.a = name; - gce.pszUID.a = id; - gce.time = ::time(0); - gce.bIsMe = false; - - Chat_Event(&gce); -} - -/** Caller must free result */ -char *FacebookProto::GetChatUsers(const char *chat_id) -{ - ptrW ptszChatID(mir_a2u(chat_id)); - - GC_INFO gci = {}; - gci.Flags = GCF_USERS; - gci.pszModule = m_szModuleName; - gci.pszID = ptszChatID; - Chat_GetInfo(&gci); - - // mir_free(gci.pszUsers); - return gci.pszUsers; -} - -bool FacebookProto::IsChatContact(const char *chat_id, const char *id) -{ - ptrA users(GetChatUsers(chat_id)); - return (users != nullptr && strstr(users, id) != nullptr); -} - -void FacebookProto::AddChat(const char *id, const wchar_t *tname) -{ - ptrW tid(mir_a2u(id)); - - // Create the group chat session - SESSION_INFO *si = Chat_NewSession(GCW_PRIVMESS, m_szModuleName, tid, tname); - if (!si) - return; - - // Send setting events - Chat_AddGroup(si, TranslateT("Myself")); - Chat_AddGroup(si, TranslateT("Friend")); - Chat_AddGroup(si, TranslateT("User")); - Chat_AddGroup(si, TranslateT("Former")); - - // Finish initialization - bool hideChats = getBool(FACEBOOK_KEY_HIDE_CHATS, DEFAULT_HIDE_CHATS); - Chat_Control(m_szModuleName, tid, (hideChats ? WINDOW_HIDDEN : SESSION_INITDONE)); - Chat_Control(m_szModuleName, tid, SESSION_ONLINE); -} - -INT_PTR FacebookProto::OnJoinChat(WPARAM hContact, LPARAM) -{ - if (isOffline() || facy.dtsg_.empty() || !m_enableChat || IsSpecialChatRoom(hContact)) - return 0; - - ptrW idT(getWStringA(hContact, "ChatRoomID")); - ptrA threadId(getStringA(hContact, FACEBOOK_KEY_TID)); - - if (!idT || !threadId) - return 0; - - facebook_chatroom *fbc; - std::string thread_id = threadId; - - auto it = facy.chat_rooms.find(thread_id); - if (it != facy.chat_rooms.end()) - fbc = it->second; - else { - // We don't have this chat loaded in memory yet, lets load some info (name, list of users) - fbc = new facebook_chatroom(thread_id); - LoadChatInfo(fbc); - facy.chat_rooms.insert(std::make_pair(thread_id, fbc)); - - // Update loaded info about this chat - setByte(hContact, FACEBOOK_KEY_CHAT_CAN_REPLY, fbc->can_reply); - setByte(hContact, FACEBOOK_KEY_CHAT_READ_ONLY, fbc->read_only); - setByte(hContact, FACEBOOK_KEY_CHAT_IS_ARCHIVED, fbc->is_archived); - setByte(hContact, FACEBOOK_KEY_CHAT_IS_SUBSCRIBED, fbc->is_subscribed); - } - - // RM TODO: better use check if chatroom exists/is in db/is online... no? - // like: if (ChatIDToHContact(thread_id) == nullptr) { - ptrA users(GetChatUsers(thread_id.c_str())); - if (users == nullptr) { - // Add chatroom - AddChat(fbc->thread_id.c_str(), fbc->chat_name.c_str()); - - // Add chat contacts - for (auto &jt : fbc->participants) - AddChatContact(fbc->thread_id.c_str(), jt.second, false); - - // Load last messages - delSetting(hContact, FACEBOOK_KEY_MESSAGE_ID); // We're creating new chatroom so we want load all recent messages - ForkThread(&FacebookProto::LoadLastMessages, new MCONTACT(hContact)); - } - - return 0; -} - -INT_PTR FacebookProto::OnLeaveChat(WPARAM wParam, LPARAM) -{ - ptrW idT(wParam ? getWStringA(wParam, "ChatRoomID") : nullptr); - - Chat_Control(m_szModuleName, idT, SESSION_OFFLINE); - Chat_Terminate(m_szModuleName, idT); - - if (!wParam) - facy.clear_chatrooms(); - else if (!IsSpecialChatRoom(wParam)) { - ptrA threadId(getStringA(wParam, FACEBOOK_KEY_TID)); - if (!threadId) - return 0; - - auto it = facy.chat_rooms.find(std::string(threadId)); - if (it != facy.chat_rooms.end()) { - delete it->second; - facy.chat_rooms.erase(it); - } - } - - return 0; -} - -int FacebookProto::OnGCMenuHook(WPARAM, LPARAM lParam) -{ - GCMENUITEMS *gcmi = (GCMENUITEMS*)lParam; - if (mir_strcmp(gcmi->pszModule, m_szModuleName)) - return 0; - - if (gcmi->Type == MENU_ON_LOG) - Chat_AddMenuItems(gcmi->hMenu, _countof(LogMenuItems), LogMenuItems, &g_plugin); - else if (gcmi->Type == MENU_ON_NICKLIST) - Chat_AddMenuItems(gcmi->hMenu, _countof(NickMenuItems), NickMenuItems, &g_plugin); - return 0; -} - -bool FacebookProto::IsSpecialChatRoom(MCONTACT hContact) -{ - if (!isChatRoom(hContact)) - return false; - - ptrA id(getStringA(hContact, "ChatRoomID")); - return id && !mir_strcmp(id, FACEBOOK_NOTIFICATIONS_CHATROOM); -} - -void FacebookProto::PrepareNotificationsChatRoom() -{ - if (!getBool(FACEBOOK_KEY_NOTIFICATIONS_CHATROOM, DEFAULT_NOTIFICATIONS_CHATROOM)) - return; - - // Prepare notifications chatroom if not exists - MCONTACT hNotificationsChatRoom = ChatIDToHContact(FACEBOOK_NOTIFICATIONS_CHATROOM); - if (hNotificationsChatRoom == 0 || getDword(hNotificationsChatRoom, "Status", ID_STATUS_OFFLINE) != ID_STATUS_ONLINE) { - wchar_t nameT[200]; - mir_snwprintf(nameT, L"%s: %s", m_tszUserName, TranslateT("Notifications")); - - // Create the group chat session - Chat_NewSession(GCW_PRIVMESS, m_szModuleName, _A2W(FACEBOOK_NOTIFICATIONS_CHATROOM), nameT); - - // Send setting events - Chat_Control(m_szModuleName, _A2W(FACEBOOK_NOTIFICATIONS_CHATROOM), WINDOW_HIDDEN); - Chat_Control(m_szModuleName, _A2W(FACEBOOK_NOTIFICATIONS_CHATROOM), SESSION_ONLINE); - } -} - -void FacebookProto::UpdateNotificationsChatRoom(facebook_notification *notification) -{ - if (!getBool(FACEBOOK_KEY_NOTIFICATIONS_CHATROOM, DEFAULT_NOTIFICATIONS_CHATROOM)) - return; - - std::stringstream text; - text << notification->text << "\n\n" << PrepareUrl(notification->link); - - std::string message = text.str(); - utils::text::replace_all(&message, "%", "%%"); - - GCEVENT gce = { m_szModuleName, FACEBOOK_NOTIFICATIONS_CHATROOM, GC_EVENT_MESSAGE }; - gce.pszText.a = message.c_str(); - gce.time = notification->time ? notification->time : ::time(0); - gce.bIsMe = false; - gce.dwFlags = GCEF_UTF8 + GCEF_ADDTOLOG; - gce.pszNick.a = TranslateU("Notifications"); - gce.pszUID.a = FACEBOOK_NOTIFICATIONS_CHATROOM; - Chat_Event(&gce); -} - -std::string FacebookProto::GenerateChatName(facebook_chatroom *fbc) -{ - std::string name = ""; - unsigned int namesUsed = 0; - - for (auto &it : fbc->participants) { - std::string participant = it.second.nick; - - // Ignore self contact, empty and numeric only participant names - if (it.second.role == ROLE_ME || participant.empty() || participant.find_first_not_of("0123456789") == std::string::npos) - continue; - - if (namesUsed > 0) - name += ", "; - - name += utils::text::prepare_name(participant, false); - - if (++namesUsed >= FACEBOOK_CHATROOM_NAMES_COUNT) - break; - } - - // Participants.size()-1 because we ignore self contact - if (fbc->participants.size() - 1 > namesUsed) { - wchar_t more[200]; - mir_snwprintf(more, TranslateT("%s and more (%d)"), fbc->chat_name.c_str(), fbc->participants.size() - 1 - namesUsed); // -1 because we ignore self contact - fbc->chat_name = more; - } - - // If there are no participants to create a name from, use just thread_id - if (name.empty()) - name = fbc->thread_id.c_str(); - - return name; -} - -void FacebookProto::LoadParticipantsNames(facebook_chatroom *fbc) -{ - std::vector<std::string> namelessIds; - - // TODO: We could load all names from server at once by skipping this for cycle and using namelessIds as all in participants list, but we would lost our local names of our contacts. But maybe that's not a problem? - for (auto &it : fbc->participants) { - const char *id = it.first.c_str(); - chatroom_participant &user = it.second; - - if (!user.loaded) { - if (!mir_strcmp(id, facy.self_.user_id.c_str())) { - user.nick = facy.self_.real_name; - user.role = ROLE_ME; - user.loaded = true; - } - else { - MCONTACT hContact = ContactIDToHContact(id); - if (hContact != 0) { - DBVARIANT dbv; - if (!getStringUtf(hContact, FACEBOOK_KEY_NICK, &dbv)) { - user.nick = dbv.pszVal; - db_free(&dbv); - } - if (user.role == ROLE_NONE) { - int type = getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE); - if (type == CONTACT_FRIEND) - user.role = ROLE_FRIEND; - else - user.role = ROLE_NONE; - } - user.loaded = true; - } - - if (!user.loaded) - namelessIds.push_back(id); - } - } - } - - if (!namelessIds.empty()) { - // we have some contacts without name, let's load them all from the server - - LIST<char> userIds(1); - for (std::string::size_type i = 0; i < namelessIds.size(); i++) - userIds.insert(mir_strdup(namelessIds.at(i).c_str())); - - http::response resp = facy.sendRequest(facy.userInfoRequest(userIds)); - - FreeList(userIds); - userIds.destroy(); - - if (resp.code == HTTP_CODE_OK) { - // TODO: We can cache these results and next time (e.g. for different chatroom) we can use that already cached names - if (EXIT_SUCCESS == ParseChatParticipants(&resp.data, &fbc->participants)) - debugLogA("*** Participant names processed"); - else - debugLogA("*** Error processing participant names"); - } - } -} - -void FacebookProto::JoinChatrooms() -{ - for (auto &hContact : AccContacts()) { - if (!isChatRoom(hContact)) - continue; - - // Ignore archived and unsubscribed chats - if (getBool(hContact, FACEBOOK_KEY_CHAT_IS_ARCHIVED, false) || !getBool(hContact, FACEBOOK_KEY_CHAT_IS_SUBSCRIBED, true)) - continue; - - OnJoinChat(hContact, 0); - } -} - -void FacebookProto::LoadChatInfo(facebook_chatroom *fbc) -{ - if (isOffline()) - return; - - // request info about chat thread - http::response resp = facy.sendRequest(facy.threadInfoRequest(true, fbc->thread_id.c_str())); - if (resp.code != HTTP_CODE_OK) { - facy.handle_error("LoadChatInfo"); - return; - } - - if (ParseChatInfo(&resp.data, fbc) == EXIT_SUCCESS) { - // Load missing participants names - LoadParticipantsNames(fbc); - - // If chat has no name, create name from participants list - if (fbc->chat_name.empty()) { - std::string newName = GenerateChatName(fbc); - fbc->chat_name = _A2T(newName.c_str(), CP_UTF8); - } - - debugLogA("*** Chat thread info processed"); - } - else debugLogA("*** Error processing chat thread info"); - - facy.handle_success("LoadChatInfo"); -} - -int FacebookProto::ParseChatInfo(std::string *data, facebook_chatroom* fbc) -{ - size_t len = data->find("\r\n"); - if (len != data->npos) - data->erase(len); - - JSONNode root = JSONNode::parse(data->c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &thread = root["o0"]["data"]["message_thread"]; - if (!thread) - return EXIT_FAILURE; - - const JSONNode &thread_fbid_ = thread["thread_key"]["thread_fbid"]; - const JSONNode &name_ = thread["name"]; - if (!thread_fbid_) - return EXIT_FAILURE; - - std::string tid = "id." + thread_fbid_.as_string(); - if (fbc->thread_id != tid) - return EXIT_FAILURE; - - chatroom_participant user; - user.is_former = false; - user.role = ROLE_NONE; - const JSONNode &participants = thread["all_participants"]["nodes"]; - for (auto &jt : participants) { - user.user_id = jt["messaging_actor"]["id"].as_string(); - fbc->participants.insert(std::make_pair(user.user_id, user)); - } - - fbc->can_reply = thread["can_reply"].as_bool(); - fbc->is_archived = thread["has_viewer_archived"].as_bool(); - fbc->is_subscribed = thread["is_viewer_subscribed"].as_bool(); - fbc->read_only = thread["read_only"].as_bool(); - fbc->chat_name = std::wstring(ptrW(mir_utf8decodeW(name_.as_string().c_str()))); - return EXIT_SUCCESS; -} diff --git a/protocols/FacebookRM/src/client.h b/protocols/FacebookRM/src/client.h deleted file mode 100644 index 07aac1af67..0000000000 --- a/protocols/FacebookRM/src/client.h +++ /dev/null @@ -1,271 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "constants.h"
-
-#pragma once
-
-#define FORCE_DISCONNECT 1
-#define FORCE_QUIT 2
-
-class facebook_client
-{
-public:
-
- ////////////////////////////////////////////////////////////
- // Client definition
-
- facebook_client()
- {
- }
-
- HNETLIBCONN hChannelCon;
- HNETLIBCONN hMessagesCon;
- HNETLIBCONN hFcbCon;
- mir_cs fcb_conn_lock_;
-
- // Random generator value for this client
-
- unsigned int random_ = 0;
-
- // Parent handle
-
- FacebookProto *parent = nullptr;
-
- // User data
-
- facebook_user self_;
-
- std::string username_;
- std::string password_;
-
- std::string dtsg_;
- std::string ttstamp_;
- std::string logout_hash_;
- std::string chat_channel_;
- std::string chat_channel_host_;
- std::string chat_channel_partition_;
- std::string chat_sequence_num_;
- std::string chat_reconnect_reason_;
- std::string chat_sticky_num_;
- std::string chat_sticky_pool_;
- std::string chat_conn_num_;
- std::string chat_clientid_;
- std::string chat_traceid_;
- time_t last_feeds_update_ = 0;
- time_t last_notification_time_ = 0;
- volatile unsigned int msgid_ = 0;
- int chat_msgs_recv_ = 0;
- volatile unsigned int chat_req_ = 0;
-
- bool mbasicWorks = true;
-
- ////////////////////////////////////////////////////////////
- // Client vs protocol communication
-
- void client_notify(const wchar_t *message);
- void info_notify(const wchar_t *message);
-
- ////////////////////////////////////////////////////////////
- // Cookies, Data storage
-
- mir_cs cookies_lock_;
-
- std::map<std::string, std::string> cookies;
- std::map<std::string, std::string> pages;
- std::map<std::string, facebook_chatroom*> chat_rooms;
- std::map<std::string, facebook_notification*> notifications;
-
- // Contact/thread id caches
- std::map<std::string, std::string> thread_id_to_user_id;
- std::map<std::string, MCONTACT> chat_id_to_hcontact;
- std::map<std::string, MCONTACT> user_id_to_hcontact;
-
- std::string get_server_type();
- std::string get_privacy_type();
-
- std::set<MCONTACT> ignore_read;
- std::set<MCONTACT> typers; // store info about typing contacts, because Facebook doesn't send "stopped typing" event when there is actual message being sent
- std::map<MCONTACT, time_t> readers;
-
- char* load_cookies();
- void store_headers(http::response* resp, NETLIBHTTPHEADER* headers, int headers_count);
- void clear_cookies();
- void clear_notifications();
- void clear_chatrooms();
- void clear_readers();
- void insert_reader(MCONTACT, time_t, const std::string &readerId = "");
- void erase_reader(MCONTACT);
-
- ////////////////////////////////////////////////////////////
-
- // Connection handling
-
- unsigned int error_count_ = 0;
-
- bool handle_entry(const std::string &method);
- bool handle_success(const std::string &method);
- bool handle_error(const std::string &method, int force_disconnect = 0);
-
- void __inline increment_error() { this->error_count_++; }
- void __inline decrement_error() { if (error_count_ > 0) error_count_--; }
- void __inline reset_error() { error_count_ = 0; }
-
- ////////////////////////////////////////////////////////////
-
- // Helpers for data
-
- __inline const char *__dyn() const {
- return "7AzkXxaA4ojgDxyLqzGomzEbHGbGey8WhLFwgoqwWhE98nwgUaoepovHyodEbbxW4E4u3ucDBwJx62i2PxOcG4K1Zxa2m4oqyUf8oCK251G6XDwnU567oeo5m4pHxC326U6OfBwHx";
- // FIXME: What's this value and where it come from? Looks like it is the same through all requests.
- }
-
- __inline CMStringA __req() {
- // Increment request number and convert it to string with radix 36 (whole numbers + whole alphabet)
- char buffer[10];
- itoa(InterlockedIncrement(&this->chat_req_), buffer, 36);
- return CMStringA(buffer);
- }
-
- __inline const char *__rev() const {
- return "3553943";
- }
-
- ////////////////////////////////////////////////////////////
- // Login handling
-
- bool login(const char *username, const char *password);
- bool logout();
- bool sms_code(const char *fb_dtsg);
-
- ////////////////////////////////////////////////////////////
- // Session handling
-
- bool home();
- bool reconnect();
- bool chat_state(bool online = true);
-
- ////////////////////////////////////////////////////////////
- // Updates handling
-
- mir_cs send_message_lock_;
- mir_cs notifications_lock_;
-
- ////////////////////////////////////////////////////////////
- // Messages handling
-
- std::map<std::string, int> messages_ignore;
- std::map<int, time_t> messages_timestamp;
-
- bool loading_history = false;
- mir_cs loading_history_lock_;
-
- bool channel();
- bool activity_ping();
- int send_message(int seqid, MCONTACT, const std::string &message_text, std::string *error_text, const std::string &captchaPersistData = "", const std::string &captcha = "");
-
- ////////////////////////////////////////////////////////////
- // Status handling
-
- bool post_status(status_data *data);
-
- ////////////////////////////////////////////////////////////
- // HTTP communication
-
- http::response sendRequest(class HttpRequest *request);
- bool save_url(const std::string &url, const std::wstring &filename, HNETLIBCONN &nlc);
-
- // channel.cpp
- enum Type { PULL, PING };
- HttpRequest* channelRequest(Type type);
-
- // contacts.cpp
- HttpRequest* addFriendRequest(const char *userId);
- HttpRequest* deleteFriendRequest(const char *userId);
- HttpRequest* getFriendshipsRequest();
- HttpRequest* answerFriendshipRequest(const char *userId, bool bConfirm);
- HttpRequest* cancelFriendshipRequest(const char *userId);
-
- HttpRequest* userInfoRequest(const LIST<char> &userIds);
- HttpRequest* userInfoAllRequest();
- HttpRequest* buddylistUpdate();
-
- // feeds.cpp
- HttpRequest* newsfeedRequest();
- HttpRequest* memoriesRequest();
-
- // history.cpp
- HttpRequest* threadInfoRequest(bool isChat, const char *id, const char* timestamp = nullptr, int limit = -1, bool loadMessages = false);
- HttpRequest* threadInfoRequest(const LIST<char> &ids, int limit);
- HttpRequest* unreadThreadsRequest();
-
- // login.cpp
- HttpRequest* loginRequest();
- HttpRequest* loginRequest(const char *username, const char *password, const char *urlData, const char *bodyData);
- HttpRequest* logoutRequest();
- HttpRequest* loginSmsRequest(const char *dtsg);
- HttpRequest* setupMachineRequest();
- HttpRequest* setupMachineRequest(const char *dtsg, const char *nh, const char *submit);
-
- // messages.cpp
- HttpRequest* sendMessageRequest(const char *userId, const char *threadId, const char *messageId, const char *messageText, bool isChat, const char *captcha, const char *captchaPersistData);
- HttpRequest* sendTypingRequest(const char *userId, bool isChat, bool isTyping);
- HttpRequest* markMessageReadRequest(const LIST<char> &ids);
-
- HttpRequest* destroyThreadRequest(facebook_chatroom *fbc);
- HttpRequest* exitThreadRequest(facebook_chatroom *fbc);
-
- // notifications.cpp
- HttpRequest* getNotificationsRequest(int count);
- HttpRequest* markNotificationReadRequest(const char *id);
-
- // profile.cpp
- HttpRequest* homeRequest();
- HttpRequest* dtsgRequest();
- HttpRequest* profileRequest(const char *data);
- HttpRequest* profileInfoRequest(const char *userId);
- HttpRequest* profilePictureRequest(const char *userId);
-
- // search.cpp
- HttpRequest* searchRequest(const char *query, int s, int pn, const char *ssid);
-
- // status.cpp
- HttpRequest* reconnectRequest();
- HttpRequest* setVisibilityRequest(bool online);
-
- // utils.cpp
- HttpRequest* linkScraperRequest(status_data *status);
- HttpRequest* refreshCaptchaRequest(const char *captchaPersistData);
- HttpRequest* getPagesRequest();
- HttpRequest* switchIdentityRequest(const char *userId);
- HttpRequest* sharePostRequest(status_data *status, const char *linkData);
- HttpRequest* sendPokeRequest(const char *userId);
-
- ////////////////////////////////////////////////////////////
- // Netlib handle
-
- HNETLIBUSER handle_ = nullptr;
- void set_handle(HNETLIBUSER h)
- {
- handle_ = h;
- }
-};
diff --git a/protocols/FacebookRM/src/communication.cpp b/protocols/FacebookRM/src/communication.cpp deleted file mode 100644 index 3b9f97d235..0000000000 --- a/protocols/FacebookRM/src/communication.cpp +++ /dev/null @@ -1,1151 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -void facebook_client::client_notify(const wchar_t *message) -{ - parent->NotifyEvent(parent->m_tszUserName, message, 0, EVENT_CLIENT); -} - -void facebook_client::info_notify(const wchar_t *message) -{ - parent->NotifyEvent(parent->m_tszUserName, message, 0, EVENT_OTHER); -} - -http::response facebook_client::sendRequest(HttpRequest *request) -{ - http::response resp; - - if (parent->isOffline()) { - resp.code = HTTP_CODE_FAKE_OFFLINE; - return resp; - } - - // Check and append user defined locale if request doesn't have it forced already - if (!parent->m_locale.empty() && request->m_szUrl.Find("&locale=") == -1) - request << CHAR_PARAM("locale", parent->m_locale.c_str()); - - request->AddHeader("Accept-Language", "en,en-US;q=0.9"); - request->AddHeader("Accept", "*/*"); - request->AddHeader("User-Agent", Netlib_GetUserAgent()); - request->AddHeader("Cookie", ptrA(load_cookies())); // FIXME: Rework load_cookies to not do strdup - - if (request->requestType == REQUEST_POST) - request->AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); - - mir_cslockfull s(fcb_conn_lock_); s.unlock(); - - // Set persistent connection (or not) - switch (request->Persistent) { - case HttpRequest::PersistentType::NONE: - request->nlc = nullptr; - request->flags &= ~NLHRF_PERSISTENT; - break; - case HttpRequest::PersistentType::CHANNEL: - request->nlc = hChannelCon; - request->flags |= NLHRF_PERSISTENT; - break; - case HttpRequest::PersistentType::MESSAGES: - request->nlc = hMessagesCon; - request->flags |= NLHRF_PERSISTENT; - break; - case HttpRequest::PersistentType::DEFAULT: - s.lock(); - request->nlc = hFcbCon; - request->flags |= NLHRF_PERSISTENT; - break; - } - - parent->debugLogA("@@@ Sending request to '%s'", request->m_szUrl.c_str()); - - // Send the request - NLHR_PTR pnlhr(request->Send(handle_)); - - // Remember the persistent connection handle (or not) - switch (request->Persistent) { - case HttpRequest::PersistentType::NONE: - break; - case HttpRequest::PersistentType::CHANNEL: - hChannelCon = pnlhr ? pnlhr->nlc : nullptr; - break; - case HttpRequest::PersistentType::MESSAGES: - hMessagesCon = pnlhr ? pnlhr->nlc : nullptr; - break; - case HttpRequest::PersistentType::DEFAULT: - s.unlock(); - hFcbCon = pnlhr ? pnlhr->nlc : nullptr; - break; - } - - // Check and copy response data - if (pnlhr != nullptr) { - parent->debugLogA("@@@ Got response with code %d", pnlhr->resultCode); - store_headers(&resp, pnlhr->headers, pnlhr->headersCount); - resp.code = pnlhr->resultCode; - resp.data = pnlhr->pData ? pnlhr->pData : ""; - } - else { - parent->debugLogA("!!! No response from server (time-out)"); - resp.code = HTTP_CODE_FAKE_DISCONNECTED; - // Better to have something set explicitely as this value is compaired in all communication requests - } - - // Get Facebook's error message - if (resp.code == HTTP_CODE_OK) { - std::string::size_type pos = resp.data.find("\"error\":"); - if (pos != std::string::npos) { - pos += 8; - int error_num = atoi(resp.data.substr(pos, resp.data.find(",", pos) - pos).c_str()); - if (error_num != 0) { - std::string error; - - pos = resp.data.find("\"errorDescription\":\"", pos); - if (pos != std::string::npos) { - pos += 20; - - std::string::size_type pos2 = resp.data.find("\",\"", pos); - if (pos2 == std::string::npos) - pos2 = resp.data.find("\"", pos); - - error = resp.data.substr(pos, pos2 - pos); - error = utils::text::trim(utils::text::html_entities_decode(utils::text::remove_html(utils::text::slashu_to_utf8(error)))); - error = ptrA(mir_utf8decodeA(error.c_str())); - } - - std::string title; - pos = resp.data.find("\"errorSummary\":\"", pos); - if (pos != std::string::npos) { - pos += 16; - title = resp.data.substr(pos, resp.data.find("\"", pos) - pos); - title = utils::text::trim(utils::text::html_entities_decode(utils::text::remove_html(utils::text::slashu_to_utf8(title)))); - title = ptrA(mir_utf8decodeA(title.c_str())); - } - - bool silent = resp.data.find("\"silentError\":1") != std::string::npos; - - resp.error_number = error_num; - resp.error_text = error; - resp.error_title = title; - resp.code = HTTP_CODE_FAKE_ERROR; - - parent->debugLogA("!!! Received Facebook error: %d -- %s", error_num, error.c_str()); - if (request->NotifyErrors && !silent) - client_notify(_A2T(error.c_str())); - } - } - } - - // Delete the request object - delete request; - - return resp; -} - -bool facebook_client::handle_entry(const std::string &method) -{ - parent->debugLogA(" >> Entering %s()", method.c_str()); - return true; -} - -bool facebook_client::handle_success(const std::string &method) -{ - parent->debugLogA(" << Quitting %s()", method.c_str()); - reset_error(); - return true; -} - -bool facebook_client::handle_error(const std::string &method, int action) -{ - increment_error(); - parent->debugLogA("!!! %s(): Something with Facebook went wrong", method.c_str()); - - bool result = (error_count_ <= (UINT)parent->getByte(FACEBOOK_KEY_TIMEOUTS_LIMIT, FACEBOOK_TIMEOUTS_LIMIT)); - if (action == FORCE_DISCONNECT || action == FORCE_QUIT) - result = false; - - if (!result) { - reset_error(); - - if (action != FORCE_QUIT) - parent->SetStatus(ID_STATUS_OFFLINE); - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////// - -std::string facebook_client::get_server_type() -{ - BYTE server_type = parent->getByte(FACEBOOK_KEY_SERVER_TYPE, 0); - if (server_type >= _countof(server_types)) - server_type = 0; - return server_types[server_type].id; -} - -std::string facebook_client::get_privacy_type() -{ - BYTE privacy_type = parent->getByte(FACEBOOK_KEY_PRIVACY_TYPE, 0); - if (privacy_type >= _countof(privacy_types)) - privacy_type = 0; - return privacy_types[privacy_type].id; -} - - -char* facebook_client::load_cookies() -{ - mir_cslock s(cookies_lock_); - - std::string cookieString; - - if (!cookies.empty()) - for (auto &iter : cookies) { - cookieString.append(iter.first); - cookieString.append(1, '='); - cookieString.append(iter.second); - cookieString.append(1, ';'); - } - - return mir_strdup(cookieString.c_str()); -} - -void facebook_client::store_headers(http::response* resp, NETLIBHTTPHEADER* headers, int headersCount) -{ - mir_cslock c(cookies_lock_); - - for (int i = 0; i < headersCount; i++) { - std::string header_name = headers[i].szName; - std::string header_value = headers[i].szValue; - - if (header_name == "Set-Cookie") { - std::string::size_type pos = header_value.find("="); - std::string cookie_name = header_value.substr(0, pos); - std::string cookie_value = header_value.substr(pos + 1, header_value.find(";", pos) - pos - 1); - - if (cookie_value == "deleted") - cookies.erase(cookie_name); - else - cookies[cookie_name] = cookie_value; - } - else resp->headers[header_name] = header_value; - } -} - -void facebook_client::clear_cookies() -{ - mir_cslock s(cookies_lock_); - - if (!cookies.empty()) - cookies.clear(); -} - -void facebook_client::clear_notifications() -{ - mir_cslock s(notifications_lock_); - - for (auto &it : notifications) { - if (it.second->hWndPopup != nullptr) - PUDeletePopup(it.second->hWndPopup); // close popup - - delete it.second; - } - - notifications.clear(); -} - -void facebook_client::clear_chatrooms() -{ - for (auto &it : chat_rooms) - delete it.second; - - chat_rooms.clear(); -} - -/** - * Clears readers info for all contacts from readers list and db - */ -void facebook_client::clear_readers() -{ - for (auto &it : readers) { - if (parent->isChatRoom(it.first)) - parent->delSetting(it.first, FACEBOOK_KEY_MESSAGE_READERS); - - parent->delSetting(it.first, FACEBOOK_KEY_MESSAGE_READ); - } - readers.clear(); -} - -/** - * Inserts info to readers list, db and writes to statusbar - */ -void facebook_client::insert_reader(MCONTACT hContact, time_t timestamp, const std::string &readerId) -{ - if (!hContact) - return; - - if (parent->isChatRoom(hContact)) { - std::string tid = ptrA(parent->getStringA(hContact, "ChatRoomID")); - - std::string name = readerId; - - // get name of this participant from chatroom's participants list - auto itRoom = chat_rooms.find(tid); - if (itRoom != chat_rooms.end()) { - facebook_chatroom *chatroom = itRoom->second; - std::map<std::string, chatroom_participant> participants = chatroom->participants; - - // try to get name of this participant - auto participant = participants.find(readerId); - if (participant != participants.end()) - name = participant->second.nick; - } - - std::wstring treaders; - - // Load old readers - ptrW told(parent->getWStringA(hContact, FACEBOOK_KEY_MESSAGE_READERS)); - if (told) - treaders = std::wstring(told) + L", "; - - // Append new reader name and remember them - std::string reader = utils::text::prepare_name(name, true); - treaders += _A2T(reader.c_str(), CP_UTF8); - parent->setWString(hContact, FACEBOOK_KEY_MESSAGE_READERS, treaders.c_str()); - } - - parent->setDword(hContact, FACEBOOK_KEY_MESSAGE_READ, timestamp); - readers.insert(std::make_pair(hContact, timestamp)); - parent->MessageRead(hContact); - if (g_bMessageState) { - MessageReadData data(timestamp, MRD_TYPE_READTIME); - CallService(MS_MESSAGESTATE_UPDATE, hContact, (LPARAM)&data); - } -} - -/** - * Removes info from readers list, db and clears statusbar - */ -void facebook_client::erase_reader(MCONTACT hContact) -{ - if (parent->isChatRoom(hContact)) - parent->delSetting(hContact, FACEBOOK_KEY_MESSAGE_READERS); - - parent->delSetting(hContact, FACEBOOK_KEY_MESSAGE_READ); - - readers.erase(hContact); - Srmm_SetStatusText(hContact, nullptr); -} - -void loginError(FacebookProto *proto, std::string error_str) -{ - utils::text::replace_all(&error_str, "<br \\/>", "\n"); - utils::text::replace_all(&error_str, "\n\n\n", "\n\n"); - - error_str = utils::text::trim( - utils::text::html_entities_decode( - utils::text::remove_html(error_str))); - - proto->debugLogA("!!! Login error: %s", !error_str.empty() ? error_str.c_str() : "Unknown error"); - - wchar_t buf[200]; - mir_snwprintf(buf, TranslateT("Login error: %s"), - (error_str.empty()) ? TranslateT("Unknown error") : ptrW(mir_utf8decodeW(error_str.c_str()))); - proto->facy.client_notify(buf); -} - -void parseJsCookies(const std::string &search, const std::string &data, std::map<std::string, std::string> &cookies) -{ - std::string::size_type pos = 0; - while ((pos = data.find(search, pos)) != std::string::npos) { - pos += search.length(); - - std::string::size_type pos2 = data.find("\",\"", pos); - if (pos2 == std::string::npos) - continue; - - std::string name = utils::url::encode(data.substr(pos, pos2 - pos)); - - pos = pos2 + 3; - pos2 = data.find("\"", pos); - if (pos2 == std::string::npos) - continue; - - std::string value = data.substr(pos, pos2 - pos); - cookies[name] = utils::url::encode(utils::text::html_entities_decode(value)); - } -} - -bool facebook_client::login(const char *username, const char *password) -{ - handle_entry("login"); - - username_ = username; - password_ = password; - - std::string postData; - std::string getData; - - if (cookies.empty()) { - // Set device ID - ptrA device(parent->getStringA(FACEBOOK_KEY_DEVICE_ID)); - if (device != nullptr) - cookies["datr"] = device; - - // Get initial cookies - http::response resp = sendRequest(loginRequest()); - - // Also parse cookies set by JavaScript - parseJsCookies("[\"CookieCore\",\"setWithoutChecksIfFirstPartyContext\",[],[\"", resp.data, cookies); - - // Parse hidden inputs and other data - std::string form = utils::text::source_get_value(&resp.data, 2, "<form", "</form>"); - utils::text::replace_all(&form, "\\\"", "\""); - - postData = utils::text::source_get_form_data(&form, true); - getData = utils::text::source_get_value(&form, 2, "login.php?login_attempt=1&", "\""); - } - - // Send validation - http::response resp = sendRequest(loginRequest(username, password, getData.c_str(), postData.c_str())); - - // Save Device ID - if (!cookies["datr"].empty()) - parent->setString(FACEBOOK_KEY_DEVICE_ID, cookies["datr"].c_str()); - - if (resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end()) { - std::string location = resp.headers["Location"]; - - // Check for invalid requests - if (location.find("invalid_request.php") != std::string::npos) { - client_notify(TranslateT("Login error: Invalid request.")); - parent->debugLogA("!!! Login error: Invalid request."); - return handle_error("login", FORCE_QUIT); - } - - // Check whether login checks are required - if (location.find("/checkpoint/") != std::string::npos) { - resp = sendRequest(setupMachineRequest()); - - if (resp.data.find("login_approvals_no_phones") != std::string::npos) { - // Code approval - but no phones in account - loginError(parent, utils::text::source_get_value(&resp.data, 4, "login_approvals_no_phones", "<div", ">", "</div>")); - return handle_error("login", FORCE_QUIT); - } - - if (resp.data.find("name=\"submit[Continue]\"") != std::string::npos) { - int attempt = 0; - // Check if we need to put approval code (aka "two-factor auth") - while (resp.data.find("id=\"approvals_code\"") != std::string::npos) { - parent->debugLogA(" Login info: Approval code required."); - - std::string fb_dtsg = utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""); - std::string nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\""); - - CFacebookGuardDialog guardDialog(parent, fb_dtsg.c_str()); - if (guardDialog.DoModal() != DIALOG_RESULT_OK) { - parent->SetStatus(ID_STATUS_OFFLINE); - return false; - } - - // We need verification code from user (he can get it via Facebook application on phone or by requesting code via SMS) - const char *givenCode = guardDialog.GetCode(); - - HttpRequest *request = setupMachineRequest(fb_dtsg.c_str(), nh.c_str(), "Continue"); - request->Body << CHAR_PARAM("approvals_code", givenCode); - resp = sendRequest(request); - - if (resp.data.find("id=\"approvals_code\"") != std::string::npos) { - // We get no error message if we put wrong code. Facebook just shows same form again. - if (++attempt >= 3) { - client_notify(TranslateT("You entered too many invalid verification codes. Plugin will disconnect.")); - parent->debugLogA("!!! Login error: Too many invalid attempts to verification code."); - return handle_error("login", FORCE_QUIT); - } - else client_notify(TranslateT("You entered wrong verification code. Try it again.")); - } - else // After successful verification is showed different page - classic form to save device (as handled at the bottom) - break; - } - - // Save this actual device - if (resp.data.find("name=\"submit[Continue]\"") != std::string::npos && resp.data.find("name=\"name_action_selected\"") != std::string::npos) { - std::string fb_dtsg = utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""); - std::string nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\""); - - HttpRequest *request = setupMachineRequest(fb_dtsg.c_str(), nh.c_str(), "Continue"); - request->Body << CHAR_PARAM("name_action_selected", "save_device"); // Save device - or "dont_save" - resp = sendRequest(request); - } - - // Check if we need to approve also last unapproved device - - // 1) Continue to check last unknown login - if (resp.data.find("name=\"submit[Continue]\"") != std::string::npos) { - std::string fb_dtsg = utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""); - std::string nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\""); - resp = sendRequest(setupMachineRequest(fb_dtsg.c_str(), nh.c_str(), "Continue")); - } - - // In this step might be needed identity confirmation - if (resp.data.find("name=\"birthday_captcha_") != std::string::npos) { - // Account is locked and needs identity confirmation - client_notify(TranslateT("Login error: Your account is temporarily locked. You need to confirm this device from web browser.")); - parent->debugLogA("!!! Login error: Birthday confirmation."); - return handle_error("login", FORCE_QUIT); - } - - // 2) Approve last unknown login - if (resp.data.find("name=\"submit[This was me]\"") != std::string::npos) { - CMStringW tszTitle; - tszTitle.AppendFormat(L"%s - %s", parent->m_tszUserName, TranslateT("Check last login")); - CMStringW tszMessage(TranslateT("Do you recognize this activity?")); - - std::string activity = utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "<body", "</strong></div>", "</div>")); - activity = utils::text::trim(utils::text::html_entities_decode(utils::text::remove_html(activity))); - if (!activity.empty()) - tszMessage.AppendFormat(L"\n\n%s", ptrW(mir_utf8decodeW(activity.c_str()))); - - if (MessageBox(nullptr, tszMessage, tszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1) != IDYES) { - // We will cancel connecting right away, because we don't want to handle password changing via Miranda - client_notify(TranslateT("Login error: You need to confirm last unknown login or revoke it from web browser.")); - return handle_error("login", FORCE_QUIT); - } - - std::string fb_dtsg = utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""); - std::string nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\""); - - // Recognize device (or "This wasn't me" - this will force to change account password) - resp = sendRequest(setupMachineRequest(fb_dtsg.c_str(), nh.c_str(), "This was me")); - - // 3) Save last device - fb_dtsg = utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""); - nh = utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\""); - - HttpRequest *request = setupMachineRequest(fb_dtsg.c_str(), nh.c_str(), "Continue"); - request->Body << CHAR_PARAM("name_action_selected", "save_device"); // Save device - or "dont_save" - resp = sendRequest(request); - } - } - else if (resp.data.find("name=\"submit[Get Started]\"") != std::string::npos) { - if (!parent->getBool(FACEBOOK_KEY_TRIED_DELETING_DEVICE_ID)) { - // Try to remove DeviceID and login again - cookies["datr"] = ""; - parent->delSetting(FACEBOOK_KEY_DEVICE_ID); - parent->setByte(FACEBOOK_KEY_TRIED_DELETING_DEVICE_ID, 1); - return login(username, password); - } - else { - // Reset flag - parent->delSetting(FACEBOOK_KEY_TRIED_DELETING_DEVICE_ID); - // Facebook things that computer was infected by malware and needs cleaning - client_notify(TranslateT("Login error: Facebook thinks your computer is infected. Solve it by logging in via 'private browsing' mode of your web browser and run their antivirus check.")); - parent->debugLogA("!!! Login error: Facebook requires computer scan."); - return handle_error("login", FORCE_QUIT); - } - } - } - } - - switch (resp.code) { - case HTTP_CODE_FAKE_DISCONNECTED: - // When is error only because timeout, try login once more - if (handle_error("login")) - return login(username, password); - else - return handle_error("login", FORCE_QUIT); - - case HTTP_CODE_OK: // OK page returned, but that is regular login page we don't want in fact - // Check whether captcha code is required - if (resp.data.find("id=\"captcha\"") != std::string::npos) { - client_notify(TranslateT("Login error: Captcha code is required. You need to confirm this device from web browser.")); - parent->debugLogA("!!! Login error: Captcha code is required."); - return handle_error("login", FORCE_QUIT); - } - else { - // Get and notify error message - std::string error = utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "[\"LoginFormError\"", "\"__html\":\"", "\"}")); - if (error.empty()) - error = utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "role=\"alert\"", ">", "</div")); - if (error.empty()) - error = utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "id=\"globalContainer\"", ">", "</div")); - if (error.empty()) - error = utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 2, "<strong>", "</strong")); - loginError(parent, error); - } - __fallthrough; - - case HTTP_CODE_FORBIDDEN: // Forbidden - case HTTP_CODE_NOT_FOUND: // Not Found - default: - return handle_error("login", FORCE_QUIT); - - case HTTP_CODE_FOUND: // Found and redirected somewhere - if (resp.headers.find("Location") != resp.headers.end()) { - std::string redirectUrl = resp.headers["Location"]; - std::string expectedUrl = HTTP_PROTO_SECURE FACEBOOK_SERVER_REGULAR "/"; - - // Remove eventual parameters - std::string::size_type pos = redirectUrl.rfind("?"); - if (pos != std::string::npos) - redirectUrl = redirectUrl.substr(0, pos); - - if (redirectUrl != expectedUrl) { - // Unexpected redirect, but we try to ignore it - maybe we were logged in anyway - parent->debugLogA("!!! Login error: Unexpected redirect: %s (Original: %s) (Expected: %s)", redirectUrl.c_str(), resp.headers["Location"].c_str(), expectedUrl.c_str()); - } - } - - if (cookies.find("c_user") != cookies.end()) { - // Probably logged in, everything seems OK - this->self_.user_id = cookies.find("c_user")->second; - parent->setString(FACEBOOK_KEY_ID, this->self_.user_id.c_str()); - parent->debugLogA(" Got self user id: %s", this->self_.user_id.c_str()); - return handle_success("login"); - } - else { - client_notify(TranslateT("Login error, probably bad login credentials.")); - parent->debugLogA("!!! Login error, probably bad login credentials."); - return handle_error("login", FORCE_QUIT); - } - } -} - -bool facebook_client::logout() -{ - handle_entry("logout"); - - http::response resp = sendRequest(logoutRequest()); - - this->username_.clear(); - this->password_.clear(); - this->self_.user_id.clear(); - - switch (resp.code) { - case HTTP_CODE_OK: - case HTTP_CODE_FOUND: - return handle_success("logout"); - - default: - return false; // Logout not finished properly, but..okay, who cares :P - } -} - -bool facebook_client::home() -{ - handle_entry("home"); - - // get fb_dtsg - http::response resp = sendRequest(dtsgRequest()); - - this->dtsg_ = utils::text::source_get_value(&resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\""); - { - // Compute ttstamp from dtsg_ - std::stringstream csrf; - for (unsigned int i = 0; i < this->dtsg_.length(); i++) - csrf << (int)this->dtsg_.at(i); - - this->ttstamp_ = "2" + csrf.str(); - } - - if (this->dtsg_.empty()) { - parent->debugLogA("!!! Empty dtsg. Source code:\n%s", resp.data.c_str()); - client_notify(TranslateT("Could not load communication token. You should report this and wait for plugin update.")); - return handle_error("home", FORCE_QUIT); - } - - parent->debugLogA(" Got self dtsg"); - - resp = sendRequest(homeRequest()); - - switch (resp.code) { - case HTTP_CODE_OK: - { - std::string touchSearch = "{\"id\":" + this->self_.user_id; - std::string touchData = utils::text::source_get_value(&resp.data, 2, touchSearch.c_str(), "}"); - - // Get real name (from touch version) - if (!touchData.empty()) - this->self_.real_name = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&touchData, 2, "\"name\":\"", "\""))); - - // Another attempt to get real name (from mbasic version) - if (this->self_.real_name.empty()) - this->self_.real_name = utils::text::source_get_value(&resp.data, 4, "id=\"root", "<strong", ">", "</strong>"); - - // Try to get name again, if we've got some some weird version of Facebook - if (this->self_.real_name.empty()) - this->self_.real_name = utils::text::source_get_value(&resp.data, 5, "id=\"root", "</a>", "<div", ">", "</div>"); - - // Another attempt to get name - if (this->self_.real_name.empty()) - this->self_.real_name = utils::text::source_get_value(&resp.data, 5, "id=\"root", "</td>", "<div", ">", "</td>"); - - // Get and strip optional nickname - std::string::size_type pos = this->self_.real_name.find("<span class=\"alternate_name\">"); - if (pos != std::string::npos) { - this->self_.nick = utils::text::source_get_value(&this->self_.real_name, 2, "<span class=\"alternate_name\">(", ")</span>"); - parent->debugLogA(" Got self nick name: %s", this->self_.nick.c_str()); - - this->self_.real_name = this->self_.real_name.substr(0, pos - 1); - } - - // Another attempt to get optional nickname - if (this->self_.nick.empty()) - this->self_.nick = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "class=\\\"alternate_name\\\"", ">(", ")\\u003C\\/"))); - - this->self_.real_name = utils::text::remove_html(this->self_.real_name); - parent->debugLogA(" Got self real name (nickname): %s (%s)", this->self_.real_name.c_str(), this->self_.nick.c_str()); - parent->SaveName(0, &this->self_); - - // Get avatar (from touch version) - if (!touchData.empty()) - this->self_.image_url = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&touchData, 2, "\"pic\":\"", "\""))); - - // Another attempt to get avatar(from mbasic version) - if (this->self_.image_url.empty()) - this->self_.image_url = utils::text::source_get_value(&resp.data, 3, "id=\"root", "<img src=\"", "\""); - - // Another attempt to get avatar - if (this->self_.image_url.empty()) { - this->self_.image_url = utils::text::source_get_value(&resp.data, 3, "id=\"root", "/photo.php?", "\""); - - // Prepare this special url (not direct image url) to be handled correctly in CheckAvatarChange() - // It must contain "/" at the beginning and also shouldn't contain "?" as parameters after that are stripped - if (!this->self_.image_url.empty()) - this->self_.image_url = "/" + this->self_.image_url; - } - - // Final attempt to get avatar as on some pages is only link to photo page and not link to image itself - if (this->self_.image_url.empty()) { - http::response resp2 = sendRequest(profilePictureRequest(self_.user_id.c_str())); - - // Get avatar (from mbasic version of photo page) - this->self_.image_url = utils::text::html_entities_decode(utils::text::source_get_value(&resp2.data, 3, "id=\"root", "<img src=\"", "\"")); - - // Get avatar (from touch version) - if (this->self_.image_url.empty()) - this->self_.image_url = utils::text::html_entities_decode(utils::text::source_get_value(&resp2.data, 3, "id=\"root", "background-image: url("", "")")); - - // Sometimes even Facebook doesn't show any picture at all! So just ignore this error in that case... - if (this->self_.image_url.empty()) { - parent->debugLogA("!!! Empty avatar even from avatar page. Source code:\n%s", resp2.data.c_str()); - - // Set dumb avatar "url" (see how it works in CheckAvatarChange()) so we can't tell if/when the avatar changed, but it will be loaded at least once - this->self_.image_url = "/NO_AVATAR/"; - } - } - - parent->debugLogA(" Got self avatar: %s", this->self_.image_url.c_str()); - parent->CheckAvatarChange(0, this->self_.image_url); - - // Get logout hash - this->logout_hash_ = utils::text::source_get_value2(&resp.data, "/logout.php?h=", "&\""); - parent->debugLogA(" Got self logout hash: %s", this->logout_hash_.c_str()); - - if (this->self_.real_name.empty() || this->self_.image_url.empty() || this->logout_hash_.empty()) { - parent->debugLogA("!!! Empty nick/avatar/hash. Source code:\n%s", resp.data.c_str()); - client_notify(TranslateT("Could not load all required data. Plugin may still work correctly, but you should report this and wait for plugin update.")); - } - } - return handle_success("home"); - - case HTTP_CODE_FOUND: - // Work-around for replica_down, f**king hell what's that? - parent->debugLogA("!!! REPLICA_DOWN is back in force!"); - return this->home(); - - default: - return handle_error("home", FORCE_QUIT); - } -} - -bool facebook_client::chat_state(bool online) -{ - handle_entry("chat_state"); - - http::response resp = sendRequest(setVisibilityRequest(online)); - if (!resp.error_title.empty()) - return handle_error("chat_state"); - - return handle_success("chat_state"); -} - -bool facebook_client::reconnect() -{ - handle_entry("reconnect"); - - // Request reconnect - http::response resp = sendRequest(reconnectRequest()); - if (resp.code != HTTP_CODE_OK) - return handle_error("reconnect", FORCE_DISCONNECT); - - std::string redir = utils::text::source_get_value(&resp.data, 2, "\"redirect\":\"", "\""); - if (!redir.empty()) { - redir = utils::text::html_entities_decode(redir); - parent->debugLogA("Redirecting to %s", redir.c_str()); - - auto *p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR); - p->m_szUrl = redir.c_str(); - resp = sendRequest(p); - if (resp.code != HTTP_CODE_OK) - return handle_error("reconnect", FORCE_DISCONNECT); - } - - this->chat_channel_ = utils::text::source_get_value(&resp.data, 2, "\"user_channel\":\"", "\""); - parent->debugLogA(" Got self channel: %s", this->chat_channel_.c_str()); - - this->chat_channel_partition_ = utils::text::source_get_value2(&resp.data, "\"partition\":", ",}"); - parent->debugLogA(" Got self channel partition: %s", this->chat_channel_partition_.c_str()); - - this->chat_channel_host_ = utils::text::source_get_value(&resp.data, 2, "\"host\":\"", "\""); - parent->debugLogA(" Got self channel host: %s", this->chat_channel_host_.c_str()); - - this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}"); - parent->debugLogA(" Got self sequence number: %s", this->chat_sequence_num_.c_str()); - - this->chat_conn_num_ = utils::text::source_get_value2(&resp.data, "\"max_conn\":", ",}"); - parent->debugLogA(" Got self max_conn: %s", this->chat_conn_num_.c_str()); - - this->chat_sticky_num_ = utils::text::source_get_value(&resp.data, 2, "\"sticky_token\":\"", "\""); - parent->debugLogA(" Got self sticky_token: %s", this->chat_sticky_num_.c_str()); - - activity_ping(); - return handle_success("reconnect"); -} - -bool facebook_client::channel() -{ - handle_entry("channel"); - - // Get updates - http::response resp = sendRequest(channelRequest(PULL)); - if (resp.data.empty()) // Something went wrong - return handle_error("channel"); - - // Load traceId, if present - std::string traceId = utils::text::source_get_value(&resp.data, 2, "\"tr\":\"", "\""); - if (!traceId.empty()) - this->chat_traceid_ = traceId; - - std::string type = utils::text::source_get_value(&resp.data, 2, "\"t\":\"", "\""); - parent->debugLogA("Pull response type = %s", type.c_str()); - - if (type == "continue" || type == "heartbeat") { - // Everything is OK, no new message received - } - else if (type == "lb") { - // Some new stuff (idk how does it work yet) - this->chat_sticky_pool_ = utils::text::source_get_value(&resp.data, 2, "\"pool\":\"", "\""); - parent->debugLogA(" Got self sticky pool: %s", this->chat_sticky_pool_.c_str()); - - this->chat_sticky_num_ = utils::text::source_get_value2(&resp.data, "\"sticky\":\"", "\""); - parent->debugLogA(" Got self sticky number: %s", this->chat_sticky_num_.c_str()); - } - else if (type == "refresh") { - // Requested relogin (due to some settings change, removing this session, etc.) - parent->debugLogA("!!! Requested refresh"); - - this->chat_sequence_num_ = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}"); - parent->debugLogA(" Got self sequence number: %s", this->chat_sequence_num_.c_str()); - - this->chat_reconnect_reason_ = utils::text::source_get_value2(&resp.data, "\"reason\":", ",}"); - parent->debugLogA(" Got reconnect reason: %s", this->chat_reconnect_reason_.c_str()); - - return this->reconnect(); - } - else if (!type.empty()) { // for "msg", "fullReload" and maybe also other types - // Something has been received, throw to new thread to process - parent->debugLogA("*** Starting processing messages"); - { - std::vector<facebook_message> messages; - if (parent->ParseMessages(resp.data, messages) == EXIT_SUCCESS) { - parent->ReceiveMessages(messages); - - if (parent->getBool(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE)) - parent->ShowNotifications(); - - parent->debugLogA("*** Messages processed"); - } - else parent->debugLogA("*** Error processing messages"); - } - - // Get new sequence number - std::string seq = utils::text::source_get_value2(&resp.data, "\"seq\":", ",}"); - parent->debugLogA(" Got self sequence number: %s", seq.c_str()); - - if (type == "msg") { - // Update msgs_recv number for every "msg" type we receive (during fullRefresh/reload responses it stays the same) - this->chat_msgs_recv_++; - } - - if (!seq.empty()) - this->chat_sequence_num_ = seq; - } - else // No type? This shouldn't happen unless there is a big API change. - return handle_error("channel"); - - // Return - switch (resp.code) { - case HTTP_CODE_OK: - return handle_success("channel"); - - case HTTP_CODE_GATEWAY_TIMEOUT: - // Maybe we have same clientid as other connected client, try to generate different one - this->chat_clientid_ = utils::text::rand_string(8, "0123456789abcdef", &this->random_); - - // Intentionally fall to handle_error() below - case HTTP_CODE_FAKE_DISCONNECTED: - case HTTP_CODE_FAKE_ERROR: - default: - return handle_error("channel"); - } -} - -bool facebook_client::activity_ping() -{ - // Don't send ping when we are not online - if (parent->m_iStatus != ID_STATUS_ONLINE) - return true; - - handle_entry("activity_ping"); - - http::response resp = sendRequest(channelRequest(PING)); - - // Remember this last ping time - parent->m_pingTS = ::time(0); - - if (resp.data.empty() || resp.data.find("\"t\":\"pong\"") == resp.data.npos) { - // Something went wrong - return handle_error("activity_ping"); - } - - return handle_success("activity_ping"); -} - -int facebook_client::send_message(int seqid, MCONTACT hContact, const std::string &message_text, std::string *error_text, const std::string &captcha_persist_data, const std::string &captcha) -{ - handle_entry("send_message"); - - bool isChatRoom = parent->isChatRoom(hContact); - - ptrA userId(parent->getStringA(hContact, FACEBOOK_KEY_ID)); - ptrA threadId(parent->getStringA(hContact, FACEBOOK_KEY_TID)); - - // Check if we have userId/threadId to be able to send message - if ((isChatRoom && (threadId == nullptr || !mir_strcmp(threadId, "null"))) || (!isChatRoom && (userId == nullptr || !mir_strcmp(userId, "null")))) { - // This shouldn't happen unless user manually deletes some data via Database Editor++ - *error_text = Translate("Contact doesn't have required data in database."); - - handle_error("send_message"); - return SEND_MESSAGE_ERROR; - } - - // Probably we can generate any random messageID, it just have to be numeric and don't start with "0". We will receive it in response as "client_message_id". - std::string messageId = utils::text::rand_string(10, "123456789", &this->random_); - - http::response resp; - { - mir_cslock s(send_message_lock_); - resp = sendRequest(sendMessageRequest(userId, threadId, messageId.c_str(), message_text.c_str(), isChatRoom, captcha.c_str(), captcha_persist_data.c_str())); - - *error_text = resp.error_text; - - if (resp.error_number == 0) { - // Everything is OK - // Remember this message id - std::string mid = utils::text::source_get_value(&resp.data, 2, "\"message_id\":\"", "\""); - if (mid.empty()) - mid = utils::text::source_get_value(&resp.data, 2, "\"mid\":\"", "\""); // TODO: This is probably not used anymore - - // For classic contacts remember last message id - if (!parent->isChatRoom(hContact)) - parent->setString(hContact, FACEBOOK_KEY_MESSAGE_ID, mid.c_str()); - - // Get timestamp - std::string timestamp = utils::text::source_get_value(&resp.data, 2, "\"timestamp\":", ","); - time_t time = utils::time::from_string(timestamp); - - // Remember last action timestamp for history sync - parent->setDword(FACEBOOK_KEY_LAST_ACTION_TS, time); - - // For classic conversation we try to replace timestamp of added event in OnPreCreateEvent() - if (seqid > 0) - messages_timestamp.insert(std::make_pair(seqid, time)); - - // We have this message in database, so ignore further tries (in channel) to add it again - messages_ignore.insert(std::make_pair(mid, 0)); - } - } - - switch (resp.error_number) { - case 0: - // Everything is OK - break; - - // case 1356002: // You are offline (probably you can't use mercury or some other request when chat is offline) - - case 1356003: // Contact is offline - parent->setWord(hContact, "Status", ID_STATUS_OFFLINE); - return SEND_MESSAGE_ERROR; - - case 1356026: // Contact has alternative client - client_notify(TranslateT("Need confirmation for sending messages to other clients.\nOpen Facebook website and try to send message to this contact again!")); - return SEND_MESSAGE_ERROR; - - case 1357007: // Security check (captcha) is required - { - std::string imageUrl = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&resp.data, 3, "img class=\\\"img\\\"", "src=\\\"", "\\\""))); - std::string captchaPersistData = utils::text::source_get_value(&resp.data, 3, "\\\"captcha_persist_data\\\"", "value=\\\"", "\\\""); - - parent->debugLogA(" Got imageUrl (first): %s", imageUrl.c_str()); - parent->debugLogA(" Got captchaPersistData (first): %s", captchaPersistData.c_str()); - - http::response capResp = sendRequest(refreshCaptchaRequest(captchaPersistData.c_str())); - if (capResp.code == HTTP_CODE_OK) { - imageUrl = utils::text::html_entities_decode(utils::text::slashu_to_utf8(utils::text::source_get_value(&capResp.data, 3, "img class=\\\"img\\\"", "src=\\\"", "\\\""))); - captchaPersistData = utils::text::source_get_value(&capResp.data, 3, "\\\"captcha_persist_data\\\"", "value=\\\"", "\\\""); - - parent->debugLogA(" Got imageUrl (second): %s", imageUrl.c_str()); - parent->debugLogA(" Got captchaPersistData (second): %s", captchaPersistData.c_str()); - - std::string result; - if (!parent->RunCaptchaForm(imageUrl, result)) { - *error_text = Translate("User cancel captcha challenge."); - return SEND_MESSAGE_CANCEL; - } - - return send_message(seqid, hContact, message_text, error_text, captchaPersistData, result); - } - } - return SEND_MESSAGE_CANCEL; // Cancel because we failed to load captcha image so we can't continue only with error - - //case 1404123: // Blocked sending messages (with URLs) because Facebook think our computer is infected with malware - - default: // Other error - parent->debugLogA("!!! Send message error #%d: %s", resp.error_number, resp.error_text.c_str()); - return SEND_MESSAGE_ERROR; - } - - switch (resp.code) { - case HTTP_CODE_OK: - handle_success("send_message"); - return SEND_MESSAGE_OK; - - case HTTP_CODE_FAKE_ERROR: - case HTTP_CODE_FAKE_DISCONNECTED: - default: - *error_text = Translate("Timeout when sending message."); - - handle_error("send_message"); - return SEND_MESSAGE_ERROR; - } -} - -bool facebook_client::post_status(status_data *status) -{ - if (status == nullptr || (status->text.empty() && status->url.empty())) - return false; - - handle_entry("post_status"); - - if (status->isPage) { - // Switch to page identity by which name we will share this post - sendRequest(switchIdentityRequest(status->user_id.c_str())); - } - - std::string linkData; - if (!status->url.empty()) { - http::response resp = sendRequest(linkScraperRequest(status)); - - std::string temp = utils::text::html_entities_decode(utils::text::slashu_to_utf8(resp.data)); - std::string form = utils::text::source_get_value(&temp, 2, "<form", "</form>"); - utils::text::replace_all(&form, "\\\"", "\""); - linkData += utils::text::source_get_form_data(&form); - // FIXME: Rework to some "scraped_link" structure to simplify working with it? - } - - http::response resp = sendRequest(sharePostRequest(status, linkData.c_str())); - - if (status->isPage) // Switch back to our identity - sendRequest(switchIdentityRequest(self_.user_id.c_str())); - - // cleanup status elements (delete users) - for (std::vector<facebook_user*>::size_type i = 0; i < status->users.size(); i++) - delete status->users[i]; - status->users.clear(); - - if (resp.isValid()) { - parent->NotifyEvent(parent->m_tszUserName, TranslateT("Status update was successful."), 0, EVENT_OTHER); - return handle_success("post_status"); - } - - return handle_error("post_status"); -} - -////////////////////////////////////////////////////////////////////////////// - -bool facebook_client::save_url(const std::string &url, const std::wstring &filename, HNETLIBCONN &nlc) -{ - NETLIBHTTPREQUEST req = { sizeof(req) }; - req.requestType = REQUEST_GET; - req.szUrl = const_cast<char*>(url.c_str()); - req.flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_PERSISTENT | NLHRF_NODUMP; - req.nlc = nlc; - - bool ret = false; - NLHR_PTR resp(Netlib_HttpTransaction(handle_, &req)); - if (resp) { - nlc = resp->nlc; - parent->debugLogA("@@@ Saving URL %s to file %s", url.c_str(), _T2A(filename.c_str())); - - // Create folder if necessary - std::wstring dir = filename.substr(0, filename.rfind('\\')); - if (_waccess(dir.c_str(), 0)) - CreateDirectoryTreeW(dir.c_str()); - - // Write to file - FILE *f = _wfopen(filename.c_str(), L"wb"); - if (f != nullptr) { - fwrite(resp->pData, 1, resp->dataLength, f); - fclose(f); - - ret = _waccess(filename.c_str(), 0) == 0; - } - } - else nlc = nullptr; - - return ret; -} - -bool facebook_client::sms_code(const char *fb_dtsg) -{ - http::response resp = sendRequest(loginSmsRequest(fb_dtsg)); - - if (resp.data.find("\"is_valid\":true", 0) == std::string::npos) { - // Code wasn't send - client_notify(TranslateT("Error occurred when requesting verification SMS code.")); - return false; - } - - parent->NotifyEvent(parent->m_tszUserName, TranslateT("Verification SMS code was sent to your mobile phone."), 0, EVENT_OTHER); - return true; -} diff --git a/protocols/FacebookRM/src/connection.cpp b/protocols/FacebookRM/src/connection.cpp deleted file mode 100644 index d129524d44..0000000000 --- a/protocols/FacebookRM/src/connection.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -static void CALLBACK timerApcFunc(HWND, UINT, UINT_PTR param, DWORD) -{ - FacebookProto *ppro = (FacebookProto *)param; - if (!ppro->isOffline()) - ppro->ForkThread(&FacebookProto::ProcessNotifications); -} - -void FacebookProto::ChangeStatus(void*) -{ - mir_cslock s(signon_lock_); - - int new_status = m_iDesiredStatus; - int old_status = m_iStatus; - - if (new_status == ID_STATUS_OFFLINE) { - // Logout - debugLogA("### Beginning SignOff process"); - m_signingOut = true; - - ::KillTimer(g_hwndHeartbeat, LPARAM(this)); - ::SetEvent(update_loop_event); - - // Shutdown and close channel handle - Netlib_Shutdown(facy.hChannelCon); - if (facy.hChannelCon) { - Netlib_CloseHandle(facy.hChannelCon); - facy.hChannelCon = nullptr; - } - - // Shutdown and close messages handle - Netlib_Shutdown(facy.hMessagesCon); - if (facy.hMessagesCon) { - Netlib_CloseHandle(facy.hMessagesCon); - facy.hMessagesCon = nullptr; - } - - // Turn off chat on Facebook - if (getByte(FACEBOOK_KEY_DISCONNECT_CHAT, DEFAULT_DISCONNECT_CHAT)) - facy.chat_state(false); - - facy.logout(); - - OnLeaveChat(0, 0); - setAllContactStatuses(ID_STATUS_OFFLINE); - ToggleStatusMenuItems(false); - delSetting(FACEBOOK_KEY_LOGON_TS); - - facy.chat_traceid_.clear(); - facy.chat_sticky_num_.clear(); - facy.chat_sticky_pool_.clear(); - facy.chat_msgs_recv_ = 0; - facy.chat_req_ = 0; - - facy.clear_cookies(); - facy.clear_notifications(); - facy.clear_chatrooms(); - facy.clear_readers(); - facy.messages_ignore.clear(); - facy.messages_timestamp.clear(); - facy.pages.clear(); - facy.typers.clear(); - - // Close connection handle - if (facy.hFcbCon) - Netlib_CloseHandle(facy.hFcbCon); - facy.hFcbCon = nullptr; - - m_iStatus = facy.self_.status_id = ID_STATUS_OFFLINE; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - - m_signingOut = false; - debugLogA("### SignOff complete"); - return; - } - else if (old_status == ID_STATUS_OFFLINE) { - // Login - SYSTEMTIME t; - GetLocalTime(&t); - debugLogA("[%d.%d.%d] Using Facebook Protocol RM %s", t.wDay, t.wMonth, t.wYear, __VERSION_STRING_DOTS); - - debugLogA("*** Beginning SignOn process"); - - m_enableChat = getBool(FACEBOOK_KEY_ENABLE_CHATS, DEFAULT_ENABLE_CHATS); - - m_iStatus = facy.self_.status_id = ID_STATUS_CONNECTING; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - - ResetEvent(update_loop_event); - - // Workaround for not working "mbasic." for some users - reset this flag at every login - facy.mbasicWorks = true; - - if (NegotiateConnection() && facy.home() && facy.reconnect()) { - // Load all friends - ProcessFriendList(nullptr); - - // Process friendship requests - ForkThread(&FacebookProto::ProcessFriendRequests, nullptr); - - // Get unread messages - ForkThread(&FacebookProto::ProcessUnreadMessages, nullptr); - - // Get notifications - if (getByte(FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE)) - ForkThread(&FacebookProto::ProcessNotifications, nullptr); - - // Load pages for post status dialog - ForkThread(&FacebookProto::ProcessPages, nullptr); - - // Load on this day posts - if (getByte(FACEBOOK_KEY_EVENT_ON_THIS_DAY_ENABLE, DEFAULT_EVENT_ON_THIS_DAY_ENABLE)) - ForkThread(&FacebookProto::ProcessMemories, nullptr); - - setDword(FACEBOOK_KEY_LOGON_TS, (DWORD)time(0)); - ForkThread(&FacebookProto::UpdateLoop, nullptr); - ForkThread(&FacebookProto::MessageLoop, nullptr); - - if (getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS)) - ForkThread(&FacebookProto::SetAwayMsgWorker, nullptr); - - ::SetTimer(g_hwndHeartbeat, LPARAM(this), 60000, timerApcFunc); - } - else { - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)old_status, m_iStatus); - - if (facy.hFcbCon) - Netlib_CloseHandle(facy.hFcbCon); - facy.hFcbCon = nullptr; - - facy.clear_cookies(); - - // Set to offline - m_iStatus = m_iDesiredStatus = facy.self_.status_id = ID_STATUS_OFFLINE; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - - debugLogA("*** SignOn failed"); - - return; - } - - // Join all locally present chatrooms (if enabled) - if (getBool(FACEBOOK_KEY_JOIN_EXISTING_CHATS, DEFAULT_JOIN_EXISTING_CHATS)) - JoinChatrooms(); - - ToggleStatusMenuItems(true); - debugLogA("*** SignOn complete"); - } - else { // Change between online/away/invisible statuses - if (new_status == ID_STATUS_INVISIBLE) - // When switching to invisible (from online/away), we need to set all contacts offline as we won't receive no status updates from Facebook - setAllContactStatuses(ID_STATUS_OFFLINE); - } - - bool wasAwayOrInvisible = (old_status == ID_STATUS_AWAY || old_status == ID_STATUS_INVISIBLE); - bool isAwayOrInvisible = (new_status == ID_STATUS_AWAY || new_status == ID_STATUS_INVISIBLE); - if (!wasAwayOrInvisible && isAwayOrInvisible) { - // Switching from "not-away" to "away" state, remember timestamp of this change (and if we are idle already, use the idle time) - m_awayTS = (m_idleTS > 0 ? m_idleTS : ::time(0)); - } - else if (wasAwayOrInvisible && !isAwayOrInvisible) { - // Switching from "away" to "not-away" state, reset the timestamp - m_awayTS = 0; - } - - m_invisible = (new_status == ID_STATUS_INVISIBLE); - facy.chat_state(!m_invisible); - - m_iStatus = facy.self_.status_id = new_status; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - - debugLogA("*** ChangeStatus complete"); -} - -/** Return true on success, false on error. */ -bool FacebookProto::NegotiateConnection() -{ - debugLogA("*** Negotiating connection with Facebook"); - - ptrA username(getStringA(FACEBOOK_KEY_LOGIN)); - if (!username || !mir_strlen(username)) { - facy.client_notify(TranslateT("Please enter a username.")); - return false; - } - - ptrA password(getStringA(FACEBOOK_KEY_PASS)); - if (!password || !*password) { - facy.client_notify(TranslateT("Please enter a password.")); - return false; - } - - password = mir_utf8encode(password); - - // Refresh last time of feeds update - facy.last_feeds_update_ = ::time(0); - - // Generate random clientid for this connection - facy.chat_clientid_ = utils::text::rand_string(8, "0123456789abcdef", &facy.random_); - - // Create default group for new contacts - if (m_tszDefaultGroup) - Clist_GroupCreate(0, m_tszDefaultGroup); - - return facy.login(username, password); -} - -void FacebookProto::UpdateLoop(void *) -{ - time_t tim = ::time(0); - debugLogA(">>> Entering Facebook::UpdateLoop[%d]", tim); - - for (int i = -1; !isOffline(); i = (i + 1) % 50) { - if (i != -1) { - if (getByte(FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE)) - ProcessFeeds(nullptr); - } - - ProcessBuddylistUpdate(nullptr); - - debugLogA("*** FacebookProto::UpdateLoop[%d] going to sleep...", tim); - if (WaitForSingleObjectEx(update_loop_event, GetPollRate() * 1000, true) != WAIT_TIMEOUT) - break; - debugLogA("*** FacebookProto::UpdateLoop[%d] waking up...", tim); - } - - ResetEvent(update_loop_event); - debugLogA("<<< Exiting FacebookProto::UpdateLoop[%d]", tim); -} - -void FacebookProto::MessageLoop(void *) -{ - time_t tim = ::time(0); - debugLogA(">>> Entering Facebook::MessageLoop[%d]", tim); - - while (facy.channel()) { - if (isOffline() || m_signingOut) - break; - - // If we're not idle, send activity_ping every few minutes... - if (!m_idleTS && (::time(0) - m_pingTS) > FACEBOOK_PING_TIME) { - debugLogA("*** FacebookProto::MessageLoop[%d] pinging...", tim); - facy.activity_ping(); - } - - debugLogA("*** FacebookProto::MessageLoop[%d] refreshing...", tim); - } - - debugLogA("<<< Exiting FacebookProto::MessageLoop[%d]", tim); -} - -BYTE FacebookProto::GetPollRate() -{ - BYTE poll_rate = getByte(FACEBOOK_KEY_POLL_RATE, FACEBOOK_DEFAULT_POLL_RATE); - return ((poll_rate >= FACEBOOK_MINIMAL_POLL_RATE && poll_rate <= FACEBOOK_MAXIMAL_POLL_RATE) ? poll_rate : FACEBOOK_DEFAULT_POLL_RATE); -} diff --git a/protocols/FacebookRM/src/constants.h b/protocols/FacebookRM/src/constants.h deleted file mode 100644 index 69a6db4373..0000000000 --- a/protocols/FacebookRM/src/constants.h +++ /dev/null @@ -1,177 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#pragma once
-
-// Product management
-#define FACEBOOK_NAME "Facebook"
-#define FACEBOOK_URL_HOMEPAGE "https://www.facebook.com"
-#define FACEBOOK_URL_REQUESTS "https://www.facebook.com/n/?reqs.php"
-#define FACEBOOK_URL_MESSAGES "https://www.facebook.com/n/?inbox"
-#define FACEBOOK_URL_NOTIFICATIONS "https://www.facebook.com/n/?notifications"
-#define FACEBOOK_URL_PROFILE "https://www.facebook.com/profile.php?id="
-#define FACEBOOK_URL_GROUP "https://www.facebook.com/n/?home.php&sk=group_"
-#define FACEBOOK_URL_PICTURE "https://graph.facebook.com/%s/picture"
-#define FACEBOOK_URL_CONVERSATION "https://www.facebook.com/messages/t/"
-
-// Connection
-#define FACEBOOK_SERVER_REGULAR "www.facebook.com"
-#define FACEBOOK_SERVER_MBASIC "mbasic.facebook.com"
-#define FACEBOOK_SERVER_MOBILE "m.facebook.com"
-#define FACEBOOK_SERVER_CHAT "%s-%s.facebook.com/%s"
-#define FACEBOOK_SERVER_LOGIN "www.facebook.com"
-#define FACEBOOK_SERVER_APPS "apps.facebook.com"
-#define FACEBOOK_SERVER_DOMAIN "facebook.com"
-
-// Facebook clients
-#define FACEBOOK_CLIENT_WEB L"Facebook (website)"
-#define FACEBOOK_CLIENT_MOBILE L"Facebook (mobile)"
-#define FACEBOOK_CLIENT_OTHER L"Facebook (other)"
-#define FACEBOOK_CLIENT_APP L"Facebook App"
-#define FACEBOOK_CLIENT_MESSENGER L"Facebook Messenger"
-
-// Various constants
-#define FACEBOOK_NOTIFICATIONS_CHATROOM "_notifications"
-#define FACEBOOK_CHATROOM_NAMES_COUNT 3 // number of participant names to use for chatrooms without specific name (on website it's 2)
-#define FACEBOOK_NOTIFICATIONS_LOAD_COUNT 20 // number of last notifications to load on login to notify
-#define MANUALLY_TRIGGERED (void*)1 // to use as thread parameter to notify this action was activated by user, so we should show info popups
-
-// Limits
-#define FACEBOOK_MESSAGE_LIMIT 200000 // this is guessed limit, in reality it is bigger
-#define FACEBOOK_MESSAGE_LIMIT_TEXT "200000"
-#define FACEBOOK_MIND_LIMIT 63206 // this should be correct maximal limit
-#define FACEBOOK_MIND_LIMIT_TEXT "63206"
-#define FACEBOOK_TIMEOUTS_LIMIT 3
-#define FACEBOOK_GROUP_NAME_LIMIT 100
-#define FACEBOOK_MESSAGES_ON_OPEN_LIMIT 99
-#define FACEBOOK_TYPING_TIME 60
-#define FACEBOOK_IGNORE_COUNTER_LIMIT 100 // how many consequent requests it should keep info about duplicit message ids
-#define FACEBOOK_PING_TIME 90 // every 90 seconds send activity_ping (it's guessed value, but it's similar how often website does it)
-
-#define MAX_NEWSFEED_LEN 500
-#define MAX_LINK_DESCRIPTION_LEN 200
-
-#define TEXT_ELLIPSIS "\xE2\x80\xA6" // unicode ellipsis
-#define TEXT_EMOJI_LINK "\xF0\x9F\x94\x97" // emoji :link:
-#define TEXT_EMOJI_CLOCK "\xF0\x9F\x95\x92" // emoji :clock3:
-#define TEXT_EMOJI_PAGE "\xF0\x9F\x93\x84" // emoji :page_facing_up:
-
-// Defaults
-#define FACEBOOK_MINIMAL_POLL_RATE 10
-#define FACEBOOK_DEFAULT_POLL_RATE 24 // in seconds
-#define FACEBOOK_MAXIMAL_POLL_RATE 60
-
-#define DEFAULT_SET_MIRANDA_STATUS 0
-#define DEFAULT_LOGGING_ENABLE 0
-#define DEFAULT_SYSTRAY_NOTIFY 0
-#define DEFAULT_DISABLE_STATUS_NOTIFY 0
-#define DEFAULT_BIG_AVATARS 0
-#define DEFAULT_DISCONNECT_CHAT 0
-#define DEFAULT_MAP_STATUSES 0
-#define DEFAULT_CUSTOM_SMILEYS 0
-#define DEFAULT_LOAD_PAGES 0
-#define DEFAULT_KEEP_UNREAD 0
-#define DEFAULT_FILTER_ADS 0
-#define DEFAULT_MESSAGES_ON_OPEN 0
-#define DEFAULT_MESSAGES_ON_OPEN_COUNT 10
-#define DEFAULT_HIDE_CHATS 0
-#define DEFAULT_ENABLE_CHATS 1
-#define DEFAULT_JOIN_EXISTING_CHATS 1
-#define DEFAULT_NOTIFICATIONS_CHATROOM 0
-#define DEFAULT_NAME_AS_NICK 1
-#define DEFAULT_LOAD_ALL_CONTACTS 0
-#define DEFAULT_PAGES_ALWAYS_ONLINE 1
-#define DEFAULT_TYPING_WHEN_INVISIBLE 1
-
-#define DEFAULT_EVENT_NOTIFICATIONS_ENABLE 1
-#define DEFAULT_EVENT_FEEDS_ENABLE 0
-#define DEFAULT_EVENT_FRIENDSHIP_ENABLE 1
-#define DEFAULT_EVENT_TICKER_ENABLE 0
-#define DEFAULT_EVENT_ON_THIS_DAY_ENABLE 0
-
-// Send message return values
-#define SEND_MESSAGE_OK 0
-#define SEND_MESSAGE_ERROR 1
-#define SEND_MESSAGE_CANCEL -1
-
-// Event types
-#define FACEBOOK_EVENTTYPE_CALL 10010
-
-enum ContactType
-{
- CONTACT_FRIEND = 1, // contact that IS on our server list
- CONTACT_NONE = 2, // contact that ISN'T on our server list
- CONTACT_REQUEST = 3, // contact that we asked for friendship
- CONTACT_APPROVE = 4, // contact that is asking us for approval of friendship
- CONTACT_PAGE = 5 // contact is Facebook page
-};
-
-enum ClientType
-{
- CLIENT_WEB = 1, // Facebook website
- CLIENT_APP = 2, // Facebook mobile application
- CLIENT_MESSENGER = 3, // Facebook Messenger application
- CLIENT_OTHER = 4, // Facebook over XMPP
- CLIENT_MOBILE = 5 // Facebook on unknown mobile client (can't be determined for offline contacts)
-};
-
-// TODO: Rework to "Events" and add also typing, seen, contact status, chat switch, etc. then have JSON parser only for parsing and a single place for processing updates
-// Each type then could have also separate class representing it. And when giving it in some list, make it map of arrays with key=thread_id to group it by contact/chat, to have it more effective
-// Use also for Poke and such events...
-
-enum MessageType
-{
- MESSAGE = 1,
- PHONE_CALL = 2,
- VIDEO_CALL = 3,
- ADMIN_TEXT = 4,
- SUBSCRIBE = 5,
- UNSUBSCRIBE = 6,
- THREAD_NAME = 7,
- THREAD_IMAGE = 8,
-};
-
-enum EventType
-{
- EVENT_CLIENT = 1, // Client error
- EVENT_NEWSFEED = 2, // Newsfeed (wall) message
- EVENT_NOTIFICATION = 3, // New notification
- EVENT_OTHER = 4, // Other event (poke sent, status update, ...)
- EVENT_FRIENDSHIP = 5, // Friendship event
- EVENT_TICKER = 6, // Ticker message
- EVENT_ON_THIS_DAY = 7, // On this day post (memories)
-};
-
-enum ParticipantRole
-{
- ROLE_ME = 0,
- ROLE_FRIEND = 1,
- ROLE_NONE = 2
-};
-
-struct ttype
-{
- const char *name;
- const char *id;
-};
-
-extern const ttype feed_types[3], server_types[3], privacy_types[5];
diff --git a/protocols/FacebookRM/src/contacts.cpp b/protocols/FacebookRM/src/contacts.cpp deleted file mode 100644 index 751eba0904..0000000000 --- a/protocols/FacebookRM/src/contacts.cpp +++ /dev/null @@ -1,735 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -void FacebookProto::SaveName(MCONTACT hContact, const facebook_user *fbu) -{ - if (fbu->type == CONTACT_PAGE) { - // Page has only nickname and no first/last names - std::string nick = m_pagePrefix + " " + fbu->real_name; - - setStringUtf(hContact, FACEBOOK_KEY_NICK, nick.c_str()); - delSetting(hContact, FACEBOOK_KEY_FIRST_NAME); - delSetting(hContact, FACEBOOK_KEY_SECOND_NAME); - delSetting(hContact, FACEBOOK_KEY_LAST_NAME); - return; - } - - // Save nick - std::string nick = fbu->real_name; - if (!getBool(FACEBOOK_KEY_NAME_AS_NICK, DEFAULT_NAME_AS_NICK) && !fbu->nick.empty()) - nick = fbu->nick; - - setStringUtf(hContact, FACEBOOK_KEY_NICK, nick.c_str()); - - // Explode whole name into first, second and last name - std::vector<std::string> names; - utils::text::explode(fbu->real_name, " ", &names); - - setStringUtf(hContact, FACEBOOK_KEY_FIRST_NAME, names.size() > 0 ? names.front().c_str() : ""); - setStringUtf(hContact, FACEBOOK_KEY_LAST_NAME, names.size() > 1 ? names.back().c_str() : ""); - - std::string middle; - if (names.size() > 2) { - for (std::string::size_type i = 1; i < names.size() - 1; i++) { - if (!middle.empty()) - middle += " "; - - middle += names.at(i); - } - } - setStringUtf(hContact, FACEBOOK_KEY_SECOND_NAME, middle.c_str()); -} - -bool FacebookProto::IsMyContact(MCONTACT hContact, bool include_chat) -{ - const char *proto = Proto_GetBaseAccountName(hContact); - if (proto && !mir_strcmp(m_szModuleName, proto)) { - if (include_chat) - return true; - return !isChatRoom(hContact); - } - return false; -} - -MCONTACT FacebookProto::ChatIDToHContact(const std::string &chat_id) -{ - if (chat_id.empty()) { - debugLogA("!!! Calling ChatIDToContactID() with empty chat_id"); - return 0; - } - - // First check cache - auto it = facy.chat_id_to_hcontact.find(chat_id); - if (it != facy.chat_id_to_hcontact.end()) { - // Check if contact is still valid - if (db_is_contact((WPARAM)it->second) == 1) - return it->second; - else - facy.chat_id_to_hcontact.erase(it); - } - - // Go through all local contacts - for (auto &hContact : AccContacts()) { - if (!IsMyContact(hContact, true)) - continue; - - ptrA id(getStringA(hContact, "ChatRoomID")); - if (id && !mir_strcmp(id, chat_id.c_str())) { - facy.chat_id_to_hcontact.insert(std::make_pair(chat_id, hContact)); - return hContact; - } - } - - return 0; -} - -MCONTACT FacebookProto::ContactIDToHContact(const std::string &user_id) -{ - if (user_id.empty()) { - debugLogA("!!! Calling ContactIDToHContact() with empty user_id"); - return 0; - } - - // First check cache - std::map<std::string, MCONTACT>::iterator it = facy.user_id_to_hcontact.find(user_id); - if (it != facy.user_id_to_hcontact.end()) { - // Check if contact is still valid - if (db_is_contact((WPARAM)it->second) == 1) - return it->second; - else - facy.user_id_to_hcontact.erase(it); - } - - // Go through all local contacts - for (auto &hContact : AccContacts()) { - if (isChatRoom(hContact)) - continue; - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (id && !mir_strcmp(id, user_id.c_str())) { - facy.user_id_to_hcontact.insert(std::make_pair(user_id, hContact)); - return hContact; - } - } - - return 0; -} - -std::string FacebookProto::ThreadIDToContactID(const std::string &thread_id) -{ - if (thread_id.empty()) { - debugLogA("!!! Calling ThreadIDToContactID() with empty thread_id"); - return ""; - } - - // First check cache - std::map<std::string, std::string>::iterator it = facy.thread_id_to_user_id.find(thread_id); - if (it != facy.thread_id_to_user_id.end()) { - return it->second; - } - - // Go through all local contacts - for (auto &hContact : AccContacts()) { - if (!IsMyContact(hContact)) - continue; - - ptrA tid(getStringA(hContact, FACEBOOK_KEY_TID)); - if (tid && !mir_strcmp(tid, thread_id.c_str())) { - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - std::string user_id = (id ? id : ""); - if (!user_id.empty()) { - facy.thread_id_to_user_id.insert(std::make_pair(thread_id, user_id)); - return user_id; - } - break; // this shouldn't happen unless user manually deletes ID from FB contact in DB - } - } - - // We don't have any contact with this thread_id cached, we must ask server - if (isOffline()) - return ""; - - http::response resp = facy.sendRequest(facy.threadInfoRequest(true, thread_id.c_str())); - - std::string user_id; - - if (resp.code == HTTP_CODE_OK) { - if (ParseThreadInfo(&resp.data, &user_id) == EXIT_SUCCESS) { - if (!user_id.empty()) - facy.thread_id_to_user_id.insert(std::make_pair(thread_id, user_id)); - - debugLogA("*** Thread info processed"); - } - else debugLogA("*** Error processing thread info"); - } - - return user_id; -} - -void FacebookProto::LoadContactInfo(facebook_user* fbu) -{ - if (isOffline()) - return; - - LIST<char> userIds(1); - userIds.insert(mir_strdup(fbu->user_id.c_str())); - - http::response resp = facy.sendRequest(facy.userInfoRequest(userIds)); - - FreeList(userIds); - userIds.destroy(); - - if (resp.code == HTTP_CODE_OK) { - if (ParseUserInfo(&resp.data, fbu) == EXIT_SUCCESS) - debugLogA("*** Contact thread info processed"); - else - debugLogA("*** Error processing contact thread info"); - } -} - -MCONTACT FacebookProto::AddToContactList(facebook_user* fbu, bool force_add, bool add_temporarily) -{ - // Ignore self user completely - if (fbu->user_id == facy.self_.user_id) - return 0; - - // First, check if this contact exists (and if does, just return it) - if (!force_add) { - MCONTACT hContact = ContactIDToHContact(fbu->user_id); - - if (hContact) - return hContact; - } - - // Try to make a new contact - MCONTACT hContact = db_add_contact(); - - if (hContact && Proto_AddToContact(hContact, m_szModuleName) != 0) { - db_delete_contact(hContact); - hContact = 0; - } - - // If we have some contact, we'll save its data - if (hContact) { - // Save these values only when adding new contact, not when updating existing - if (add_temporarily) { - Contact_Hide(hContact); - Contact_RemoveFromList(hContact); - } - - setString(hContact, FACEBOOK_KEY_ID, fbu->user_id.c_str()); - - std::string homepage = FACEBOOK_URL_PROFILE + fbu->user_id; - setString(hContact, "Homepage", homepage.c_str()); - setWString(hContact, "MirVer", fbu->getMirVer()); - - db_unset(hContact, "CList", "MyHandle"); - - Clist_SetGroup(hContact, m_tszDefaultGroup); - - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, fbu->type); - - if (getByte(FACEBOOK_KEY_DISABLE_STATUS_NOTIFY, 0)) - Ignore_Ignore(hContact, IGNOREEVENT_USERONLINE); - - if (!fbu->real_name.empty()) - SaveName(hContact, fbu); - - if (!fbu->username.empty()) - setString(hContact, FACEBOOK_KEY_USERNAME, fbu->username.c_str()); - - if (fbu->gender) - setByte(hContact, "Gender", fbu->gender); - - // CheckAvatarChange(hContact, fbu->image_url); - } - - return hContact; -} - -void FacebookProto::DeleteContactFromServer(void *data) -{ - facy.handle_entry("DeleteContactFromServer"); - - if (data == nullptr) - return; - - std::string id = *(std::string*)data; - delete (std::string*)data; - - if (isOffline()) - return; - - // Delete contact from server - http::response resp = facy.sendRequest(facy.deleteFriendRequest(id.c_str())); - if (resp.data.find("\"payload\":null", 0) != std::string::npos) { - // If contact wasn't deleted from database - MCONTACT hContact = ContactIDToHContact(id); - if (hContact != 0) { - setWord(hContact, "Status", ID_STATUS_OFFLINE); - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE); - setDword(hContact, FACEBOOK_KEY_DELETED, ::time(0)); - } - - NotifyEvent(m_tszUserName, TranslateT("Contact was removed from your server list."), 0, EVENT_FRIENDSHIP); - } - else facy.client_notify(TranslateT("Error occurred when removing contact from server.")); - - if (resp.code != HTTP_CODE_OK) - facy.handle_error("DeleteContactFromServer"); -} - -void FacebookProto::AddContactToServer(void *data) -{ - facy.handle_entry("AddContactToServer"); - - if (data == nullptr) - return; - - std::string id = *(std::string*)data; - delete (std::string*)data; - - if (isOffline()) - return; - - // Request friendship - http::response resp = facy.sendRequest(facy.addFriendRequest(id.c_str())); - - if (resp.data.find("\"success\":true", 0) != std::string::npos) { - MCONTACT hContact = ContactIDToHContact(id); - - // If contact wasn't deleted from database - if (hContact != 0) - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_REQUEST); - - NotifyEvent(m_tszUserName, TranslateT("Request for friendship was sent."), 0, EVENT_FRIENDSHIP); - } - else facy.client_notify(TranslateT("Error occurred when requesting friendship.")); - - if (resp.code != HTTP_CODE_OK) - facy.handle_error("AddContactToServer"); -} - -void FacebookProto::ApproveContactToServer(void *data) -{ - facy.handle_entry("ApproveContactToServer"); - - if (data == nullptr) - return; - - MCONTACT hContact = *(MCONTACT*)data; - delete (MCONTACT*)data; - - if (isOffline()) - return; - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (!id) - return; - - // Confirm friendship request - http::response resp = facy.sendRequest(facy.answerFriendshipRequest(id, true)); - - if (resp.data.find("\"success\":true") != std::string::npos) { - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_FRIEND); - NotifyEvent(m_tszUserName, TranslateT("Request for friendship was accepted."), 0, EVENT_FRIENDSHIP); - } - else facy.client_notify(TranslateT("Error occurred when accepting friendship request.")); - - if (resp.code != HTTP_CODE_OK) - facy.handle_error("ApproveContactToServer"); -} - -void FacebookProto::CancelFriendsRequest(void *data) -{ - facy.handle_entry("CancelFriendsRequest"); - - if (data == nullptr) - return; - - MCONTACT hContact = *(MCONTACT*)data; - delete (MCONTACT*)data; - - if (isOffline()) - return; - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (!id) - return; - - // Cancel (our) friendship request - http::response resp = facy.sendRequest(facy.cancelFriendshipRequest(id)); - if (resp.data.find("\"payload\":null", 0) != std::string::npos) { - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE); - NotifyEvent(m_tszUserName, TranslateT("Request for friendship was canceled."), 0, EVENT_FRIENDSHIP); - } - else facy.client_notify(TranslateT("Error occurred when canceling friendship request.")); - - if (resp.code != HTTP_CODE_OK) - facy.handle_error("CancelFriendsRequest"); -} - -void FacebookProto::IgnoreFriendshipRequest(void *data) -{ - facy.handle_entry("IgnoreFriendshipRequest"); - - if (data == nullptr) - return; - - MCONTACT hContact = *(MCONTACT*)data; - delete (MCONTACT*)data; - - if (isOffline()) - return; - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (!id) - return; - - // Ignore friendship request - http::response resp = facy.sendRequest(facy.answerFriendshipRequest(id, false)); - - if (resp.data.find("\"success\":true") != std::string::npos) { - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE); - NotifyEvent(m_tszUserName, TranslateT("Request for friendship was ignored."), 0, EVENT_FRIENDSHIP); - - // Delete this contact, if he's temporary - if (!Contact_OnList(hContact)) - db_delete_contact(hContact); - } - else facy.client_notify(TranslateT("Error occurred when ignoring friendship request.")); - - if (resp.code != HTTP_CODE_OK) - facy.handle_error("IgnoreFriendshipRequest"); -} - -void FacebookProto::SendPokeWorker(void *p) -{ - facy.handle_entry("SendPokeWorker"); - - if (p == nullptr) - return; - - std::string *id = (std::string*)p; - - if (isOffline()) { - delete id; - return; - } - - // Send poke - http::response resp = facy.sendRequest(facy.sendPokeRequest(id->c_str())); - - if (resp.data.find("\"payload\":null", 0) != std::string::npos) { - resp.data = utils::text::slashu_to_utf8( - utils::text::source_get_value(&resp.data, 2, "__html\":\"", "\"}")); - - std::string message = utils::text::source_get_value(&resp.data, 4, "<img", "<div", ">", "<\\/div>"); - - if (message.empty()) // message has different format, show whole message - message = resp.data; - - message = utils::text::html_entities_decode( - utils::text::remove_html(message)); - - ptrW tmessage(mir_utf8decodeW(message.c_str())); - NotifyEvent(m_tszUserName, tmessage, 0, EVENT_OTHER); - } - - facy.handle_success("SendPokeWorker"); - - delete id; -} - -void FacebookProto::RefreshUserInfo(void *data) -{ - if (data == nullptr) - return; - - MCONTACT hContact = *(MCONTACT*)data; - delete (MCONTACT*)data; - - ptrA user_id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (user_id == nullptr || isOffline()) { - ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, nullptr); - return; - } - - facebook_user fbu; - fbu.user_id = user_id; - - LoadContactInfo(&fbu); - - // TODO: don't duplicate code this way, refactor all this userInfo loading - // TODO: load more info about user (authorization state,...) - - std::string homepage = FACEBOOK_URL_PROFILE + fbu.user_id; - setString(hContact, "Homepage", homepage.c_str()); - - if (!fbu.real_name.empty()) - SaveName(hContact, &fbu); - - if (fbu.gender) - setByte(hContact, "Gender", fbu.gender); - - int oldType = getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE); - // From server we won't get request/approve types, only none, so we don't want to overwrite and lost it in that case - if (fbu.type != CONTACT_NONE || (oldType != CONTACT_REQUEST && oldType != CONTACT_APPROVE)) { - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, fbu.type); - } - - // If this contact is page, set it as invisible (if enabled in options) - if (getBool(FACEBOOK_KEY_PAGES_ALWAYS_ONLINE, DEFAULT_PAGES_ALWAYS_ONLINE) && fbu.type == CONTACT_PAGE) - setWord(hContact, "Status", ID_STATUS_INVISIBLE); - - CheckAvatarChange(hContact, fbu.image_url); - - // Load additional info from profile page (e.g., birthday) - http::response resp = facy.sendRequest(facy.profileInfoRequest(fbu.user_id.c_str())); - - if (resp.code == HTTP_CODE_OK) { - std::string birthday = utils::text::source_get_value(&resp.data, 4, ">Birthday</", "<td", ">", "</td>"); - birthday = utils::text::remove_html(birthday); - - std::string::size_type pos = birthday.find(" "); - std::string::size_type pos2 = birthday.find(","); - if (pos != std::string::npos) { - std::string month = birthday.substr(0, pos); - std::string day = birthday.substr(pos + 1, pos2 != std::string::npos ? pos2 - pos - 1 : std::string::npos); - - setByte(hContact, "BirthDay", atoi(day.c_str())); - - const static char *months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; - for (int i = 0; i < 12; i++) { - if (!mir_strcmp(months[i], month.c_str())) { - setByte(hContact, "BirthMonth", i + 1); - break; - } - } - - if (pos2 != std::string::npos) { - std::string year = birthday.substr(pos2 + 2, 4); - setWord(hContact, "BirthYear", atoi(year.c_str())); - } - else // We have to set ANY year, otherwise UserInfoEx shows completely wrong date - setWord(hContact, "BirthYear", 1800); - } - } - - ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, nullptr); -} - -void FacebookProto::OnContactDeleted(MCONTACT hContact) -{ - // Remove this contact from caches - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (id) - facy.user_id_to_hcontact.erase(std::string(id)); - - ptrA tid(getStringA(hContact, FACEBOOK_KEY_TID)); - if (tid) - facy.thread_id_to_user_id.erase(std::string(tid)); - - if (isChatRoom(hContact)) { - ptrA chat_id(getStringA(hContact, "ChatRoomID")); - if (chat_id) - facy.chat_id_to_hcontact.erase(std::string(chat_id)); - } - - // Cancel friendship (with confirmation) - CancelFriendship(hContact, 1); -} - - -void FacebookProto::StartTyping(MCONTACT hContact) -{ - // ignore if contact is already typing - if (facy.typers.find(hContact) != facy.typers.end()) - return; - - // show notification and insert into typing set - CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)FACEBOOK_TYPING_TIME); - facy.typers.insert(hContact); -} - -void FacebookProto::StopTyping(MCONTACT hContact) -{ - // ignore if contact is not typing - if (facy.typers.find(hContact) == facy.typers.end()) - return; - - // show notification and remove from typing set - CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF); - facy.typers.erase(hContact); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// handling friends requests - -HttpRequest* facebook_client::addFriendRequest(const char *userId) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/add_friend/action.php"); - - p << INT_PARAM("__a", 1); - - p->Body - << CHAR_PARAM("to_friend", userId) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("action", "add_friend") - << CHAR_PARAM("how_found", "profile_button") - << CHAR_PARAM("ref_param", "ts") - << CHAR_PARAM("no_flyout_on_click", "false"); - - return p; -} - -HttpRequest* facebook_client::deleteFriendRequest(const char *userId) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/profile/removefriendconfirm.php"); - - p << INT_PARAM("__a", 1) - << CHAR_PARAM("norefresh", "true") - << CHAR_PARAM("unref", "button_dropdown") - << CHAR_PARAM("uid", userId); - - p->Body - << CHAR_PARAM("uid", userId) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("norefresh", "true") - << CHAR_PARAM("unref", "button_dropdown") - << INT_PARAM("confirmed", 1) - << INT_PARAM("__a", 1); - - return p; -} - -HttpRequest* facebook_client::getFriendshipsRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FORMAT, "%s/friends/center/requests/", mbasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE); - - p->flags |= NLHRF_REDIRECT; - - return p; -} - -HttpRequest* facebook_client::cancelFriendshipRequest(const char *userId) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/friends/requests/cancel.php"); - - p << INT_PARAM("__a", 1); - - p->Body - << INT_PARAM("confirmed", 1) - << CHAR_PARAM("friend", userId) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()); - - return p; -} - -HttpRequest* facebook_client::answerFriendshipRequest(const char *userId, bool bConfirm) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/requests/friends/ajax/"); - - p << INT_PARAM("__a", 1); - - p->Body - << CHAR_PARAM("action", (bConfirm) ? "confirm" : "reject") - << CHAR_PARAM("id", userId) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()); - - return p; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// requesting user info - -HttpRequest* facebook_client::userInfoRequest(const LIST<char> &userIds) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/chat/user_info/"); - - p << INT_PARAM("dpr", 1); - - for (int i = 0; i < userIds.getCount(); i++) { - CMStringA id(::FORMAT, "ids[%i]", i); - p->Body << CHAR_PARAM(id, userIds[i]); - } - - p->Body - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << INT_PARAM("__a", 1) - << INT_PARAM("__be", 1) - << CHAR_PARAM("__pc", "PHASED:DEFAULT"); - - return p; -} - -HttpRequest* facebook_client::userInfoAllRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/chat/user_info_all/"); - - p << INT_PARAM("dpr", 1) - << CHAR_PARAM("viewer", self_.user_id.c_str()); - - p->Body - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__a", 1) - << INT_PARAM("__be", -1); - - return p; -} - -HttpRequest* facebook_client::buddylistUpdate() -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_MOBILE "/buddylist_update.php"); - - p->Body - << CHAR_PARAM("data_fetch", "true") - << CHAR_PARAM("m_sess", "") - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("jazoest", "21824") - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__ajax__", "") - << CHAR_PARAM("__user", self_.user_id.c_str()); - - // send_full_data=true sends more data - - return p; -} diff --git a/protocols/FacebookRM/src/db.h b/protocols/FacebookRM/src/db.h deleted file mode 100644 index d71e9458ab..0000000000 --- a/protocols/FacebookRM/src/db.h +++ /dev/null @@ -1,98 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#pragma once
-
-// Contact DB keys
-#define FACEBOOK_KEY_LOGIN "Email"
-#define FACEBOOK_KEY_ID "ID"
-#define FACEBOOK_KEY_TID "ThreadID"
-#define FACEBOOK_KEY_FIRST_NAME "FirstName"
-#define FACEBOOK_KEY_SECOND_NAME "SecondName"
-#define FACEBOOK_KEY_LAST_NAME "LastName"
-#define FACEBOOK_KEY_NICK "Nick"
-#define FACEBOOK_KEY_USERNAME "Username"
-#define FACEBOOK_KEY_PASS "Password"
-#define FACEBOOK_KEY_DEVICE_ID "DeviceID"
-#define FACEBOOK_KEY_AVATAR "Avatar"
-#define FACEBOOK_KEY_DELETED "DeletedTS"
-#define FACEBOOK_KEY_CONTACT_TYPE "ContactType"
-#define FACEBOOK_KEY_MESSAGE_ID "LastMessageId"
-#define FACEBOOK_KEY_MESSAGE_READ "LastMsgReadTime"
-#define FACEBOOK_KEY_MESSAGE_READERS "MessageReaders"
-
-// Thread specific DB keys
-#define FACEBOOK_KEY_CHAT_CAN_REPLY "CanReply"
-#define FACEBOOK_KEY_CHAT_READ_ONLY "ReadOnly"
-#define FACEBOOK_KEY_CHAT_IS_ARCHIVED "IsArchived"
-#define FACEBOOK_KEY_CHAT_IS_SUBSCRIBED "IsSubscribed"
-
-// Contact and account DB keys
-#define FACEBOOK_KEY_KEEP_UNREAD "KeepUnread" // (byte) 1 = don't mark messages as read on server (works globally or per contact)
-
-// Account DB keys
-#define FACEBOOK_KEY_DEF_GROUP "DefaultGroup"
-#define FACEBOOK_KEY_SET_MIRANDA_STATUS "SetMirandaStatus"
-#define FACEBOOK_KEY_SYSTRAY_NOTIFY "UseSystrayNotify"
-#define FACEBOOK_KEY_DISABLE_STATUS_NOTIFY "DisableStatusNotify"
-#define FACEBOOK_KEY_BIG_AVATARS "UseBigAvatars"
-#define FACEBOOK_KEY_DISCONNECT_CHAT "DisconnectChatEnable"
-#define FACEBOOK_KEY_MAP_STATUSES "MapStatuses"
-#define FACEBOOK_KEY_CUSTOM_SMILEYS "CustomSmileys"
-#define FACEBOOK_KEY_SERVER_TYPE "ServerType"
-#define FACEBOOK_KEY_PRIVACY_TYPE "PrivacyType"
-#define FACEBOOK_KEY_PLACE "Place"
-#define FACEBOOK_KEY_LAST_WALL "LastWall"
-#define FACEBOOK_KEY_LOAD_PAGES "LoadPages"
-#define FACEBOOK_KEY_FILTER_ADS "FilterAds"
-#define FACEBOOK_KEY_LOGON_TS "LogonTS"
-#define FACEBOOK_KEY_LAST_ACTION_TS "LastActionTS"
-#define FACEBOOK_KEY_MESSAGES_ON_OPEN "MessagesOnOpen"
-#define FACEBOOK_KEY_MESSAGES_ON_OPEN_COUNT "MessagesOnOpenCount"
-#define FACEBOOK_KEY_HIDE_CHATS "HideChats"
-#define FACEBOOK_KEY_ENABLE_CHATS "EnableChat"
-#define FACEBOOK_KEY_JOIN_EXISTING_CHATS "JoinExistingChats"
-#define FACEBOOK_KEY_NOTIFICATIONS_CHATROOM "NotificationsChatroom"
-#define FACEBOOK_KEY_NAME_AS_NICK "NameAsNick"
-#define FACEBOOK_KEY_LOAD_ALL_CONTACTS "LoadAllContacts"
-#define FACEBOOK_KEY_PAGES_ALWAYS_ONLINE "PagesAlwaysOnline"
-#define FACEBOOK_KEY_TYPING_WHEN_INVISIBLE "TypingWhenInvisible"
-
-// Account DB keys - notifications
-#define FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE "EventNotificationsEnable"
-#define FACEBOOK_KEY_EVENT_FEEDS_ENABLE "EventFeedsEnable"
-#define FACEBOOK_KEY_EVENT_FRIENDSHIP_ENABLE "EventFriendshipEnable"
-#define FACEBOOK_KEY_EVENT_TICKER_ENABLE "EventTickerEnable"
-#define FACEBOOK_KEY_EVENT_ON_THIS_DAY_ENABLE "EventMemoriesEnable"
-#define FACEBOOK_KEY_FEED_TYPE "EventFeedsType"
-
-// Hidden account DB keys (can't be changed through GUI)
-#define FACEBOOK_KEY_POLL_RATE "PollRate" // [HIDDEN] - (byte)
-#define FACEBOOK_KEY_TIMEOUTS_LIMIT "TimeoutsLimit" // [HIDDEN] - (byte)
-#define FACEBOOK_KEY_LOCALE "Locale" // [HIDDEN] - (string) en_US, cs_CZ, etc. (requires restart to apply)
-#define FACEBOOK_KEY_NASEEMS_SPAM_MODE "NaseemsSpamMode" // [HIDDEN] - (byte) 1 = don't load messages sent from other instances (e.g., browser) - known as "Naseem's spam mode"
-#define FACEBOOK_KEY_OPEN_URL_BROWSER "OpenUrlBrowser" // [HIDDEN] - (unicode) = absolute path to browser to open url links with
-#define FACEBOOK_KEY_SEND_MESSAGE_TRIES "SendMessageTries" // [HIDDEN] - (byte) = number of tries to send message, default=1, min=1, max=5
-#define FACEBOOK_KEY_PAGE_PREFIX "PagePrefix" // [HIDDEN] - (unicode) = prefix for name of "page" contacts (requires restart to apply), default is emoji :page_facing_up: (written as unicode char)
-
-// Temporary key for login
-#define FACEBOOK_KEY_TRIED_DELETING_DEVICE_ID "_TriedDeletingDeviceID"
\ No newline at end of file diff --git a/protocols/FacebookRM/src/dialogs.cpp b/protocols/FacebookRM/src/dialogs.cpp deleted file mode 100644 index 0c7c9616dd..0000000000 --- a/protocols/FacebookRM/src/dialogs.cpp +++ /dev/null @@ -1,666 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -// News Feed types -const ttype feed_types[3] = -{ - { LPGEN("Top News"), "h_nor" }, - { LPGEN("Most Recent"), "h_chr" }, - { LPGEN("Pages"), "pages" }, -}; - -// Server types -const ttype server_types[3] = -{ - { LPGEN("Classic website"), "www.facebook.com" }, - { LPGEN("Mobile website"), "m.facebook.com" }, - { LPGEN("Smartphone website"), "touch.facebook.com" }, -}; - -// Status privacy types -const ttype privacy_types[5] = -{ - { LPGEN("Public"), "80" }, - { LPGEN("Friends of friends"), "111&audience[0][custom_value]=50" }, - { LPGEN("Friends"), "40" }, - { LPGEN("Friends except acquaintances"), "127" }, - { LPGEN("Only me"), "10" }, -}; - -static BOOL LoadDBCheckState(FacebookProto* ppro, HWND hwnd, int idCtrl, const char* szSetting, BYTE bDef) -{ - BOOL state = ppro->getByte(szSetting, bDef); - CheckDlgButton(hwnd, idCtrl, state ? BST_CHECKED : BST_UNCHECKED); - return state; -} - -static BOOL StoreDBCheckState(FacebookProto* ppro, HWND hwnd, int idCtrl, const char* szSetting) -{ - BOOL state = IsDlgButtonChecked(hwnd, idCtrl); - ppro->setByte(szSetting, (BYTE)state); - return state; -} - -INT_PTR CALLBACK FBAccountProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - switch (message) { - - case WM_INITDIALOG: - { - TranslateDialogDefault(hwnd); - - proto = reinterpret_cast<FacebookProto*>(lparam); - SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam); - - ptrA login(db_get_sa(0, proto->ModuleName(), FACEBOOK_KEY_LOGIN)); - if (login != nullptr) - SetDlgItemTextA(hwnd, IDC_UN, login); - - ptrA password(db_get_sa(0, proto->ModuleName(), FACEBOOK_KEY_PASS)); - if (password != nullptr) - SetDlgItemTextA(hwnd, IDC_PW, password); - - if (!proto->isOffline()) { - SendDlgItemMessage(hwnd, IDC_UN, EM_SETREADONLY, 1, 0); - SendDlgItemMessage(hwnd, IDC_PW, EM_SETREADONLY, 1, 0); - } - return TRUE; - } - case WM_COMMAND: - if (LOWORD(wparam) == IDC_NEWACCOUNTLINK) { - proto->OpenUrl(std::string(FACEBOOK_URL_HOMEPAGE)); - return TRUE; - } - - if (HIWORD(wparam) == EN_CHANGE && reinterpret_cast<HWND>(lparam) == GetFocus()) { - switch (LOWORD(wparam)) { - case IDC_UN: - case IDC_PW: - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - } - } - break; - - case WM_NOTIFY: - if (reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY) { - char str[128]; - - GetDlgItemTextA(hwnd, IDC_UN, str, _countof(str)); - db_set_s(0, proto->ModuleName(), FACEBOOK_KEY_LOGIN, str); - - GetDlgItemTextA(hwnd, IDC_PW, str, _countof(str)); - db_set_s(0, proto->ModuleName(), FACEBOOK_KEY_PASS, str); - return TRUE; - } - break; - - } - - return FALSE; -} - -void RefreshPrivacy(HWND hwnd, post_status_data *data) -{ - SendDlgItemMessage(hwnd, IDC_PRIVACY, CB_RESETCONTENT, 0, 0); - int wall_id = SendDlgItemMessage(hwnd, IDC_WALL, CB_GETCURSEL, 0, 0); - if (data->walls[wall_id]->user_id == data->proto->facy.self_.user_id) { - for (size_t i = 0; i < _countof(privacy_types); i++) - SendDlgItemMessageA(hwnd, IDC_PRIVACY, CB_INSERTSTRING, i, reinterpret_cast<LPARAM>(Translate(privacy_types[i].name))); - } - else { - SendDlgItemMessage(hwnd, IDC_PRIVACY, CB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(TranslateT("Default"))); - } - SendDlgItemMessage(hwnd, IDC_PRIVACY, CB_SETCURSEL, 0, 0); - SendDlgItemMessage(hwnd, IDC_PRIVACY, CB_SETCURSEL, data->proto->getByte(FACEBOOK_KEY_PRIVACY_TYPE, 0), 0); -} - -void ClistPrepare(FacebookProto *proto, MCONTACT hItem, HWND hwndList) -{ - if (hItem == 0) - hItem = (MCONTACT)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0); - - while (hItem) { - MCONTACT hItemN = (MCONTACT)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem); - - if (IsHContactGroup(hItem)) { - MCONTACT hItemT = (MCONTACT)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); - if (hItemT) - ClistPrepare(proto, hItemT, hwndList); - } - else if (IsHContactContact(hItem)) { - if (!proto->IsMyContact(hItem) || ptrA(proto->getStringA(hItem, FACEBOOK_KEY_ID)) == nullptr) - SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0); - } - - hItem = hItemN; - } -} - -void GetSelectedContacts(FacebookProto *proto, MCONTACT hItem, HWND hwndList, std::vector<facebook_user*> *contacts) -{ - if (hItem == 0) - hItem = (MCONTACT)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0); - - while (hItem) { - if (IsHContactGroup(hItem)) { - MCONTACT hItemT = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); - if (hItemT) - GetSelectedContacts(proto, hItemT, hwndList, contacts); - } - else { - if (SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) { - facebook_user *fu = new facebook_user(); - - ptrA userId(proto->getStringA(hItem, FACEBOOK_KEY_ID)); - if (userId) - fu->user_id = userId; - - ptrW realName(proto->getWStringA(hItem, FACEBOOK_KEY_NICK)); - if (realName) - fu->real_name = _T2A(realName); - - contacts->push_back(fu); - } - } - hItem = (MCONTACT)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem); - } -} - -void ResizeHorizontal(HWND hwnd, bool wide) -{ - RECT r = { 0, 0, wide ? 422 : 271, 116 }; - MapDialogRect(hwnd, &r); - r.bottom += GetSystemMetrics(SM_CYSMCAPTION); - SetWindowPos(hwnd, nullptr, 0, 0, r.right, r.bottom, SWP_NOMOVE | SWP_NOZORDER); - SetDlgItemText(hwnd, IDC_EXPAND, (wide ? TranslateT("<< Contacts") : TranslateT("Contacts >>"))); - ShowWindow(GetDlgItem(hwnd, IDC_CCLIST), wide); - ShowWindow(GetDlgItem(hwnd, IDC_CCLIST_LABEL), wide); -} - -static bool bShowContacts; - -INT_PTR CALLBACK FBMindProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - post_status_data *data; - - switch (message) { - - case WM_INITDIALOG: - { - TranslateDialogDefault(hwnd); - - Window_SetIcon_IcoLib(hwnd, g_plugin.getIconHandle(IDI_MIND)); - - data = reinterpret_cast<post_status_data*>(lparam); - - SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam); - SendDlgItemMessage(hwnd, IDC_MINDMSG, EM_LIMITTEXT, FACEBOOK_MIND_LIMIT, 0); - SendDlgItemMessage(hwnd, IDC_URL, EM_LIMITTEXT, 1024, 0); - - ptrW place(data->proto->getWStringA(FACEBOOK_KEY_PLACE)); - SetDlgItemText(hwnd, IDC_PLACE, place != nullptr ? place : L"Miranda NG"); - - bShowContacts = data->proto->getByte("PostStatusExpand", 0) > 0; - ResizeHorizontal(hwnd, bShowContacts); - - HWND hwndClist = GetDlgItem(hwnd, IDC_CCLIST); - SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) & ~CLS_HIDEOFFLINE); - - for (std::vector<wall_data*>::size_type i = 0; i < data->walls.size(); i++) - SendDlgItemMessage(hwnd, IDC_WALL, CB_INSERTSTRING, i, reinterpret_cast<LPARAM>(data->walls[i]->title)); - SendDlgItemMessage(hwnd, IDC_WALL, CB_SETCURSEL, 0, 0); - SendDlgItemMessage(hwnd, IDC_WALL, CB_SETCURSEL, data->proto->getByte(FACEBOOK_KEY_LAST_WALL, 0), 0); - RefreshPrivacy(hwnd, data); - - ptrA firstname(data->proto->getStringA(FACEBOOK_KEY_FIRST_NAME)); - if (firstname != nullptr) { - char title[100]; - mir_snprintf(title, Translate("What's on your mind, %s?"), firstname); - SetWindowTextA(hwnd, title); - } - } - - EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); - return TRUE; - - case WM_NOTIFY: - { - NMCLISTCONTROL *nmc = (NMCLISTCONTROL *)lparam; - if (nmc->hdr.idFrom == IDC_CCLIST) { - switch (nmc->hdr.code) { - case CLN_LISTREBUILT: - data = reinterpret_cast<post_status_data*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - ClistPrepare(data->proto, 0, nmc->hdr.hwndFrom); - break; - } - } - } - break; - - case WM_COMMAND: - switch (LOWORD(wparam)) { - case IDC_WALL: - if (HIWORD(wparam) == CBN_SELCHANGE) { - data = reinterpret_cast<post_status_data*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - RefreshPrivacy(hwnd, data); - } - break; - - case IDC_MINDMSG: - case IDC_URL: - if (HIWORD(wparam) == EN_CHANGE) { - bool ok = SendDlgItemMessage(hwnd, IDC_MINDMSG, WM_GETTEXTLENGTH, 0, 0) > 0; - if (!ok && SendDlgItemMessage(hwnd, IDC_URL, WM_GETTEXTLENGTH, 0, 0) > 0) - ok = true; - - EnableWindow(GetDlgItem(hwnd, IDOK), ok); - return TRUE; - } - break; - - case IDC_EXPAND: - bShowContacts = !bShowContacts; - ResizeHorizontal(hwnd, bShowContacts); - break; - - case IDOK: - { - data = reinterpret_cast<post_status_data*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - wchar_t mindMessageT[FACEBOOK_MIND_LIMIT + 1]; - wchar_t urlT[1024]; - wchar_t placeT[100]; - - GetDlgItemText(hwnd, IDC_MINDMSG, mindMessageT, _countof(mindMessageT)); - GetDlgItemText(hwnd, IDC_PLACE, placeT, _countof(placeT)); - GetDlgItemText(hwnd, IDC_URL, urlT, _countof(urlT)); - ShowWindow(hwnd, SW_HIDE); - - int wall_id = SendDlgItemMessage(hwnd, IDC_WALL, CB_GETCURSEL, 0, 0); - int privacy_id = SendDlgItemMessage(hwnd, IDC_PRIVACY, CB_GETCURSEL, 0, 0); - - data->proto->setWString(FACEBOOK_KEY_PLACE, placeT); - data->proto->setByte("PostStatusExpand", bShowContacts); - - // remember last wall, only when there are more options - if (SendDlgItemMessage(hwnd, IDC_WALL, CB_GETCOUNT, 0, 0) > 1) - data->proto->setByte(FACEBOOK_KEY_LAST_WALL, wall_id); - - // remember last privacy, only when there are more options - if (SendDlgItemMessage(hwnd, IDC_PRIVACY, CB_GETCOUNT, 0, 0) > 1) - data->proto->setByte(FACEBOOK_KEY_PRIVACY_TYPE, privacy_id); - - status_data *status = new status_data(); - status->user_id = data->walls[wall_id]->user_id; - status->isPage = data->walls[wall_id]->isPage; - status->privacy = privacy_types[privacy_id].id; - status->place = T2Utf(placeT); - status->url = _T2A(urlT); - - HWND hwndList = GetDlgItem(hwnd, IDC_CCLIST); - GetSelectedContacts(data->proto, 0, hwndList, &status->users); - - T2Utf narrow(mindMessageT); - status->text = narrow; - - if (status->user_id == data->proto->facy.self_.user_id && data->proto->last_status_msg_ != (char*)narrow) - data->proto->last_status_msg_ = narrow; - - data->proto->ForkThread(&FacebookProto::SetAwayMsgWorker, status); - - EndDialog(hwnd, wparam); - return TRUE; - } - - case IDCANCEL: - EndDialog(hwnd, wparam); - return TRUE; - } - break; - - case WM_DESTROY: - data = reinterpret_cast<post_status_data*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - for (std::vector<wall_data*>::size_type i = 0; i < data->walls.size(); i++) { - mir_free(data->walls[i]->title); - delete data->walls[i]; - } - - delete data; - } - - return FALSE; -} - -INT_PTR CALLBACK FBOptionsProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - switch (message) { - case WM_INITDIALOG: - { - TranslateDialogDefault(hwnd); - - proto = reinterpret_cast<FacebookProto*>(lparam); - SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam); - - ptrA login(db_get_sa(0, proto->ModuleName(), FACEBOOK_KEY_LOGIN)); - if (login != nullptr) - SetDlgItemTextA(hwnd, IDC_UN, login); - - ptrA password(db_get_sa(0, proto->ModuleName(), FACEBOOK_KEY_PASS)); - if (password != nullptr) - SetDlgItemTextA(hwnd, IDC_PW, password); - - if (!proto->isOffline()) { - SendDlgItemMessage(hwnd, IDC_UN, EM_SETREADONLY, TRUE, 0); - SendDlgItemMessage(hwnd, IDC_PW, EM_SETREADONLY, TRUE, 0); - } - - SendDlgItemMessage(hwnd, IDC_GROUP, EM_LIMITTEXT, FACEBOOK_GROUP_NAME_LIMIT, 0); - - if (proto->m_tszDefaultGroup != nullptr) - SetDlgItemText(hwnd, IDC_GROUP, proto->m_tszDefaultGroup); - - 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_NAME_AS_NICK, FACEBOOK_KEY_NAME_AS_NICK, DEFAULT_NAME_AS_NICK); - LoadDBCheckState(proto, hwnd, IDC_LOAD_ALL_CONTACTS, FACEBOOK_KEY_LOAD_ALL_CONTACTS, DEFAULT_LOAD_ALL_CONTACTS); - LoadDBCheckState(proto, hwnd, IDC_PAGES_ALWAYS_ONLINE, FACEBOOK_KEY_PAGES_ALWAYS_ONLINE, DEFAULT_PAGES_ALWAYS_ONLINE); - } - return TRUE; - - case WM_COMMAND: - { - switch (LOWORD(wparam)) { - case IDC_NEWACCOUNTLINK: - proto->OpenUrl(std::string(FACEBOOK_URL_HOMEPAGE)); - return TRUE; - case IDC_UN: - case IDC_PW: - case IDC_GROUP: - if (HIWORD(wparam) == EN_CHANGE && (HWND)lparam == GetFocus()) - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - break; - default: - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - } - } - break; - - case WM_NOTIFY: - if (reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY) { - char str[128]; wchar_t tstr[128]; - - GetDlgItemTextA(hwnd, IDC_UN, str, _countof(str)); - db_set_s(0, proto->ModuleName(), FACEBOOK_KEY_LOGIN, str); - - GetDlgItemTextA(hwnd, IDC_PW, str, _countof(str)); - proto->setString(FACEBOOK_KEY_PASS, str); - - GetDlgItemText(hwnd, IDC_GROUP, tstr, _countof(tstr)); - if (tstr[0] != '\0') { - proto->m_tszDefaultGroup = mir_wstrdup(tstr); - proto->setWString(FACEBOOK_KEY_DEF_GROUP, tstr); - Clist_GroupCreate(0, tstr); - } - else { - proto->delSetting(FACEBOOK_KEY_DEF_GROUP); - proto->m_tszDefaultGroup = nullptr; - } - - 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_NAME_AS_NICK, FACEBOOK_KEY_NAME_AS_NICK); - StoreDBCheckState(proto, hwnd, IDC_LOAD_ALL_CONTACTS, FACEBOOK_KEY_LOAD_ALL_CONTACTS); - StoreDBCheckState(proto, hwnd, IDC_PAGES_ALWAYS_ONLINE, FACEBOOK_KEY_PAGES_ALWAYS_ONLINE); - return TRUE; - } - break; - } - - return FALSE; -} - -INT_PTR CALLBACK FBOptionsStatusesProc(HWND hwnd, UINT message, WPARAM, LPARAM lparam) -{ - FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - switch (message) { - case WM_INITDIALOG: - TranslateDialogDefault(hwnd); - - proto = reinterpret_cast<FacebookProto*>(lparam); - SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam); - - LoadDBCheckState(proto, hwnd, IDC_DISCONNECT_CHAT, FACEBOOK_KEY_DISCONNECT_CHAT, DEFAULT_DISCONNECT_CHAT); - LoadDBCheckState(proto, hwnd, IDC_SET_STATUS, FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS); - LoadDBCheckState(proto, hwnd, IDC_MAP_STATUSES, FACEBOOK_KEY_MAP_STATUSES, DEFAULT_MAP_STATUSES); - LoadDBCheckState(proto, hwnd, IDC_LOAD_PAGES, FACEBOOK_KEY_LOAD_PAGES, DEFAULT_LOAD_PAGES); - LoadDBCheckState(proto, hwnd, IDC_TYPING_WHEN_INVISIBLE, FACEBOOK_KEY_TYPING_WHEN_INVISIBLE, DEFAULT_TYPING_WHEN_INVISIBLE); - return TRUE; - - case WM_COMMAND: { - //switch (LOWORD(wparam)) { - //default: - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - break; - //} - //break; - } - - case WM_NOTIFY: - if (reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY) { - StoreDBCheckState(proto, hwnd, IDC_DISCONNECT_CHAT, FACEBOOK_KEY_DISCONNECT_CHAT); - StoreDBCheckState(proto, hwnd, IDC_MAP_STATUSES, FACEBOOK_KEY_MAP_STATUSES); - StoreDBCheckState(proto, hwnd, IDC_LOAD_PAGES, FACEBOOK_KEY_LOAD_PAGES); - StoreDBCheckState(proto, hwnd, IDC_TYPING_WHEN_INVISIBLE, FACEBOOK_KEY_TYPING_WHEN_INVISIBLE); - - BOOL setStatus = IsDlgButtonChecked(hwnd, IDC_SET_STATUS); - BOOL setStatusOld = proto->getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS); - if (setStatus != setStatusOld) { - proto->setByte(FACEBOOK_KEY_SET_MIRANDA_STATUS, setStatus); - if (setStatus && proto->isOnline()) - proto->ForkThread(&FacebookProto::SetAwayMsgWorker, nullptr); - } - - return TRUE; - } - - break; - } - - return FALSE; -} - -INT_PTR CALLBACK FBOptionsEventsProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - switch (message) { - case WM_INITDIALOG: - TranslateDialogDefault(hwnd); - - proto = reinterpret_cast<FacebookProto*>(lparam); - SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam); - - for (size_t i = 0; i < _countof(feed_types); i++) - SendDlgItemMessageA(hwnd, IDC_FEED_TYPE, CB_INSERTSTRING, i, reinterpret_cast<LPARAM>(Translate(feed_types[i].name))); - SendDlgItemMessage(hwnd, IDC_FEED_TYPE, CB_SETCURSEL, proto->getByte(FACEBOOK_KEY_FEED_TYPE, 0), 0); - - for (size_t i = 0; i < _countof(server_types); i++) - SendDlgItemMessageA(hwnd, IDC_URL_SERVER, CB_INSERTSTRING, i, reinterpret_cast<LPARAM>(Translate(server_types[i].name))); - SendDlgItemMessage(hwnd, IDC_URL_SERVER, CB_SETCURSEL, proto->getByte(FACEBOOK_KEY_SERVER_TYPE, 0), 0); - - LoadDBCheckState(proto, hwnd, IDC_SYSTRAY_NOTIFY, FACEBOOK_KEY_SYSTRAY_NOTIFY, DEFAULT_SYSTRAY_NOTIFY); - LoadDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_CHATROOM, FACEBOOK_KEY_NOTIFICATIONS_CHATROOM, DEFAULT_NOTIFICATIONS_CHATROOM); - - LoadDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_ENABLE, FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE, DEFAULT_EVENT_NOTIFICATIONS_ENABLE); - LoadDBCheckState(proto, hwnd, IDC_FEEDS_ENABLE, FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE); - LoadDBCheckState(proto, hwnd, IDC_FRIENDSHIP_ENABLE, FACEBOOK_KEY_EVENT_FRIENDSHIP_ENABLE, DEFAULT_EVENT_FRIENDSHIP_ENABLE); - LoadDBCheckState(proto, hwnd, IDC_TICKER_ENABLE, FACEBOOK_KEY_EVENT_TICKER_ENABLE, DEFAULT_EVENT_TICKER_ENABLE); - LoadDBCheckState(proto, hwnd, IDC_ON_THIS_DAY_ENABLE, FACEBOOK_KEY_EVENT_ON_THIS_DAY_ENABLE, DEFAULT_EVENT_ON_THIS_DAY_ENABLE); - LoadDBCheckState(proto, hwnd, IDC_FILTER_ADS, FACEBOOK_KEY_FILTER_ADS, DEFAULT_FILTER_ADS); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wparam)) { - case IDC_FEED_TYPE: - case IDC_URL_SERVER: - if (HIWORD(wparam) == CBN_SELCHANGE) - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - break; - default: - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - } - return TRUE; - - case WM_NOTIFY: - if (reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY) { - proto->setByte(FACEBOOK_KEY_FEED_TYPE, SendDlgItemMessage(hwnd, IDC_FEED_TYPE, CB_GETCURSEL, 0, 0)); - proto->setByte(FACEBOOK_KEY_SERVER_TYPE, SendDlgItemMessage(hwnd, IDC_URL_SERVER, CB_GETCURSEL, 0, 0)); - - StoreDBCheckState(proto, hwnd, IDC_SYSTRAY_NOTIFY, FACEBOOK_KEY_SYSTRAY_NOTIFY); - StoreDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_CHATROOM, FACEBOOK_KEY_NOTIFICATIONS_CHATROOM); - - StoreDBCheckState(proto, hwnd, IDC_NOTIFICATIONS_ENABLE, FACEBOOK_KEY_EVENT_NOTIFICATIONS_ENABLE); - StoreDBCheckState(proto, hwnd, IDC_FEEDS_ENABLE, FACEBOOK_KEY_EVENT_FEEDS_ENABLE); - StoreDBCheckState(proto, hwnd, IDC_FRIENDSHIP_ENABLE, FACEBOOK_KEY_EVENT_FRIENDSHIP_ENABLE); - StoreDBCheckState(proto, hwnd, IDC_TICKER_ENABLE, FACEBOOK_KEY_EVENT_TICKER_ENABLE); - StoreDBCheckState(proto, hwnd, IDC_ON_THIS_DAY_ENABLE, FACEBOOK_KEY_EVENT_ON_THIS_DAY_ENABLE); - StoreDBCheckState(proto, hwnd, IDC_FILTER_ADS, FACEBOOK_KEY_FILTER_ADS); - } - return TRUE; - } - - return FALSE; -} - -INT_PTR CALLBACK FBOptionsMessagingProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - FacebookProto *proto = reinterpret_cast<FacebookProto*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - switch (message) { - - case WM_INITDIALOG: - TranslateDialogDefault(hwnd); - - proto = reinterpret_cast<FacebookProto*>(lparam); - SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam); - - LoadDBCheckState(proto, hwnd, IDC_CUSTOM_SMILEYS, FACEBOOK_KEY_CUSTOM_SMILEYS, DEFAULT_CUSTOM_SMILEYS); - LoadDBCheckState(proto, hwnd, IDC_KEEP_UNREAD, FACEBOOK_KEY_KEEP_UNREAD, DEFAULT_KEEP_UNREAD); - LoadDBCheckState(proto, hwnd, IDC_MESSAGES_ON_OPEN, FACEBOOK_KEY_MESSAGES_ON_OPEN, DEFAULT_MESSAGES_ON_OPEN); - - LoadDBCheckState(proto, hwnd, IDC_ENABLE_CHATS, FACEBOOK_KEY_ENABLE_CHATS, DEFAULT_ENABLE_CHATS); - LoadDBCheckState(proto, hwnd, IDC_HIDE_CHATS, FACEBOOK_KEY_HIDE_CHATS, DEFAULT_HIDE_CHATS); - LoadDBCheckState(proto, hwnd, IDC_JOIN_EXISTING_CHATS, FACEBOOK_KEY_JOIN_EXISTING_CHATS, DEFAULT_JOIN_EXISTING_CHATS); - { - int count = proto->getByte(FACEBOOK_KEY_MESSAGES_ON_OPEN_COUNT, 10); - count = min(count, FACEBOOK_MESSAGES_ON_OPEN_LIMIT); - SetDlgItemInt(hwnd, IDC_MESSAGES_COUNT, count, TRUE); - } - SendDlgItemMessage(hwnd, IDC_MESSAGES_COUNT, EM_LIMITTEXT, 2, 0); - SendDlgItemMessage(hwnd, IDC_MESSAGES_COUNT_SPIN, UDM_SETRANGE32, 1, 99); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wparam)) { - case IDC_MESSAGES_COUNT: - if (HIWORD(wparam) == EN_CHANGE && (HWND)lparam == GetFocus()) - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - break; - default: - SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); - } - return TRUE; - - case WM_NOTIFY: - if (reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY) { - StoreDBCheckState(proto, hwnd, IDC_CUSTOM_SMILEYS, FACEBOOK_KEY_CUSTOM_SMILEYS); - StoreDBCheckState(proto, hwnd, IDC_KEEP_UNREAD, FACEBOOK_KEY_KEEP_UNREAD); - StoreDBCheckState(proto, hwnd, IDC_MESSAGES_ON_OPEN, FACEBOOK_KEY_MESSAGES_ON_OPEN); - - StoreDBCheckState(proto, hwnd, IDC_ENABLE_CHATS, FACEBOOK_KEY_ENABLE_CHATS); - StoreDBCheckState(proto, hwnd, IDC_HIDE_CHATS, FACEBOOK_KEY_HIDE_CHATS); - StoreDBCheckState(proto, hwnd, IDC_JOIN_EXISTING_CHATS, FACEBOOK_KEY_JOIN_EXISTING_CHATS); - - int count = GetDlgItemInt(hwnd, IDC_MESSAGES_COUNT, nullptr, TRUE); - count = min(count, FACEBOOK_MESSAGES_ON_OPEN_LIMIT); - proto->setByte(FACEBOOK_KEY_MESSAGES_ON_OPEN_COUNT, count); - } - return TRUE; - } - - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////// - -CFacebookGuardDialog::CFacebookGuardDialog(FacebookProto *proto, const char *fb_dtsg) - : CFacebookDlgBase(proto, IDD_GUARD), - m_ok(this, IDOK), - m_sms(this, IDC_SEND_SMS), - m_text(this, IDC_TEXT), - m_fb_dtsg(fb_dtsg) -{ - memset(m_code, 0, sizeof(m_code)); - m_ok.OnClick = Callback(this, &CFacebookGuardDialog::OnOk); - m_sms.OnClick = Callback(this, &CFacebookGuardDialog::OnSms); -} - -bool CFacebookGuardDialog::OnInitDialog() -{ - Window_SetIcon_IcoLib(m_hwnd, g_plugin.getIconHandle(IDI_FACEBOOK)); - - SendMessage(m_text.GetHwnd(), EM_LIMITTEXT, 6, 0); - - Utils_RestoreWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "GuardWindow"); - return true; -} - -void CFacebookGuardDialog::OnOk(CCtrlButton*) -{ - mir_strncpy(m_code, ptrA(m_text.GetTextA()), _countof(m_code)); - EndDialog(m_hwnd, DIALOG_RESULT_OK); -} - -void CFacebookGuardDialog::OnSms(CCtrlButton *btn) -{ - btn->Disable(); - m_proto->facy.sms_code(m_fb_dtsg); -} - -bool CFacebookGuardDialog::OnClose() -{ - Utils_SaveWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "GuardWindow"); - return true; -} - -const char* CFacebookGuardDialog::GetCode() -{ - return m_code; -} diff --git a/protocols/FacebookRM/src/dialogs.h b/protocols/FacebookRM/src/dialogs.h deleted file mode 100644 index a730ef6d81..0000000000 --- a/protocols/FacebookRM/src/dialogs.h +++ /dev/null @@ -1,59 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#pragma once
-
-INT_PTR CALLBACK FBAccountProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-INT_PTR CALLBACK FBMindProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-INT_PTR CALLBACK FBOptionsProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-INT_PTR CALLBACK FBOptionsMessagingProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-INT_PTR CALLBACK FBOptionsEventsProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-INT_PTR CALLBACK FBOptionsStatusesProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-
-/////////////////////////////////////////////////////////////////////////////////
-
-typedef CProtoDlgBase<FacebookProto> CFacebookDlgBase;
-
-#define DIALOG_RESULT_OK 1
-
-class CFacebookGuardDialog : public CFacebookDlgBase
-{
-private:
- const char *m_fb_dtsg;
- char m_code[7];
-
- CCtrlEdit m_text;
- CCtrlButton m_ok;
- CCtrlButton m_sms;
-
-protected:
- bool OnInitDialog() override;
- bool OnClose() override;
-
- void OnOk(CCtrlButton*);
- void OnSms(CCtrlButton*);
-
-public:
- CFacebookGuardDialog(FacebookProto *proto, const char *fb_dtsg);
-
- const char *GetCode();
-};
diff --git a/protocols/FacebookRM/src/entities.h b/protocols/FacebookRM/src/entities.h deleted file mode 100644 index 317b6a5c78..0000000000 --- a/protocols/FacebookRM/src/entities.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#pragma once - -struct facebook_user -{ - MCONTACT handle; - - std::string user_id; - std::string real_name; - std::string nick; - std::string username; - - unsigned int status_id; - unsigned int gender; - time_t last_active; - - std::string image_url; - - bool deleted; - bool idle; - - bool updated; - - ClientType client; - ContactType type; - - facebook_user() - { - handle = 0; - status_id = ID_STATUS_OFFLINE; - gender = last_active = 0; - deleted = idle = updated = false; - client = CLIENT_WEB; - type = CONTACT_NONE; - } - - wchar_t *getMirVer() - { - switch (this->client) { - case CLIENT_APP: - return FACEBOOK_CLIENT_APP; - case CLIENT_MESSENGER: - return FACEBOOK_CLIENT_MESSENGER; - case CLIENT_OTHER: - return FACEBOOK_CLIENT_OTHER; - case CLIENT_MOBILE: - return FACEBOOK_CLIENT_MOBILE; - case CLIENT_WEB: - default: - return FACEBOOK_CLIENT_WEB; - } - } -}; - -struct chatroom_participant -{ - std::string user_id; - std::string nick; - ParticipantRole role = ROLE_NONE; - bool is_former = false; - bool loaded = false; -}; - -struct facebook_chatroom -{ - std::string thread_id; - std::wstring chat_name; - std::map<std::string, chatroom_participant> participants; - bool can_reply = true; - bool is_archived = false; - bool is_subscribed = true; - bool read_only = false; - - facebook_chatroom(std::string _thread_id) : - thread_id(_thread_id) - {} -}; - -struct facebook_message -{ - std::string user_id; - std::string message_text; - std::string message_id; - std::string thread_id; - std::string data; - time_t time; - bool isIncoming; - bool isUnread; - bool isChat; - MessageType type; - - int flag_; - - facebook_message() - { - this->time = 0; - this->isUnread = true; - this->isIncoming = true; - this->isChat = false; - this->type = MESSAGE; - this->flag_ = 0; - } -}; - -struct facebook_notification -{ - std::string user_id; - std::string text; - std::string link; - std::string id; - const char *icon = nullptr; - time_t time = 0; - bool seen = false; - HWND hWndPopup = nullptr; -}; - -struct facebook_newsfeed -{ - std::string user_id; - std::string title; - std::string text; - std::string link; - - facebook_newsfeed() {} -}; - -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(MCONTACT hContact,const std::string &msg, int msgid) : hContact(hContact), msg(msg), msgid(msgid) {} - MCONTACT hContact; - std::string msg; - int msgid; -}; - -struct send_typing -{ - send_typing(MCONTACT hContact,const int status) : hContact(hContact), status(status) {} - MCONTACT hContact; - int status; -}; - -struct popup_data -{ - popup_data(FacebookProto *proto) : proto(proto) {} - popup_data(FacebookProto *proto, std::string url) : proto(proto), url(url) {} - FacebookProto *proto; - std::string url; - std::string notification_id; -}; - -struct status_data -{ - status_data() { - this->isPage = false; - } - std::string user_id; - std::string text; - std::string url; - std::string place; - std::string privacy; - bool isPage; - std::vector<facebook_user*> users; -}; - -struct wall_data -{ - wall_data() { - this->title = nullptr; - this->isPage = false; - } - wall_data(std::string user_id, wchar_t *title, bool isPage = false) : user_id(user_id), title(title), isPage(isPage) {} - std::string user_id; - wchar_t *title; - bool isPage; -}; - -struct post_status_data { - post_status_data(FacebookProto *proto) : proto(proto) {} - post_status_data(FacebookProto *proto, wall_data *wall) : proto(proto) { - this->walls.push_back(wall); - } - FacebookProto *proto; - std::vector<wall_data*> walls; -}; - -struct open_url -{ - open_url(wchar_t *browser, wchar_t *url) : browser(browser), url(url) {} - wchar_t *browser; - wchar_t *url; -}; diff --git a/protocols/FacebookRM/src/events.cpp b/protocols/FacebookRM/src/events.cpp deleted file mode 100644 index d04cbb38ad..0000000000 --- a/protocols/FacebookRM/src/events.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -HWND FacebookProto::NotifyEvent(const wchar_t* title, const wchar_t* text, MCONTACT contact, EventType type, std::string *url, std::string *notification_id, const char *icon) -{ - if (title == nullptr || text == nullptr) - return nullptr; - - char name[256]; - if (icon != nullptr) { - strncpy_s(name, icon, _TRUNCATE); - Skin_PlaySound("Notification"); - } - else - switch (type) { - case EVENT_CLIENT: - mir_snprintf(name, "%s_%s", m_szModuleName, "Client"); - break; - - case EVENT_NEWSFEED: - mir_snprintf(name, "%s_%s", m_szModuleName, "Newsfeed"); - break; - - case EVENT_NOTIFICATION: - mir_snprintf(name, "%s_%s", m_szModuleName, "Notification"); - Skin_PlaySound("Notification"); - break; - - case EVENT_OTHER: - mir_snprintf(name, "%s_%s", m_szModuleName, "Other"); - Skin_PlaySound("OtherEvent"); - break; - - case EVENT_FRIENDSHIP: - mir_snprintf(name, "%s_%s", m_szModuleName, "Friendship"); - Skin_PlaySound("Friendship"); - break; - - case EVENT_TICKER: - mir_snprintf(name, "%s_%s", m_szModuleName, "Ticker"); - Skin_PlaySound("Ticker"); - break; - - case EVENT_ON_THIS_DAY: - mir_snprintf(name, "%s_%s", m_szModuleName, "Memories"); - break; - } - - if (!getByte(FACEBOOK_KEY_SYSTRAY_NOTIFY, DEFAULT_SYSTRAY_NOTIFY)) { - POPUPDATACLASS pd = { sizeof(pd) }; - pd.szTitle.w = title; - pd.szText.w = text; - pd.pszClassName = name; - pd.hContact = contact; - - if (url != nullptr || notification_id != nullptr) { - popup_data *data = new popup_data(this); - if (url != nullptr) - data->url = *url; - if (notification_id != nullptr) - data->notification_id = *notification_id; - pd.PluginData = data; - } - return Popup_AddClass(&pd); - } - else { - if (!Clist_TrayNotifyW(m_szModuleName, title, text, type == EVENT_CLIENT ? NIIF_WARNING : NIIF_INFO, 10000)) - return nullptr; - } - - if (type == EVENT_CLIENT) - MessageBox(nullptr, text, title, MB_OK | MB_ICONERROR); - - return nullptr; -} diff --git a/protocols/FacebookRM/src/feeds.cpp b/protocols/FacebookRM/src/feeds.cpp deleted file mode 100644 index c7db495d4e..0000000000 --- a/protocols/FacebookRM/src/feeds.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -// getting newsfeed posts -HttpRequest* facebook_client::newsfeedRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/ajax/home/generic.php"); - - BYTE feed_type = parent->getByte(FACEBOOK_KEY_FEED_TYPE, 0); - if (feed_type >= _countof(feed_types)) - feed_type = 0; - - p << CHAR_PARAM("sk", feed_types[feed_type].id) - << CHAR_PARAM("key", (feed_type < 2) ? "nf" : feed_types[feed_type].id) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << INT_PARAM("__a", 1); - - return p; -} - -HttpRequest* facebook_client::memoriesRequest() -{ - HttpRequest * p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/onthisday/story/query/"); - - p << INT_PARAM("__a", 1) - << INT_PARAM("start_index", 0) - << INT_PARAM("num_stories", 20) - << INT_PARAM("last_section_header", 0) - << CHAR_PARAM("last_section_key", "regular_story") - << INT_PARAM("__be", -1) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT64_PARAM("timestamp", ::time(0) * 1000) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("__user", self_.user_id.c_str()); - - return p; -} diff --git a/protocols/FacebookRM/src/history.cpp b/protocols/FacebookRM/src/history.cpp deleted file mode 100644 index baa31d3a70..0000000000 --- a/protocols/FacebookRM/src/history.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -HttpRequest* facebook_client::threadInfoRequest(bool isChat, const char *id, const char* timestamp, int limit, bool loadMessages) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/api/graphqlbatch/"); - - p->Body - << CHAR_PARAM("batch_name", "MessengerGraphQLThreadFetcherRe") - << CHAR_PARAM("__user", self_.user_id.c_str()) - << INT_PARAM("__a", 1) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << INT_PARAM("__be", 1) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()); - - std::string id_ = id; - if (isChat) { - if (id_.substr(0, 3) == "id.") - id_ = id_.substr(3); - } - - JSONNode root, o0, query_params; - query_params - << CHAR_PARAM("id", id_.c_str()) - << INT_PARAM("message_limit", (limit == -1) ? 50 : limit) - << BOOL_PARAM("load_messages", loadMessages) - << BOOL_PARAM("load_read_receipts", false); - - if (timestamp == nullptr || strcmp(timestamp, "") == 0) - query_params << NULL_PARAM("before"); - else - query_params << CHAR_PARAM("before", timestamp); - - o0 << CHAR_PARAM("doc_id", "1549485615075443") << JSON_PARAM("query_params", query_params); - root << JSON_PARAM("o0", o0); - - p->Body << CHAR_PARAM("queries", root.write().c_str()); - - return p; -} - -// Request both thread info and messages for more threads -HttpRequest* facebook_client::threadInfoRequest(const LIST<char> &ids, int limit) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/api/graphqlbatch/"); - - p->Body - << CHAR_PARAM("batch_name", "MessengerGraphQLThreadFetcherRe") - << CHAR_PARAM("__user", self_.user_id.c_str()) - << INT_PARAM("__a", 1) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << INT_PARAM("__be", 1) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()); - - JSONNode root; - for (int i = 0; i < ids.getCount(); i++) { - // NOTE: Remove "id." prefix as here we need to give threadFbId and not threadId - std::string id_ = ids[i]; // FIXME: Rewrite this without std::string... - if (id_.substr(0, 3) == "id.") - id_ = id_.substr(3); - - // Build query - JSONNode oX, query_params; - query_params - << CHAR_PARAM("id", id_.c_str()) - << INT_PARAM("message_limit", limit) - << BOOL_PARAM("load_messages", true) - << BOOL_PARAM("load_read_receipts", false) - << NULL_PARAM("before"); - - oX << CHAR_PARAM("doc_id", "1508526735892416") << JSON_PARAM("query_params", query_params); - root << JSON_PARAM(("o" + std::to_string(i)).c_str(), oX); - } - - p->Body << CHAR_PARAM("queries", root.write().c_str()); - - return p; -} - -HttpRequest* facebook_client::unreadThreadsRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/unread_threads.php"); - - p << INT_PARAM("dpr", 1); - - p->Body - << CHAR_PARAM("folders[0]", "inbox") - << CHAR_PARAM("folders[1]", "other") // TODO: "other" is probably unused, and there is now "pending" instead - << CHAR_PARAM("client", "mercury") - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__a", 1) - << INT_PARAM("__be", -1); - - return p; -} diff --git a/protocols/FacebookRM/src/http.h b/protocols/FacebookRM/src/http.h deleted file mode 100644 index 125a3e9212..0000000000 --- a/protocols/FacebookRM/src/http.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#pragma once - -#define HTTP_PROTO_SECURE "https://" - -#define HTTP_CODE_FAKE_DISCONNECTED 0 -#define HTTP_CODE_FAKE_ERROR 1 -#define HTTP_CODE_FAKE_OFFLINE 2 - -namespace http -{ - struct response - { - response() : code(0), error_number(0) {} - - int code; - std::map<std::string, std::string> headers; - std::string data; - - // Facebook's error data - unsigned int error_number; - std::string error_title; - std::string error_text; - - bool isValid() { - return (code == HTTP_CODE_OK && error_number == 0); - } - }; -} diff --git a/protocols/FacebookRM/src/http_request.cpp b/protocols/FacebookRM/src/http_request.cpp deleted file mode 100644 index 6cce6f8388..0000000000 --- a/protocols/FacebookRM/src/http_request.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright (c) 2015-19 Miranda NG team (https://miranda-ng.org) - -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 version 2 -of the License. - -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 <http://www.gnu.org/licenses/>. -*/ - -#include "stdafx.h" - -HttpRequest::HttpRequest(int type, LPCSTR url) -{ - m_szUrl = url; - flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_DUMPASTEXT; - requestType = type; - timeout = 600 * 1000; - - NotifyErrors = true; - Persistent = DEFAULT; -} - -HttpRequest::HttpRequest(int type, CMStringDataFormat, LPCSTR urlFormat, ...) -{ - m_szUrl.AppendFormatV(urlFormat, (va_start(formatArgs, urlFormat), formatArgs)); - flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_DUMPASTEXT; - requestType = type; - va_end(formatArgs); - timeout = 20 * 1000; - - NotifyErrors = true; - Persistent = DEFAULT; -} - -NETLIBHTTPREQUEST* HttpRequest::Send(HNETLIBUSER nlu) -{ - if (m_szUrl.Find("://") == -1) - m_szUrl.Insert(0, ((flags & NLHRF_SSL) ? "https://" : "http://")); - if (!m_szParam.IsEmpty()) { - m_szUrl.AppendChar('?'); - m_szUrl += m_szParam; - } - szUrl = m_szUrl.GetBuffer(); - - if (!pData) { - pData = Body.ToString(); - dataLength = (int)mir_strlen(pData); - } - - Netlib_Logf(nlu, "Send request to %s", szUrl); - - return Netlib_HttpTransaction(nlu, this); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -HttpRequest::HttpRequestBody& HttpRequest::HttpRequestBody::operator<<(const char *str) -{ - AppendSeparator(); - if (str != nullptr) - content.Append(str); - return *this; -} - -HttpRequest::HttpRequestBody& HttpRequest::HttpRequestBody::operator<<(const BOOL_PARAM ¶m) -{ - AppendSeparator(); - content.AppendFormat("%s=%s", param.szName, param.bValue ? "true" : "false"); - return *this; -} - -HttpRequest::HttpRequestBody& HttpRequest::HttpRequestBody::operator<<(const INT_PARAM ¶m) -{ - AppendSeparator(); - content.AppendFormat("%s=%i", param.szName, param.iValue); - return *this; -} - -HttpRequest::HttpRequestBody& HttpRequest::HttpRequestBody::operator<<(const INT64_PARAM ¶m) -{ - AppendSeparator(); - content.AppendFormat("%s=%lld", param.szName, param.iValue); - return *this; -} - -HttpRequest::HttpRequestBody& HttpRequest::HttpRequestBody::operator<<(const CHAR_PARAM ¶m) -{ - AppendSeparator(); - content.AppendFormat("%s=%s", param.szName, utils::url::encode(param.szValue).c_str()); - return *this; -} diff --git a/protocols/FacebookRM/src/http_request.h b/protocols/FacebookRM/src/http_request.h deleted file mode 100644 index 9a4e02535b..0000000000 --- a/protocols/FacebookRM/src/http_request.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright (c) 2015-19 Miranda NG team (https://miranda-ng.org) - -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 version 2 -of the License. - -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 <http://www.gnu.org/licenses/>. -*/ - -#ifndef _HTTP_REQUEST_H_ -#define _HTTP_REQUEST_H_ - -class HttpRequest : public MHttpRequest -{ - va_list formatArgs; - -protected: - class HttpRequestBody - { - private: - CMStringA content; - - void AppendSeparator() - { - if (!content.IsEmpty()) - content.AppendChar('&'); - } - - public: - HttpRequestBody() {} - - HttpRequestBody& operator<<(const char *str); - HttpRequestBody& operator<<(const BOOL_PARAM ¶m); - HttpRequestBody& operator<<(const INT_PARAM ¶m); - HttpRequestBody& operator<<(const INT64_PARAM ¶m); - HttpRequestBody& operator<<(const CHAR_PARAM ¶m); - - char* ToString() - { - return content.Detach(); - } - }; - -public: - HttpRequestBody Body; - - enum PersistentType { NONE, DEFAULT, CHANNEL, MESSAGES }; - - bool NotifyErrors; - PersistentType Persistent; - - HttpRequest(int type, LPCSTR url); - HttpRequest(int type, CMStringDataFormat, LPCSTR urlFormat, ...); - - NETLIBHTTPREQUEST* Send(HNETLIBUSER nlu); -}; - -#endif //_HTTP_REQUEST_H_
\ No newline at end of file diff --git a/protocols/FacebookRM/src/json.cpp b/protocols/FacebookRM/src/json.cpp deleted file mode 100644 index 1e309e9c1e..0000000000 --- a/protocols/FacebookRM/src/json.cpp +++ /dev/null @@ -1,1533 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -LRESULT CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - -void parseUser(const JSONNode &it, facebook_user *fbu) -{ - fbu->user_id = it.name(); - - std::string id = it["id"].as_string(); // same as element's name, but doesn't exists for "page" type - std::string alternateName = it["alternateName"].as_string(); // nickname - std::string name = it["name"].as_string(); - std::string thumbSrc = it["thumbSrc"].as_string(); - std::string vanity = it["vanity"].as_string(); // username - std::string type = it["type"].as_string(); // "friend", "page", "user" (friend with disabled account or not friend) - bool isFriend = it["is_friend"].as_bool(); // e.g. "True" or "False" for type="friend" (I don't know why), "False" for type="user", doesn't exist for type="page" - int gender = it["gender"].as_int(); - // bool isMessengerContact = it["is_nonfriend_messenger_contact"].as_bool(); // "True" or "False", but we don't care as "is_friend" and "type" are enough for us - - //const JSONNode &uri = it["uri"); // profile url - - if (type == "user" && (id.empty() || id == "0")) { - // this user has deleted account or is just unavailable for us (e.g., ignore list) -> don't read dummy name and avatar and rather ignore that completely - return; - } - - if (type == "friend" && isFriend) - fbu->type = CONTACT_FRIEND; - else if (type == "user" || (type == "friend" && !isFriend)) - fbu->type = CONTACT_NONE; - else if (type == "page") - fbu->type = CONTACT_PAGE; - - if (!name.empty()) - fbu->real_name = utils::text::slashu_to_utf8(name); - if (!thumbSrc.empty()) - fbu->image_url = utils::text::slashu_to_utf8(thumbSrc); - if (!vanity.empty()) - fbu->username = utils::text::slashu_to_utf8(vanity); - if (!alternateName.empty()) - fbu->nick = alternateName; - - if (gender) { - switch (gender) { - case 1: // female - fbu->gender = 70; - break; - case 2: // male - fbu->gender = 77; - break; - // case 7: // not available female? - // case 11: // page - } - } -} - -void FacebookProto::ParseMessageType(facebook_message &message, const JSONNode &log_type_, const JSONNode &log_body_, const JSONNode &log_data_) -{ - if (!log_type_ || !log_body_ || !log_data_) - return; - - std::string logType = log_type_.as_string(); - - if (logType == "log:phone-call") { - message.type = PHONE_CALL; - } - else if (logType == "log:video-call") { - message.type = VIDEO_CALL; - } - else if (logType == "log:generic-admin-text") { - message.type = ADMIN_TEXT; - } - else if (logType == "log:subscribe") { - message.type = SUBSCRIBE; - - const JSONNode &fbids_ = log_data_["added_participants"]; - for (auto &it2 : fbids_) { - std::string id = it2.as_string().substr(5); // strip "fbid:" prefix - if (!message.data.empty()) - message.data += ";"; - message.data += id; - } - } - else if (logType == "log:unsubscribe") { - message.type = UNSUBSCRIBE; - - const JSONNode &client_id = log_data_["client_message_id"]; - if (client_id) - message.message_id = client_id.as_string(); - - const JSONNode &fbids_ = log_data_["removed_participants"]; - for (auto &it2 : fbids_) { - std::string id = it2.as_string().substr(5); // strip "fbid:" prefix - if (!message.data.empty()) - message.data += ";"; - message.data += id; - } - } - else if (logType == "log:thread-name") { - message.type = THREAD_NAME; - message.data = log_data_["name"].as_string(); - } - else if (logType == "log:thread-image") { - message.type = THREAD_IMAGE; - } - else { - debugLogA("!!! Unknown log type - %s", logType.c_str()); - } -} - -int FacebookProto::ParseChatParticipants(std::string *data, std::map<std::string, chatroom_participant>* participants) -{ - std::string jsonData = data->substr(9); - - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &profiles = root["payload"].at("profiles"); - if (!profiles) - return EXIT_FAILURE; - - for (auto &it : profiles) { - std::string userId = it.name(); - std::string userName = it["name"].as_string(); - std::string type = it["type"].as_string(); - - if (userId.empty() || userName.empty()) - continue; - - auto participant = participants->find(userId); - if (participant != participants->end()) { - chatroom_participant &user = participant->second; - user.nick = userName; - - if (type == "friend") - user.role = ROLE_FRIEND; - else if (type == "user") - user.role = ROLE_NONE; - else if (type == "page") { - user.role = ROLE_NONE; - // Use prefix for "page" users - user.nick = m_pagePrefix + " " + userName; - } - - user.loaded = true; - } - } - - return EXIT_SUCCESS; -} - -int FacebookProto::ParseFriends(std::string *data, std::map< std::string, facebook_user* >* friends, bool loadAllContacts) -{ - std::string jsonData = data->substr(9); - - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &payload = root["payload"]; - if (!payload) - return EXIT_FAILURE; - - for (auto &it : payload) { - facebook_user *fbu = new facebook_user(); - parseUser(it, fbu); - - // Facebook now sends also other types of contacts, which we do not want here - if (!loadAllContacts && fbu->type != CONTACT_FRIEND) { - delete fbu; - continue; - } - - friends->insert(std::make_pair(fbu->user_id, fbu)); - } - - return EXIT_SUCCESS; -} - -int FacebookProto::ParseNotifications(std::string *data, std::map< std::string, facebook_notification* > *notifications) -{ - std::string jsonData = data->substr(9); - - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &list = root["payload"].at("nodes"); - if (!list) - return EXIT_FAILURE; - - // Create notifications chatroom (if it doesn't exists), because we will be writing to it new notifications here - PrepareNotificationsChatRoom(); - - for (auto &it : list) { - const JSONNode &id_ = it["alert_id"]; - const JSONNode &state_ = it["seen_state"]; - const JSONNode &time_ = it["timestamp"]["time"]; - const JSONNode &text_ = it["title"]["text"]; - const JSONNode &url_ = it["url"]; - const JSONNode &icon_ = it["icon"]["uri"]; - - // Ignore empty and old notifications - if (!text_ || !state_ || state_.as_string() == "SEEN_AND_READ" || !time_) - continue; - - // Fix notification ID - std::string msgid = id_.as_string(); - std::string::size_type pos = msgid.find(":"); - if (pos != std::string::npos) - msgid = msgid.substr(pos + 1); - - // Skip duplicate notifications - if (notifications->find(msgid) != notifications->end()) - continue; - - facebook_notification *notification = new facebook_notification(); - notification->id = msgid; - notification->link = url_.as_string(); - notification->text = utils::text::html_entities_decode(utils::text::slashu_to_utf8(text_.as_string())); - notification->time = utils::time::from_string(time_.as_string()); - notification->icon = ParseIcon(icon_.as_string()); - - // Write notification to chatroom - UpdateNotificationsChatRoom(notification); - notifications->insert(std::make_pair(notification->id, notification)); - } - - return EXIT_SUCCESS; -} - -bool FacebookProto::IgnoreDuplicates(const std::string &mid) -{ - mir_cslock s(facy.send_message_lock_); - - std::map<std::string, int>::iterator it = facy.messages_ignore.find(mid); - if (it != facy.messages_ignore.end()) { - debugLogA("??? Ignoring duplicit/sent message ID: %s", mid.c_str()); - it->second++; // increase counter (for deleting it later) - return true; - } - - // remember this id to ignore duplicits - facy.messages_ignore.insert(std::make_pair(mid, 1)); - return false; -} - -std::string absolutizeUrl(std::string &url) -{ - if (url.find("/") == 0) { - url = HTTP_PROTO_SECURE FACEBOOK_SERVER_REGULAR + url; - } - return url; -} - -void FacebookProto::ParseAttachments(std::string &message_text, const JSONNode &delta_, std::string other_user_fbid, bool legacy) -{ - std::string attachments_text; - std::wstring newText; - bool hasAttachement = false; - - // define parsing methods by type - // sticker - auto parseSticker = [this, &newText, &attachments_text, other_user_fbid](JSONNode sticker_) { - newText = TranslateT("a sticker"); - attachments_text += "\n"; - - std::string link = sticker_["url"].as_string(); - if (!link.empty()) - attachments_text += absolutizeUrl(link) + "\n"; - - std::string label = sticker_["label"].as_string(); - if (!label.empty()) - attachments_text += label + "\n"; - - const JSONNode &stickerId_ = sticker_["id"]; - if (stickerId_) { - // Stickers as smileys - if (getByte(FACEBOOK_KEY_CUSTOM_SMILEYS, DEFAULT_CUSTOM_SMILEYS) && !facy.loading_history) { - // FIXME: rewrite smileyadd to use custom smileys per protocol and not per contact and then remove this ugliness - if (!other_user_fbid.empty()) { - std::string sticker = "[[sticker:" + stickerId_.as_string() + "]]"; - StickerAsSmiley(sticker, link, ContactIDToHContact(other_user_fbid)); - } - } - } - }; - // blob attachment - auto parseBlobAttachment = [this, &newText, &attachments_text](JSONNode blob_) { - std::string type = blob_["__typename"].as_string(); - if (type == "MessageAnimatedImage") { // a GIF - newText = TranslateT("a GIF"); - - std::string link = blob_["animated_image"]["uri"].as_string(); - if (!link.empty()) - attachments_text += "\n" + absolutizeUrl(link) + "\n"; - } - else if (type == "MessageVideo" || type == "MessageAudio") { // a video or audio attachement - std::string filename = blob_["filename"].as_string(); - // playable_duration_in_ms=;video_type=FILE_ATTACHMENT - - std::string link = blob_["playable_url"].as_string(); - if (!link.empty()) - attachments_text += "\n" + (!filename.empty() ? "<" + filename + "> " : "") + absolutizeUrl(link) + "\n"; - } - else if (type == "MessageImage") { // an image - std::string filename = blob_["filename"].as_string(); - - std::string link = blob_["large_preview"]["uri"].as_string(); - if (!link.empty()) - attachments_text += "\n" + (!filename.empty() ? "<" + filename + "> " : "") + absolutizeUrl(link) + "\n"; - } - else { // other - // newText = (attachments_.size() > 1) ? TranslateT("files") : TranslateT("a file"); // pull - std::string filename = blob_["filename"].as_string(); - /*std::string filesize = attach_["fileSize"].as_string(); // pull - if (!filesize.empty()) - filename += ", " + filesize + " bytes";*/ - - std::string link = blob_["url"].as_string(); - if (!link.empty()) - attachments_text += "\n" + (!filename.empty() ? "<" + filename + "> " : "") + absolutizeUrl(link) + "\n"; - } - }; - // link - auto parseLink = [this, &newText, &attachments_text](JSONNode story_) { - newText = TranslateT("a link"); - - std::string title = story_["title_with_entities"]["text"].as_string(); - std::string description = story_["description"]["text"].as_string(); - std::string link = story_["url"].as_string(); - - // shorten long descriptions - description = utils::text::truncate_utf8(description, MAX_LINK_DESCRIPTION_LEN); - - if (link.find("//www." FACEBOOK_SERVER_DOMAIN "/l.php") != std::string::npos || link.find("//l." FACEBOOK_SERVER_DOMAIN) != std::string::npos) { - // de-facebook this link - link = utils::url::decode(utils::text::source_get_value2(&link, "l.php?u=", "&", true)); - } - - if (!link.empty()) { - attachments_text += "\n"; - if (!title.empty()) - attachments_text += title + "\n"; - if (!description.empty()) - attachments_text += description + "\n"; - attachments_text += absolutizeUrl(link) + "\n"; - } - }; - - // do parsing - if (legacy) { - // api graph.. request - const JSONNode sticker_ = delta_["sticker"]; - if (!sticker_.empty()) { - hasAttachement = true; - parseSticker(sticker_); - } - const JSONNode blobs_ = delta_["blob_attachments"]; - if (!blobs_.empty()) { - hasAttachement = true; - newText = (blobs_.size() > 1) ? TranslateT("files") : TranslateT("a file"); - for (auto &blob_ : blobs_) { - parseBlobAttachment(blob_); - } - } - const JSONNode story_ = delta_["extensible_attachment"]["story_attachment"]; - if (!story_.empty()) { - hasAttachement = true; - std::string type = story_["target"]["__typename"].as_string(); - if (type == "ExternalUrl" || type == "Story" || type == "QuickInvite") { - parseLink(story_); - } - else debugLogA("json::parseAttachments (%s) - Unknown extensible attachment type %s", legacy ? "legacy" : "not legacy", type.c_str()); - } - // else debugLogA("json::parseAttachments (%s) - Unknown attachment type", legacy ? "legacy" : "not legacy"); - } - else { - // pull request, i.e. from chat message - const JSONNode &attachments_ = delta_["attachments"]; - if (!attachments_ || attachments_.empty()) - ; - else { - hasAttachement = true; - for (auto &itAttachment : attachments_) { - const JSONNode &attach_ = itAttachment["mercury"]; - if (const JSONNode sticker_ = attach_["sticker_attachment"]) { - parseSticker(sticker_); - } - else if (const JSONNode blob_ = attach_["blob_attachment"]) { - parseBlobAttachment(blob_); - } - else if (const JSONNode story_ = attach_["extensible_attachment"]["story_attachment"]) { - std::string type = story_["target"]["__typename"].as_string(); - if (type == "ExternalUrl" || type == "Story" || type == "QuickInvite") { - parseLink(story_); - } - else debugLogA("json::parseAttachments (%s) - Unknown extensible attachment type %s", legacy ? "legacy" : "not legacy", type.c_str()); - } - else debugLogA("json::parseAttachments (%s) - Unknown attachment type", legacy ? "legacy" : "not legacy"); - } - } - } - - if (hasAttachement) { - // TODO: have this as extra event, not replace or append message content - if (!message_text.empty()) - message_text += "\n\n"; - - if (!attachments_text.empty()) { - wchar_t title[200]; - mir_snwprintf(title, TranslateT("User sent %s:"), newText.c_str()); - - message_text += T2Utf(title); - message_text += attachments_text; - } - else { - message_text += T2Utf(TranslateT("User sent an unsupported attachment. Open your browser to see it.")); - debugLogA("json::parseAttachments (%s) - Unsupported attachment:\n%s", legacy ? "legacy" : "not legacy", /*attachments_*/delta_.as_string().c_str()); - } - } -} - -bool FacebookProto::ParseMessageMetadata(facebook_message &message, const JSONNode &meta_) -{ - if (!meta_) - return false; - - const JSONNode &actorFbId_ = meta_["actorFbId"]; // who did the action - const JSONNode &adminText_ = meta_["adminText"]; // description of the event (only for special events, not for user messages) - const JSONNode &messageId_ = meta_["messageId"]; - const JSONNode &otherUserFbId_ = meta_["threadKey"]["otherUserFbId"]; // for whom the event is (only for single conversations) - const JSONNode &threadFbId_ = meta_["threadKey"]["threadFbId"]; // thread of the event (only for multi chat conversations) - const JSONNode ×tamp_ = meta_["timestamp"]; - - if (!actorFbId_ || !messageId_ || !timestamp_) - return false; - - std::string actorFbId = (actorFbId_ ? actorFbId_.as_string() : ""); - std::string otherUserFbId = (otherUserFbId_ ? otherUserFbId_.as_string() : ""); - std::string threadFbId = (!otherUserFbId_ && threadFbId_ ? "id." + threadFbId_.as_string() : ""); // NOTE: we must add "id." prefix as this is threadFbId and we want threadId (but only for multi chats) - - message.isChat = otherUserFbId.empty(); - message.isIncoming = (actorFbId_.as_string() != facy.self_.user_id); - message.isUnread = message.isIncoming; - message.message_text = (adminText_ ? adminText_.as_string() : ""); - message.time = utils::time::from_string(timestamp_.as_string()); - message.user_id = message.isChat ? actorFbId : otherUserFbId; - message.message_id = messageId_.as_string(); - message.thread_id = threadFbId; - return true; -} - -bool FacebookProto::ProcessSpecialMessage(std::vector<facebook_message> &messages, const JSONNode &meta_, MessageType messageType, const std::string &messageData) -{ - facebook_message message; - message.type = messageType; - message.data = messageData; - - // Parse message metadata - if (!ParseMessageMetadata(message, meta_)) { - debugLogA("json::ProcessSpecialMessage - given empty messageMetadata"); - return false; - } - - // Ignore duplicits or messages sent from miranda - if (IgnoreDuplicates(message.message_id)) { - return false; - } - - messages.push_back(message); - return true; -} - -const char* FacebookProto::ParseIcon(const std::string &url) -{ - if (url.empty()) - return nullptr; - - auto itr = reactions.find(url); - if (itr == reactions.end()) { - UCHAR hash[MIR_SHA256_HASH_SIZE]; - mir_sha256_hash(url.c_str(), url.length(), hash); - - wchar_t wszHash[MIR_SHA256_HASH_SIZE * 2 + 10]; - bin2hexW(hash, sizeof(hash), wszHash); - - wchar_t wszFileName[MAX_PATH]; - mir_snwprintf(wszFileName, L"%s\\%s", VARSW(L"%miranda_avatarcache%"), m_tszUserName); - if (_waccess(wszFileName, 0)) - CreateDirectoryTreeW(wszFileName); - - wcscat_s(wszFileName, L"\\"); - wcscat_s(wszFileName, wszHash); - wcscat_s(wszFileName, L".ico"); - if (_waccess(wszFileName, 0)) { - NETLIBHTTPREQUEST req = { sizeof(req) }; - req.requestType = REQUEST_GET; - req.szUrl = (char*)url.c_str(); - req.flags = NLHRF_NODUMPHEADERS; - - NETLIBHTTPREQUEST *reply = Netlib_HttpTransaction(facy.handle_, &req); - if (reply != nullptr && reply->resultCode == HTTP_CODE_OK) { - HBITMAP hBmp = Image_LoadFromMem(reply->pData, reply->dataLength, FIF_UNKNOWN); - if (hBmp != nullptr) { - IMGSRVC_INFO info = { sizeof(info) }; - info.pwszName = wszFileName; - info.fif = FIF_ICO; - info.dwMask = IMGI_HBITMAP; - info.hbm = hBmp; - Image_Save(&info); - } - } - } - - HICON hIcon; - if (ExtractIconEx(wszFileName, 0, nullptr, &hIcon, 1) == 1) { - int idx = (int)reactions.size() + 1; - wchar_t desc[256]; - char name[256]; - mir_snwprintf(desc, L"%s/%s%d", m_tszUserName, TranslateT("Reaction"), idx); - mir_snprintf(name, "%s_%s%d", m_szModuleName, "Reaction", idx); - - POPUPCLASS ppc = { sizeof(ppc) }; - ppc.flags = PCF_UNICODE; - ppc.PluginWindowProc = PopupDlgProc; - ppc.lParam = APF_RETURN_HWND; - ppc.pszDescription.w = desc; - ppc.pszName = name; - ppc.hIcon = hIcon; - ppc.colorBack = RGB(59, 89, 152); // Facebook's blue - ppc.colorText = RGB(255, 255, 255); // white - ppc.iSeconds = 0; - popupClasses.push_back(Popup_RegisterClass(&ppc)); - - mir_cslock lck(csReactions); - reactions.insert(std::make_pair(url, name)); - } - - itr = reactions.find(url); - } - - return (itr == reactions.end()) ? nullptr : itr->second.c_str(); -} - -int FacebookProto::ParseMessages(std::string &pData, std::vector<facebook_message> &messages) -{ - // remove old received messages from map - for (auto it = facy.messages_ignore.begin(); it != facy.messages_ignore.end();) { - if (it->second > FACEBOOK_IGNORE_COUNTER_LIMIT) - it = facy.messages_ignore.erase(it); - else { - it->second++; // increase counter on each request - ++it; - } - } - - JSONNode root = JSONNode::parse(pData.substr(9).c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &ms = root["ms"]; - if (!ms) - return EXIT_FAILURE; - - for (auto &it : ms) { - const JSONNode &type = it["type"]; - if (!type) - continue; - - std::string t = type.as_string(); - if (t == "delta") { - // new messaging stuff - - const JSONNode &delta_ = it["delta"]; - if (!delta_) - continue; - - const JSONNode &cls_ = delta_["class"]; - std::string cls = cls_.as_string(); - if (cls == "NewMessage") { // revised 5.3.2017 - facebook_message message; - - // Parse message metadata - const JSONNode &meta_ = delta_["messageMetadata"]; - if (!ParseMessageMetadata(message, meta_)) { - debugLogA("json::ParseMessages - No messageMetadata element"); - continue; - } - - // Ignore duplicits or messages sent from miranda - if (IgnoreDuplicates(message.message_id)) - continue; - - const JSONNode &body_ = delta_["body"]; - std::string messageText = body_.as_string(); - - // Process attachements and stickers - ParseAttachments(messageText, delta_, (message.isChat ? "" : message.user_id), false); - - message.message_text = utils::text::trim(messageText, true); - messages.push_back(message); - } - else if (cls == "ReplaceMessage") { // revised 5.3.2017 - //const JSONNode &newMessage_ = delta_["newMessage"]; - // In newMessage object: "attachments", "body", "data"["meta_ranges"], "messageMetadata"["actorFbId", "messageId", "threadKey"["otherUserFbId", "threadFbId"], "timestamp"], "ttl" - // ttl is usually "TTL_OFF" - // meta_ranges is e.g. meta_ranges=[{"offset":11,"length":3,"type":1,"data":{"name":"timestamp","value":1488715200}}] - } - else if (cls == "ReadReceipt") { - // user read message - - // when read - const JSONNode &time_ = delta_["actionTimestampMs"]; - if (!time_) - continue; - - time_t timestamp = utils::time::from_string(time_.as_string()); - - // for multi chats (not available for single) - const JSONNode &actor_ = delta_["actorFbId"]; // who read the message - const JSONNode &thread_ = delta_["threadKey"]["threadFbId"]; // chat thread - - // for single chats (not available for multi) - const JSONNode &reader_ = delta_["threadKey"]["otherUserFbId"]; // who read the message - - if (actor_ && thread_) { - // multi chat - - // ignore if disabled - if (!m_enableChat) - continue; - - std::string readerId = actor_.as_string(); - std::string tid = "id." + thread_.as_string(); // NOTE: threadFbId means just numeric id of thread, without "id." prefix. We add it here to have it consistent with other methods (where threadId is used) - - MCONTACT hContact = ChatIDToHContact(tid); - facy.insert_reader(hContact, timestamp, readerId); - } - else if (reader_) { - // single chat - std::string userId = reader_.as_string(); - - MCONTACT hContact = ContactIDToHContact(userId); - facy.insert_reader(hContact, timestamp); - } - } - else if (cls == "MarkRead") { // revised 5.3.2017 - // Messages (thread) was marked as read on server - //const JSONNode &other_user_id_ = delta_["threadKeys"]["otherUserFbId"]; // for whom the message is (only for single conversations) - //const JSONNode &thread_fbid_ = delta_["threadKeys"]["threadFbId"]; // thread of the message (only for multi chat conversations) - //const JSONNode &actionTimestamp_ = delta_["actionTimestamp"]; // timestamp; more recent than watermarkTimestamp - //const JSONNode &watermarkTimestamp_ = delta_["watermarkTimestamp"]; // timestamp - } - else if (cls == "NoOp") { // revised 5.3.2017 - //const JSONNode &numNoOps_ = delta_["numNoOps"]; // number, usually 1 but I don't know what is it for - continue; - } - else if (cls == "ForcedFetch") { // revised 5.3.2017 - // when something related to thread changes (e.g. change of nickname of other user, thread image, etc.) - } - else if (cls == "AdminTextMessage") { // revised 5.3.2017 - // various system messages - approving friendship, changing thread nickname, etc. - const JSONNode &meta_ = delta_["messageMetadata"]; - MessageType messageType = ADMIN_TEXT; - - // TODO: Do something special with some delta types - const JSONNode &type_ = delta_["type"]; - //const JSONNode &untyped_ = delta_["untypedData"]; - - std::string deltaType = type_.as_string(); - if (deltaType == "confirm_friend_request") { - //const JSONNode &connection_type_ = untyped_["connection_type"]; // e.g. "friend_request" - //const JSONNode &friend_request_recipient_ = untyped_["friend_request_recipient"]; // userid - //const JSONNode &friend_request_sender_ = untyped_["friend_request_sender"]; // userid - } - else if (deltaType == "change_thread_nickname") { - //const JSONNode &nickname_ = untyped_["nickname"]; // new nickname - //const JSONNode &participant_id_ = untyped_["participant_id"]; // user fbid of that participant - } - else if (deltaType == "change_thread_theme") { - //const JSONNode &theme_color_ = untyped_["theme_color"]; // hexa format aarrggbb - } - else if (deltaType == "type=change_thread_icon") { - //const JSONNode &thread_icon_ = untyped_["thread_icon"]; // emoji symbol - } - else { - debugLogA("json::ParseMessages - Unknown AdminTextMessage type '%s'", deltaType.c_str()); - } - - if (!ProcessSpecialMessage(messages, meta_, messageType)) { - // Message wasn't added - either it is duplicate or there was some error - continue; - } - } - else if (cls == "RTCEventLog") { // revised 5.3.2017 - // various voice/video calls events - const JSONNode &meta_ = delta_["messageMetadata"]; - MessageType messageType = ADMIN_TEXT; - - // TODO: Do something special with some types - //const JSONNode &duration_ = delta_["duration"]; // numeric, probably length of call, e.g. 0 - const JSONNode &eventType_ = delta_["eventType"]; // e.g. "VOICE_EVENT", "VIDEO_EVENT" - - std::string eventType = eventType_.as_string(); - if (eventType == "VOICE_EVENT") - messageType = PHONE_CALL; - else if (eventType == "VIDEO_EVENT") - messageType = VIDEO_CALL; - else - debugLogA("json::ParseMessages - Unknown RTCEventLog type '%s'", eventType.c_str()); - - if (!ProcessSpecialMessage(messages, meta_, messageType)) { - // Message wasn't added - either it is duplicate or there was some error - continue; - } - } - else if (cls == "ThreadName") { - // changed thread name (multi user chat) - const JSONNode &meta_ = delta_["messageMetadata"]; - - const JSONNode &name_ = delta_["name"]; // new name of the chat (could be empty) - std::string data = (name_ ? name_.as_string() : ""); - - ProcessSpecialMessage(messages, meta_, THREAD_NAME, data); - } - else if (cls == "ThreadMuteSettings") { - //const JSONNode &expireTime_ = delta_["expireTime"]; // timestamp until which this thread will be muted; could be 0 = unmuted - // _delta["threadKey"] contains "threadFbId" or "otherUserId" identifier - } - else if (cls == "ParticipantLeftGroupThread") { - // user was removed from multi user chat - const JSONNode &meta_ = delta_["messageMetadata"]; - - const JSONNode &leftParticipantFbId_ = delta_["leftParticipantFbId"]; - std::string data = (leftParticipantFbId_ ? leftParticipantFbId_.as_string() : ""); - - ProcessSpecialMessage(messages, meta_, UNSUBSCRIBE, data); - } - else if (cls == "ParticipantsAddedToGroupThread") { - // user was added to multi user chat - const JSONNode &meta_ = delta_["messageMetadata"]; - std::string data = ""; - - const JSONNode &addedParticipants_ = delta_["addedParticipants"]; // array of added participants - for (auto &it2 : addedParticipants_) { - const JSONNode &userFbId_ = it2["userFbId"]; // userid - - // TODO: Take advantage of given fullName so we don't need to load it manually afterwards - if (userFbId_) { - if (!data.empty()) - data += ";"; - data += userFbId_.as_string(); - } - } - - ProcessSpecialMessage(messages, meta_, SUBSCRIBE, data); - } - else { - // DeliveryReceipt, MarkRead, ThreadDelete - debugLogA("json::ParseMessages - Unknown delta class '%s'", cls.c_str()); - } - } - else if (t == "notification_json") { - // event notification - const JSONNode &nodes = it["nodes"]; - - // Create notifications chatroom (if it doesn't exists), because we will be writing to it new notifications here - PrepareNotificationsChatRoom(); - - for (auto &itNodes : nodes) { - const JSONNode &text_ = itNodes["unaggregatedTitle"]; // notifications one by one, not grouped - if (!text_) - continue; - - const JSONNode &text = text_["text"]; - const JSONNode &url = itNodes["url"]; - const JSONNode &alert_id = itNodes["alert_id"]; - const JSONNode &icon_ = itNodes["icon"]["uri"]; - - const JSONNode &time_ = itNodes["timestamp"]; - if (!time_) - continue; - const JSONNode &time = time_["time"]; - if (!time || !text || !url || !alert_id) - continue; - - time_t timestamp = utils::time::from_string(time.as_string()); - if (timestamp > facy.last_notification_time_) { - // Only new notifications - facy.last_notification_time_ = timestamp; - - facebook_notification *notification = new facebook_notification(); - notification->text = utils::text::slashu_to_utf8(text.as_string()); - notification->link = url.as_string(); - notification->id = alert_id.as_string(); - notification->time = timestamp; - notification->icon = ParseIcon(icon_.as_string()); - - // Fix notification ID - std::string::size_type pos = notification->id.find(":"); - if (pos != std::string::npos) - notification->id = notification->id.substr(pos + 1); - - // Write notification to chatroom - UpdateNotificationsChatRoom(notification); - - // If it's unseen, remember it, otherwise forget it (here it will always be unseen) - if (facy.notifications.find(notification->id) == facy.notifications.end() && !notification->seen) - facy.notifications.insert(std::make_pair(notification->id, notification)); - else - delete notification; - } - } - } - else if (t == "m_notification") { - const JSONNode &data = it["data"]; - if (!data) - continue; - - const JSONNode &html_ = data["body"]["__html"]; - const JSONNode &href_ = data["href"]; - const JSONNode &unread_ = data["unread"]; - if (!html_ || !href_ || !unread_ || unread_.as_int() == 0) - continue; - - std::string alert_id = data["alert_id"].as_string(); - - const JSONNode &type_ = data["type"]; - if (type_.as_string() == "friend_confirmed") { - std::string text = utils::text::remove_html(utils::text::slashu_to_utf8(html_.as_string())); - std::string url = href_.as_string(); - - // Notify it, if user wants to be notified - if (getByte(FACEBOOK_KEY_EVENT_FRIENDSHIP_ENABLE, DEFAULT_EVENT_FRIENDSHIP_ENABLE)) - NotifyEvent(m_tszUserName, ptrW(mir_utf8decodeW(text.c_str())), 0, EVENT_FRIENDSHIP, &url, alert_id.empty() ? nullptr : &alert_id); - } - else { // new comment, like or reaction - PrepareNotificationsChatRoom(); - - // Fix notification ID - std::string::size_type pos = alert_id.find(":"); - if (pos != std::string::npos) - alert_id = alert_id.substr(pos + 1); - - facebook_notification *notification = new facebook_notification(); - notification->text = utils::text::remove_html(utils::text::html_entities_decode(html_.as_string())); - notification->link = href_.as_string(); - notification->id = alert_id; - notification->time = utils::time::from_string(data["time"].as_string()); - - const JSONNode &app_icon_ = data["app_icon"]["__html"]; - if (app_icon_) { - std::string url = app_icon_.as_string(); - notification->icon = ParseIcon(utils::text::source_get_value(&url, 3, "img class=\"img\"", "src=\"", "\"")); - } - - // Write notification to chatroom - UpdateNotificationsChatRoom(notification); - - facy.notifications.insert(std::make_pair(notification->id, notification)); - } - } - else if (t == "jewel_requests_add") { - // New friendship request, load them all with real names (because there is only user_id in "from" field) - ForkThread(&FacebookProto::ProcessFriendRequests, nullptr); - } - else if (t == "typ") { // revised 5.3.2017 - // chat typing notification - const JSONNode &from_ = it["from"]; // user fbid - const JSONNode &to_ = it["to"]; // user fbid (should be our own, but could be from our page too) - //const JSONNode &realtime_viewer_fbid_ = it["realtime_viewer_fbid"]; // our user fbid - //const JSONNode &from_mobile_ = it["from_mobile"]; // boolean // TODO: perhaps we should update user client based on this? - const JSONNode &st_ = it["st"]; // typing status - 1 = started typing, 0 = stopped typing - - // Ignore wrong (without "from") typing notifications or that are not meant for us (but e.g. for our page) - if (!from_ || to_.as_string() != facy.self_.user_id) - continue; - - facebook_user fbu; - fbu.user_id = from_.as_string(); - fbu.type = CONTACT_FRIEND; // only friends are able to send typing notifications - MCONTACT hContact = AddToContactList(&fbu); - - if (st_.as_int() == 1) - StartTyping(hContact); - else - StopTyping(hContact); - } - else if (t == "ttyp") { - // multi chat typing notification - if (!m_enableChat) - continue; - - const JSONNode &from_ = it["from"]; - const JSONNode &thread_ = it["thread"]; - const JSONNode &st_ = it["st"]; - if (!from_ || !thread_ || !st_) - continue; - - std::string tid = thread_.as_string(); - std::string from_id = from_.as_string(); - - auto itRoom = facy.chat_rooms.find(thread_.as_string()); - if (itRoom != facy.chat_rooms.end()) { - facebook_chatroom *chatroom = itRoom->second; - std::map<std::string, chatroom_participant> participants = chatroom->participants; - - auto participant = participants.find(from_id); - if (participant == participants.end()) { - // TODO: load name of this participant - chatroom_participant new_participant; - new_participant.user_id = from_id; - new_participant.nick = from_id; - AddChatContact(tid.c_str(), new_participant, true); - } - - participant = participants.find(from_id); - if (participant != participants.end()) { - MCONTACT hChatContact = ChatIDToHContact(tid); - ptrW name(mir_utf8decodeW(participant->second.nick.c_str())); - - if (st_.as_int() == 1) - Srmm_SetStatusText(hChatContact, CMStringW(FORMAT, TranslateT("%s is typing a message..."), name)); - else - Srmm_SetStatusText(hChatContact, nullptr); - - // TODO: support proper MS_PROTO_CONTACTISTYPING service for chatrooms (when it will be implemented) - } - } - } - else if (t == "privacy_changed") { - // settings changed - - const JSONNode &event_type = it["event"]; - const JSONNode &event_data = it["data"]; - if (!event_type || !event_data) - continue; - - std::string et = event_type.as_string(); - if (et == "visibility_update") { - // change of chat status - const JSONNode &visibility = event_data["visibility"]; - - bool isVisible = visibility && visibility.as_bool(); - debugLogA(" Requested chat switch to %s", isVisible ? "Online" : "Offline"); - - // If actual status is not what server says, change it (handle also local away status, which means online) - if (isVisible != (m_iStatus != ID_STATUS_INVISIBLE)) - SetStatus(isVisible ? ID_STATUS_ONLINE : ID_STATUS_INVISIBLE); - } - } - else if (t == "chatproxy-presence") { - const JSONNode &buddyList = it["buddyList"]; - if (!buddyList) - continue; - - time_t offlineThreshold = time(0) - 15 * 60; // contacts last active more than 15 minutes will be marked offline - - for (auto &itNodes : buddyList) { - // Facebook now sends info also about some nonfriends, so we just ignore status change of contacts we don't have in list - MCONTACT hContact = ContactIDToHContact(itNodes.name()); - if (!hContact) - continue; - - // TODO: Check for friends existence/inexistence? Here we should get all friends (but we're already doing friendslist request, so we should have fresh data already) - - const JSONNode &p_ = itNodes["p"]; // possible values: 0, 2 (something more?) (might not be present) - const JSONNode &lat_ = itNodes["lat"]; // timestamp of last activity (could be 0) (is always present) - const JSONNode &vc_ = itNodes["vc"]; // possible values: 0, 8, 10 (something more?) (might not be present) - - int status = ID_STATUS_DND; // DND to easily spot some problem, as we expect it will always be p==0 or p==2 below - - // Probably means presence: 0 = away, 2 = online, when not present then that probably means don't change that status - if (p_) { - int p = p_.as_int(); - - if (p == 0) - status = ID_STATUS_AWAY; - else if (p == 2) - status = ID_STATUS_ONLINE; - - setWord(hContact, "Status", status); - } - - // Last active time - if (lat_) { - time_t last_active = utils::time::from_string(lat_.as_string()); - - if (last_active > 0) - setDword(hContact, "LastActiveTS", last_active); - else - delSetting(hContact, "LastActiveTS"); - - // Set users inactive for too long as offline - if (last_active > 0 && last_active < offlineThreshold) - setWord(hContact, "Status", ID_STATUS_OFFLINE); - } - - // Probably means client: guess 0 = web, 8 = messenger, 10 = something else? - if (vc_) { - wchar_t *client; - switch (vc_.as_int()) { - case 0: client = FACEBOOK_CLIENT_WEB; break; - case 8: client = FACEBOOK_CLIENT_MESSENGER; break; - case 10: client = FACEBOOK_CLIENT_MOBILE; break; - default: client = FACEBOOK_CLIENT_OTHER; break; - } - setWString(hContact, "MirVer", client); - } - } - } - else if (t == "buddylist_overlay") { - // TODO: This is now supported also via /ajax/mercury/tabs_presence.php request (probably) - // additional info about user status (status, used client) - const JSONNode &overlay_ = it["overlay"]; - if (!overlay_) - continue; - - time_t offlineThreshold = time(0) - 15 * 60; // contacts last active more than 15 minutes will be marked offline - - for (auto &itNodes : overlay_) { - MCONTACT hContact = ContactIDToHContact(itNodes.name()); - if (!hContact) { - // Facebook now sends info also about some nonfriends, so we just ignore status change of contacts we don't have in list - continue; - } - - /* ptrW client(getWStringA(fbu->handle, "MirVer")); - if (!client || mir_wstrcmp(client, fbu->getMirVer())) - setWString(fbu->handle, "MirVer", fbu->getMirVer()); - */ - - const JSONNode &a_ = itNodes["a"]; // possible values: 0, 2 (something more?) - const JSONNode &la_ = itNodes["la"]; // timestamp of last activity (could be 0) - const JSONNode &s_ = itNodes["s"]; // possible values: push (something more?) - const JSONNode &vc_ = itNodes["vc"]; // possible values: 0, 8, 10 (something more?) - - // Friller account has also these: - // const JSONNode &ol_ = itNodes["ol"]; // possible values: -1 (when goes to offline), 0 (when goes back online) (something more?) - // const JSONNode &p_ = itNodes["p"]; // class with fbAppStatus, messengerStatus, otherStatus, status, webStatus - - int status = ID_STATUS_FREECHAT; // FREECHAT to easily spot some problem, as we expect it will always be p==0 or p==2 below - - if (a_) { - int a = a_.as_int(); - - if (a == 0) - status = ID_STATUS_OFFLINE; - else if (a == 2) - status = ID_STATUS_ONLINE; - } - else { - status = ID_STATUS_OFFLINE; - } - - if (la_ /*&& status != ID_STATUS_ONLINE*/) { - time_t last_active = utils::time::from_string(la_.as_string()); - - // Set users inactive for too long as offline - if (last_active > 0 && last_active < offlineThreshold) - status = ID_STATUS_OFFLINE; - } - else delSetting(hContact, "IdleTS"); - - setWord(hContact, "Status", status); - - if (s_) { - // what to do with this? - } - // Probably means client: guess 0 = web, 8 = messenger, 10 = something else? - if (vc_) { - wchar_t *client = FACEBOOK_CLIENT_WEB; - - /*if (vc == 0) { - // means active some time ago? (on messenger or also on web) - client = FACEBOOK_CLIENT_WEB; - } - else if (vc == 8) { - client = FACEBOOK_CLIENT_MESSENGER; // I was online on Miranda, but when looked at myself at messenger.com I had icon of Messenger. - } - else if (vc == 10) { - // means actually active on messenger - client = FACEBOOK_CLIENT_MOBILE; - } - else { - client = FACEBOOK_CLIENT_OTHER; - }*/ - - setWString(hContact, "MirVer", client); - } - } - } - else if (t == "ticker_update:home") { - if (!getByte(FACEBOOK_KEY_EVENT_TICKER_ENABLE, DEFAULT_EVENT_TICKER_ENABLE)) - continue; - - const JSONNode &actor_ = it["actor"]; - const JSONNode &story_ = it["story_xhp"]; - - std::string text = story_.as_string(); - text = utils::text::html_entities_decode(utils::text::slashu_to_utf8(text)); - - std::string url = utils::text::source_get_value(&text, 3, "\"tickerStoryLink\"", "href=\"", "\""); - std::string story_type = utils::text::source_get_value2(&text, "\"type\":\"", "\""); - std::string story_class = utils::text::source_get_value2(&text, "\"entstory_class\":\"", "\""); - - text = utils::text::trim(utils::text::remove_html(text)); - - std::string userId = actor_.as_string(); - - MCONTACT hContact = ContactIDToHContact(userId); - - debugLogA("+++ Got ticker type='%s' class='%s'", story_type.c_str(), story_class.c_str()); - - if (!text.empty()) - NotifyEvent(m_tszUserName, ptrW(mir_utf8decodeW(text.c_str())), hContact, EVENT_TICKER, &url); - } - else if (t == "notifications_read" || t == "notifications_seen") { // revised 5.3.2017 - mir_cslock s(facy.notifications_lock_); - - const JSONNode &alerts = it["alert_ids"]; - for (auto &itAlerts : alerts) { - auto itAlert = facy.notifications.find(itAlerts.as_string()); - if (itAlert != facy.notifications.end()) { - if (itAlert->second->hWndPopup != nullptr) - PUDeletePopup(itAlert->second->hWndPopup); // close popup - - delete itAlert->second; - facy.notifications.erase(itAlert); - } - } - } - /*else if (t == "mobile_requests_count") { // revised 5.3.2017 - // Notifies about remaining friendship requests (happens e.g. after approving friendship) - const JSONNode &num_friend_confirmed_unseen_ = it["num_friend_confirmed_unseen"]; // number, e.g. "0" - const JSONNode &num_unread_ = it["num_unread"]; // number, e.g. "0" - const JSONNode &num_unseen_ = it["num_unseen"]; // number, e.g. "0" - const JSONNode &realtime_viewer_fbid_ = it["realtime_viewer_fbid"]; // our user fbid - } - else if (t == "friending_state_change") { // revised 5.3.2017 - const JSONNode &userid_ = it["userid"]; // fbid of user this event is about - const JSONNode &realtime_viewer_fbid_ = it["realtime_viewer_fbid"]; // our user fbid - const JSONNode &action_ = it["action"]; // "confirm" = when we approved friendship - - if (action_.as_string() == "confirm") { - // ... - } - } - else if (t == "inbox") { // revised 5.3.2017 - const JSONNode &realtime_viewer_fbid_ = it["realtime_viewer_fbid"]; // our user fbid - const JSONNode &recent_unread_ = it["recent_unread"]; // number - const JSONNode &seen_timestamp_ = it["seen_timestamp"]; // number - const JSONNode &unread_ = it["unread"]; // number - const JSONNode &unseen_ = it["unseen"]; // number - } - else if (t == "webrtc") { // revised 5.3.2017 - const JSONNode &realtime_viewer_fbid_ = it["realtime_viewer_fbid"]; // our user fbid - const JSONNode &source_ = it["source"]; // e.g. "www" - const JSONNode &msg_type_ = it["msg_type"]; // e.g. "hang_up", "other_dismiss", "ice_candidate", "offer", "offer_ack", ...? - const JSONNode &id_ = it["id"]; // some numeric id - const JSONNode &call_id_ = it["call_id"]; // some numeric id - const JSONNode &from_ = it["from"]; // user fbid that started this event - const JSONNode &payload_ = it["payload"]; // string with some metadata (usually same as above) - }*/ - else - continue; - } - - return EXIT_SUCCESS; -} - - -int FacebookProto::ParseBuddylistUpdate(std::string* data) -{ - std::string jsonData = data->substr(9); - - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &buddylist = root["payload"].at("buddylist"); - if (!buddylist) - return EXIT_FAILURE; - - std::map<MCONTACT, bool> list; - - for (auto &it : buddylist) { - const JSONNode &id = it["id"]; - - // Facebook now sends info also about some nonfriends, so we just ignore status change of contacts we don't have in list - MCONTACT hContact = ContactIDToHContact(id.as_string()); - if (hContact) { - setWord(hContact, "Status", ID_STATUS_ONLINE); - list.insert(std::pair<MCONTACT, bool>(hContact, true)); - } - } - - for (auto &it : AccContacts()) - if (list.find(it) == list.end()) - setWord(it, "Status", ID_STATUS_OFFLINE); - - return EXIT_SUCCESS; -} - -int FacebookProto::ParseUnreadThreads(std::string *data, std::vector< std::string >* threads) -{ - std::string jsonData = data->substr(9); - - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &unread_threads = root["payload"].at("unread_thread_fbids"); - if (!unread_threads) - return EXIT_FAILURE; - - for (auto &it : unread_threads) { - // For multi user chats - const JSONNode &thread_fbids = it["thread_fbids"]; - for (auto &jt : thread_fbids) - threads->push_back(jt.as_string()); - - // For classic conversations - const JSONNode &other_user_fbids = it["other_user_fbids"]; - for (auto &jt : other_user_fbids) - threads->push_back(jt.as_string()); - } - - return EXIT_SUCCESS; -} - -int FacebookProto::ParseThreadMessages(std::string *data, std::vector< facebook_message >* messages, bool unreadOnly) -{ - // cuts out the rest (summary result) - size_t len = data->find("\r\n{\n \"successful_results"); - if (len != data->npos) - data->erase(len); - - // make data to be valid json (queries are standalone JSONs --> merge them into one) - std::string::size_type n = 0; - std::string replaceFrom = "}\r\n{"; - std::string replaceTo = ", "; - while ((n = data->find(replaceFrom, n)) != std::string::npos) { - data->replace(n, replaceFrom.size(), replaceTo); - n += replaceTo.size(); - } - - JSONNode root = JSONNode::parse(data->c_str()); - if (!root) - return EXIT_FAILURE; - - // since it could loop over multiple queries not all can be valid - // so return EXIT_FAILURE only if none is processed - bool hasResult = false; - - // loop over queries - for (auto &itr : root) { - const JSONNode &thread = itr["data"]["message_thread"]; - if (!thread) - continue; - - const JSONNode &nodes = thread["messages"]["nodes"]; - if (!nodes) - continue; - - // TODO! process commented sections and better pair json (this is just quick attempt, + I do not know what everything means yet) - - const JSONNode &other_user_fbid_ = thread["thread_key"]["other_user_id"]; - const JSONNode &thread_fbid_ = thread["thread_key"]["thread_fbid"]; - - for (auto &it : nodes) { - const JSONNode &author_ = it["message_sender"]["id"]; - const JSONNode &body_ = it["message"]["text"]; - const JSONNode &thread_id_ = it["offline_threading_id"]; - const JSONNode &mid_ = it["message_id"]; - const JSONNode ×tamp_ = it["timestamp_precise"]; - const JSONNode &is_unread_ = it["unread"]; - - // Either there is "body" (for classic messages), or "log_message_type" and "log_message_body" (for log messages) - const JSONNode &log_type_ = it["log_message_type"]; - const JSONNode &log_body_ = it["log_message_body"]; - const JSONNode &log_data_ = it["log_message_data"]; // additional data for this log message - - if (!author_ || (!body_ && !log_body_) || !mid_ || (!thread_fbid_ && !thread_id_) || !timestamp_) { - debugLogA("ParseThreadMessages: ignoring message (%s) - missing attribute", mid_.as_string().c_str()); - continue; - } - - std::string thread_id = thread_id_.as_string(); - std::string thread_fbid = thread_fbid_.as_string(); - std::string message_id = mid_.as_string(); - std::string message_text = body_ ? body_.as_string() : log_body_.as_string(); - std::string author_id = author_.as_string(); - std::string other_user_fbid = other_user_fbid_ ? other_user_fbid_.as_string() : ""; - std::string::size_type pos = author_id.find(":"); // strip "fbid:" prefix - if (pos != std::string::npos) - author_id = author_id.substr(pos + 1); - - // Process attachements and stickers - ParseAttachments(message_text, it, other_user_fbid, true); - - message_text = utils::text::trim(utils::text::slashu_to_utf8(message_text), true); - if (message_text.empty()) { - debugLogA("ParseThreadMessages: ignoring message (%s) - empty message text", mid_.as_string().c_str()); - continue; - } - - bool isUnread = is_unread_.as_bool(); - - // Ignore read messages if we want only unread messages - if (unreadOnly && !isUnread) - continue; - - facebook_message message; - message.message_text = message_text; - message.time = utils::time::from_string(timestamp_.as_string()); - message.message_id = message_id; - message.isIncoming = (author_id != facy.self_.user_id); - message.isUnread = isUnread; - - message.isChat = other_user_fbid.empty(); - if (message.isChat) { - message.user_id = author_id; - message.thread_id = "id." + thread_fbid; - } - else { - message.user_id = other_user_fbid; - message.thread_id = thread_id; - } - - ParseMessageType(message, log_type_, log_body_, log_data_); - - messages->push_back(message); - hasResult = true; - } - } - - return hasResult ? EXIT_SUCCESS : EXIT_FAILURE; -} - -int FacebookProto::ParseHistory(std::string *data, std::vector< facebook_message > &messages, std::string* firstTimestamp) -{ - size_t len = data->find("\r\n"); - if (len != data->npos) - data->erase(len); - - JSONNode root = JSONNode::parse(data->c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &thread = root["o0"]["data"]["message_thread"]; - if (!thread) - return EXIT_FAILURE; - - const JSONNode &nodes = thread["messages"]["nodes"]; - if (!nodes) - return EXIT_FAILURE; - - // TODO! process commented sections and better pair json (this is just quick attempt, + I do not know what everything means yet) - - bool first = true; - - const JSONNode &other_user_fbid_ = thread["thread_key"]["other_user_id"]; - // const JSONNode &thread_fbid_ = thread["thread_key"]["thread_fbid"]; - - for (auto &it : nodes) { - const JSONNode &author = it["message_sender"]["id"]; - const JSONNode &body = it["message"]["text"]; - const JSONNode &tid = it["offline_threading_id"]; - const JSONNode &mid = it["message_id"]; - const JSONNode ×tamp = it["timestamp_precise"]; - // const JSONNode &filtered = it["is_filtered_content"]; - const JSONNode &is_unread = it["unread"]; - - // Either there is "body" (for classic messages), or "log_message_type" and "log_message_body" (for log messages) - const JSONNode &log_type_ = it["log_message_type"]; - const JSONNode &log_body_ = it["log_message_body"]; - const JSONNode &log_data_ = it["log_message_data"]; - - if (!author || (!body && !log_body_) || !mid || !tid || !timestamp) { - debugLogA("ParseHistory: ignoring message (%s) - missing attribute", mid.as_string().c_str()); - continue; - } - - if (first) { - *firstTimestamp = timestamp.as_string(); - first = false; - } - - std::string thread_id = tid.as_string(); - std::string message_id = mid.as_string(); - std::string message_text = body ? body.as_string() : log_body_.as_string(); - std::string author_id = author.as_string(); - std::string other_user_id = other_user_fbid_ ? other_user_fbid_.as_string() : ""; - std::string::size_type pos = author_id.find(":"); // strip "fbid:" prefix - if (pos != std::string::npos) - author_id = author_id.substr(pos + 1); - - // Process attachements and stickers - ParseAttachments(message_text, it, other_user_id, true); - - //if (filtered.as_bool() && message_text.empty()) - // message_text = Translate("This message is no longer available, because it was marked as abusive or spam."); - - message_text = utils::text::trim(utils::text::slashu_to_utf8(message_text), true); - if (message_text.empty()) { - debugLogA("ParseHistory: ignoring message (%s) - empty message text", mid.as_string().c_str()); - continue; - } - - facebook_message message; - message.message_text = message_text; - message.time = utils::time::from_string(timestamp.as_string()); - message.thread_id = thread_id; - message.message_id = message_id; - message.isIncoming = (author_id != facy.self_.user_id); - message.isUnread = is_unread.as_bool(); - message.isChat = false; - message.user_id = other_user_id; - - ParseMessageType(message, log_type_, log_body_, log_data_); - - messages.push_back(message); - } - - return EXIT_SUCCESS; -} - -int FacebookProto::ParseThreadInfo(std::string *data, std::string *user_id) -{ - std::string jsonData = data->substr(9); - - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &threads = root["payload"].at("threads"); - if (!threads) - return EXIT_FAILURE; - - //std::map<std::string, std::string> thread_ids; - for (auto &it : threads) { - const JSONNode &canonical = it["canonical_fbid"]; - const JSONNode &thread_id = it["thread_id"]; - //const JSONNode &message_count = it["message_count"); // TODO: this could be useful for loading history from server - if (!canonical || !thread_id) - continue; - - std::string id = canonical.as_string(); - if (id == "null") - continue; - - *user_id = id; - } - - return EXIT_SUCCESS; -} - - -int FacebookProto::ParseUserInfo(std::string *data, facebook_user* fbu) -{ - std::string jsonData = data->substr(9); - - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &profiles = root["payload"].at("profiles"); - if (!profiles) - return EXIT_FAILURE; - - //std::map<std::string, std::string> user_ids; - for (auto &it : profiles) { - // TODO: allow more users to parse at once - std::string id = it.name(); - - if (fbu->user_id == id) { - parseUser(it, fbu); - break; - } - } - - return EXIT_SUCCESS; -} - -int FacebookProto::ParseMessagesCount(std::string *data, int *messagesCount, int *unreadCount) -{ - size_t len = data->find("\r\n"); - if (len != data->npos) - data->erase(len); - - JSONNode root = JSONNode::parse(data->c_str()); - if (!root) - return EXIT_FAILURE; - - const JSONNode &thread = root["o0"]["data"]["message_thread"]; - if (!thread) - return EXIT_FAILURE; - - const JSONNode &message_count_ = thread["messages_count"]; - const JSONNode &unread_count_ = thread["unread_count"]; - - if (!message_count_ || !unread_count_) - return EXIT_FAILURE; - - *messagesCount = message_count_.as_int(); - *unreadCount = unread_count_.as_int(); - - return EXIT_SUCCESS; -} diff --git a/protocols/FacebookRM/src/login.cpp b/protocols/FacebookRM/src/login.cpp deleted file mode 100644 index 9222f6ca59..0000000000 --- a/protocols/FacebookRM/src/login.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// connecting physically - -HttpRequest* facebook_client::loginRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_LOGIN "/login.php"); - p->flags |= NLHRF_NODUMP; - p << INT_PARAM("login_attempt", 1) << INT_PARAM("lwv", 110); - return p; -} - -HttpRequest* facebook_client::loginRequest(const char *username, const char *password, const char *urlData, const char *bodyData) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_LOGIN "/login.php"); - p->flags |= NLHRF_NODUMP; - p->Persistent = p->NONE; - - p << INT_PARAM("login_attempt", 1) << INT_PARAM("lwv", 110); - if (mir_strlen(urlData)) { - p->m_szParam.AppendChar('&'); - p->m_szParam.Append(urlData); // additional data parsed from form - } - - p->Body - << INT_PARAM("persistent", 1) - << CHAR_PARAM("email", username) - << CHAR_PARAM("pass", password) - << CHAR_PARAM("lgndim", "eyJ3IjoxOTIwLCJoIjoxMDgwLCJhdyI6MTgzNCwiYWgiOjEwODAsImMiOjMyfQ==") // means base64 encoded: {"w":1920,"h":1080,"aw":1834,"ah":1080,"c":32} - << bodyData; // additional data parsed from form - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// request to receive login code via SMS - -HttpRequest* facebook_client::loginSmsRequest(const char *dtsg) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/login/approvals/send_sms"); - - p << INT_PARAM("dpr", 1); - - p->Body - << CHAR_PARAM("method_requested", "sms_requested") - << INT_PARAM("__a", 1) - << INT_PARAM("__user", 0) - << INT_PARAM("__be", 0) - << CHAR_PARAM("__pc", "EXP1:DEFAULT") - << CHAR_PARAM("current_time", (utils::time::unix_timestamp() + ".000").c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("fb_dtsg", dtsg) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__rev", __rev()); - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// setting machine name - -HttpRequest* facebook_client::setupMachineRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/checkpoint/"); - p->m_szParam.Append("next"); - return p; -} - -HttpRequest* facebook_client::setupMachineRequest(const char *dtsg, const char *nh, const char *submit) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/checkpoint/"); - - p->m_szParam.Append("next"); - - p->Body - << CHAR_PARAM(CMStringA(::FORMAT, "submit[%s]", submit), submit) - << CHAR_PARAM("nh", nh) - << CHAR_PARAM("fb_dtsg", dtsg); - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// disconnecting physically - -HttpRequest* facebook_client::logoutRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/logout.php"); - - p->flags |= NLHRF_REDIRECT | NLHRF_NODUMP; - - p->Body - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("h", logout_hash_.c_str()); - - return p; -} diff --git a/protocols/FacebookRM/src/main.cpp b/protocols/FacebookRM/src/main.cpp deleted file mode 100644 index bf80befe1c..0000000000 --- a/protocols/FacebookRM/src/main.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "stdafx.h"
-
-CMPlugin g_plugin;
-
-DWORD g_mirandaVersion;
-bool g_bMessageState;
-HWND g_hwndHeartbeat;
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-PLUGININFOEX pluginInfoEx = {
- sizeof(PLUGININFOEX),
- __PLUGIN_NAME,
- PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
- __DESCRIPTION,
- __AUTHOR,
- __COPYRIGHT,
- __AUTHORWEB,
- UNICODE_AWARE,
- // {8432B009-FF32-4727-AAE6-A9035038FD58}
- { 0x8432b009, 0xff32, 0x4727, { 0xaa, 0xe6, 0xa9, 0x3, 0x50, 0x38, 0xfd, 0x58 } }
-};
-
-CMPlugin::CMPlugin() :
- ACCPROTOPLUGIN<FacebookProto>(FACEBOOK_NAME, pluginInfoEx)
-{
- SetUniqueId(FACEBOOK_KEY_ID);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Interface information
-
-extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Load
-
-static int OnModuleLoaded(WPARAM, LPARAM)
-{
- g_bMessageState = ServiceExists(MS_MESSAGESTATE_UPDATE) != 0;
- return 0;
-}
-
-int CMPlugin::Load()
-{
- g_hwndHeartbeat = CreateWindowEx(0, L"STATIC", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
-
- HookEvent(ME_SYSTEM_MODULELOAD, OnModuleLoaded);
- HookEvent(ME_SYSTEM_MODULEUNLOAD, OnModuleLoaded);
- HookEvent(ME_SYSTEM_MODULESLOADED, OnModuleLoaded);
-
- InitIcons();
- InitContactMenus();
-
- // Initialize random generator (used only as fallback in utils)
- srand(::time(0));
- return 0;
-}
-
-int CMPlugin::Unload()
-{
- DestroyWindow(g_hwndHeartbeat);
- return 0;
-}
diff --git a/protocols/FacebookRM/src/messages.cpp b/protocols/FacebookRM/src/messages.cpp deleted file mode 100644 index dc103b739d..0000000000 --- a/protocols/FacebookRM/src/messages.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -MEVENT FacebookProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre) -{ - StopTyping(hContact); - - return CSuper::RecvMsg(hContact, pre); -} - -void FacebookProto::SendMsgWorker(void *p) -{ - if (p == nullptr) - return; - - send_direct *data = static_cast<send_direct*>(p); - - ptrA id(getStringA(data->hContact, FACEBOOK_KEY_ID)); - - if (!isOnline()) - ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)data->msgid, (LPARAM)TranslateT("You cannot send messages when you are offline.")); - else if (id == nullptr) - ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)data->msgid); - else { - int tries = getByte(FACEBOOK_KEY_SEND_MESSAGE_TRIES, 1); - tries = min(max(tries, 1), 5); - - std::string error_text; - int result = SEND_MESSAGE_ERROR; - while (result == SEND_MESSAGE_ERROR && tries-- > 0) - result = facy.send_message(data->msgid, data->hContact, data->msg, &error_text); - - if (result == SEND_MESSAGE_OK) { - ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)data->msgid); - - // Remove from "readers" list and clear statusbar - facy.erase_reader(data->hContact); - } - else ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)data->msgid, (LPARAM)_A2T(error_text.c_str())); - } - - delete data; -} - -void FacebookProto::SendChatMsgWorker(void *p) -{ - if (p == nullptr) - return; - - send_chat *data = static_cast<send_chat*>(p); - std::string err_message; - - // replace %% back to %, because chat automatically does this to sent messages - utils::text::replace_all(&data->msg, "%%", "%"); - - MCONTACT hContact = ChatIDToHContact(data->chat_id); - if (hContact) { - ptrA tid_(getStringA(hContact, FACEBOOK_KEY_TID)); - std::string tid; - if (tid_ != nullptr && mir_strcmp(tid_, "null")) - tid = tid_; - else { - // request info about chat thread - http::response resp = facy.sendRequest(facy.threadInfoRequest(true, data->chat_id.c_str())); - - tid = utils::text::source_get_value(&resp.data, 2, "\"thread_id\":\"", "\""); - if (!tid.empty() && tid.compare("null")) - setString(hContact, FACEBOOK_KEY_TID, tid.c_str()); - debugLogA(" Got thread info: %s = %s", data->chat_id.c_str(), tid.c_str()); - } - - if (!tid.empty()) { - if (facy.send_message(0, hContact, data->msg, &err_message) == SEND_MESSAGE_OK) - UpdateChat(data->chat_id.c_str(), facy.self_.user_id.c_str(), facy.self_.real_name.c_str(), data->msg.c_str()); - else { - ptrA text(mir_utf8encode(err_message.c_str())); - UpdateChat(data->chat_id.c_str(), nullptr, nullptr, text); - } - } - } - - delete data; -} - -int FacebookProto::SendMsg(MCONTACT hContact, int, const char *msg) -{ - std::string message = msg; - unsigned int msgId = InterlockedIncrement(&facy.msgid_); - - ForkThread(&FacebookProto::SendMsgWorker, new send_direct(hContact, message, msgId)); - return msgId; -} - -int FacebookProto::UserIsTyping(MCONTACT hContact, int type) -{ - if (hContact && isOnline()) - ForkThread(&FacebookProto::SendTypingWorker, new send_typing(hContact, type)); - - return 0; -} - -void FacebookProto::SendTypingWorker(void *p) -{ - if (p == nullptr) - return; - - send_typing *typing = static_cast<send_typing*>(p); - - // Don't send typing notifications when we are invisible and user don't want that - bool typingWhenInvisible = getBool(FACEBOOK_KEY_TYPING_WHEN_INVISIBLE, DEFAULT_TYPING_WHEN_INVISIBLE); - if (isInvisible() && !typingWhenInvisible) { - delete typing; - return; - } - - // Dont send typing notifications to not friends - Facebook won't give them that info anyway - if (!isChatRoom(typing->hContact) && getWord(typing->hContact, FACEBOOK_KEY_CONTACT_TYPE, 0) != CONTACT_FRIEND) { - delete typing; - return; - } - - const char *value = (isChatRoom(typing->hContact) ? FACEBOOK_KEY_TID : FACEBOOK_KEY_ID); - ptrA id(getStringA(typing->hContact, value)); - if (id != nullptr) - http::response resp = facy.sendRequest(facy.sendTypingRequest(id, isChatRoom(typing->hContact), typing->status == PROTOTYPE_SELFTYPING_ON)); - - delete typing; -} - -void FacebookProto::ReadMessageWorker(void *p) -{ - if (p == nullptr) - return; - - if (getBool(FACEBOOK_KEY_KEEP_UNREAD, 0)) - return; - - std::set<MCONTACT> *hContacts = (std::set<MCONTACT>*)p; - - if (hContacts->empty()) { - delete hContacts; - return; - } - - LIST<char> ids(1); - for (auto &hContact : *hContacts) { - if (getBool(hContact, FACEBOOK_KEY_KEEP_UNREAD, 0)) - continue; - - // mark message read (also send seen info) - const char *value = (isChatRoom(hContact) ? FACEBOOK_KEY_TID : FACEBOOK_KEY_ID); - ptrA id(getStringA(hContact, value)); - if (id == nullptr) - continue; - - ids.insert(mir_strdup(id)); - } - - hContacts->clear(); - delete hContacts; - - facy.sendRequest(facy.markMessageReadRequest(ids)); - - FreeList(ids); - ids.destroy(); -} - -void FacebookProto::StickerAsSmiley(std::string sticker, const std::string &url, MCONTACT hContact) -{ - // Don't load stickers as smileys when we're loading history - if (facy.loading_history) - return; - - std::string b64 = ptrA(mir_base64_encode(sticker.c_str(), sticker.length())); - b64 = utils::url::encode(b64); - - std::wstring filename = GetAvatarFolder() + L"\\stickers\\"; - ptrW dir(mir_wstrdup(filename.c_str())); - - filename += (wchar_t*)_A2T(b64.c_str()); - filename += L".png"; - - // Check if we have this sticker already and download it if not - if (GetFileAttributes(filename.c_str()) == INVALID_FILE_ATTRIBUTES) { - HNETLIBCONN nlc = nullptr; - facy.save_url(url, filename, nlc); - Netlib_CloseHandle(nlc); - } - - SMADD_CONT cont; - cont.cbSize = sizeof(SMADD_CONT); - cont.hContact = hContact; - cont.type = 0; - cont.path = dir; - CallService(MS_SMILEYADD_LOADCONTACTSMILEYS, 0, (LPARAM)&cont); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -HttpRequest* facebook_client::sendMessageRequest( - const char *userId, - const char *threadId, - const char *messageId, - const char *messageText, - bool isChat, - const char *captcha, - const char *captchaPersistData) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/messaging/send/"); - - // Don't notify errors for this request, because we're getting them inline in messaging window - p->NotifyErrors = false; - - // Use own persistent connection for sending messages - p->Persistent = p->MESSAGES; - - p << INT_PARAM("dpr", 1); - - if (mir_strlen(captcha) > 0) - p->Body << CHAR_PARAM("captcha_persist_data", captchaPersistData) << CHAR_PARAM("captcha_response", captcha); - - p->Body << CHAR_PARAM("client", "mercury") << CHAR_PARAM("action_type", "ma-type:user-generated-message"); - - // Experimental sticker sending support - std::string message_text = messageText; // FIXME: Rewrite this without std::string... - if (message_text.substr(0, 10) == "[[sticker:" && message_text.substr(message_text.length() - 2) == "]]") - // TODO: For sending GIF images instead of "sticker_id=" there is "image_ids[0]=", otherwise it's same - p->Body - << CHAR_PARAM("body", "") - << CHAR_PARAM("sticker_id", message_text.substr(10, message_text.length() - 10 - 2).c_str()) - << BOOL_PARAM("has_attachment", true); - else - p->Body << CHAR_PARAM("body", messageText) << BOOL_PARAM("has_attachment", false); - - p->Body - << INT_PARAM("ephemeral_ttl_mode", 0) - << CHAR_PARAM("message_id", messageId) - << CHAR_PARAM("offline_threading_id", messageId); // Same as message ID - - if (isChat) { - // NOTE: Remove "id." prefix as here we need to give threadFbId and not threadId - std::string threadFbid = threadId; // FIXME: Rewrite this without std::string... - if (threadFbid.substr(0, 3) == "id.") - threadFbid = threadFbid.substr(3); - - p->Body << CHAR_PARAM("thread_fbid", threadFbid.c_str()); - } - else - p->Body - << CHAR_PARAM("other_user_fbid", userId) - << CHAR_PARAM("specific_to_list[0]", CMStringA(::FORMAT, "fbid:%s", userId)) - << CHAR_PARAM("specific_to_list[1]", CMStringA(::FORMAT, "fbid:%s", self_.user_id.c_str())); - - p->Body - // << "signature_id=" // TODO: How to generate signature ID? It is present only when sending via "mercury" - << CHAR_PARAM("source", "source:chat:web") // or "source:titan:web" for web_messenger - << CHAR_PARAM("timestamp", utils::time::mili_timestamp().c_str()) - << CHAR_PARAM("ui_push_phase", "V3") - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << INT_PARAM("__a", 1) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__be", -1); - - return p; -} - -HttpRequest* facebook_client::sendTypingRequest(const char *userId, bool isChat, bool isTyping) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/messaging/typ.php"); - - p << INT_PARAM("dpr", 1); - - p->Body - << INT_PARAM("typ", isTyping ? 1 : 0) - << CHAR_PARAM("to", isChat ? "" : userId) - << CHAR_PARAM("thread", userId) - << CHAR_PARAM("source", "mercury-chat") - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__a", 1) - << INT_PARAM("__be", -1); - - return p; -} - -HttpRequest* facebook_client::markMessageReadRequest(const LIST<char> &ids) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/change_read_status.php"); - - p << INT_PARAM("__a", 1); - - for (auto &it : ids) { - std::string id_ = it; - // NOTE: Remove "id." prefix as here we need to give threadFbId and not threadId - if (id_.substr(0, 3) == "id.") - id_ = id_.substr(3); - - CMStringA id(::FORMAT, "ids[%s]", mir_urlEncode(id_.c_str()).c_str()); - p->Body << BOOL_PARAM(id, true); - } - - p->Body - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << INT_PARAM("__a", 1); - - return p; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -HttpRequest* facebook_client::destroyThreadRequest(facebook_chatroom *fbc) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/mercury/delete_thread.php"); - - p << INT_PARAM("dpr", 1); - - p->Body - << CHAR_PARAM("ids[0]", fbc->thread_id.substr(3).c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__a", 1) - << INT_PARAM("__be", 1); - - return p; -} - -HttpRequest* facebook_client::exitThreadRequest(facebook_chatroom *fbc) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/messaging/send/"); - - p << INT_PARAM("dpr", 1); - - std::string msgid = utils::text::rand_string(15); - - p->Body - << CHAR_PARAM("client", "mercury") - << CHAR_PARAM("action_type", "ma-type:log-message") - << CHAR_PARAM("log_message_data[removed_participants][0]", ("fbid:" + self_.user_id).c_str()) - << CHAR_PARAM("log_message_type", "log:unsubscribe") - << CHAR_PARAM("message_id", msgid.c_str()) - << CHAR_PARAM("offline_threading_id", msgid.c_str()) - << CHAR_PARAM("source", "source:chat:web") - << CHAR_PARAM("thread_fbid", fbc->thread_id.substr(3).c_str()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << INT64_PARAM("timestamp", ::time(0) * 1000) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__a", 1) - << INT_PARAM("__be", 1); - - return p; -} diff --git a/protocols/FacebookRM/src/notifications.cpp b/protocols/FacebookRM/src/notifications.cpp deleted file mode 100644 index 7755afbc8b..0000000000 --- a/protocols/FacebookRM/src/notifications.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// getting notifications - -HttpRequest* facebook_client::getNotificationsRequest(int count) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/notifications/client/get.php"); - - p << INT_PARAM("dpr", 1); - - p->Body - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << INT_PARAM("length", count) // number of items to load - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__be", -1) - << INT_PARAM("__a", 1); - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// marking notifications read - -HttpRequest* facebook_client::markNotificationReadRequest(const char *id) -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/ajax/notifications/mark_read.php"); - - p << INT_PARAM("__a", 1) - << INT_PARAM("seen", 0) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("alert_ids[0]", id); - - return p; -} diff --git a/protocols/FacebookRM/src/process.cpp b/protocols/FacebookRM/src/process.cpp deleted file mode 100644 index fd03128b60..0000000000 --- a/protocols/FacebookRM/src/process.cpp +++ /dev/null @@ -1,1304 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -/** - * Helper function for loading name from database (or use default one specified as parameter), used for title of few notifications. - */ - - - -void FacebookProto::ProcessBuddylistUpdate(void*) -{ - if (isOffline()) - return; - - facy.handle_entry("buddylist_update"); - - // Get friends list - http::response resp = facy.sendRequest(facy.buddylistUpdate()); - if (resp.code != HTTP_CODE_OK) { - facy.handle_error("buddylist_update"); - return; - } - - debugLogA("*** Starting processing buddylist update"); - - if (ParseBuddylistUpdate(&resp.data) != EXIT_SUCCESS) { - debugLogA("*** Error processing buddylist update"); - return; - } - - debugLogA("*** Buddylist update processed"); -} - - -void FacebookProto::ProcessFriendList(void*) -{ - if (isOffline()) - return; - - facy.handle_entry("load_friends"); - - // Get friends list - http::response resp = facy.sendRequest(facy.userInfoAllRequest()); - if (resp.code != HTTP_CODE_OK) { - facy.handle_error("load_friends"); - return; - } - - debugLogA("*** Starting processing friend list"); - - - bool loadAllContacts = getBool(FACEBOOK_KEY_LOAD_ALL_CONTACTS, DEFAULT_LOAD_ALL_CONTACTS); - bool pagesAlwaysOnline = getBool(FACEBOOK_KEY_PAGES_ALWAYS_ONLINE, DEFAULT_PAGES_ALWAYS_ONLINE); - - std::map<std::string, facebook_user*> friends; - if (ParseFriends(&resp.data, &friends, loadAllContacts) != EXIT_SUCCESS) { - debugLogA("*** Error processing friend list"); - return; - } - - // Check and update old contacts - for (auto &hContact : AccContacts()) { - if (isChatRoom(hContact)) - continue; - - // TODO RM: change name of "Deleted" key to "DeletedTS", remove this code in some next version - int deletedTS = getDword(hContact, "Deleted", 0); - if (deletedTS != 0) { - delSetting(hContact, "Deleted"); - setDword(hContact, FACEBOOK_KEY_DELETED, deletedTS); - } - - // If this contact is page, set it as invisible (if enabled in options) - if (pagesAlwaysOnline && getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE) == CONTACT_PAGE) - setWord(hContact, "Status", ID_STATUS_INVISIBLE); - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (id != nullptr) { - std::map< std::string, facebook_user* >::iterator iter; - - if ((iter = friends.find(std::string(id))) != friends.end()) { - // Found contact, update it and remove from map - facebook_user *fbu = iter->second; - - // TODO RM: remove, because contacts cant change it, so its only for "first run" - // - but what with contacts, that was added after logon? - // Update gender - setByte(hContact, "Gender", (int)fbu->gender); - - // TODO: remove this in some future version? - // Remove old useless "RealName" field - delSetting(hContact, "RealName"); - - // Update real name and nick - if (!fbu->real_name.empty()) - SaveName(hContact, fbu); - - // Update username - if (!fbu->username.empty()) - setString(hContact, FACEBOOK_KEY_USERNAME, fbu->username.c_str()); - else - delSetting(hContact, FACEBOOK_KEY_USERNAME); - - // Update contact type - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, fbu->type); - // TODO: remove that popup and use "Contact added you" event? - - // Wasn't contact removed from "server-list" someday? And is it friend now? (as we can get also non-friends from this request now)? - if (fbu->type == CONTACT_FRIEND && getDword(hContact, FACEBOOK_KEY_DELETED, 0)) { - delSetting(hContact, FACEBOOK_KEY_DELETED); - - // Notify it, if user wants to be notified - if (getByte(FACEBOOK_KEY_EVENT_FRIENDSHIP_ENABLE, DEFAULT_EVENT_FRIENDSHIP_ENABLE)) { - std::string url = FACEBOOK_URL_PROFILE + fbu->user_id; - NotifyEvent(Clist_GetContactDisplayName(hContact), TranslateT("Contact is back on server-list."), hContact, EVENT_FRIENDSHIP, &url); - } - } - - // Check avatar change - CheckAvatarChange(hContact, fbu->image_url); - - // Mark this contact as deleted ("processed") and delete them later (as there may be some duplicit contacts to use) - fbu->deleted = true; - } - else { - // Contact is not on "server-list", notify it was removed (if it was real friend before) - - // Was this real friend before? - if (getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE) == CONTACT_FRIEND) { - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_NONE); - - // Wasn't we already been notified about this contact? - if (!getDword(hContact, FACEBOOK_KEY_DELETED, 0)) { - setDword(hContact, FACEBOOK_KEY_DELETED, ::time(0)); - - // Notify it, if user wants to be notified - if (getByte(FACEBOOK_KEY_EVENT_FRIENDSHIP_ENABLE, DEFAULT_EVENT_FRIENDSHIP_ENABLE)) { - std::string url = FACEBOOK_URL_PROFILE + std::string(id); - NotifyEvent(Clist_GetContactDisplayName(hContact), TranslateT("Contact is no longer on server-list."), hContact, EVENT_FRIENDSHIP, &url); - } - } - } - } - } - } - - // Check remaining contacts in map and add them to contact list - for (auto &it : friends) { - if (!it.second->deleted) - AddToContactList(it.second, true); // we know this contact doesn't exists, so we force add it - - delete it.second; - } - friends.clear(); - - debugLogA("*** Friend list processed"); -} - -void FacebookProto::ProcessUnreadMessages(void*) -{ - if (isOffline()) - return; - - facy.handle_entry("ProcessUnreadMessages"); - - http::response resp = facy.sendRequest(facy.unreadThreadsRequest()); - if (resp.code != HTTP_CODE_OK) { - facy.handle_error("ProcessUnreadMessages"); - return; - } - - std::vector<std::string> threads; - if (ParseUnreadThreads(&resp.data, &threads) == EXIT_SUCCESS) { - ForkThread(&FacebookProto::ProcessUnreadMessage, new std::vector<std::string>(threads)); - debugLogA("*** Unread threads list processed"); - } - else debugLogA("*** Error processing unread threads list"); - - facy.handle_success("ProcessUnreadMessages"); -} - -void FacebookProto::ProcessUnreadMessage(void *pParam) -{ - if (pParam == nullptr) - return; - - std::vector<std::string> *threads = (std::vector<std::string>*)pParam; - - if (isOffline()) { - delete threads; - return; - } - - facy.handle_entry("ProcessUnreadMessage"); - - int limit = 21; - - // FIXME: Rework this whole request as offset doesn't work anyway, and allow to load all the unread messages for each thread (IMHO could be done in 2 single requests = 1) get number of messages for all threads 2) load the counts of messages for all threads) - - // TODO: First load info about amount of unread messages, then load exactly this amount for each thread - - while (!threads->empty()) { - LIST<char> ids(1); - for (std::vector<std::string>::size_type i = 0; i < threads->size(); i++) - ids.insert(mir_strdup(threads->at(i).c_str())); - - http::response resp = facy.sendRequest(facy.threadInfoRequest(ids, limit)); - - FreeList(ids); - ids.destroy(); - - if (resp.code == HTTP_CODE_OK) { - std::vector<facebook_message> messages; - if (ParseThreadMessages(&resp.data, &messages, false) == EXIT_SUCCESS) { - ReceiveMessages(messages, true); - debugLogA("*** Unread messages processed"); - } - else debugLogA("*** Error processing unread messages"); - - facy.handle_success("ProcessUnreadMessage"); - } - else facy.handle_error("ProcessUnreadMessage"); - - // limit = 20; // TODO: use better limits? - - threads->clear(); // TODO: if we have limit messages from one user, there may be more unread messages... continue with it... otherwise remove that threadd from threads list -- or do it in json parser? hm = allow more than "limit" unread messages to be parsed - } - - delete threads; -} - -void FacebookProto::LoadLastMessages(void *pParam) -{ - if (pParam == nullptr) - return; - - MCONTACT hContact = *(MCONTACT*)pParam; - delete (MCONTACT*)pParam; - - if (isOffline()) - return; - - facy.handle_entry("LoadLastMessages"); - if (!isOnline()) - return; - - bool isChat = isChatRoom(hContact); - if (isChat && (!m_enableChat || IsSpecialChatRoom(hContact))) // disabled chats or special chatroom (e.g. nofitications) - return; - - ptrA item_id(getStringA(hContact, isChat ? FACEBOOK_KEY_TID : FACEBOOK_KEY_ID)); - if (item_id == nullptr) { - debugLogA("!!! LoadLastMessages(): Contact has no TID/ID"); - return; - } - - int count = min(FACEBOOK_MESSAGES_ON_OPEN_LIMIT, getByte(FACEBOOK_KEY_MESSAGES_ON_OPEN_COUNT, DEFAULT_MESSAGES_ON_OPEN_COUNT)); - - http::response resp = facy.sendRequest(facy.threadInfoRequest(isChat, (const char*)item_id, nullptr, count, true)); - if (resp.code != HTTP_CODE_OK || resp.data.empty()) { - facy.handle_error("LoadLastMessages"); - return; - } - - // Temporarily disable marking messages as read for this contact - facy.ignore_read.insert(hContact); - - std::vector<facebook_message> messages; - if (ParseThreadMessages(&resp.data, &messages, false) == EXIT_SUCCESS) { - ReceiveMessages(messages, true); - debugLogA("*** Thread messages processed"); - } - else debugLogA("*** Error processing thread messages"); - - facy.handle_success("LoadLastMessages"); - - // Enable marking messages as read for this contact - facy.ignore_read.erase(hContact); - - // And force mark read - OnDbEventRead(hContact, 0); -} - -void FacebookProto::LoadHistory(void *pParam) -{ - if (pParam == nullptr) - return; - - MCONTACT hContact = *(MCONTACT*)pParam; - delete (MCONTACT*)pParam; - - mir_cslock s(facy.loading_history_lock_); - - // Allow loading history only from one contact at a time - if (!isOnline() || facy.loading_history) - return; - - facy.handle_entry("LoadHistory"); - - bool isChat = isChatRoom(hContact); - if (isChat) - return; - - ptrA item_id(getStringA(hContact, isChat ? FACEBOOK_KEY_TID : FACEBOOK_KEY_ID)); - if (item_id == nullptr) { - debugLogA("!!! LoadHistory(): Contact has no TID/ID"); - return; - } - - // first get info about this thread and how many messages is there - http::response resp = facy.sendRequest(facy.threadInfoRequest(isChat, (char*)item_id)); - if (resp.code != HTTP_CODE_OK || resp.data.empty()) { - facy.handle_error("LoadHistory"); - return; - } - - int messagesCount = -1; - int unreadCount = -1; - - if (ParseMessagesCount(&resp.data, &messagesCount, &unreadCount) == EXIT_FAILURE) { - facy.handle_error("LoadHistory"); - return; - } - - // Temporarily disable marking messages as read for this contact - facy.ignore_read.insert(hContact); - // Mark we're loading history, so we can behave differently (e.g., stickers won't be refreshed as it slows the whole process down drastically) - facy.loading_history = true; - - POPUPDATAW ppd; - ppd.iSeconds = 5; - ppd.lchContact = hContact; - ppd.lchIcon = IcoLib_GetIconByHandle(g_plugin.getIconHandle(IDI_CONVERSATION)); // TODO: Use better icon - wcsncpy(ppd.lpwzContactName, m_tszUserName, MAX_CONTACTNAME); - wcsncpy(ppd.lpwzText, TranslateT("Loading history started."), MAX_SECONDLINE); - - HWND popupHwnd = (HWND)PUAddPopupW(&ppd, (LPARAM)APF_RETURN_HWND); - - std::vector<facebook_message> messages; - std::string firstTimestamp; - std::string firstMessageId; - std::string lastMessageId; - int loadedMessages = 0; - int messagesPerBatch = messagesCount > 10000 ? 500 : 100; - for (int batch = 0, batchLimit = messagesCount + messagesPerBatch; batch < batchLimit; batch += messagesPerBatch) { - if (!isOnline()) - break; - - // Load batch of messages - resp = facy.sendRequest(facy.threadInfoRequest(isChat, item_id, firstTimestamp.c_str(), messagesPerBatch, true)); - - if (resp.code != HTTP_CODE_OK || resp.data.empty()) { - facy.handle_error("LoadHistory"); - break; - } - - // Parse the result - messages.clear(); - - if (ParseHistory(&resp.data, messages, &firstTimestamp) == EXIT_SUCCESS) { - // Receive messages - std::string previousFirstMessageId = firstMessageId; - for (std::vector<facebook_message*>::size_type i = 0; i < messages.size(); i++) { - facebook_message &msg = messages[i]; - - // First message might overlap (as we are using it's timestamp for the next loading), so we need to check for it - if (i == 0) - firstMessageId = msg.message_id; - - if (previousFirstMessageId == msg.message_id) - continue; - - lastMessageId = msg.message_id; - - // We don't use ProtoChainRecvMsg here as this is just loading of old messages, which we just add to log - DBEVENTINFO dbei = {}; - if (msg.type == MESSAGE) - dbei.eventType = EVENTTYPE_MESSAGE; - else if (msg.type == VIDEO_CALL || msg.type == PHONE_CALL) - dbei.eventType = FACEBOOK_EVENTTYPE_CALL; - - dbei.flags = DBEF_UTF; - - if (!msg.isIncoming) - dbei.flags |= DBEF_SENT; - - if (!msg.isUnread) - dbei.flags |= DBEF_READ; - - dbei.szModule = m_szModuleName; - dbei.timestamp = msg.time; - dbei.cbBlob = (DWORD)msg.message_text.length() + 1; - dbei.pBlob = (PBYTE)msg.message_text.c_str(); - db_event_add(hContact, &dbei); - - loadedMessages++; - } - - // Save last message id of first batch which is latest message completely, because we're going backwards - if (batch == 0 && !lastMessageId.empty()) { - setString(hContact, FACEBOOK_KEY_MESSAGE_ID, lastMessageId.c_str()); - } - - debugLogA("*** Load history messages processed"); - } - else { - debugLogA("*** Error processing load history messages"); - break; - } - - // Update progress popup - CMStringW text; - text.AppendFormat(TranslateT("Loading messages: %d/%d"), loadedMessages, messagesCount); - - if (popupHwnd) - PUChangeTextW(popupHwnd, text); - else { - wcsncpy(ppd.lpwzText, text, MAX_SECONDLINE); - ppd.iSeconds = 1; - popupHwnd = (HWND)PUAddPopupW(&ppd); - } - - // There is no more messages - if (messages.empty() || loadedMessages > messagesCount) { - break; - } - } - - facy.handle_success("LoadHistory"); - - // Enable marking messages as read for this contact - facy.ignore_read.erase(hContact); - // Reset loading history flag - facy.loading_history = false; - - if (popupHwnd) - PUChangeTextW(popupHwnd, TranslateT("Loading history completed.")); - else { - ppd.iSeconds = 5; - wcsncpy(ppd.lpwzText, TranslateT("Loading history completed."), MAX_SECONDLINE); - popupHwnd = (HWND)PUAddPopupW(&ppd); - } -} - -void parseFeeds(const std::string &text, std::vector<facebook_newsfeed *> &news, DWORD &last_post_time, bool filterAds = true) -{ - std::string::size_type pos = 0; - UINT limit = 0; - - DWORD new_time = last_post_time; - - while ((pos = text.find("fbUserPost\"", pos)) != std::string::npos && limit <= 25) { - std::string post = text.substr(pos, text.find("</form>", pos) - pos); - pos += 5; - - std::string post_header = utils::text::source_get_value(&post, 3, "<h5", ">", "</h5>"); - std::string post_message = utils::text::source_get_value(&post, 3, " userContent\"", ">", "<form"); - std::string post_link = utils::text::source_get_value(&post, 4, "</h5>", "<a", "href=\"", "\""); - if (post_link == "#") { - post_link = utils::text::source_get_value(&post, 5, "</h5>", "<a", "<a", "href=\"", "\""); - } - std::string post_time = utils::text::source_get_value(&post, 3, "</h5>", "<abbr", "</a>"); - - std::string time = utils::text::source_get_value(&post_time, 2, "data-utime=\"", "\""); - std::string time_text = utils::text::source_get_value(&post_time, 2, ">", "</abbr>"); - - if (time.empty()) { - // alternative parsing (probably page like or advertisement) - time = utils::text::source_get_value(&post, 2, "content_timestamp":"", """); - } - - DWORD ttime; - if (!utils::conversion::from_string<DWORD>(ttime, time, std::dec)) - continue; - - if (ttime > new_time) - new_time = ttime; // remember newest time from all these posts - else if (ttime <= last_post_time) - continue; // ignore posts older than newest post of previous check - - std::string timeandloc = utils::text::trim(utils::text::html_entities_decode(utils::text::remove_html(time_text))); - std::string post_place = utils::text::source_get_value(&post, 4, "</abbr>", "<a", ">", "</a>"); - post_place = utils::text::trim(utils::text::remove_html(post_place)); - if (!post_place.empty()) - timeandloc += " · " + post_place; - - // in title keep only name, end of events like "X shared link" put into message - std::string::size_type pos2 = post_header.find("</a>"); - std::string header_author = utils::text::trim( - utils::text::html_entities_decode( - utils::text::remove_html( - post_header.substr(0, pos2)))); - std::string header_rest = utils::text::trim( - utils::text::html_entities_decode( - utils::text::remove_html( - post_header.substr(pos2, post_header.length() - pos2)))); - - // Strip "Translate" and other buttons - do { - pos2 = post_message.find("role=\"button\""); - if (pos2 != std::string::npos) { - pos2 = post_message.find(">", pos2); - if (pos2 != std::string::npos) { - std::string::size_type pos3 = post_message.find("</a>", pos2); - std::string tmp = post_message.substr(0, pos2); - if (pos3 != std::string::npos) - tmp += post_message.substr(pos3, post_message.length() - pos3); - - post_message = tmp; - } - } - } while (pos2 != std::string::npos); - - // Strip "See more" link - pos2 = post_message.find("<span class=\"see_more_link_inner\">"); - if (pos2 != std::string::npos) - post_message = post_message.substr(0, pos2); - - // Process attachment (if present) - std::string post_attachment = ""; - pos2 = post_message.find("class=\"mtm\">"); - if (pos2 != std::string::npos) { - pos2 += 12; - post_attachment = post_message.substr(pos2, post_message.length() - pos2); - post_message = post_message.substr(0, pos2); - - // Add new lines between some elements to improve formatting - utils::text::replace_all(&post_attachment, "</a>", "</a>\n"); - utils::text::replace_all(&post_attachment, "ellipsis\">", "ellipsis\">\n"); - - post_attachment = utils::text::trim( - utils::text::html_entities_decode( - utils::text::remove_html(post_attachment))); - - post_attachment = utils::text::truncate_utf8(post_attachment, MAX_LINK_DESCRIPTION_LEN); - - if (post_attachment.empty()) // This is some textless attachment, so mention it - post_attachment = ptrA(mir_utf8encode(Translate("<attachment without text>"))); - } - - post_message = utils::text::trim(utils::text::html_entities_decode(utils::text::remove_html(post_message))); - - // Truncate text of newsfeed when it's too long - post_message = utils::text::truncate_utf8(post_message, MAX_NEWSFEED_LEN); - - std::string content = ""; - if (header_rest.length() > 2) - content += TEXT_ELLIPSIS + header_rest + "\n"; - if (!post_message.empty()) - content += post_message + "\n"; - if (!post_attachment.empty()) - content += TEXT_EMOJI_LINK" " + post_attachment + "\n"; - if (!timeandloc.empty()) - content += TEXT_EMOJI_CLOCK" " + timeandloc; - - facebook_newsfeed* nf = new facebook_newsfeed; - - nf->title = header_author; - nf->user_id = utils::text::source_get_value(&post_header, 2, "user.php?id=", "&"); - nf->link = utils::text::html_entities_decode(post_link); - - // Check if we don't want to show ads posts - bool filtered = filterAds && (nf->link.find("/about/ads") != std::string::npos - || post.find("class=\"uiStreamSponsoredLink\"") != std::string::npos - || post.find("href=\"/about/ads\"") != std::string::npos); - - nf->text = utils::text::trim(content); - - if (filtered || nf->title.empty() || nf->text.empty()) { - delete nf; - continue; - } - - news.push_back(nf); - pos++; - limit++; - } - - last_post_time = new_time; -} - -void FacebookProto::ProcessMemories(void *p) -{ - if (isOffline()) - return; - - bool manuallyTriggered = (p == MANUALLY_TRIGGERED); - if (manuallyTriggered) - facy.info_notify(TranslateT("Loading memories...")); - - size_t numMemories = 0; - - facy.handle_entry(__FUNCTION__); - - http::response resp = facy.sendRequest(facy.memoriesRequest()); - if (resp.code != HTTP_CODE_OK || resp.data.empty()) { - facy.handle_error(__FUNCTION__); - return; - } - - std::string jsonData = resp.data.substr(9); - JSONNode root = JSONNode::parse(jsonData.c_str()); - if (root) { - const JSONNode &html_ = root["domops"].at((json_index_t)0).at((json_index_t)3).at("__html"); - if (html_) { - std::string html = utils::text::html_entities_decode(utils::text::slashu_to_utf8(html_.as_string())); - - std::vector<facebook_newsfeed *> news; - DWORD new_time = 0; - parseFeeds(html, news, new_time, true); - - if (!news.empty()) - Skin_PlaySound("Memories"); - - numMemories = news.size(); - - for (std::vector<facebook_newsfeed*>::size_type i = 0; i < news.size(); i++) { - ptrW tszTitle(mir_utf8decodeW(news[i]->title.c_str())); - ptrW tszText(mir_utf8decodeW(news[i]->text.c_str())); - - NotifyEvent(TranslateT("On this day"), tszText, 0, EVENT_ON_THIS_DAY, &news[i]->link); - delete news[i]; - } - news.clear(); - } - } - - if (manuallyTriggered) - facy.info_notify(CMStringW(FORMAT, TranslateT("Found %d memories."), numMemories)); - - facy.handle_success(__FUNCTION__); -} - -void FacebookProto::ReceiveMessages(std::vector<facebook_message> &messages, bool check_duplicates) -{ - bool naseemsSpamMode = getBool(FACEBOOK_KEY_NASEEMS_SPAM_MODE, false); - - // TODO: make this checking more lightweight as now it is not effective at all... - if (check_duplicates) { - // 1. check if there are some message that we already have (compare FACEBOOK_KEY_MESSAGE_ID = last received message ID) - for (size_t i = 0; i < messages.size(); i++) { - facebook_message &msg = messages[i]; - - MCONTACT hContact = msg.isChat ? ChatIDToHContact(msg.thread_id) : ContactIDToHContact(msg.user_id); - if (hContact == 0) - continue; - - ptrA lastId(getStringA(hContact, FACEBOOK_KEY_MESSAGE_ID)); - if (lastId == nullptr) - continue; - - if (!msg.message_id.compare(lastId)) { - // Equal, ignore all older messages (including this) from same contact - for (std::vector<facebook_message*>::size_type j = 0; j < messages.size(); j++) { - bool equalsId = msg.isChat - ? (messages[j].thread_id == msg.thread_id) - : (messages[j].user_id == msg.user_id); - - if (equalsId && messages[j].time <= msg.time) - messages[j].flag_ = 1; - } - } - } - - // 2. remove all marked messages from list - for (auto it = messages.begin(); it != messages.end();) { - if ((*it).flag_ == 1) - it = messages.erase(it); - else - ++it; - } - } - - std::set<MCONTACT> *hChatContacts = new std::set<MCONTACT>(); - - for (auto &msg : messages) { - if (msg.isChat) { - if (!m_enableChat) - continue; - - // Multi-user message - debugLogA(" < Got chat message ID: %s", msg.message_id.c_str()); - - facebook_chatroom *fbc; - std::string thread_id = msg.thread_id.c_str(); - - auto it = facy.chat_rooms.find(thread_id); - if (it != facy.chat_rooms.end()) - fbc = it->second; - else { - // In Naseem's spam mode we ignore outgoing messages sent from other instances - if (naseemsSpamMode && !msg.isIncoming) - continue; - - // We don't have this chat loaded in memory yet, lets load some info (name, list of users) - fbc = new facebook_chatroom(thread_id); - LoadChatInfo(fbc); - facy.chat_rooms.insert(std::make_pair(thread_id, fbc)); - } - - MCONTACT hChatContact = 0; - // RM TODO: better use check if chatroom exists/is in db/is online... no? - // like: if (ChatIDToHContact(thread_id) == nullptr) { - ptrA users(GetChatUsers(fbc->thread_id.c_str())); - if (users == nullptr) { - AddChat(fbc->thread_id.c_str(), fbc->chat_name.c_str()); - hChatContact = ChatIDToHContact(fbc->thread_id); - // Set thread id (TID) for later - setString(hChatContact, FACEBOOK_KEY_TID, fbc->thread_id.c_str()); - - for (auto &jt : fbc->participants) - AddChatContact(fbc->thread_id.c_str(), jt.second, false); - } - - if (!hChatContact) - hChatContact = ChatIDToHContact(fbc->thread_id); - - if (!hChatContact) { - // hopefully shouldn't happen, but who knows? - debugLogW(L"!!! No hChatContact for %s", fbc->thread_id.c_str()); - continue; - } - - // We don't want to save (this) message ID for chatrooms - // setString(hChatContact, FACEBOOK_KEY_MESSAGE_ID, msg.message_id.c_str()); - setDword(FACEBOOK_KEY_LAST_ACTION_TS, msg.time); - - // Save TID - setString(hChatContact, FACEBOOK_KEY_TID, msg.thread_id.c_str()); - - // Get name of this chat participant - std::string name = msg.user_id; // fallback to numeric id - { - auto jt = fbc->participants.find(msg.user_id); - if (jt != fbc->participants.end()) - name = jt->second.nick; - } - - switch (msg.type) { - default: - case MESSAGE: - UpdateChat(fbc->thread_id.c_str(), msg.user_id.c_str(), name.c_str(), msg.message_text.c_str(), msg.time); - break; - - case ADMIN_TEXT: - UpdateChat(thread_id.c_str(), nullptr, nullptr, msg.message_text.c_str()); - break; - - case UNSUBSCRIBE: - case SUBSCRIBE: - UpdateChat(thread_id.c_str(), nullptr, nullptr, msg.message_text.c_str()); - { - std::vector<std::string> ids; - utils::text::explode(msg.data, ";", &ids); - for (auto &id : ids) { - auto jt = fbc->participants.find(id); - if (jt == fbc->participants.end()) { - // We don't have this user there yet, so load info about him and then process event - chatroom_participant participant; - participant.is_former = (msg.type == UNSUBSCRIBE); - participant.user_id = id; - - // FIXME: Load info about all participants at once - fbc->participants.insert(std::make_pair(participant.user_id, participant)); - LoadParticipantsNames(fbc); - jt = fbc->participants.find(id); - } - if (jt != fbc->participants.end()) { - if (msg.type == SUBSCRIBE) - AddChatContact(thread_id.c_str(), jt->second, msg.isUnread); - else { - if (jt->second.user_id == facy.self_.user_id) { - // we exited the thread - Chat_Terminate(m_szModuleName, _A2T(fbc->thread_id.c_str()), true); - facy.chat_rooms.erase(thread_id); - delete fbc; - } - else RemoveChatContact(thread_id.c_str(), jt->second.user_id.c_str(), jt->second.nick.c_str()); - } - } - } - } - break; - - case THREAD_NAME: - UpdateChat(thread_id.c_str(), nullptr, nullptr, msg.message_text.c_str()); - { - std::string chatName = (!msg.data.empty() ? msg.data : GenerateChatName(fbc)); - // proto->RenameChat(thread_id.c_str(), chatName.c_str()); // this don't work, why? - setStringUtf(hChatContact, FACEBOOK_KEY_NICK, chatName.c_str()); - } - break; - - case THREAD_IMAGE: - UpdateChat(thread_id.c_str(), nullptr, nullptr, msg.message_text.c_str()); - break; - } - - // Automatically mark message as read because chatroom doesn't support onRead event (yet) - hChatContacts->insert(hChatContact); // std::set checks duplicates at insert automatically - } - else { - // Single-user message - debugLogA(" < Got message ID: %s", msg.message_id.c_str()); - - facebook_user fbu; - fbu.user_id = msg.user_id; - - MCONTACT hContact = ContactIDToHContact(fbu.user_id); - if (hContact == 0) { - // In Naseem's spam mode we ignore outgoing messages sent from other instances - if (naseemsSpamMode && !msg.isIncoming) - continue; - - // We don't have this contact, lets load info about him - LoadContactInfo(&fbu); - - hContact = AddToContactList(&fbu); - } - - if (!hContact) { - // hopefully shouldn't happen, but who knows? - debugLogA("!!! No hContact for %s", msg.user_id.c_str()); - continue; - } - - // Save last (this) message ID - setString(hContact, FACEBOOK_KEY_MESSAGE_ID, msg.message_id.c_str()); - - // Save TID - setString(hContact, FACEBOOK_KEY_TID, msg.thread_id.c_str()); - - if (msg.isIncoming && msg.isUnread && msg.type == MESSAGE) { - PROTORECVEVENT recv = { 0 }; - recv.szMessage = const_cast<char*>(msg.message_text.c_str()); - recv.timestamp = msg.time; - ProtoChainRecvMsg(hContact, &recv); - } - else { - DBEVENTINFO dbei = {}; - if (msg.type == MESSAGE) - dbei.eventType = EVENTTYPE_MESSAGE; - else if (msg.type == VIDEO_CALL || msg.type == PHONE_CALL) - dbei.eventType = FACEBOOK_EVENTTYPE_CALL; - - dbei.flags = DBEF_UTF; - - if (!msg.isIncoming) - dbei.flags |= DBEF_SENT; - - if (!msg.isUnread) - dbei.flags |= DBEF_READ; - - dbei.szModule = m_szModuleName; - dbei.timestamp = msg.time; - dbei.cbBlob = (DWORD)msg.message_text.length() + 1; - dbei.pBlob = (PBYTE)msg.message_text.c_str(); - db_event_add(hContact, &dbei); - } - - // Reset the "message seen" info when we get any new message (doesn't matter if sent from other instance or received) - if (msg.isUnread || !msg.isIncoming) - facy.erase_reader(hContact); - } - } - - if (!hChatContacts->empty()) - ForkThread(&FacebookProto::ReadMessageWorker, (void*)hChatContacts); - else - delete hChatContacts; -} - -void FacebookProto::ShowNotifications() -{ - mir_cslock s(facy.notifications_lock_); - - // Show popups for unseen notifications and/or write them to chatroom - for (auto &it : facy.notifications) { - facebook_notification *notification = it.second; - if (notification != nullptr && !notification->seen) { - debugLogA(" Showing popup for notification ID: %s", notification->id.c_str()); - ptrW szText(mir_utf8decodeW(notification->text.c_str())); - MCONTACT hContact = (notification->user_id.empty() ? 0 : ContactIDToHContact(notification->user_id)); - notification->hWndPopup = NotifyEvent(m_tszUserName, szText, hContact, EVENT_NOTIFICATION, ¬ification->link, ¬ification->id, notification->icon); - notification->seen = true; - } - } -} - -void FacebookProto::ProcessNotifications(void *p) -{ - if (isOffline()) - return; - - bool manuallyTriggered = (p == MANUALLY_TRIGGERED); - if (manuallyTriggered) - facy.info_notify(TranslateT("Loading notifications...")); - - facy.handle_entry("notifications"); - - // Get notifications - http::response resp = facy.sendRequest(facy.getNotificationsRequest(FACEBOOK_NOTIFICATIONS_LOAD_COUNT)); - if (resp.code != HTTP_CODE_OK) { - facy.handle_error("notifications"); - return; - } - - // Process notifications - debugLogA("*** Starting processing notifications"); - - size_t numNotifications = facy.notifications.size(); - if (ParseNotifications(&resp.data, &facy.notifications) == EXIT_SUCCESS) { - if (manuallyTriggered) { - numNotifications = facy.notifications.size() - numNotifications; - facy.info_notify(CMStringW(FORMAT, TranslateT("Found %d notifications."), numNotifications)); - } - - ShowNotifications(); - - debugLogA("*** Notifications processed"); - } - else debugLogA("*** Error processing notifications"); -} - -void FacebookProto::ProcessFriendRequests(void *p) -{ - if (isOffline()) - return; - - bool manuallyTriggered = (p == MANUALLY_TRIGGERED); - if (manuallyTriggered) - facy.info_notify(TranslateT("Loading friendship requests...")); - - facy.handle_entry("friendRequests"); - - // Get load friendships - http::response resp = facy.sendRequest(facy.getFriendshipsRequest()); - - // Workaround not working "mbasic." website for some people - if (!resp.isValid()) { - // Remember it didn't worked and try it again (internally it will use "m." this time) - facy.mbasicWorks = false; - resp = facy.sendRequest(facy.getFriendshipsRequest()); - } - - if (resp.code != HTTP_CODE_OK) { - facy.handle_error("friendRequests"); - return; - } - - int numRequestsNew = 0; - int numRequestsOld = 0; - - // Parse it - std::string reqs = utils::text::source_get_value(&resp.data, 3, "id=\"friends_center_main\"", "</h3>", "/friends/center/suggestions/"); - - std::string::size_type pos = 0; - std::string::size_type pos2 = 0; - bool last = (reqs.find("seenrequesttime=") == std::string::npos); // false when there are some requests - - while (!last && !reqs.empty()) { - std::string req; - if ((pos2 = reqs.find("</table>", pos)) != std::string::npos) { - req = reqs.substr(pos, pos2 - pos); - pos = pos2 + 8; - } - else { - req = reqs.substr(pos); - last = true; - } - - std::string get = utils::text::source_get_value(&req, 2, "notifications.php?", "\""); - std::string time = utils::text::source_get_value2(&get, "seenrequesttime=", "&\""); - std::string reason = utils::text::remove_html(utils::text::source_get_value(&req, 4, "</a>", "<div", ">", "</div>")); - - facebook_user fbu; - fbu.real_name = utils::text::remove_html(utils::text::source_get_value(&req, 3, "<a", ">", "</a>")); - fbu.user_id = utils::text::source_get_value2(&get, "confirm=", "&\""); - fbu.type = CONTACT_APPROVE; - - if (!fbu.user_id.empty() && !fbu.real_name.empty()) { - MCONTACT hContact = AddToContactList(&fbu); - setByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, CONTACT_APPROVE); - - bool isNew = false; - ptrA oldTime(getStringA(hContact, "RequestTime")); - if (oldTime == nullptr || mir_strcmp(oldTime, time.c_str())) { - // This is new request - isNew = true; - setString(hContact, "RequestTime", time.c_str()); - - DB_AUTH_BLOB blob(hContact, fbu.real_name.c_str(), nullptr, nullptr, fbu.user_id.c_str(), reason.c_str()); - - DBEVENTINFO dbei = {}; - dbei.szModule = m_szModuleName; - dbei.timestamp = ::time(0); - dbei.flags = DBEF_UTF; - dbei.eventType = EVENTTYPE_AUTHREQUEST; - dbei.cbBlob = blob.size(); - dbei.pBlob = blob; - db_event_add(0, &dbei); - } - debugLogA(" < (%s) Friendship request [%s]", (isNew ? "New" : "Old"), time.c_str()); - - if (isNew) - numRequestsNew++; - else - numRequestsOld++; - } - else debugLogA("!!! Wrong friendship request:\n%s", req.c_str()); - } - - if (manuallyTriggered) { - CMStringW text; - if (numRequestsOld > 0) - text.AppendFormat(TranslateT("Found %d friendship requests (%d seen)."), numRequestsNew, numRequestsOld); - else - text.AppendFormat(TranslateT("Found %d friendship requests."), numRequestsNew); - facy.info_notify(text); - } - - facy.handle_success("friendRequests"); -} - -void FacebookProto::ProcessFeeds(void *p) -{ - if (!isOnline()) - return; - - bool manuallyTriggered = (p == MANUALLY_TRIGGERED); - if (manuallyTriggered) - facy.info_notify(TranslateT("Loading wall posts...")); - - facy.handle_entry("feeds"); - - // Get feeds - http::response resp = facy.sendRequest(facy.newsfeedRequest()); - if (resp.code != HTTP_CODE_OK || resp.data.empty()) { - facy.handle_error("feeds"); - return; - } - - std::vector<facebook_newsfeed *> news; - DWORD new_time = facy.last_feeds_update_; - bool filterAds = getBool(FACEBOOK_KEY_FILTER_ADS, DEFAULT_FILTER_ADS); - - parseFeeds(resp.data, news, new_time, filterAds); - - if (!news.empty()) - Skin_PlaySound("NewsFeed"); - - if (manuallyTriggered) - facy.info_notify(CMStringW(FORMAT, TranslateT("Found %d wall posts."), news.size())); - - for (std::vector<facebook_newsfeed*>::size_type i = 0; i < news.size(); i++) { - ptrW tszTitle(mir_utf8decodeW(news[i]->title.c_str())); - ptrW tszText(mir_utf8decodeW(news[i]->text.c_str())); - MCONTACT hContact = ContactIDToHContact(news[i]->user_id); - - NotifyEvent(tszTitle, tszText, hContact, EVENT_NEWSFEED, &news[i]->link); - delete news[i]; - } - news.clear(); - - // Set time of last update to time of newest post - this->facy.last_feeds_update_ = new_time; - - facy.handle_success("feeds"); -} - -void FacebookProto::ProcessPages(void*) -{ - if (isOffline() || !getByte(FACEBOOK_KEY_LOAD_PAGES, DEFAULT_LOAD_PAGES)) - return; - - facy.handle_entry("load_pages"); - - // Get feeds - http::response resp = facy.sendRequest(facy.getPagesRequest()); - if (resp.code != HTTP_CODE_OK) { - facy.handle_error("load_pages"); - return; - } - - std::string content = utils::text::source_get_value(&resp.data, 2, "id=\"bookmarksSeeAllSection\"", "</code>"); - - std::string::size_type start, end; - start = content.find("<li", 0); - while (start != std::string::npos) { - end = content.find("<li", start + 1); - if (end == std::string::npos) - end = content.length(); - - std::string item = content.substr(start, end - start); - //item = utils::text::source_get_value(&item, 2, "data-gt=", ">"); - - start = content.find("<li", start + 1); - - std::string id = utils::text::source_get_value(&item, 3, "data-gt=", "bmid":"", """); - std::string title = utils::text::slashu_to_utf8(utils::text::source_get_value(&item, 3, "data-gt=", "title=\"", "\"")); - std::string href = utils::text::source_get_value(&item, 3, "data-gt=", "href=\"", "\""); - - // Ignore pages channel - if (href.find("/pages/feed") != std::string::npos) - continue; - - if (id.empty() || title.empty()) - continue; - - debugLogA(" Got page ID: %s", id.c_str()); - facy.pages[id] = title; - } - - facy.handle_success("load_pages"); -} - -void FacebookProto::SearchAckThread(void *targ) -{ - facy.handle_entry("searchAckThread"); - - int count = 0; - std::string search = utils::url::encode(T2Utf((wchar_t *)targ).str()); - std::string ssid; - int pn = 1; - - while (count < 50 && !isOffline()) { - http::response resp = facy.sendRequest(facy.searchRequest(search.c_str(), count, pn, ssid.c_str())); - if (resp.code == HTTP_CODE_OK) { - std::string items = utils::text::source_get_value(&resp.data, 4, "<body", "</form", "<table", "</table>"); - - std::string::size_type pos = 0; - std::string::size_type pos2 = 0; - - while ((pos = items.find("<tr", pos)) != std::string::npos) { - std::string item = items.substr(pos, items.find("</tr>", pos) - pos); - pos++; count++; - - std::string id; - std::string type; // Type of search result: 69=group, 274=page, 844=event, 2048=contact - std::string name = utils::text::source_get_value(&item, 3, "<a", ">", "</"); - std::string surname; - std::string nick; - std::string common = utils::text::source_get_value(&item, 4, "</a>", "<span", ">", "</span>"); - - std::string url = utils::text::source_get_value(&item, 3, "<a", "href=\"", "\""); - std::string sld = utils::text::source_get_value2(&url, "sld=", "&\"", true); - // sld is Base64 encoded and then URL encoded string. So replace potential "%3D" with "=" - utils::text::replace_all(&sld, "%3D", "="); - // decode Base64 string - ptrA data_((char*)mir_base64_decode(sld.c_str(), nullptr)); - if (data_) { - std::string data = data_; - id = utils::text::source_get_value2(&data, "\"ent_id\":", ",}"); - type = utils::text::source_get_value2(&data, "\"result_type\":", ",}"); - } - - if (type == "274") { // page - // When searching pages we use whole name as nick and use prefix - nick = m_pagePrefix + " " + name; - name = ""; - if (common.empty()) { - // Pages has additional data in <div>, not in <span> as people - common = utils::text::source_get_value(&item, 4, "</a>", "<div", ">", "</div>"); - } - } - else if (type == "2048") { // people - // When searching for people we try to parse nick and split first/last name - if ((pos2 = name.find("<span class=\"alternate_name\">")) != std::string::npos) { - nick = name.substr(pos2 + 30, name.length() - pos2 - 31); // also remove brackets around nickname - name = name.substr(0, pos2 - 1); - } - - if ((pos2 = name.find(" ")) != std::string::npos) { - surname = name.substr(pos2 + 1, name.length() - pos2 - 1); - name = name.substr(0, pos2); - } - } - else // This is group or event, let's ignore that - continue; - - // ignore self contact and empty ids - if (id.empty() || id == facy.self_.user_id) - continue; - - ptrW tid(mir_utf8decodeW(id.c_str())); - ptrW tname(mir_utf8decodeW(utils::text::html_entities_decode(name).c_str())); - ptrW tsurname(mir_utf8decodeW(utils::text::html_entities_decode(surname).c_str())); - ptrW tnick(mir_utf8decodeW(utils::text::html_entities_decode(nick).c_str())); - ptrW tcommon(mir_utf8decodeW(utils::text::html_entities_decode(common).c_str())); - - PROTOSEARCHRESULT psr = { 0 }; - psr.cbSize = sizeof(psr); - psr.flags = PSR_UNICODE; - psr.id.w = tid; - psr.nick.w = tnick; - psr.firstName.w = tname; - psr.lastName.w = tsurname; - psr.email.w = tcommon; - ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, targ, (LPARAM)&psr); - } - - ssid = utils::text::source_get_value(&resp.data, 3, "id=\"more_objects\"", "ssid=", "&"); - pn++; // increment page number - if (ssid.empty()) - break; // No more results - } - else break; - } - - ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, targ, 0); - - facy.handle_success("searchAckThread"); - - mir_free(targ); -} - -void FacebookProto::SearchIdAckThread(void *targ) -{ - facy.handle_entry("searchIdAckThread"); - - std::string search = T2Utf((wchar_t*)targ).str(); - if (search.find(FACEBOOK_SERVER_DOMAIN "/") != std::string::npos) { - // User entered URL, let's extract id/username from it - std::string id = utils::text::source_get_value2(&search, "/profile.php?id=", "&#", true); - if (id.empty()) { - // This link probably contains username (if user entered proper profile url) - id = utils::text::source_get_value2(&search, FACEBOOK_SERVER_DOMAIN "/", "?&#", true); - } - search = id; - } - search = utils::url::encode(search); - - if (!isOffline() && !search.empty()) { - http::response resp = facy.sendRequest(facy.profileRequest(search.c_str())); - - if (resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end()) { - search = utils::text::source_get_value(&resp.headers["Location"], 2, FACEBOOK_SERVER_MBASIC"/", "_rdr"); - - // Use only valid username redirects - if (search.find("home.php") == std::string::npos) - resp = facy.sendRequest(facy.profileRequest(search.c_str())); - } - - if (resp.code == HTTP_CODE_OK) { - std::string about = utils::text::source_get_value(&resp.data, 2, "id=\"root\"", "</body>"); - - std::string id = utils::text::source_get_value2(&about, ";id=", "&\""); - if (id.empty()) - id = utils::text::source_get_value2(&about, "?bid=", "&\""); - std::string name = utils::text::source_get_value(&about, 3, "<strong", ">", "</strong"); - if (name.empty()) - name = utils::text::source_get_value(&resp.data, 2, "<title>", "</title>"); - - std::string surname; - std::string::size_type pos; - if ((pos = name.find(" ")) != std::string::npos) { - surname = name.substr(pos + 1, name.length() - pos - 1); - name = name.substr(0, pos); - } - - // ignore self contact and empty ids - if (!id.empty() && id != facy.self_.user_id) { - ptrW tid(mir_utf8decodeW(id.c_str())); - ptrW tname(mir_utf8decodeW(name.c_str())); - ptrW tsurname(mir_utf8decodeW(surname.c_str())); - - PROTOSEARCHRESULT psr = { 0 }; - psr.cbSize = sizeof(psr); - psr.flags = PSR_UNICODE; - psr.id.w = tid; - psr.firstName.w = tname; - psr.lastName.w = tsurname; - ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, targ, (LPARAM)&psr); - } - } - } - - ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, targ, 0); - - facy.handle_success("searchIdAckThread"); - - mir_free(targ); -} diff --git a/protocols/FacebookRM/src/profile.cpp b/protocols/FacebookRM/src/profile.cpp deleted file mode 100644 index 04de4e3e80..0000000000 --- a/protocols/FacebookRM/src/profile.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// getting own name, avatar, ... - -HttpRequest* facebook_client::homeRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_MOBILE "/profile.php"); - p->flags |= NLHRF_REDIRECT; - p << CHAR_PARAM("v", "info"); - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// getting fb_dtsg - -HttpRequest* facebook_client::dtsgRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_MOBILE "/profile/basic/intro/bio/"); - p->flags |= NLHRF_REDIRECT; - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// request mobile page containing profile picture - -HttpRequest* facebook_client::profilePictureRequest(const char *userId) -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FORMAT, "%s/profile/picture/view/", mbasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE); - p->flags |= NLHRF_REDIRECT; - p << CHAR_PARAM("profile_id", userId); - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// request mobile page containing user profile - -HttpRequest* facebook_client::profileRequest(const char *data) -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FORMAT, "%s/%s", mbasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE, data); - p << CHAR_PARAM("v", "info"); - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// request mobile page containing user profile by his id, and in english language (for parsing data) - -HttpRequest* facebook_client::profileInfoRequest(const char *userId) -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FORMAT, "%s/profile.php", mbasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE); - p << CHAR_PARAM("id", userId) << CHAR_PARAM("v", "info") << CHAR_PARAM("locale", "en_US"); - return p; -} diff --git a/protocols/FacebookRM/src/proto.cpp b/protocols/FacebookRM/src/proto.cpp deleted file mode 100644 index 1c73d3194f..0000000000 --- a/protocols/FacebookRM/src/proto.cpp +++ /dev/null @@ -1,1053 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -FacebookProto::FacebookProto(const char *proto_name, const wchar_t *username) : - PROTO<FacebookProto>(proto_name, username), - m_tszDefaultGroup(getWStringA(FACEBOOK_KEY_DEF_GROUP)) -{ - facy.parent = this; - - update_loop_event = CreateEventW(nullptr, FALSE, FALSE, nullptr); - - // Initialize random seed for this client - facy.random_ = ::time(0) + PtrToUint(&facy); - - m_enableChat = DEFAULT_ENABLE_CHATS; - - // Load custom locale, if set - ptrA locale(getStringA(FACEBOOK_KEY_LOCALE)); - if (locale != nullptr) - m_locale = locale; - - // Load custom page prefix, if set - ptrW pagePrefix(getWStringA(FACEBOOK_KEY_PAGE_PREFIX)); - m_pagePrefix = (pagePrefix != nullptr) ? _T2A(pagePrefix, CP_UTF8) : TEXT_EMOJI_PAGE; - - if (m_tszDefaultGroup == nullptr) - m_tszDefaultGroup = mir_wstrdup(L"Facebook"); - - CreateProtoService(PS_CREATEACCMGRUI, &FacebookProto::SvcCreateAccMgrUI); - CreateProtoService(PS_GETMYAWAYMSG, &FacebookProto::GetMyAwayMsg); - CreateProtoService(PS_GETMYAVATAR, &FacebookProto::GetMyAvatar); - CreateProtoService(PS_GETAVATARINFO, &FacebookProto::GetAvatarInfo); - CreateProtoService(PS_GETAVATARCAPS, &FacebookProto::GetAvatarCaps); - CreateProtoService(PS_GETUNREADEMAILCOUNT, &FacebookProto::GetNotificationsCount); - - CreateProtoService(PS_JOINCHAT, &FacebookProto::OnJoinChat); - CreateProtoService(PS_LEAVECHAT, &FacebookProto::OnLeaveChat); - - CreateProtoService(PS_MENU_REQAUTH, &FacebookProto::RequestFriendship); - CreateProtoService(PS_MENU_GRANTAUTH, &FacebookProto::ApproveFriendship); - CreateProtoService(PS_MENU_REVOKEAUTH, &FacebookProto::CancelFriendship); - - HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &FacebookProto::OnBuildStatusMenu); - HookProtoEvent(ME_OPT_INITIALISE, &FacebookProto::OnOptionsInit); - HookProtoEvent(ME_IDLE_CHANGED, &FacebookProto::OnIdleChanged); - HookProtoEvent(ME_TTB_MODULELOADED, &FacebookProto::OnToolbarInit); - HookProtoEvent(ME_GC_EVENT, &FacebookProto::OnGCEvent); - HookProtoEvent(ME_GC_BUILDMENU, &FacebookProto::OnGCMenuHook); - HookProtoEvent(ME_DB_EVENT_MARKED_READ, &FacebookProto::OnDbEventRead); - - db_set_resident(m_szModuleName, "IdleTS"); - db_set_resident(m_szModuleName, FACEBOOK_KEY_MESSAGE_READ); - db_set_resident(m_szModuleName, FACEBOOK_KEY_MESSAGE_READERS); - db_set_resident(m_szModuleName, FACEBOOK_KEY_TRIED_DELETING_DEVICE_ID); - - InitHotkeys(); - InitPopups(); - InitSounds(); - - // Create standard network connection - wchar_t descr[512]; - NETLIBUSER nlu = {}; - nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; - nlu.szSettingsModule = m_szModuleName; - mir_snwprintf(descr, TranslateT("%s server connection"), m_tszUserName); - nlu.szDescriptiveName.w = descr; - m_hNetlibUser = Netlib_RegisterUser(&nlu); - if (m_hNetlibUser == nullptr) { - wchar_t error[200]; - mir_snwprintf(error, TranslateT("Unable to initialize Netlib for %s."), m_tszUserName); - MessageBox(nullptr, error, L"Miranda NG", MB_OK | MB_ICONERROR); - } - - facy.set_handle(m_hNetlibUser); - - // Set all contacts offline -- in case we crashed - setAllContactStatuses(ID_STATUS_OFFLINE); - - // register special type of event - // there's no need to declare the special service for getting text - // because a blob contains only text - DBEVENTTYPEDESCR evtype = {}; - evtype.module = m_szModuleName; - evtype.eventType = FACEBOOK_EVENTTYPE_CALL; - evtype.descr = LPGEN("Video call"); - evtype.eventIcon = g_plugin.getIconHandle(IDI_FACEBOOK); - evtype.flags = DETF_HISTORY | DETF_MSGWINDOW; - DbEvent_RegisterType(&evtype); -} - -FacebookProto::~FacebookProto() -{ - // Uninit popup classes - for (auto &it : popupClasses) - Popup_UnregisterClass(it); - popupClasses.clear(); - - CloseHandle(update_loop_event); -} - -////////////////////////////////////////////////////////////////////////////// - -INT_PTR FacebookProto::GetCaps(int type, MCONTACT) -{ - switch (type) { - case PFLAGNUM_1: - { - DWORD_PTR flags = PF1_IM | PF1_CHAT | PF1_SERVERCLIST | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | PF1_ADDSEARCHRES; - - if (getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS)) - return flags |= PF1_MODEMSG; - else - return flags |= PF1_MODEMSGRECV; - } - - case PFLAGNUM_2: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE | PF2_IDLE; - - case PFLAGNUM_3: - if (getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS)) - return PF2_ONLINE; // | PF2_SHORTAWAY; - else - return 0; - - case PFLAGNUM_4: - return PF4_NOCUSTOMAUTH | PF4_AVATARS | PF4_SUPPORTTYPING | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE | PF4_READNOTIFY; - - case PFLAG_MAXLENOFMESSAGE: - return FACEBOOK_MESSAGE_LIMIT; - case PFLAG_UNIQUEIDTEXT: - return (INT_PTR) "Facebook ID"; - } - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - -int FacebookProto::SetStatus(int new_status) -{ - debugLogA("=== Beginning SetStatus process"); - - if (new_status != ID_STATUS_OFFLINE && m_iStatus == ID_STATUS_CONNECTING) { - debugLogA("=== Status is already connecting, no change"); - return 0; - } - - // Routing statuses not supported by Facebook - switch (new_status) { - case ID_STATUS_ONLINE: - case ID_STATUS_AWAY: - case ID_STATUS_INVISIBLE: - case ID_STATUS_OFFLINE: - m_iDesiredStatus = new_status; - break; - case ID_STATUS_NA: - m_iDesiredStatus = ID_STATUS_AWAY; - break; - case ID_STATUS_FREECHAT: - m_iDesiredStatus = ID_STATUS_ONLINE; - break; - default: - m_iDesiredStatus = getByte(FACEBOOK_KEY_MAP_STATUSES, DEFAULT_MAP_STATUSES) ? ID_STATUS_INVISIBLE : ID_STATUS_AWAY; - break; - } - - if (m_iStatus == m_iDesiredStatus) { - debugLogA("=== Statuses are same, no change"); - return 0; - } - - m_invisible = (new_status == ID_STATUS_INVISIBLE); - - ForkThread(&FacebookProto::ChangeStatus, this); - return 0; -} - -int FacebookProto::SetAwayMsg(int, const wchar_t *msg) -{ - if (!msg) { - last_status_msg_.clear(); - return 0; - } - - T2Utf narrow(msg); - if (last_status_msg_ != (char*)narrow) - last_status_msg_ = narrow; - - if (isOnline() && getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS)) - ForkThread(&FacebookProto::SetAwayMsgWorker, nullptr); - - return 0; -} - -void FacebookProto::SetAwayMsgWorker(void *p) -{ - if (p != nullptr) { - status_data *data = static_cast<status_data*>(p); - facy.post_status(data); - delete data; - } - else if (!last_status_msg_.empty()) { - status_data data; - data.text = last_status_msg_; - data.privacy = facy.get_privacy_type(); - facy.post_status(&data); - } -} - -HANDLE FacebookProto::SearchBasic(const wchar_t* id) -{ - if (isOffline()) - return nullptr; - - wchar_t *tid = mir_wstrdup(id); - ForkThread(&FacebookProto::SearchIdAckThread, tid); - return tid; -} - -HANDLE FacebookProto::SearchByEmail(const wchar_t* email) -{ - if (isOffline()) - return nullptr; - - wchar_t *temail = mir_wstrdup(email); - ForkThread(&FacebookProto::SearchAckThread, temail); - return temail; -} - -HANDLE FacebookProto::SearchByName(const wchar_t* nick, const wchar_t* firstName, const wchar_t* lastName) -{ - wchar_t arg[200]; - mir_snwprintf(arg, L"%s %s %s", nick, firstName, lastName); - return SearchByEmail(arg); // Facebook is using one search method for everything (except IDs) -} - -MCONTACT FacebookProto::AddToList(int flags, PROTOSEARCHRESULT* psr) -{ - ptrA id(mir_u2a_cp(psr->id.w, CP_UTF8)); - ptrA name(mir_u2a_cp(psr->firstName.w, CP_UTF8)); - ptrA surname(mir_u2a_cp(psr->lastName.w, CP_UTF8)); - - if (id == nullptr) - return 0; - - facebook_user fbu; - fbu.user_id = id; - if (name != nullptr) - fbu.real_name = name; - if (surname != nullptr) { - fbu.real_name += " "; - fbu.real_name += surname; - } - - if (fbu.user_id.find_first_not_of("0123456789") != std::string::npos) { - MessageBox(nullptr, TranslateT("Facebook ID must be numeric value."), m_tszUserName, MB_ICONERROR | MB_OK); - return 0; - } - - bool add_temporarily = (flags & PALF_TEMPORARY); - MCONTACT hContact = AddToContactList(&fbu, false, add_temporarily); - - // Reset NotOnList flag if present and we're adding this contact not temporarily - if (hContact && !add_temporarily && !Contact_OnList(hContact)) { - Contact_Hide(hContact, false); - Contact_PutOnList(hContact); - } - - return hContact; -} - -int FacebookProto::AuthRequest(MCONTACT hContact, const wchar_t *) -{ - return RequestFriendship(hContact, 0); -} - -int FacebookProto::Authorize(MEVENT hDbEvent) -{ - if (!hDbEvent || isOffline()) - return 1; - - MCONTACT hContact = HContactFromAuthEvent(hDbEvent); - if (hContact == INVALID_CONTACT_ID) - return 1; - - return ApproveFriendship(hContact, 0); -} - -int FacebookProto::AuthDeny(MEVENT hDbEvent, const wchar_t *) -{ - if (!hDbEvent || isOffline()) - return 1; - - MCONTACT hContact = HContactFromAuthEvent(hDbEvent); - if (hContact == INVALID_CONTACT_ID) - return 1; - - return DenyFriendship(hContact, 0); -} - -int FacebookProto::GetInfo(MCONTACT hContact, int) -{ - ForkThread(&FacebookProto::RefreshUserInfo, (void*)new MCONTACT(hContact)); - return 0; -} - -////////////////////////////////////////////////////////////////////////////// -// SERVICES - -INT_PTR FacebookProto::GetMyAwayMsg(WPARAM, LPARAM lParam) -{ - ptrW statusMsg(getWStringA("StatusMsg")); - if (statusMsg == nullptr || statusMsg[0] == '\0') - return 0; - - return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_wstrdup(statusMsg) : (INT_PTR)mir_u2a(statusMsg); -} - -int FacebookProto::OnIdleChanged(WPARAM, LPARAM lParam) -{ - bool idle = (lParam & IDF_ISIDLE) != 0; - bool privacy = (lParam & IDF_PRIVACY) != 0; - - // Respect user choice about (not) notifying idle to protocols - if (privacy) { - // Reset it to 0 if there is some time already - if (m_idleTS) { - m_idleTS = 0; - delSetting("IdleTS"); - } - - return 0; - } - - // We don't want to reset idle time when we're already in idle state - if (idle && m_idleTS > 0) - return 0; - - if (idle) { - // User started being idle - MIRANDA_IDLE_INFO mii; - Idle_GetInfo(mii); - - // Compute time when user really became idle - m_idleTS = time(0) - mii.idleTime * 60; - setDword("IdleTS", m_idleTS); - } - else { - // User stopped being idle - m_idleTS = 0; - delSetting("IdleTS"); - - // Set sending activity_ping at next channel request (because I don't want to create new thread here for such small thing) - m_pingTS = 0; - } - - return 0; -} - -INT_PTR FacebookProto::GetNotificationsCount(WPARAM, LPARAM) -{ - if (isOffline()) - return 0; - - return facy.notifications.size(); -} - -////////////////////////////////////////////////////////////////////////////// -// EVENTS - -INT_PTR FacebookProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) -{ - return (INT_PTR)CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FACEBOOKACCOUNT), - (HWND)lParam, FBAccountProc, (LPARAM)this); -} - -void FacebookProto::OnModulesLoaded() -{ - HookProtoEvent(ME_MSG_WINDOWEVENT, &FacebookProto::OnProcessSrmmEvent); - HookProtoEvent(ME_MSG_PRECREATEEVENT, &FacebookProto::OnPreCreateEvent); - - // Register group chat - GCREGISTER gcr = {}; - gcr.pszModule = m_szModuleName; - gcr.ptszDispName = m_tszUserName; - gcr.iMaxText = FACEBOOK_MESSAGE_LIMIT; - Chat_Register(&gcr); -} - -void FacebookProto::OnShutdown() -{ - SetStatus(ID_STATUS_OFFLINE); -} - -int FacebookProto::OnOptionsInit(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {}; - odp.szTitle.w = m_tszUserName; - odp.dwInitParam = LPARAM(this); - odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE | ODPF_DONTTRANSLATE; - - odp.position = 271828; - odp.szGroup.w = LPGENW("Network"); - odp.szTab.w = LPGENW("Account"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); - odp.pfnDlgProc = FBOptionsProc; - g_plugin.addOptions(wParam, &odp); - - odp.position = 271829; - odp.szTab.w = LPGENW("Events"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_EVENTS); - odp.pfnDlgProc = FBOptionsEventsProc; - g_plugin.addOptions(wParam, &odp); - - odp.position = 271830; - odp.szTab.w = LPGENW("Statuses"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_STATUSES); - odp.pfnDlgProc = FBOptionsStatusesProc; - g_plugin.addOptions(wParam, &odp); - - odp.position = 271831; - odp.szTab.w = LPGENW("Messaging"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_MESSAGING); - odp.pfnDlgProc = FBOptionsMessagingProc; - g_plugin.addOptions(wParam, &odp); - return 0; -} - -int FacebookProto::OnToolbarInit(WPARAM, LPARAM) -{ - TTBButton ttb = {}; - ttb.dwFlags = TTBBF_SHOWTOOLTIP | TTBBF_VISIBLE; - - char service[100]; - mir_snprintf(service, "%s%s", m_szModuleName, "/Mind"); - - ttb.pszService = service; - ttb.pszTooltipUp = ttb.name = LPGEN("Share status..."); - ttb.hIconHandleUp = g_plugin.getIconHandle(IDI_MIND); - g_plugin.addTTB(&ttb); - - return 0; -} - -INT_PTR FacebookProto::OnMind(WPARAM wParam, LPARAM) -{ - if (!isOnline()) - return 1; - - MCONTACT hContact = MCONTACT(wParam); - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (!id) - return 1; - - wall_data *wall = new wall_data(); - wall->user_id = id; - wall->isPage = false; - if (wall->user_id == facy.self_.user_id) { - wall->title = wcsdup(TranslateT("Own wall")); - } - else - wall->title = getWStringA(hContact, FACEBOOK_KEY_NICK); - - post_status_data *data = new post_status_data(this, wall); - - if (wall->user_id == facy.self_.user_id) - for (auto &iter : facy.pages) - data->walls.push_back(new wall_data(iter.first, mir_utf8decodeW(iter.second.c_str()), true)); - - HWND hDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_MIND), (HWND)nullptr, FBMindProc, reinterpret_cast<LPARAM>(data)); - ShowWindow(hDlg, SW_SHOW); - - return 0; -} - -int FacebookProto::OnDbEventRead(WPARAM, LPARAM lParam) -{ - MCONTACT hContact = db_event_getContact((MEVENT)lParam); - - if (isOffline() || !IsMyContact(hContact, false)) // ignore chats - return 0; - - if (facy.ignore_read.find(hContact) != facy.ignore_read.end()) - return 0; // it's there, so we ignore this - - std::set<MCONTACT> *hContacts = new std::set<MCONTACT>(); - hContacts->insert(hContact); - - ForkThread(&FacebookProto::ReadMessageWorker, (void*)hContacts); - - return 0; -} - - -int FacebookProto::OnProcessSrmmEvent(WPARAM, LPARAM lParam) -{ - MessageWindowEventData *event = (MessageWindowEventData *)lParam; - - if (event->uType == MSG_WINDOW_EVT_OPENING) { - // Set statusbar to "Message read" time (if present) - MessageRead(event->hContact); - } - else if (event->uType == MSG_WINDOW_EVT_OPEN) { - // Check if we have enabled loading messages on open window - if (!getBool(FACEBOOK_KEY_MESSAGES_ON_OPEN, DEFAULT_MESSAGES_ON_OPEN) || isChatRoom(event->hContact)) - return 0; - - // Load last messages for this contact - ForkThread(&FacebookProto::LoadLastMessages, new MCONTACT(event->hContact)); - } - - return 0; -} - -int FacebookProto::OnPreCreateEvent(WPARAM, LPARAM lParam) -{ - MessageWindowEvent *evt = (MessageWindowEvent *)lParam; - if (mir_strcmp(Proto_GetBaseAccountName(evt->hContact), m_szModuleName)) - return 0; - - std::map<int, time_t>::iterator it = facy.messages_timestamp.find(evt->seq); - if (it != facy.messages_timestamp.end()) { - // set correct timestamp of this message - evt->dbei->timestamp = it->second; - facy.messages_timestamp.erase(it); - } - - return 1; -} - -INT_PTR FacebookProto::CheckNewsfeeds(WPARAM, LPARAM) -{ - if (!isOffline()) { - // If holding control, load all newsfeeds (not only newer since last check) - bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - if (ctrlPressed) { - facy.last_feeds_update_ = 0; - } - ForkThread(&FacebookProto::ProcessFeeds, MANUALLY_TRIGGERED); - } - return 0; -} - -INT_PTR FacebookProto::CheckFriendRequests(WPARAM, LPARAM) -{ - if (!isOffline()) - ForkThread(&FacebookProto::ProcessFriendRequests, MANUALLY_TRIGGERED); - return 0; -} - -INT_PTR FacebookProto::CheckNotifications(WPARAM, LPARAM) -{ - if (!isOffline()) - ForkThread(&FacebookProto::ProcessNotifications, MANUALLY_TRIGGERED); - return 0; -} - -INT_PTR FacebookProto::CheckMemories(WPARAM, LPARAM) -{ - if (!isOffline()) - ForkThread(&FacebookProto::ProcessMemories, MANUALLY_TRIGGERED); - return 0; -} - - -INT_PTR FacebookProto::VisitProfile(WPARAM wParam, LPARAM) -{ - MCONTACT hContact = MCONTACT(wParam); - - std::string url = FACEBOOK_URL_PROFILE; - - ptrA val(getStringA(hContact, "Homepage")); - if (val != nullptr) // Homepage link already present, get it - url = val; - else { - // No homepage link, create and save it - val = getStringA(hContact, FACEBOOK_KEY_ID); - if (val != nullptr) { - url += val; - setString(hContact, "Homepage", url.c_str()); - } - } - - OpenUrl(url); - return 0; -} - -INT_PTR FacebookProto::VisitFriendship(WPARAM wParam, LPARAM) -{ - MCONTACT hContact = MCONTACT(wParam); - - if (wParam == 0 || !IsMyContact(hContact)) - return 1; - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (!id) - return 1; - - std::string url = FACEBOOK_URL_PROFILE; - url += facy.self_.user_id; - url += "&and=" + std::string(id); - - OpenUrl(url); - return 0; -} - -INT_PTR FacebookProto::VisitConversation(WPARAM wParam, LPARAM) -{ - MCONTACT hContact = MCONTACT(wParam); - - if (wParam == 0 || !IsMyContact(hContact, true)) - return 1; - - bool isChat = isChatRoom(hContact); - ptrA id(getStringA(hContact, isChat ? FACEBOOK_KEY_TID : FACEBOOK_KEY_ID)); - if (id == nullptr) - return 1; - - std::string url = FACEBOOK_URL_CONVERSATION + std::string(id); - - OpenUrl(url); - return 0; -} - -INT_PTR FacebookProto::VisitNotifications(WPARAM, LPARAM) -{ - /*bool useChatRoom = getBool(FACEBOOK_KEY_NOTIFICATIONS_CHATROOM, DEFAULT_NOTIFICATIONS_CHATROOM); - - if (useChatRoom) { - GCEVENT gce = { m_szModuleName, _T(FACEBOOK_NOTIFICATIONS_CHATROOM), GC_EVENT_CONTROL }; - Chat_Control(WINDOW_VISIBLE); - } - else {*/ - OpenUrl(FACEBOOK_URL_NOTIFICATIONS); - /*}*/ - - return 0; -} - -INT_PTR FacebookProto::Poke(WPARAM wParam, LPARAM) -{ - if (wParam == 0 || isOffline()) - return 1; - - MCONTACT hContact = MCONTACT(wParam); - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (id == nullptr) - return 1; - - ForkThread(&FacebookProto::SendPokeWorker, new std::string(id)); - return 0; -} - -INT_PTR FacebookProto::LoadHistory(WPARAM wParam, LPARAM) -{ - if (wParam == 0 || isOffline()) - return 1; - - MCONTACT hContact = MCONTACT(wParam); - - // Ignore groupchats // TODO: Support for groupchats? - if (isChatRoom(hContact)) - return 0; - - // Allow loading history only from one contact at a time - if (facy.loading_history) { - const wchar_t *message = TranslateT("Loading history is already in progress. It can't run for more contacts at once so please wait until it finishes."); - MessageBox(nullptr, message, m_tszUserName, MB_ICONWARNING | MB_OK); - return 0; - } - - ptrW name(getWStringA(hContact, FACEBOOK_KEY_NICK)); - if (name == nullptr) - name = getWStringA(hContact, FACEBOOK_KEY_ID); - if (name == nullptr) - return 1; - - CMStringW title; - title.AppendFormat(L"%s - %s", m_tszUserName, name); - const wchar_t *message = TranslateT("This will load all messages from the server. To avoid having duplicate messages in your history, delete existing messages manually before continuing.\nLoading process might take a while, so be patient.\n\nDo you want to continue?"); - - if (MessageBox(nullptr, message, title, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) == IDYES) { - ForkThread(&FacebookProto::LoadHistory, new MCONTACT(hContact)); - } - - return 0; -} - -INT_PTR FacebookProto::CancelFriendship(WPARAM wParam, LPARAM lParam) -{ - if (wParam == 0 || isOffline()) - return 1; - - bool deleting = (lParam == 1); - - MCONTACT hContact = MCONTACT(wParam); - - // Ignore groupchats and, if deleting, also not-friends - if (isChatRoom(hContact) || (deleting && getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE) != CONTACT_FRIEND)) - return 0; - - ptrW tname(getWStringA(hContact, FACEBOOK_KEY_NICK)); - if (tname == nullptr) - tname = getWStringA(hContact, FACEBOOK_KEY_ID); - - if (tname == nullptr) - return 1; - - wchar_t tstr[256]; - mir_snwprintf(tstr, TranslateT("Do you want to cancel your friendship with '%s'?"), tname); - if (MessageBox(nullptr, tstr, m_tszUserName, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2) == IDYES) { - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (id == nullptr) - return 1; - - std::string *val = new std::string(id); - ForkThread(&FacebookProto::DeleteContactFromServer, val); - } - - return 0; -} - -INT_PTR FacebookProto::RequestFriendship(WPARAM hContact, LPARAM) -{ - if (hContact == 0 || isOffline()) - return 1; - - ptrA id(getStringA(hContact, FACEBOOK_KEY_ID)); - if (id == nullptr) - return 1; - - ForkThread(&FacebookProto::AddContactToServer, new std::string(id)); - return 0; -} - -INT_PTR FacebookProto::ApproveFriendship(WPARAM hContact, LPARAM) -{ - if (hContact == 0 || isOffline()) - return 1; - - ForkThread(&FacebookProto::ApproveContactToServer, new MCONTACT(hContact)); - return 0; -} - -INT_PTR FacebookProto::DenyFriendship(WPARAM hContact, LPARAM) -{ - if (hContact == 0 || isOffline()) - return 1; - - ForkThread(&FacebookProto::IgnoreFriendshipRequest, new MCONTACT(hContact)); - return 0; -} - -INT_PTR FacebookProto::OnCancelFriendshipRequest(WPARAM wParam, LPARAM) -{ - if (wParam == 0 || isOffline()) - return 1; - - MCONTACT *hContact = new MCONTACT((MCONTACT)wParam); - - ForkThread(&FacebookProto::CancelFriendsRequest, hContact); - return 0; -} - -MCONTACT FacebookProto::HContactFromAuthEvent(MEVENT hEvent) -{ - DWORD body[2]; - DBEVENTINFO dbei = {}; - dbei.cbBlob = sizeof(DWORD) * 2; - dbei.pBlob = (PBYTE)&body; - - if (db_event_get(hEvent, &dbei)) - return INVALID_CONTACT_ID; - - if (dbei.eventType != EVENTTYPE_AUTHREQUEST) - return INVALID_CONTACT_ID; - - if (mir_strcmp(dbei.szModule, m_szModuleName)) - return INVALID_CONTACT_ID; - - return DbGetAuthEventContact(&dbei); -} - -void FacebookProto::OpenUrlThread(void *p) -{ - if (p == nullptr) - return; - - open_url *data = static_cast<open_url*>(p); - - ShellExecute(nullptr, L"open", data->browser, data->url, nullptr, SW_SHOWDEFAULT); - - delete data; -} - -std::string FacebookProto::PrepareUrl(std::string url) -{ - std::string::size_type pos = url.find(FACEBOOK_SERVER_DOMAIN); - bool isFacebookUrl = (pos != std::string::npos); - bool isAbsoluteUrl = (url.find("://") != std::string::npos); - - // Do nothing with absolute non-Facebook URLs - if (isAbsoluteUrl && !isFacebookUrl) - return url; - - // Transform absolute URL to relative - if (isAbsoluteUrl) { - // Check and ignore special subdomains - std::string subdomain = utils::text::source_get_value(&url, 2, "://", "." FACEBOOK_SERVER_DOMAIN); - if (subdomain == "developers") - return url; - - // Make relative url - url = url.substr(pos + mir_strlen(FACEBOOK_SERVER_DOMAIN)); - - // Strip eventual port - pos = url.find("/"); - if (pos != std::string::npos && pos != 0) - url = url.substr(pos); - } - - // URL is relative now, make and return absolute - return HTTP_PROTO_SECURE + facy.get_server_type() + url; -} - -void FacebookProto::OpenUrl(std::string url) -{ - url = PrepareUrl(url); - ptrW data(mir_utf8decodeW(url.c_str())); - - // Check if there is user defined browser for opening links - ptrW browser(getWStringA(FACEBOOK_KEY_OPEN_URL_BROWSER)); - if (browser != nullptr) - // If so, use it to open this link - ForkThread(&FacebookProto::OpenUrlThread, new open_url(browser, data)); - else - // Or use Miranda's service - Utils_OpenUrlW(data); -} - -void FacebookProto::ReadNotificationWorker(void *p) -{ - if (p == nullptr) - return; - - std::string *id = (std::string*)p; - if (!isOffline()) - facy.sendRequest(facy.markNotificationReadRequest(id->c_str())); - delete id; -} - -/** - * Popup processing callback - */ -LRESULT CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) { - case WM_COMMAND: - case WM_CONTEXTMENU: - { - // Get the plugin data (we need the Popup service to do it) - popup_data *data = (popup_data *)PUGetPluginData(hwnd); - if (data != nullptr) { - if (!data->notification_id.empty()) - data->proto->ForkThread(&FacebookProto::ReadNotificationWorker, new std::string(data->notification_id)); - - if (message == WM_COMMAND && !data->url.empty()) - data->proto->OpenUrl(data->url); - } - - // After a click, destroy popup - PUDeletePopup(hwnd); - } break; - - case UM_FREEPLUGINDATA: - { - // After close, free - popup_data *data = (popup_data *)PUGetPluginData(hwnd); - delete data; - } return FALSE; - - default: - break; - } - - return DefWindowProc(hwnd, message, wParam, lParam); -}; - -/** - * Popup classes initialization - */ -void FacebookProto::InitPopups() -{ - char name[256]; - wchar_t desc[256]; - - POPUPCLASS ppc = {}; - ppc.cbSize = sizeof(ppc); - ppc.flags = PCF_UNICODE; - ppc.PluginWindowProc = PopupDlgProc; - ppc.lParam = APF_RETURN_HWND; - ppc.pszName = name; - ppc.pszDescription.w = desc; - - // Client - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Client errors")); - mir_snprintf(name, "%s_%s", m_szModuleName, "Client"); - ppc.hIcon = g_plugin.getIcon(IDI_FACEBOOK); - ppc.colorBack = RGB(191, 0, 0); // red - ppc.colorText = RGB(255, 255, 255); // white - popupClasses.push_back(Popup_RegisterClass(&ppc)); - - // Newsfeeds - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Wall posts")); - mir_snprintf(name, "%s_%s", m_szModuleName, "Newsfeed"); - ppc.hIcon = g_plugin.getIcon(IDI_NEWSFEED); - ppc.colorBack = RGB(255, 255, 255); // white - ppc.colorText = RGB(0, 0, 0); // black - popupClasses.push_back(Popup_RegisterClass(&ppc)); - - // Notifications - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Notifications")); - mir_snprintf(name, "%s_%s", m_szModuleName, "Notification"); - ppc.hIcon = g_plugin.getIcon(IDI_NOTIFICATION); - ppc.colorBack = RGB(59, 89, 152); // Facebook's blue - ppc.colorText = RGB(255, 255, 255); // white - popupClasses.push_back(Popup_RegisterClass(&ppc)); - - // Others - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Other events")); - mir_snprintf(name, "%s_%s", m_szModuleName, "Other"); - ppc.hIcon = g_plugin.getIcon(IDI_FACEBOOK); - ppc.colorBack = RGB(255, 255, 255); // white - ppc.colorText = RGB(0, 0, 0); // black - popupClasses.push_back(Popup_RegisterClass(&ppc)); - - // Friendship changes - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Friendship events")); - mir_snprintf(name, "%s_%s", m_szModuleName, "Friendship"); - ppc.hIcon = g_plugin.getIcon(IDI_FRIENDS); - ppc.colorBack = RGB(47, 71, 122); // Facebook's darker blue - ppc.colorText = RGB(255, 255, 255); // white - popupClasses.push_back(Popup_RegisterClass(&ppc)); - - // Ticker - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Real-time friends activity")); - mir_snprintf(name, "%s_%s", m_szModuleName, "Ticker"); - ppc.hIcon = g_plugin.getIcon(IDI_NEWSFEED); - ppc.colorBack = RGB(255, 255, 255); // white - ppc.colorText = RGB(0, 0, 0); // black - popupClasses.push_back(Popup_RegisterClass(&ppc)); - - // On this day (memories) - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Memories")); - mir_snprintf(name, "%s_%s", m_szModuleName, "Memories"); - ppc.hIcon = g_plugin.getIcon(IDI_MEMORIES); - ppc.colorBack = RGB(255, 255, 255); // white - ppc.colorText = RGB(0, 0, 0); // black - popupClasses.push_back(Popup_RegisterClass(&ppc)); -} - -/** - * Hotkeys initialiation - */ -void FacebookProto::InitHotkeys() -{ - char text[200]; - mir_strncpy(text, m_szModuleName, 100); - char *tDest = text + mir_strlen(text); - - HOTKEYDESC hkd = {}; - hkd.pszName = text; - hkd.pszService = text; - hkd.szSection.w = m_tszUserName; - hkd.dwFlags = HKD_UNICODE; - - mir_strcpy(tDest, "/VisitProfile"); - hkd.szDescription.w = LPGENW("Visit profile"); - g_plugin.addHotkey(&hkd); - - mir_strcpy(tDest, "/VisitNotifications"); - hkd.szDescription.w = LPGENW("Visit notifications"); - g_plugin.addHotkey(&hkd); - - mir_strcpy(tDest, "/Mind"); - hkd.szDescription.w = LPGENW("Show 'Share status' window"); - hkd.DefHotKey = HOTKEYCODE(HOTKEYF_ALT | HOTKEYF_EXT, 'F'); - g_plugin.addHotkey(&hkd); -} - -/** - * Sounds initialization - */ -void FacebookProto::InitSounds() -{ - g_plugin.addSound("Notification", m_tszUserName, LPGENW("Notification")); - g_plugin.addSound("NewsFeed", m_tszUserName, LPGENW("Newsfeed event")); - g_plugin.addSound("OtherEvent", m_tszUserName, LPGENW("Other event")); - g_plugin.addSound("Friendship", m_tszUserName, LPGENW("Friendship event")); - g_plugin.addSound("Ticker", m_tszUserName, LPGENW("Ticker event")); - g_plugin.addSound("Memories", m_tszUserName, LPGENW("Memories")); -} - -/** - * Sets statusbar text of hContact with last read time (from facy.readers map) - */ -void FacebookProto::MessageRead(MCONTACT hContact) -{ - /*std::map<MCONTACT, time_t>::iterator it = facy.readers.find(hContact); - if (it == facy.readers.end()) - return;*/ - - // We may use this instead of checing map as we have this info already in memory (this value is resident) - time_t time = getDword(hContact, FACEBOOK_KEY_MESSAGE_READ, 0); - if (!time) - return; - - wchar_t ttime[64]; - wcsftime(ttime, _countof(ttime), L"%X", localtime(&time)); - - HICON hIcon = g_plugin.getIcon(IDI_READ); - - if (isChatRoom(hContact)) { - // Load readers names - ptrW treaders(getWStringA(hContact, FACEBOOK_KEY_MESSAGE_READERS)); - Srmm_SetStatusText(hContact, CMStringW(FORMAT, TranslateT("Message read: %s by %s"), ttime, treaders ? treaders : L"???"), hIcon); - } - else if (!g_bMessageState) - Srmm_SetStatusText(hContact, CMStringW(FORMAT, TranslateT("Message read: %s"), ttime), hIcon); -} diff --git a/protocols/FacebookRM/src/proto.h b/protocols/FacebookRM/src/proto.h deleted file mode 100644 index a23db24e91..0000000000 --- a/protocols/FacebookRM/src/proto.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "constants.h" - -#pragma once - -class FacebookProto : public PROTO<FacebookProto> -{ - friend class facebook_client; - - bool IgnoreDuplicates(const std::string &mid); - bool ProcessSpecialMessage(std::vector<facebook_message> &messages, const JSONNode &meta_, MessageType messageType, const std::string &messageData = ""); - - void ParseAttachments(std::string &message_text, const JSONNode &delta_, std::string other_user_fbid, bool legacy); - void ParseMessageType(facebook_message &message, const JSONNode &log_type_, const JSONNode &log_body_, const JSONNode &log_data_); - bool ParseMessageMetadata(facebook_message &message, const JSONNode &meta_); - - int ParseChatInfo(std::string* data, facebook_chatroom* fbc); - int ParseChatParticipants(std::string *data, std::map<std::string, chatroom_participant>* participants); - int ParseFriends(std::string*, std::map< std::string, facebook_user* >*, bool); - int ParseHistory(std::string* data, std::vector<facebook_message> &messages, std::string *firstTimestamp); - int ParseMessages(std::string &data, std::vector< facebook_message >&); - int ParseMessagesCount(std::string *data, int *messagesCount, int *unreadCount); - int ParseNotifications(std::string*, std::map< std::string, facebook_notification* >*); - int ParseThreadInfo(std::string* data, std::string* user_id); - int ParseThreadMessages(std::string*, std::vector< facebook_message >*, bool unreadOnly); - int ParseUnreadThreads(std::string*, std::vector< std::string >*); - int ParseUserInfo(std::string* data, facebook_user* fbu); - int ParseBuddylistUpdate(std::string* data); - - const char* ParseIcon(const std::string &url); - -public: - FacebookProto(const char *proto_name, const wchar_t *username); - ~FacebookProto(); - - inline const char* ModuleName() const - { - return m_szModuleName; - } - - inline bool isOnline() - { - return (m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING); - } - - inline bool isOffline() - { - return (m_iStatus == ID_STATUS_OFFLINE); - } - - inline bool isInvisible() - { - return m_invisible; - } - - inline int IdleSeconds() - { - if ((m_iStatus == ID_STATUS_AWAY || m_iStatus == ID_STATUS_INVISIBLE) && m_awayTS) - return time(0) - m_awayTS; - - return m_idleTS ? time(0) - m_idleTS : 0; - } - - bool m_invisible; - bool m_enableChat; - bool m_signingOut; - time_t m_idleTS; - time_t m_awayTS; - time_t m_pingTS; - std::string m_locale; - std::string m_pagePrefix; - - // DB utils missing in proto_interface - - __forceinline INT_PTR getStringUtf(const char *name, DBVARIANT *result) { - return db_get_utf(0, m_szModuleName, name, result); } - __forceinline INT_PTR getStringUtf(MCONTACT hContact, const char *name, DBVARIANT *result) { - return db_get_utf(hContact, m_szModuleName, name, result); } - - __forceinline void setStringUtf(const char *name, const char* value) { db_set_utf(0, m_szModuleName, name, value); } - __forceinline void setStringUtf(MCONTACT hContact, const char *name, const char* value) { db_set_utf(hContact, m_szModuleName, name, value); } - - //////////////////////////////////////////////////////////////////////////////////////// - // PROTO_INTERFACE - - MCONTACT AddToList(int flags, PROTOSEARCHRESULT* psr) override; - - int Authorize(MEVENT hDbEvent) override; - int AuthDeny(MEVENT hDbEvent, const wchar_t* szReason) override; - int AuthRequest(MCONTACT hContact, const wchar_t* szMessage) override; - - INT_PTR GetCaps(int type, MCONTACT hContact = 0) override; - int GetInfo(MCONTACT hContact, int infoType) override; - - HANDLE SearchBasic(const wchar_t* id) override; - HANDLE SearchByEmail(const wchar_t* email) override; - HANDLE SearchByName(const wchar_t* nick, const wchar_t* firstName, const wchar_t* lastName) override; - - MEVENT RecvMsg(MCONTACT hContact, PROTORECVEVENT*) override; - int SendMsg(MCONTACT hContact, int flags, const char* msg) override; - - int SetStatus(int iNewStatus) override; - - int SetAwayMsg(int iStatus, const wchar_t* msg) override; - - int UserIsTyping(MCONTACT hContact, int type) override; - - void OnBuildProtoMenu(void) override; - void OnContactDeleted(MCONTACT) override; - void OnModulesLoaded() override; - void OnShutdown() override; - - //////////////////////// - - // Services - INT_PTR __cdecl GetMyAwayMsg(WPARAM, LPARAM); - INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); - INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); - INT_PTR __cdecl VisitProfile(WPARAM, LPARAM); - INT_PTR __cdecl VisitFriendship(WPARAM, LPARAM); - INT_PTR __cdecl VisitConversation(WPARAM, LPARAM); - INT_PTR __cdecl VisitNotifications(WPARAM, LPARAM); - INT_PTR __cdecl Poke(WPARAM, LPARAM); - INT_PTR __cdecl LoadHistory(WPARAM, LPARAM); - INT_PTR __cdecl CancelFriendship(WPARAM, LPARAM); - INT_PTR __cdecl RequestFriendship(WPARAM, LPARAM); - INT_PTR __cdecl ApproveFriendship(WPARAM, LPARAM); - INT_PTR __cdecl DenyFriendship(WPARAM, LPARAM); - INT_PTR __cdecl OnCancelFriendshipRequest(WPARAM, LPARAM); - INT_PTR __cdecl CheckNewsfeeds(WPARAM, LPARAM); - INT_PTR __cdecl CheckFriendRequests(WPARAM, LPARAM); - INT_PTR __cdecl CheckNotifications(WPARAM, LPARAM); - INT_PTR __cdecl CheckMemories(WPARAM, LPARAM); - INT_PTR __cdecl GetNotificationsCount(WPARAM, LPARAM); - - INT_PTR __cdecl OnJoinChat(WPARAM,LPARAM); - INT_PTR __cdecl OnLeaveChat(WPARAM,LPARAM); - - INT_PTR __cdecl OnMind(WPARAM,LPARAM); - - // Initialization - void InitPopups(); - void InitHotkeys(); - void InitSounds(); - - // Events - int __cdecl OnOptionsInit(WPARAM, LPARAM); - int __cdecl OnToolbarInit(WPARAM, LPARAM); - int __cdecl OnBuildStatusMenu(WPARAM,LPARAM); - int __cdecl OnPrebuildContactMenu(WPARAM,LPARAM); - int __cdecl OnIdleChanged(WPARAM,LPARAM); - int __cdecl OnGCEvent(WPARAM,LPARAM); - int __cdecl OnGCMenuHook(WPARAM,LPARAM); - int __cdecl OnDbEventRead(WPARAM, LPARAM); - int __cdecl OnProcessSrmmEvent(WPARAM, LPARAM); - int __cdecl OnPreCreateEvent(WPARAM, LPARAM); - - // Loops - bool NegotiateConnection(); - BYTE GetPollRate(); - void __cdecl MessageLoop(void*); - void __cdecl UpdateLoop(void*); - - // Processing threads - void __cdecl ProcessFriendList(void*); - void __cdecl ProcessBuddylistUpdate(void*); - void __cdecl ProcessUnreadMessages(void*); - void __cdecl ProcessUnreadMessage(void*); - void __cdecl ProcessFeeds(void*); - void __cdecl ProcessNotifications(void*); - void __cdecl ProcessFriendRequests(void*); - void __cdecl SearchAckThread(void*); - void __cdecl SearchIdAckThread(void*); - void __cdecl ProcessPages(void*); - void __cdecl LoadLastMessages(void*); - void __cdecl LoadHistory(void*); - void __cdecl ProcessMemories(void*); - - // Worker threads - void __cdecl ChangeStatus(void*); - void __cdecl SetAwayMsgWorker(void*); - void __cdecl UpdateAvatarWorker(void*); - void __cdecl SendMsgWorker(void*); - void __cdecl SendChatMsgWorker(void*); - void __cdecl SendTypingWorker(void*); - void __cdecl ReadMessageWorker(void*); - void __cdecl ReadNotificationWorker(void*); - void __cdecl DeleteContactFromServer(void*); - void __cdecl AddContactToServer(void*); - void __cdecl ApproveContactToServer(void*); - void __cdecl CancelFriendsRequest(void*); - void __cdecl SendPokeWorker(void*); - void __cdecl IgnoreFriendshipRequest(void*); - void __cdecl RefreshUserInfo(void*); - - // Contacts handling - bool IsMyContact(MCONTACT, bool include_chat = false); - MCONTACT ContactIDToHContact(const std::string&); - MCONTACT ChatIDToHContact(const std::string&); - std::string ThreadIDToContactID(const std::string&); - void LoadContactInfo(facebook_user* fbu); - MCONTACT AddToContactList(facebook_user*, bool force_add = false, bool add_temporarily = false); - MCONTACT HContactFromAuthEvent(MEVENT hEvent); - void StartTyping(MCONTACT hContact); - void StopTyping(MCONTACT hContact); - - // Chats handling - void AddChat(const char *chat_id, const wchar_t *name); - void UpdateChat(const char *chat_id, const char *id, const char *name, const char *message, DWORD timestamp = 0, bool is_old = false); - void RenameChat(const char *chat_id, const char *name); - bool IsChatContact(const char *chat_id, const char *id); - void AddChatContact(const char *chat_id, const chatroom_participant &user, bool addToLog); - void RemoveChatContact(const char *chat_id, const char *id, const char *name); - char *GetChatUsers(const char *chat_id); - void ReceiveMessages(std::vector<facebook_message> &messages, bool check_duplicates = false); - void LoadChatInfo(facebook_chatroom* fbc); - void LoadParticipantsNames(facebook_chatroom *fbc); - void JoinChatrooms(); - - bool IsSpecialChatRoom(MCONTACT hContact); - void PrepareNotificationsChatRoom(); - void UpdateNotificationsChatRoom(facebook_notification *notification); - std::string FacebookProto::GenerateChatName(facebook_chatroom *fbc); - - // Connection client - facebook_client facy; // TODO: Refactor to "client" and make dynamic - - // Helpers - std::wstring GetAvatarFolder(); - bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATION &ai, std::string *url); - void CheckAvatarChange(MCONTACT hContact, const std::string &image_url); - void ToggleStatusMenuItems(bool bEnable); - void StickerAsSmiley(std::string stickerId, const std::string &url, MCONTACT hContact); - void SaveName(MCONTACT hContact, const facebook_user *fbu); - std::string PrepareUrl(std::string url); - void OpenUrl(std::string url); - void __cdecl OpenUrlThread(void*); - void MessageRead(MCONTACT hContact); - bool RunCaptchaForm(std::string imageUrl, std::string &result); - - // Menu items - HGENMENU m_hMenuServicesRoot; - HGENMENU m_hStatusMind; - - // Locks - mir_cs signon_lock_; - mir_cs avatar_lock_; - mir_cs log_lock_; - HANDLE update_loop_event; - - ptrW m_tszDefaultGroup; - - std::vector<HANDLE> popupClasses; - - std::string last_status_msg_; - std::vector<MCONTACT> avatar_queue; - - mir_cs csReactions; - std::map<std::string, std::string> reactions; - - // Information providing - HWND NotifyEvent(const wchar_t* title, const wchar_t* text, MCONTACT contact, EventType type, std::string *url = nullptr, std::string *notification_id = nullptr, const char *icon = nullptr); - void ShowNotifications(); -}; - -struct CMPlugin : public ACCPROTOPLUGIN<FacebookProto> -{ - CMPlugin(); - - int Load() override; - int Unload() override; -}; diff --git a/protocols/FacebookRM/src/resource.h b/protocols/FacebookRM/src/resource.h deleted file mode 100644 index 4044214338..0000000000 --- a/protocols/FacebookRM/src/resource.h +++ /dev/null @@ -1,86 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by D:\Development\Miranda NG\Miranda NG\protocols\FacebookRM\res\facebook.rc -// -#define IDC_EXPAND 3 -#define IDI_FACEBOOK 101 -#define IDI_MIND 102 -#define IDD_FACEBOOKACCOUNT 111 -#define IDD_MIND 112 -#define IDD_OPTIONS 113 -#define IDD_OPTIONS_EVENTS 114 -#define IDD_OPTIONS_STATUSES 115 -#define IDD_CAPTCHAFORM 116 -#define IDD_OPTIONS_MESSAGING 117 -#define IDI_POKE 127 -#define IDI_NOTIFICATION 128 -#define IDI_NEWSFEED 129 -#define IDI_FRIENDS 130 -#define IDI_CONVERSATION 131 -#define IDI_READ 132 -#define IDD_GUARD 134 -#define IDI_ANGRY 135 -#define IDI_HAHA 136 -#define IDI_LIKE 137 -#define IDI_LOVE 138 -#define IDI_SAD 139 -#define IDI_WOW 140 -#define IDI_MEMORIES 141 -#define IDC_UN 1001 -#define IDC_PW 1002 -#define IDC_NEWACCOUNTLINK 1003 -#define IDC_MINDMSG 1012 -#define IDC_GROUP 1021 -#define IDC_SET_IGNORE_STATUS 1025 -#define IDC_DISCONNECT_CHAT 1028 -#define IDC_BIGGER_AVATARS 1030 -#define IDC_NAME_AS_NICK 1031 -#define IDC_MAP_STATUSES 1032 -#define IDC_LOAD_ALL_CONTACTS 1033 -#define IDC_CUSTOM_SMILEYS 1034 -#define IDC_PAGES_ALWAYS_ONLINE 1035 -#define IDC_LOAD_PAGES 1036 -#define IDC_KEEP_UNREAD 1037 -#define IDC_TYPING_WHEN_INVISIBLE 1038 -#define IDC_MESSAGES_ON_OPEN 1039 -#define IDC_HIDE_CHATS 1040 -#define IDC_NOTIFICATIONS_ENABLE 1041 -#define IDC_FEEDS_ENABLE 1042 -#define IDC_FILTER_ADS 1045 -#define IDC_ENABLE_CHATS 1047 -#define IDC_FRIENDSHIP_ENABLE 1048 -#define IDC_TICKER_ENABLE 1049 -#define IDC_ON_THIS_DAY_ENABLE 1050 -#define IDC_SYSTRAY_NOTIFY 1098 -#define IDC_NOTIFICATIONS_CHATROOM 1100 -#define IDC_SET_STATUS 1126 -#define IDC_FEED_TYPE 1201 -#define IDC_URL_SERVER 1202 -#define IDC_PLACE 1203 -#define IDC_PRIVACY 1204 -#define IDC_WALL 1205 -#define IDC_URL 1206 -#define IDC_CCLIST 1207 -#define IDC_CCLIST_LABEL 1208 -#define IDC_MESSAGES_COUNT 1209 -#define IDC_MESSAGES_COUNT_SPIN 1210 -#define IDC_VALUE 1211 -#define IDC_WHITERECT 1212 -#define IDC_TITLE 1213 -#define IDC_INSTRUCTION 1214 -#define IDC_FRAME1 1215 -#define IDC_FRAME2 1216 -#define IDC_TEXT 1217 -#define IDC_SEND_SMS 1218 -#define IDC_JOIN_EXISTING_CHATS 1219 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 142 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1220 -#define _APS_NEXT_SYMED_VALUE 134 -#endif -#endif diff --git a/protocols/FacebookRM/src/search.cpp b/protocols/FacebookRM/src/search.cpp deleted file mode 100644 index e9d2c213bf..0000000000 --- a/protocols/FacebookRM/src/search.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -// searching -HttpRequest* facebook_client::searchRequest(const char *query, int s, int pn, const char *ssid) -{ - HttpRequest* p = new HttpRequest(REQUEST_GET, FORMAT, "%s/search/", mbasicWorks ? FACEBOOK_SERVER_MBASIC : FACEBOOK_SERVER_MOBILE); - p->flags |= NLHRF_REDIRECT; - - p << CHAR_PARAM("q", query) - << INT_PARAM("s", s) - << INT_PARAM("pn", pn); - - if (mir_strlen(ssid) > 0) - p << CHAR_PARAM("ssid", ssid); - - return p; -} diff --git a/protocols/FacebookRM/src/status.cpp b/protocols/FacebookRM/src/status.cpp deleted file mode 100644 index 5e813bd757..0000000000 --- a/protocols/FacebookRM/src/status.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// getting info about channel and connecting to it - -HttpRequest* facebook_client::reconnectRequest() -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/ajax/presence/reconnect.php"); - - p << INT_PARAM("__a", 1) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__be", -1) - << CHAR_PARAM("reason", chat_reconnect_reason_.empty() ? "6" : chat_reconnect_reason_.c_str()) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()); - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// setting chat visibility - -HttpRequest* facebook_client::setVisibilityRequest(bool online) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/chat/privacy/visibility.php"); - - p << INT_PARAM("dpr", 1); - - p->Body - << INT_PARAM("visibility", online ? 1 : 0) - << INT_PARAM("window_id", 0) - << INT_PARAM("__a", 1) - << CHAR_PARAM("__pc", "PHASED:DEFAULT") - << INT_PARAM("__be", -1) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()); - - return p; -} diff --git a/protocols/FacebookRM/src/stdafx.cxx b/protocols/FacebookRM/src/stdafx.cxx deleted file mode 100644 index ac1978fbc2..0000000000 --- a/protocols/FacebookRM/src/stdafx.cxx +++ /dev/null @@ -1,18 +0,0 @@ -/*
-Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
-
-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 version 2
-of the License.
-
-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 <http://www.gnu.org/licenses/>.
-*/
-
-#include "stdafx.h"
diff --git a/protocols/FacebookRM/src/stdafx.h b/protocols/FacebookRM/src/stdafx.h deleted file mode 100644 index 67cec1b4d3..0000000000 --- a/protocols/FacebookRM/src/stdafx.h +++ /dev/null @@ -1,92 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#pragma once
-
-#pragma warning(disable:4996)
-
-#define _CRT_RAND_S
-
-#include <sstream>
-#include <fstream>
-#include <map>
-#include <vector>
-#include <set>
-#include <algorithm>
-
-#include <windows.h>
-#include <time.h>
-
-#include <win2k.h>
-#include <newpluginapi.h>
-#include <m_avatars.h>
-#include <m_chat.h>
-#include <m_clistint.h>
-#include <m_contacts.h>
-#include <m_database.h>
-#include <m_idle.h>
-#include <m_ignore.h>
-#include <m_langpack.h>
-#include <m_message.h>
-#include <m_netlib.h>
-#include <m_options.h>
-#include <m_popup.h>
-#include <m_protosvc.h>
-#include <m_protoint.h>
-#include <m_skin.h>
-#include <m_icolib.h>
-#include <m_hotkeys.h>
-#include <m_folders.h>
-#include <m_smileyadd.h>
-#include <m_toptoolbar.h>
-#include <m_json.h>
-#include <m_imgsrvc.h>
-#include <m_http.h>
-#include <m_messagestate.h>
-#include <m_gui.h>
-
-class FacebookProto;
-
-#include "../../utils/std_string_utils.h"
-
-#include "constants.h"
-#include "entities.h"
-#include "http.h"
-#include "client.h"
-#include "http_request.h"
-#include "db.h"
-#include "proto.h"
-#include "dialogs.h"
-#include "theme.h"
-#include "resource.h"
-#include "version.h"
-
-extern DWORD g_mirandaVersion;
-extern bool g_bMessageState;
-extern HWND g_hwndHeartbeat;
-
-template <typename T>
-__inline static void FreeList(const LIST<T> &lst)
-{
- for (auto &it : lst)
- mir_free(it);
-}
diff --git a/protocols/FacebookRM/src/theme.cpp b/protocols/FacebookRM/src/theme.cpp deleted file mode 100644 index 9c0400456a..0000000000 --- a/protocols/FacebookRM/src/theme.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "stdafx.h"
-
-// Contact menu items
-HGENMENU g_hContactMenuVisitProfile;
-HGENMENU g_hContactMenuVisitFriendship;
-HGENMENU g_hContactMenuAuthCancel;
-HGENMENU g_hContactMenuAuthDeny;
-HGENMENU g_hContactMenuPoke;
-HGENMENU g_hContactMenuPostStatus;
-HGENMENU g_hContactMenuVisitConversation;
-HGENMENU g_hContactMenuLoadHistory;
-
-static IconItem icons[] =
-{
- { LPGEN("Facebook icon"), "facebook", IDI_FACEBOOK },
- { LPGEN("Mind"), "mind", IDI_MIND },
- { LPGEN("Poke"), "poke", IDI_POKE },
- { LPGEN("Notification"), "notification", IDI_NOTIFICATION },
- { LPGEN("Newsfeed"), "newsfeed", IDI_NEWSFEED },
- { LPGEN("Memories"), "memories", IDI_MEMORIES },
- { LPGEN("Friendship details"), "friendship", IDI_FRIENDS },
- { LPGEN("Conversation"), "conversation", IDI_CONVERSATION },
- { LPGEN("Message read"), "read", IDI_READ },
- { LPGEN("Angry"), "angry", IDI_ANGRY },
- { LPGEN("Haha"), "haha", IDI_HAHA },
- { LPGEN("Like"), "like", IDI_LIKE },
- { LPGEN("Love"), "love", IDI_LOVE },
- { LPGEN("Sad"), "sad", IDI_SAD },
- { LPGEN("Wow"), "wow", IDI_WOW },
-};
-
-void InitIcons(void)
-{
- g_plugin.registerIcon("Protocols/Facebook", icons, "Facebook");
-}
-
-// Helper functions
-template<INT_PTR(__cdecl FacebookProto::*Fcn)(WPARAM, LPARAM)>
-INT_PTR GlobalService(WPARAM wParam, LPARAM lParam)
-{
- FacebookProto *proto = CMPlugin::getInstance(MCONTACT(wParam));
- return proto ? (proto->*Fcn)(wParam, lParam) : 0;
-}
-
-static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
-{
- // Hide our all contact menu items first
- Menu_ShowItem(g_hContactMenuVisitProfile, false);
- Menu_ShowItem(g_hContactMenuVisitFriendship, false);
- Menu_ShowItem(g_hContactMenuAuthCancel, false);
- Menu_ShowItem(g_hContactMenuAuthDeny, false);
- Menu_ShowItem(g_hContactMenuPoke, false);
- Menu_ShowItem(g_hContactMenuPostStatus, false);
- Menu_ShowItem(g_hContactMenuVisitConversation, false);
- Menu_ShowItem(g_hContactMenuLoadHistory, false);
-
- // Process them in correct account
- FacebookProto *proto = CMPlugin::getInstance(MCONTACT(wParam));
- return proto ? proto->OnPrebuildContactMenu(wParam, lParam) : 0;
-}
-
-void InitContactMenus()
-{
- HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu);
-
- CMenuItem mi(&g_plugin);
-
- SET_UID(mi, 0x4f006492, 0x9fe5, 0x4d10, 0x88, 0xce, 0x47, 0x53, 0xba, 0x27, 0xe9, 0xc9);
- mi.position = -2000006000;
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_EVENT_URL);
- mi.name.a = LPGEN("Visit profile");
- mi.pszService = "FacebookProto/VisitProfile";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::VisitProfile>);
- g_hContactMenuVisitProfile = Menu_AddContactMenuItem(&mi);
-
- SET_UID(mi, 0x1e9d0534, 0xc319, 0x42a2, 0xbe, 0xd5, 0x1e, 0xae, 0xe1, 0x54, 0xd, 0x89);
- mi.position = -2000006001;
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_FRIENDS);
- mi.name.a = LPGEN("Visit friendship details");
- mi.pszService = "FacebookProto/VisitFriendship";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::VisitFriendship>);
- g_hContactMenuVisitFriendship = Menu_AddContactMenuItem(&mi);
-
- SET_UID(mi, 0xd3bfd7d6, 0x43c3, 0x4b05, 0x81, 0x40, 0xc8, 0xbe, 0x81, 0xd9, 0x95, 0xff);
- mi.position = -2000006002;
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_CONVERSATION);
- mi.name.a = LPGEN("Visit conversation");
- mi.pszService = "FacebookProto/VisitConversation";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::VisitConversation>);
- g_hContactMenuVisitConversation = Menu_AddContactMenuItem(&mi);
-
- SET_UID(mi, 0xc631b2ea, 0xa133, 0x4cc9, 0x81, 0x1e, 0xad, 0x8f, 0x36, 0x5c, 0x74, 0xbf);
- mi.position = -2000006003;
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_MIND);
- mi.name.a = LPGEN("Share status...");
- mi.pszService = "FacebookProto/Mind";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::OnMind>);
- g_hContactMenuPostStatus = Menu_AddContactMenuItem(&mi);
-
- SET_UID(mi, 0x10ce2dbf, 0x8acf, 0x4f51, 0x89, 0x76, 0xd9, 0x67, 0xef, 0x69, 0x1d, 0x9d);
- mi.position = -2000006004;
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_POKE);
- mi.name.a = LPGEN("Poke");
- mi.pszService = "FacebookProto/Poke";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::Poke>);
- g_hContactMenuPoke = Menu_AddContactMenuItem(&mi);
-
- SET_UID(mi, 0x58e75db0, 0xb9e0, 0x4aa8, 0xbb, 0x42, 0x8d, 0x7d, 0xd1, 0xf6, 0x8e, 0x99);
- mi.position = -2000006005;
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_CONVERSATION); // TODO: Use better icon
- mi.name.a = LPGEN("Load history");
- mi.pszService = "FacebookProto/LoadHistory";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::LoadHistory>);
- g_hContactMenuLoadHistory = Menu_AddContactMenuItem(&mi);
-
- SET_UID(mi, 0x6d6b49b9, 0x71b8, 0x4a57, 0xab, 0x80, 0xc3, 0xb2, 0xbe, 0x2b, 0x9b, 0xf5);
- mi.position = -2000006011;
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_AUTH_REVOKE);
- mi.name.a = LPGEN("Cancel friendship request");
- mi.pszService = "FacebookProto/CancelFriendshipRequest";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::OnCancelFriendshipRequest>);
- g_hContactMenuAuthCancel = Menu_AddContactMenuItem(&mi);
- SET_UID(mi, 0x29d0a371, 0xb8a7, 0x4fb2, 0x91, 0x10, 0x13, 0x6f, 0x8c, 0x5f, 0xb5, 0x7);
- mi.position = -2000006014;
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_AUTH_REVOKE);
- mi.name.a = LPGEN("Deny friendship request");
- mi.pszService = "FacebookProto/DenyFriendship";
- CreateServiceFunction(mi.pszService, GlobalService<&FacebookProto::DenyFriendship>);
- g_hContactMenuAuthDeny = Menu_AddContactMenuItem(&mi);
-}
-
-int FacebookProto::OnPrebuildContactMenu(WPARAM wParam, LPARAM)
-{
- MCONTACT hContact = MCONTACT(wParam);
-
- BYTE type = getByte(hContact, FACEBOOK_KEY_CONTACT_TYPE, 0);
- bool bIsChatroom = isChatRoom(hContact);
- bool bIsSpecialChatroom = IsSpecialChatRoom(hContact);
- bool bIsPage = (type == CONTACT_PAGE);
-
- Menu_ShowItem(g_hContactMenuVisitProfile, !bIsChatroom);
- Menu_ShowItem(g_hContactMenuVisitFriendship, !bIsChatroom && !bIsPage);
- Menu_ShowItem(g_hContactMenuVisitConversation, !bIsSpecialChatroom);
- Menu_ShowItem(g_hContactMenuPostStatus, !bIsChatroom);
- Menu_ShowItem(g_hContactMenuLoadHistory, !bIsChatroom);
-
- if (!isOffline() && !bIsChatroom && !bIsPage) {
- bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
-
- Menu_ShowItem(m_hmiReqAuth, ctrlPressed || type == CONTACT_NONE || !type);
- Menu_ShowItem(m_hmiGrantAuth, ctrlPressed || type == CONTACT_APPROVE);
- Menu_ShowItem(m_hmiRevokeAuth, ctrlPressed || type == CONTACT_FRIEND);
-
- Menu_ShowItem(g_hContactMenuAuthCancel, ctrlPressed || type == CONTACT_REQUEST);
- Menu_ShowItem(g_hContactMenuAuthDeny, ctrlPressed || type == CONTACT_APPROVE);
- Menu_ShowItem(g_hContactMenuPoke, true);
- }
-
- return 0;
-}
-
-void FacebookProto::OnBuildProtoMenu()
-{
- CMenuItem mi(&g_plugin);
- mi.position = 201001;
- mi.root = Menu_GetProtocolRoot(this);
-
- mi.pszService = "/Mind";
- CreateProtoService(mi.pszService, &FacebookProto::OnMind);
- mi.name.a = LPGEN("Share status...");
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_MIND);
- m_hStatusMind = Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/VisitProfile";
- CreateProtoService(mi.pszService, &FacebookProto::VisitProfile);
- mi.name.a = LPGEN("Visit profile");
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_EVENT_URL);
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/VisitNotifications";
- CreateProtoService(mi.pszService, &FacebookProto::VisitNotifications);
- mi.name.a = LPGEN("Visit notifications");
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_EVENT_URL);
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- // Services...
- mi.name.a = LPGEN("Services...");
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_HELP);
- mi.root = m_hMenuServicesRoot = Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/CheckFriendRequests";
- CreateProtoService(mi.pszService, &FacebookProto::CheckFriendRequests);
- mi.name.a = LPGEN("Check friendship requests");
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_AUTH_REQUEST);
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/CheckNewsfeeds";
- CreateProtoService(mi.pszService, &FacebookProto::CheckNewsfeeds);
- mi.name.a = LPGEN("Check newsfeeds");
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_NEWSFEED);
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/CheckMemories";
- CreateProtoService(mi.pszService, &FacebookProto::CheckMemories);
- mi.name.a = LPGEN("Check memories");
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_MEMORIES);
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
-
- mi.pszService = "/CheckNotifications";
- CreateProtoService(mi.pszService, &FacebookProto::CheckNotifications);
- mi.name.a = LPGEN("Check notifications");
- mi.hIcolibItem = g_plugin.getIconHandle(IDI_NOTIFICATION);
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
-}
-
-int FacebookProto::OnBuildStatusMenu(WPARAM, LPARAM)
-{
- ToggleStatusMenuItems(this->isOnline());
- return 0;
-}
-
-void FacebookProto::ToggleStatusMenuItems(bool bEnable)
-{
- Menu_EnableItem(m_hmiMainMenu, bEnable);
- Menu_EnableItem(m_hStatusMind, bEnable);
- Menu_EnableItem(m_hMenuServicesRoot, bEnable);
-}
diff --git a/protocols/FacebookRM/src/theme.h b/protocols/FacebookRM/src/theme.h deleted file mode 100644 index 550816f565..0000000000 --- a/protocols/FacebookRM/src/theme.h +++ /dev/null @@ -1,26 +0,0 @@ -/*
-
-Facebook plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team
-
-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 <http://www.gnu.org/licenses/>.
-
-*/
-
-#pragma once
-
-void InitIcons(void);
-void InitContactMenus(void);
diff --git a/protocols/FacebookRM/src/utils.cpp b/protocols/FacebookRM/src/utils.cpp deleted file mode 100644 index 3131d2f326..0000000000 --- a/protocols/FacebookRM/src/utils.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - -Facebook plugin for Miranda Instant Messenger -_____________________________________________ - -Copyright © 2011-17 Robert Pösel, 2017-19 Miranda NG team - -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 <http://www.gnu.org/licenses/>. - -*/ - -#include "stdafx.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// getting owned/admined pages list - -HttpRequest* facebook_client::getPagesRequest() -{ - return new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/bookmarks/pages"); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// refreshing captcha dialog (changing captcha type) - -HttpRequest* facebook_client::refreshCaptchaRequest(const char *captchaPersistData) -{ - HttpRequest *p = new HttpRequest(REQUEST_GET, FACEBOOK_SERVER_REGULAR "/captcha/refresh_ajax.php"); - - p << INT_PARAM("__a", 1) - << CHAR_PARAM("new_captcha_type", "TFBCaptcha") - << CHAR_PARAM("skipped_captcha_data", captchaPersistData) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("__rev", __rev()) - << CHAR_PARAM("__user", self_.user_id.c_str()); - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// getting data for given url (for sending/posting reasons) - -HttpRequest* facebook_client::linkScraperRequest(status_data *status) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/composerx/attachment/link/scraper/"); - - p << INT_PARAM("__a", 1) - << INT_PARAM("composerurihash", 2) - << CHAR_PARAM("scrape_url", status->url.c_str()); - - p->Body - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("targetid", status->user_id.empty() ? self_.user_id.c_str() : status->user_id.c_str()) - << CHAR_PARAM("xhpc_targetid", status->user_id.empty() ? self_.user_id.c_str() : status->user_id.c_str()) - << INT_PARAM("istimeline", 1) - << CHAR_PARAM("composercontext", "composer") - << INT_PARAM("onecolumn", 1) - << CHAR_PARAM("nctr[_mod]", "pagelet_timeline_recent") - << INT_PARAM("__a", 1) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__user", status->isPage && !status->user_id.empty() ? status->user_id.c_str() : self_.user_id.c_str()) - << CHAR_PARAM("loaded_components[0]", "maininput") - << CHAR_PARAM("loaded_components[1]", "backdateicon") - << CHAR_PARAM("loaded_components[2]", "withtaggericon") - << CHAR_PARAM("loaded_components[3]", "cameraicon") - << CHAR_PARAM("loaded_components[4]", "placetaggericon") - << CHAR_PARAM("loaded_components[5]", "mainprivacywidget") - << CHAR_PARAM("loaded_components[6]", "withtaggericon") - << CHAR_PARAM("loaded_components[7]", "backdateicon") - << CHAR_PARAM("loaded_components[8]", "placetaggericon") - << CHAR_PARAM("loaded_components[9]", "cameraicon") - << CHAR_PARAM("loaded_components[10]", "mainprivacywidget") - << CHAR_PARAM("loaded_components[11]", "maininput") - << CHAR_PARAM("loaded_components[12]", "explicitplaceinput") - << CHAR_PARAM("loaded_components[13]", "hiddenplaceinput") - << CHAR_PARAM("loaded_components[14]", "placenameinput") - << CHAR_PARAM("loaded_components[15]", "hiddensessionid") - << CHAR_PARAM("loaded_components[16]", "withtagger") - << CHAR_PARAM("loaded_components[17]", "backdatepicker") - << CHAR_PARAM("loaded_components[18]", "placetagger") - << CHAR_PARAM("loaded_components[19]", "citysharericon"); - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// changing identity to post status for pages - -HttpRequest* facebook_client::switchIdentityRequest(const char *userId) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/identity_switch.php"); - - p << INT_PARAM("__a", 1); - - p->Body << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) << CHAR_PARAM("user_id", userId) << CHAR_PARAM("url", FACEBOOK_URL_HOMEPAGE); - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// posting status to our or friends's wall - -HttpRequest* facebook_client::sharePostRequest(status_data *status, const char *linkData) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/ajax/updatestatus.php"); - - p << INT_PARAM("__a", 1); - - p->Body - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__dyn", __dyn()) - << CHAR_PARAM("__req", __req()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()) - << CHAR_PARAM("__user", status->isPage && !status->user_id.empty() ? status->user_id.c_str() : self_.user_id.c_str()) - << CHAR_PARAM("xhpc_targetid", status->user_id.empty() ? self_.user_id.c_str() : status->user_id.c_str()) - << CHAR_PARAM("xhpc_message", status->text.c_str()) - << CHAR_PARAM("xhpc_message_text", status->text.c_str()) - << CHAR_PARAM("xhpc_context", "profile") - << INT_PARAM("xhpc_ismeta", 1) - << INT_PARAM("xhpc_timeline", 1) - << CHAR_PARAM("xhpc_composerid", "u_0_2y") - << BOOL_PARAM("disable_location_sharing", false) - << CHAR_PARAM("nctr[_mod]", "pagelet_composer"); - - if (!status->isPage) - p->Body << CHAR_PARAM("audience[0][value]", get_privacy_type().c_str()); - - if (!status->place.empty()) - p->Body << CHAR_PARAM("composertags_place_name", status->place.c_str()); - - // Status with users - for (std::vector<facebook_user*>::size_type i = 0; i < status->users.size(); i++) { - CMStringA withId(::FORMAT, "composertags_with[%i]", i); - CMStringA withName(::FORMAT, "text_composertags_with[%i]", i); - - p->Body - << CHAR_PARAM(withId.c_str(), status->users[i]->user_id.c_str()) - << CHAR_PARAM(withName.c_str(), status->users[i]->real_name.c_str()); - } - - // Link attachment - if (mir_strlen(linkData) > 0) - p->Body << linkData; - - return p; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// sending pokes - -HttpRequest* facebook_client::sendPokeRequest(const char *userId) -{ - HttpRequest *p = new HttpRequest(REQUEST_POST, FACEBOOK_SERVER_REGULAR "/pokes/dialog/"); - - p << INT_PARAM("__a", 1); - - p->Body - << INT_PARAM("do_confirm", 0) - << CHAR_PARAM("poke_target", userId) - << CHAR_PARAM("fb_dtsg", dtsg_.c_str()) - << CHAR_PARAM("__user", self_.user_id.c_str()) - << CHAR_PARAM("ttstamp", ttstamp_.c_str()); - - return p; -} diff --git a/protocols/FacebookRM/src/version.h b/protocols/FacebookRM/src/version.h deleted file mode 100644 index 707f990a20..0000000000 --- a/protocols/FacebookRM/src/version.h +++ /dev/null @@ -1,13 +0,0 @@ -#define __MAJOR_VERSION 0 -#define __MINOR_VERSION 4 -#define __RELEASE_NUM 2 -#define __BUILD_NUM 4 - -#include <stdver.h> - -#define __PLUGIN_NAME "Facebook" -#define __FILENAME "Facebook.dll" -#define __DESCRIPTION "Facebook protocol support for Miranda NG." -#define __AUTHOR "Michal Zelinka, Robert Pösel" -#define __AUTHORWEB "https://miranda-ng.org/p/Facebook/" -#define __COPYRIGHT "© 2009-11 Michal Zelinka, 2011-17 Robert Pösel, 2017-19 Miranda NG team" |