summaryrefslogtreecommitdiff
path: root/protocols/Teams/src/teams_proto.h
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Teams/src/teams_proto.h')
-rw-r--r--protocols/Teams/src/teams_proto.h386
1 files changed, 386 insertions, 0 deletions
diff --git a/protocols/Teams/src/teams_proto.h b/protocols/Teams/src/teams_proto.h
new file mode 100644
index 0000000000..921a8e1ef1
--- /dev/null
+++ b/protocols/Teams/src/teams_proto.h
@@ -0,0 +1,386 @@
+#define TEAMS_CLIENT_ID "8ec6bc83-69c8-4392-8f08-b3c986009232"
+#define TEAMS_CLIENTINFO_NAME "skypeteams"
+#define TEAMS_CLIENTINFO_VERSION "49/24062722442"
+
+#define TEAMS_BASE_HOST "teams.live.com"
+
+#define TEAMS_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0 Teams/24165.1410.2974.6689/49"
+
+#define DBKEY_ID "id"
+#define DBKEY_GROUP "DefaultGroup"
+#define DBKEY_RTOKEN "RefreshToken"
+
+struct COwnMessage
+{
+ COwnMessage(int _1, int64_t _2) :
+ hMessage(_1),
+ hClientMessageId(_2)
+ {}
+
+ COwnMessage(const char *pszText) :
+ hMessage(0),
+ hClientMessageId(0),
+ szMessage(mir_strdup(pszText))
+ {}
+
+ int hMessage;
+ int64_t hClientMessageId, iTimestamp = -1;
+ ptrA szMessage;
+};
+
+struct CSkypeTransfer
+{
+ CMStringA docId, fileName, fileType, url;
+ int iFileSize = 0, iWidth = -1, iHeight = -1;
+};
+
+class CTeamsProto : public PROTO<CTeamsProto>
+{
+ friend class COptionsMainDlg;
+ friend class CDeviceCodeDlg;
+
+ friend class CSkypeOptionsMain;
+ friend class CSkypeGCCreateDlg;
+ friend class CSkypeInviteDlg;
+ friend class CMoodDialog;
+ friend class CDeviceCodeDlg;
+
+ class CTeamsProtoImpl
+ {
+ friend class CTeamsProto;
+ CTeamsProto &m_proto;
+
+ CTimer m_heartBeat, m_loginPoll;
+ void OnHeartBeat(CTimer *)
+ {
+ m_proto.TRouterSendJson("ping");
+ }
+ void OnLoginPoll(CTimer *)
+ {
+ m_proto.LoginPoll();
+ }
+
+ CTeamsProtoImpl(CTeamsProto &pro) :
+ m_proto(pro),
+ m_heartBeat(Miranda_GetSystemWindow(), UINT_PTR(this) + 1),
+ m_loginPoll(Miranda_GetSystemWindow(), UINT_PTR(this) + 2)
+ {
+ m_heartBeat.OnEvent = Callback(this, &CTeamsProtoImpl::OnHeartBeat);
+ m_loginPoll.OnEvent = Callback(this, &CTeamsProtoImpl::OnLoginPoll);
+ }
+ } m_impl;
+
+public:
+ // constructor
+ CTeamsProto(const char *protoName, const wchar_t *userName);
+ ~CTeamsProto();
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Virtual functions
+
+ MCONTACT AddToList(int flags, PROTOSEARCHRESULT* psr) override;
+ MCONTACT AddToListByEvent(int flags, int iContact, MEVENT hDbEvent) override;
+ int AuthRequest(MCONTACT hContact, const wchar_t* szMessage) override;
+ int Authorize(MEVENT hDbEvent) override;
+ int AuthDeny(MEVENT hDbEvent, const wchar_t* szReason) override;
+ int AuthRecv(MCONTACT hContact, DB::EventInfo &dbei) override;
+ INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override;
+ int GetInfo(MCONTACT hContact, int infoType) override;
+ HANDLE SearchBasic(const wchar_t* id) override;
+ int SendMsg(MCONTACT hContact, MEVENT hReplyEvent, const char* msg) override;
+ int SetStatus(int iNewStatus) override;
+ int UserIsTyping(MCONTACT hContact, int type) override;
+ int RecvContacts(MCONTACT hContact, DB::EventInfo &dbei) override;
+ HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override;
+
+ void OnBuildProtoMenu(void) override;
+ bool OnContactDeleted(MCONTACT, uint32_t flags) override;
+ MWindow OnCreateAccMgrUI(MWindow) override;
+ void OnEventEdited(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO &dbei) override;
+ void OnEventDeleted(MCONTACT hContact, MEVENT hDbEvent, int flags) override;
+ void OnMarkRead(MCONTACT, MEVENT) override;
+ void OnModulesLoaded() override;
+ void OnReceiveOfflineFile(DB::EventInfo &dbei, DB::FILE_BLOB &blob) override;
+ void OnShutdown() override;
+
+ // menus
+ static void InitMenus();
+
+ // popups
+ void InitPopups();
+ void UninitPopups();
+
+ // search
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // settings
+
+ CMOption<bool> m_bAutoHistorySync;
+ CMOption<bool> m_bUseBBCodes;
+
+ CMOption<bool> m_bUseHostnameAsPlace;
+ CMOption<wchar_t*> m_wstrPlace;
+
+ CMOption<wchar_t*> m_wstrCListGroup;
+
+ CMOption<uint8_t> m_iMood;
+ CMOption<wchar_t*> m_wstrMoodMessage, m_wstrMoodEmoji;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // other data
+
+ int m_iPollingId, m_iMessageId = 1;
+ CMStringA m_szSkypename, m_szMyname, m_szOwnSkypeId, m_szSkypeToken, m_szEndpoint, m_szApiCookie;
+ MCONTACT m_hMyContact;
+
+ __forceinline CMStringA getId(MCONTACT hContact) {
+ return getMStringA(hContact, DBKEY_ID);
+ }
+
+private:
+ bool m_bHistorySynced;
+
+ static std::map<std::wstring, std::wstring> languages;
+
+ LIST<void> m_PopupClasses;
+
+ // avatars
+ bool ReceiveAvatar(MCONTACT hContact);
+ void OnReceiveAvatar(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ void SetAvatarUrl(MCONTACT hContact, const CMStringW &tszUrl);
+
+ void ReloadAvatarInfo(MCONTACT hContact);
+ void GetAvatarFileName(MCONTACT hContact, wchar_t *pszDest, size_t cbLen);
+
+ INT_PTR __cdecl SvcGetAvatarInfo(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcGetAvatarCaps(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcGetMyAvatar(WPARAM, LPARAM);
+
+ void OnSentAvatar(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ INT_PTR __cdecl SvcSetMyAvatar(WPARAM, LPARAM);
+
+ // chats
+ void InitGroupChatModule();
+
+ int __cdecl OnGroupChatEventHook(WPARAM, LPARAM lParam);
+ int __cdecl OnGroupChatMenuHook(WPARAM, LPARAM lParam);
+ INT_PTR __cdecl OnJoinChatRoom(WPARAM hContact, LPARAM);
+ INT_PTR __cdecl OnLeaveChatRoom(WPARAM hContact, LPARAM);
+
+ void OnGetChatInfo(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void GetChatInfo(const wchar_t *chatId);
+
+ void OnGetChatMembers(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void GetChatMembers(const LIST<char> &ids, SESSION_INFO *si);
+
+ SESSION_INFO *StartChatRoom(const wchar_t *tid, const wchar_t *tname, const char *pszVersion = nullptr);
+
+ bool OnChatEvent(const JSONNode &node);
+ wchar_t *GetChatContactNick(SESSION_INFO *si, const wchar_t *id, const wchar_t *name = nullptr, bool *isQualified = nullptr);
+
+ bool AddChatContact(SESSION_INFO *si, const wchar_t *id, const wchar_t *role, bool isChange = false);
+ void RemoveChatContact(SESSION_INFO *si, const wchar_t *id, const wchar_t *initiator = L"");
+ void SendChatMessage(SESSION_INFO *si, const wchar_t *tszMessage);
+
+ void InviteUserToChat(const char *chatId, const char *skypename, const char *role);
+ void KickChatUser(const char *chatId, const char *userId);
+ void SetChatProperty(const char *chatId, const char *propname, const char *value);
+ void SetChatStatus(MCONTACT hContact, int iStatus);
+
+ bool ParseMessage(const JSONNode &node, DB::EventInfo &dbei);
+
+ // contacts
+ void LoadContactsAuth(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnGotContactsInfo(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ void GetShortInfo(const OBJLIST<char> &ids);
+ void RefreshContactsInfo();
+ void SetContactStatus(MCONTACT hContact, uint16_t status);
+
+ MCONTACT FindContact(const char *skypeId);
+ MCONTACT FindContact(const wchar_t *skypeId);
+
+ MCONTACT AddContact(const char *skypename, const char *nick, bool isTemporary = false);
+
+ MCONTACT GetContactFromAuthEvent(MEVENT hEvent);
+
+ INT_PTR __cdecl BlockContact(WPARAM hContact, LPARAM);
+ void OnBlockContact(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ INT_PTR __cdecl UnblockContact(WPARAM hContact, LPARAM);
+ void OnUnblockContact(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ // files
+ void SendFile(CFileUploadParam *fup);
+ void OnASMObjectCreated(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnASMObjectUploaded(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ void __cdecl ReceiveFileThread(void *param);
+
+ INT_PTR __cdecl SvcOfflineFile(WPARAM, LPARAM);
+
+ // history
+ void FetchMissingHistory(const JSONNode &node, MCONTACT);
+ void GetServerHistory(MCONTACT hContact, int pageSize, int64_t timestamp, bool bOperative);
+ void RefreshConversations();
+
+ void OnGetServerHistory(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnSyncConversations(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ // http queue
+ bool m_isTerminated = true;
+ mir_cs m_requestQueueLock;
+ LIST<AsyncHttpRequest> m_requests;
+ MEventHandle m_hRequestQueueEvent;
+ HANDLE m_hRequestQueueThread;
+ CMStringA m_szAccessToken, m_szSubstrateToken;
+
+ void __cdecl WorkerThread(void *);
+
+ void StartQueue();
+ void StopQueue();
+
+ MHttpResponse *DoSend(AsyncHttpRequest *request);
+
+ void Execute(AsyncHttpRequest *request);
+ void PushRequest(AsyncHttpRequest *request);
+
+ // login
+ CMStringW m_wszUserCode;
+ CMStringA m_szDeviceCode, m_szDeviceCookie, m_szVerificationUrl;
+ time_t m_iLoginExpires;
+
+ void Login();
+ void LoggedIn();
+ void LoginPoll();
+ void LoginError();
+
+ void OnEndpointCreated(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnReceiveApiCookie(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ void OauthRefreshServices();
+ void RefreshToken(const char *pszScope, AsyncHttpRequest::MTHttpRequestHandler pFunc);
+
+ void OnReceiveSkypeToken(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnReceiveDevicePoll(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnReceiveDeviceToken(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnRefreshAccessToken(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnRefreshSkypeToken(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnRefreshSubstrate(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ // menus
+ static HGENMENU ContactMenuItems[CMI_MAX];
+ int OnPrebuildContactMenu(WPARAM hContact, LPARAM);
+ static int PrebuildContactMenu(WPARAM hContact, LPARAM lParam);
+
+ // messages
+ mir_cs m_lckOutMessagesList;
+ LIST<COwnMessage> m_OutMessages;
+
+ void OnMessageSent(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ int SendServerMsg(MCONTACT hContact, const char *szMessage, int64_t iMessageId = 0);
+
+ int __cdecl OnPreCreateMessage(WPARAM, LPARAM lParam);
+
+ void ProcessContactRecv(MCONTACT hContact, const char *szContent, DB::EventInfo &dbei);
+ void ProcessFileRecv(MCONTACT hContact, const char *szContent, DB::EventInfo &dbei);
+
+ // options
+ int __cdecl OnOptionsInit(WPARAM wParam, LPARAM lParam);
+
+ // profile
+ void OnGetProfileInfo(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void GetProfileInfo(MCONTACT hContact);
+
+ void UpdateProfileDisplayName(const JSONNode &root, MCONTACT hContact = NULL);
+ void UpdateProfileGender(const JSONNode &root, MCONTACT hContact = NULL);
+ void UpdateProfileBirthday(const JSONNode &root, MCONTACT hContact = NULL);
+ void UpdateProfileCountry(const JSONNode &node, MCONTACT hContact = NULL);
+ void UpdateProfileEmails(const JSONNode &root, MCONTACT hContact = NULL);
+ void UpdateProfileAvatar(const JSONNode &root, MCONTACT hContact = NULL);
+
+ // search
+ void OnSearch(MHttpResponse *response, AsyncHttpRequest *pRequest);
+
+ // server requests
+ void OnStatusChanged(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void SetServerStatus(int iStatus);
+
+ void CreateContactSubscription();
+
+ // utils
+ __forceinline bool IsOnline() const
+ { return (m_iStatus > ID_STATUS_OFFLINE);
+ }
+
+ bool IsMe(const wchar_t *str);
+ bool IsMe(const char *str);
+
+ int64_t getLastTime(MCONTACT);
+ void setLastTime(MCONTACT, int64_t);
+
+ CMStringW RemoveHtml(const CMStringW &src);
+
+ void ShowNotification(const wchar_t *message, MCONTACT hContact = NULL);
+ void ShowNotification(const wchar_t *caption, const wchar_t *message, MCONTACT hContact = NULL, int type = 0);
+ static bool IsFileExists(std::wstring path);
+
+ static LRESULT CALLBACK PopupDlgProcCall(HWND hPopup, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ void SetString(MCONTACT hContact, const char *pszSetting, const JSONNode &node);
+
+ CMStringW ChangeTopicForm();
+
+ // services
+ INT_PTR __cdecl OnRequestAuth(WPARAM hContact, LPARAM);
+ INT_PTR __cdecl OnGrantAuth(WPARAM hContact, LPARAM);
+ INT_PTR __cdecl SvcLoadHistory(WPARAM hContact, LPARAM);
+ INT_PTR __cdecl SvcEmptyHistory(WPARAM hContact, LPARAM);
+ INT_PTR __cdecl SvcCreateChat(WPARAM, LPARAM);
+ INT_PTR __cdecl ParseSkypeUriService(WPARAM, LPARAM lParam);
+
+ // trouter
+public:
+ void TRouterProcess(const char *str);
+
+private:
+ HNETLIBUSER m_hTrouterNetlibUser;
+ CMStringA m_szTrouterUrl, m_szTrouterSurl;
+ WebSocket<CTeamsProto> *m_ws;
+ MHttpHeaders m_connectParams;
+ int iCommandId;
+
+ void ProcessEvent(const JSONNode &node);
+ void ProcessNewMessage(const JSONNode &node);
+ void ProcessUserPresence(const JSONNode &node);
+ void ProcessThreadUpdate(const JSONNode &node);
+ void ProcessServerMessage(const std::string &szName, int packetId, const JSONNode &args);
+ void ProcessConversationUpdate(const JSONNode &node);
+
+ void __cdecl GatewayThread(void *);
+ void GatewayThreadWorker();
+
+ void TRouterSendJson(const char *szName, const JSONNode *node = nullptr, int iReplyTo = -1);
+ void TRouterSendJson(const JSONNode &node, int iReplyTo = -1);
+
+ void TRouterSendActive(bool bActive, int iReplyTo = -1);
+ void TRouterRegister();
+ void TRouterRegister(const char *pszAppId, const char *pszKey, const char *pszPath, const char *pszContext);
+
+ void StartTrouter();
+ void StopTrouter();
+
+ void OnTrouterInfo(MHttpResponse *response, AsyncHttpRequest *pRequest);
+ void OnTrouterSession(MHttpResponse *response, AsyncHttpRequest *pRequest);
+};
+
+typedef CProtoDlgBase<CTeamsProto> CTeamsDlgBase;
+
+struct CMPlugin : public ACCPROTOPLUGIN<CTeamsProto>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};