summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--protocols/Facebook/res/facebook.rc9
-rw-r--r--protocols/Facebook/src/groupchats.cpp235
-rw-r--r--protocols/Facebook/src/options.cpp2
-rw-r--r--protocols/Facebook/src/proto.cpp2
-rw-r--r--protocols/Facebook/src/proto.h14
-rw-r--r--protocols/Facebook/src/resource.h8
-rw-r--r--protocols/Facebook/src/server.cpp2
-rw-r--r--protocols/Facebook/src/stdafx.h3
8 files changed, 268 insertions, 7 deletions
diff --git a/protocols/Facebook/res/facebook.rc b/protocols/Facebook/res/facebook.rc
index 825fea836d..5044c073ae 100644
--- a/protocols/Facebook/res/facebook.rc
+++ b/protocols/Facebook/res/facebook.rc
@@ -93,6 +93,15 @@ BEGIN
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,130,277,10
END
+IDD_GROUPCHAT_INVITE DIALOGEX 0, 0, 215, 263
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Send group chat invitation"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,7,7,201,231,WS_EX_CLIENTEDGE
+ DEFPUSHBUTTON "&Invite",IDOK,104,243,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,158,243,50,14
+END
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/protocols/Facebook/src/groupchats.cpp b/protocols/Facebook/src/groupchats.cpp
new file mode 100644
index 0000000000..281fc49611
--- /dev/null
+++ b/protocols/Facebook/src/groupchats.cpp
@@ -0,0 +1,235 @@
+/*
+
+Facebook plugin for Miranda NG
+Copyright © 2019-20 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"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Invitation dialog
+
+class CGroupchatInviteDlg : public CFBDlgBase
+{
+ CCtrlClc m_clc;
+ SESSION_INFO *m_si;
+
+ void FilterList(CCtrlClc *)
+ {
+ for (auto &hContact : Contacts()) {
+ char *proto = Proto_GetBaseAccountName(hContact);
+ if (mir_strcmp(proto, m_proto->m_szModuleName) || m_proto->isChatRoom(hContact))
+ if (HANDLE hItem = m_clc.FindContact(hContact))
+ m_clc.DeleteItem(hItem);
+ }
+ }
+
+ void ResetListOptions(CCtrlClc *)
+ {
+ m_clc.SetBkBitmap(0, nullptr);
+ m_clc.SetBkColor(GetSysColor(COLOR_WINDOW));
+ m_clc.SetGreyoutFlags(0);
+ m_clc.SetLeftMargin(4);
+ m_clc.SetIndent(10);
+ m_clc.SetHideEmptyGroups(1);
+ m_clc.SetHideOfflineRoot(1);
+ for (int i = 0; i <= FONTID_MAX; i++)
+ m_clc.SetTextColor(i, GetSysColor(COLOR_WINDOWTEXT));
+ }
+
+public:
+ CGroupchatInviteDlg(FacebookProto *ppro, SESSION_INFO *si) :
+ CFBDlgBase(ppro, IDD_GROUPCHAT_INVITE),
+ m_si(si),
+ m_clc(this, IDC_CLIST)
+ {
+ m_clc.OnNewContact =
+ m_clc.OnListRebuilt = Callback(this, &CGroupchatInviteDlg::FilterList);
+ m_clc.OnOptionsChanged = Callback(this, &CGroupchatInviteDlg::ResetListOptions);
+ }
+
+ bool OnInitDialog() override
+ {
+ SetWindowLongPtr(m_clc.GetHwnd(), GWL_STYLE,
+ GetWindowLongPtr(m_clc.GetHwnd(), GWL_STYLE) | CLS_SHOWHIDDEN | CLS_HIDEOFFLINE | CLS_CHECKBOXES | CLS_HIDEEMPTYGROUPS | CLS_USEGROUPS | CLS_GREYALTERNATE | CLS_GROUPCHECKBOXES);
+ m_clc.SendMsg(CLM_SETEXSTYLE, CLS_EX_DISABLEDRAGDROP | CLS_EX_TRACKSELECT, 0);
+
+ ResetListOptions(&m_clc);
+ FilterList(&m_clc);
+ return true;
+ }
+
+ bool OnApply() override
+ {
+ JSONNode list(JSON_ARRAY);
+
+ for (auto &hContact : m_proto->AccContacts()) {
+ if (m_proto->isChatRoom(hContact))
+ continue;
+
+ if (HANDLE hItem = m_clc.FindContact(hContact)) {
+ if (m_clc.GetCheck(hItem)) {
+ JSONNode user; user << CHAR_PARAM("type", "id") << CHAR_PARAM("id", m_proto->getMStringA(DBKEY_ID));
+ list << user;
+ }
+ }
+ }
+
+ auto *pReq = m_proto->CreateRequest(FB_API_URL_PARTS, "addMembers", "POST");
+ pReq << CHAR_PARAM("to", list.write().c_str()) << WCHAR_PARAM("id", CMStringW(FORMAT, L"t_%s", m_si->ptszID));
+ pReq->CalcSig();
+
+ JsonReply reply(m_proto->ExecuteRequest(pReq));
+ return true;
+ }
+};
+
+void FacebookProto::Chat_InviteUser(SESSION_INFO *si)
+{
+ CGroupchatInviteDlg dlg(this, si);
+ if (si->pDlg)
+ dlg.SetParent(((CDlgBase *)si->pDlg)->GetHwnd());
+ dlg.DoModal();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Group chats
+
+enum ChatMenuItems
+{
+ IDM_INVITE = 10, IDM_LEAVE
+};
+
+static gc_item sttLogListItems[] =
+{
+ { LPGENW("&Invite a user"), IDM_INVITE, MENU_ITEM },
+ { nullptr, 0, MENU_SEPARATOR },
+ { LPGENW("&Leave/destroy chat"), IDM_LEAVE, MENU_ITEM }
+};
+
+int FacebookProto::GroupchatMenuHook(WPARAM, LPARAM lParam)
+{
+ GCMENUITEMS *gcmi = (GCMENUITEMS *)lParam;
+ if (gcmi == nullptr)
+ return 0;
+
+ if (mir_strcmpi(gcmi->pszModule, m_szModuleName))
+ return 0;
+
+ SESSION_INFO *si = g_chatApi.SM_FindSession(gcmi->pszID, gcmi->pszModule);
+ if (si == nullptr)
+ return 0;
+
+ if (gcmi->Type == MENU_ON_LOG)
+ Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin);
+
+ return 0;
+}
+
+int FacebookProto::GroupchatEventHook(WPARAM, LPARAM lParam)
+{
+ GCHOOK *gch = (GCHOOK *)lParam;
+ if (gch == nullptr)
+ return 0;
+
+ if (mir_strcmpi(gch->pszModule, m_szModuleName))
+ return 0;
+
+ SESSION_INFO *si = g_chatApi.SM_FindSession(gch->ptszID, gch->pszModule);
+ if (si == nullptr)
+ return 0;
+
+ switch (gch->iType) {
+ case GC_USER_MESSAGE:
+ rtrimw(gch->ptszText);
+ if (!mir_wstrlen(gch->ptszText))
+ break;
+
+ if (m_bOnline) {
+ wchar_t *wszText = NEWWSTR_ALLOCA(gch->ptszText);
+ Chat_UnescapeTags(wszText);
+ SendMsg(si->hContact, 0, T2Utf(wszText));
+ }
+ break;
+
+ case GC_USER_PRIVMESS:
+ Chat_SendPrivateMessage(gch);
+ break;
+
+ case GC_USER_LOGMENU:
+ Chat_ProcessLogMenu(si, gch->dwData);
+ break;
+ }
+
+ return 0;
+}
+
+void FacebookProto::Chat_ProcessLogMenu(SESSION_INFO *si, int iChoice)
+{
+ switch (iChoice) {
+ case IDM_INVITE:
+ Chat_InviteUser(si);
+ break;
+
+ case IDM_LEAVE:
+ Chat_Leave(si);
+ break;
+ }
+}
+
+void FacebookProto::Chat_SendPrivateMessage(GCHOOK *gch)
+{
+ auto *pUser = FindUser(_wtoi64(gch->ptszUID));
+ if (pUser == nullptr) {
+ pUser = AddContact(gch->ptszUID, true);
+ setWString(pUser->hContact, "Nick", gch->ptszNick);
+ db_set_b(pUser->hContact, "CList", "Hidden", 1);
+ db_set_dw(pUser->hContact, "Ignore", "Mask1", 0);
+ }
+
+ CallService(MS_MSG_SENDMESSAGE, pUser->hContact, 0);
+}
+
+int FacebookProto::Chat_KickUser(SESSION_INFO *si, const wchar_t *pwszUid)
+{
+ auto *pReq = CreateRequest(FB_API_URL_PARTS, "removeMembers", "DELETE");
+ pReq << WCHAR_PARAM("id", CMStringW(FORMAT, L"t_%s", si->ptszID));
+ if (pwszUid != nullptr) {
+ JSONNode list(JSON_ARRAY);
+ JSONNode user; user << CHAR_PARAM("type", "id") << WCHAR_PARAM("id", pwszUid);
+ list << user;
+ pReq << CHAR_PARAM("to", list.write().c_str());
+ }
+ pReq->CalcSig();
+
+ JsonReply reply(ExecuteRequest(pReq));
+ return reply.error();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void __cdecl DestroyRoomThread(SESSION_INFO *si)
+{
+ ::Sleep(100);
+ Chat_Terminate(si->pszModule, si->ptszID, true);
+}
+
+void FacebookProto::Chat_Leave(SESSION_INFO *si)
+{
+ if (Chat_KickUser(si, nullptr) == 0)
+ mir_forkThread<SESSION_INFO>(DestroyRoomThread, si);
+}
diff --git a/protocols/Facebook/src/options.cpp b/protocols/Facebook/src/options.cpp
index 9e9f778298..cb353caf70 100644
--- a/protocols/Facebook/src/options.cpp
+++ b/protocols/Facebook/src/options.cpp
@@ -20,8 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
-typedef CProtoDlgBase<FacebookProto> CFBDlgBase;
-
class CFacebookAccOptsDlg : public CFBDlgBase
{
CCtrlEdit edtGroup;
diff --git a/protocols/Facebook/src/proto.cpp b/protocols/Facebook/src/proto.cpp
index 0e1697705b..dd7ef0903d 100644
--- a/protocols/Facebook/src/proto.cpp
+++ b/protocols/Facebook/src/proto.cpp
@@ -106,6 +106,8 @@ FacebookProto::FacebookProto(const char *proto_name, const wchar_t *username) :
CreateProtoService(PS_GETAVATARCAPS, &FacebookProto::GetAvatarCaps);
// Events
+ HookProtoEvent(ME_GC_EVENT, &FacebookProto::GroupchatEventHook);
+ HookProtoEvent(ME_GC_BUILDMENU, &FacebookProto::GroupchatMenuHook);
HookProtoEvent(ME_OPT_INITIALISE, &FacebookProto::OnOptionsInit);
// Default group
diff --git a/protocols/Facebook/src/proto.h b/protocols/Facebook/src/proto.h
index 4f6923431d..950408c34b 100644
--- a/protocols/Facebook/src/proto.h
+++ b/protocols/Facebook/src/proto.h
@@ -368,6 +368,8 @@ struct COwnMessage
class FacebookProto : public PROTO<FacebookProto>
{
+ friend class CGroupchatInviteDlg;
+
class FacebookImpl
{
friend class FacebookProto;
@@ -401,6 +403,13 @@ class FacebookProto : public PROTO<FacebookProto>
void __cdecl AvatarsUpdate(void *);
void GetAvatarFilename(MCONTACT hContact, wchar_t *pwszFileName);
+ // Group chats
+ void Chat_InviteUser(SESSION_INFO *si);
+ int Chat_KickUser(SESSION_INFO *si, const wchar_t *pwszUid);
+ void Chat_Leave(SESSION_INFO *si);
+ void Chat_SendPrivateMessage(GCHOOK *gch);
+ void Chat_ProcessLogMenu(SESSION_INFO *si, int iChoice);
+
// MQTT
void MqttLogin();
@@ -496,6 +505,9 @@ public:
// Events
int __cdecl OnOptionsInit(WPARAM, LPARAM);
+
+ int __cdecl GroupchatMenuHook(WPARAM, LPARAM);
+ int __cdecl GroupchatEventHook(WPARAM, LPARAM);
////////////////////////////////////////////////////////////////////////////////////////
// Services
@@ -505,6 +517,8 @@ public:
INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM);
};
+typedef CProtoDlgBase<FacebookProto> CFBDlgBase;
+
struct CMPlugin : public ACCPROTOPLUGIN<FacebookProto>
{
CMPlugin();
diff --git a/protocols/Facebook/src/resource.h b/protocols/Facebook/src/resource.h
index 86512c93e7..b0819aeff8 100644
--- a/protocols/Facebook/src/resource.h
+++ b/protocols/Facebook/src/resource.h
@@ -4,7 +4,8 @@
//
#define IDI_FACEBOOK 101
#define IDD_OPTIONS 102
-#define IDD_FACEBOOKACCOUNT 111
+#define IDD_GROUPCHAT_INVITE 103
+#define IDD_FACEBOOKACCOUNT 104
#define IDC_EDIT1 1000
#define IDC_UN 1001
#define IDC_PW 1002
@@ -12,14 +13,15 @@
#define IDC_GROUP 1004
#define IDC_ENABLECHATS 1005
#define IDC_HIDECHATS 1006
+#define IDC_CLIST 1007
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1006
+#define _APS_NEXT_CONTROL_VALUE 1008
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/protocols/Facebook/src/server.cpp b/protocols/Facebook/src/server.cpp
index 2dd06bab7b..2e21d01bf1 100644
--- a/protocols/Facebook/src/server.cpp
+++ b/protocols/Facebook/src/server.cpp
@@ -175,7 +175,7 @@ void FacebookProto::RefreshThreads()
if (!n["is_group_thread"].as_bool())
continue;
- CMStringW chatId(n["id"].as_mstring());
+ CMStringW chatId(n["thread_key"]["thread_fbid"].as_mstring());
CMStringW name(n["name"].as_mstring());
auto *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, chatId, name);
diff --git a/protocols/Facebook/src/stdafx.h b/protocols/Facebook/src/stdafx.h
index 8a9e9e579c..e591cc3ec3 100644
--- a/protocols/Facebook/src/stdafx.h
+++ b/protocols/Facebook/src/stdafx.h
@@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <windows.h>
+#include <malloc.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
@@ -30,7 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <win2k.h>
#include <newpluginapi.h>
#include <m_avatars.h>
-#include <m_chat.h>
+#include <m_chat_int.h>
#include <m_clistint.h>
#include <m_contacts.h>
#include <m_database.h>