From 13eb656152eb83e6b246293da72294ce22c6cc48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20P=C3=B6sel?= Date: Mon, 8 Dec 2014 22:57:21 +0000 Subject: Steam: Support for sending to server how long are we idle git-svn-id: http://svn.miranda-ng.org/main/trunk@11290 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Steam/src/Steam/poll.h | 4 +- protocols/Steam/src/common.h | 91 ++-- protocols/Steam/src/steam_events.cpp | 166 ++++--- protocols/Steam/src/steam_pooling.cpp | 2 +- protocols/Steam/src/steam_proto.cpp | 829 +++++++++++++++++----------------- protocols/Steam/src/steam_proto.h | 565 +++++++++++------------ 6 files changed, 851 insertions(+), 806 deletions(-) (limited to 'protocols/Steam/src') diff --git a/protocols/Steam/src/Steam/poll.h b/protocols/Steam/src/Steam/poll.h index 7411ad85e6..35d8330385 100644 --- a/protocols/Steam/src/Steam/poll.h +++ b/protocols/Steam/src/Steam/poll.h @@ -6,14 +6,14 @@ namespace SteamWebApi class PollRequest : public HttpsPostRequest { public: - PollRequest(const char *token, const char *umqId, UINT32 messageId) : + PollRequest(const char *token, const char *umqId, UINT32 messageId, int idleSeconds) : HttpsPostRequest(STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001") { timeout = 30000; flags |= NLHRF_PERSISTENT; char data[256]; - mir_snprintf(data, SIZEOF(data), "access_token=%s&umqid=%s&message=%u", token, umqId, messageId); + mir_snprintf(data, SIZEOF(data), "access_token=%s&umqid=%s&message=%u&secidletime=%d", token, umqId, messageId, idleSeconds); SetData(data, strlen(data)); AddHeader("Connection", "keep-alive"); diff --git a/protocols/Steam/src/common.h b/protocols/Steam/src/common.h index 4c43df32b7..36427d7a1c 100644 --- a/protocols/Steam/src/common.h +++ b/protocols/Steam/src/common.h @@ -1,46 +1,47 @@ -#ifndef _COMMON_H_ -#define _COMMON_H_ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "resource.h" -#include "version.h" - -#define MODULE "Steam" - -class CSteamProto; -extern HINSTANCE g_hInstance; - -#include "Steam\steam.h" - -#include "steam_proto.h" - +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "resource.h" +#include "version.h" + +#define MODULE "Steam" + +class CSteamProto; +extern HINSTANCE g_hInstance; + +#include "Steam\steam.h" + +#include "steam_proto.h" + #endif //_COMMON_H_ \ No newline at end of file diff --git a/protocols/Steam/src/steam_events.cpp b/protocols/Steam/src/steam_events.cpp index 4a61c913ef..3c8d758f54 100644 --- a/protocols/Steam/src/steam_events.cpp +++ b/protocols/Steam/src/steam_events.cpp @@ -1,67 +1,101 @@ -#include "common.h" - -int CSteamProto::OnModulesLoaded(WPARAM, LPARAM) -{ - HookEventObj(ME_OPT_INITIALISE, OnOptionsInit, this); - - TCHAR name[128]; - mir_sntprintf(name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName); - - NETLIBUSER nlu = { sizeof(nlu) }; - nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR; - nlu.ptszDescriptiveName = name; - nlu.szSettingsModule = m_szModuleName; - m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); - - HookEvent(ME_CLIST_PREBUILDCONTACTMENU, &CSteamProto::PrebuildContactMenu); - - return 0; -} - -int CSteamProto::OnPreShutdown(WPARAM, LPARAM) -{ - //SetStatus(ID_STATUS_OFFLINE); - - Netlib_CloseHandle(this->m_hNetlibUser); - this->m_hNetlibUser = NULL; - - return 0; -} - -INT_PTR CSteamProto::OnAccountManagerInit(WPARAM wParam, LPARAM lParam) -{ - return (int)CreateDialogParam( - g_hInstance, - MAKEINTRESOURCE(IDD_ACCMGR), - (HWND)lParam, - CSteamProto::MainOptionsProc, - (LPARAM)this); -} - -int CSteamProto::OnOptionsInit(void *obj, WPARAM wParam, LPARAM lParam) -{ - CSteamProto *instance = (CSteamProto*)obj; - - char *title = mir_t2a(instance->m_tszUserName); - - OPTIONSDIALOGPAGE odp = { sizeof(odp) }; - odp.hInstance = g_hInstance; - odp.pszTitle = title; - odp.dwInitParam = LPARAM(obj); - odp.flags = ODPF_BOLDGROUPS; - odp.pszGroup = LPGEN("Network"); - - odp.pszTab = LPGEN("Account"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MAIN); - odp.pfnDlgProc = MainOptionsProc; - Options_AddPage(wParam, &odp); - - odp.pszTab = LPGEN("Blocked contacts"); - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_BLOCK_LIST); - odp.pfnDlgProc = BlockListOptionsProc; - Options_AddPage(wParam, &odp); - - mir_free(title); - - return 0; +#include "common.h" + +int CSteamProto::OnModulesLoaded(WPARAM, LPARAM) +{ + HookEventObj(ME_OPT_INITIALISE, OnOptionsInit, this); + HookProtoEvent(ME_IDLE_CHANGED, &CSteamProto::OnIdleChanged); + + TCHAR name[128]; + mir_sntprintf(name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName); + + NETLIBUSER nlu = { sizeof(nlu) }; + nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR; + nlu.ptszDescriptiveName = name; + nlu.szSettingsModule = m_szModuleName; + m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + + HookEvent(ME_CLIST_PREBUILDCONTACTMENU, &CSteamProto::PrebuildContactMenu); + + return 0; +} + +int CSteamProto::OnPreShutdown(WPARAM, LPARAM) +{ + //SetStatus(ID_STATUS_OFFLINE); + + Netlib_CloseHandle(this->m_hNetlibUser); + this->m_hNetlibUser = NULL; + + return 0; +} + +INT_PTR CSteamProto::OnAccountManagerInit(WPARAM wParam, LPARAM lParam) +{ + return (int)CreateDialogParam( + g_hInstance, + MAKEINTRESOURCE(IDD_ACCMGR), + (HWND)lParam, + CSteamProto::MainOptionsProc, + (LPARAM)this); +} + +int CSteamProto::OnOptionsInit(void *obj, WPARAM wParam, LPARAM lParam) +{ + CSteamProto *instance = (CSteamProto*)obj; + + char *title = mir_t2a(instance->m_tszUserName); + + OPTIONSDIALOGPAGE odp = { sizeof(odp) }; + odp.hInstance = g_hInstance; + odp.pszTitle = title; + odp.dwInitParam = LPARAM(obj); + odp.flags = ODPF_BOLDGROUPS; + odp.pszGroup = LPGEN("Network"); + + odp.pszTab = LPGEN("Account"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MAIN); + odp.pfnDlgProc = MainOptionsProc; + Options_AddPage(wParam, &odp); + + odp.pszTab = LPGEN("Blocked contacts"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_BLOCK_LIST); + odp.pfnDlgProc = BlockListOptionsProc; + Options_AddPage(wParam, &odp); + + mir_free(title); + + return 0; +} + +int CSteamProto::OnIdleChanged(WPARAM 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) + 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 = { sizeof(mii) }; + CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&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"); + } + + return 0; } \ No newline at end of file diff --git a/protocols/Steam/src/steam_pooling.cpp b/protocols/Steam/src/steam_pooling.cpp index 41adf28304..ff21a8e9c2 100644 --- a/protocols/Steam/src/steam_pooling.cpp +++ b/protocols/Steam/src/steam_pooling.cpp @@ -177,7 +177,7 @@ void CSteamProto::PollingThread(void*) bool breaked = false; while (!isTerminated && !breaked && errors < POLLING_ERRORS_LIMIT) { - SteamWebApi::PollRequest *request = new SteamWebApi::PollRequest(token, umqId, messageId); + SteamWebApi::PollRequest *request = new SteamWebApi::PollRequest(token, umqId, messageId, IdleSeconds()); debugLogA("CSteamProto::PollingThread: %s", request->szUrl); request->szUrl = (char*)request->url.c_str(); request->nlc = m_pollingConnection; diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp index f2878659f0..612d66768f 100644 --- a/protocols/Steam/src/steam_proto.cpp +++ b/protocols/Steam/src/steam_proto.cpp @@ -1,413 +1,418 @@ -#include "common.h" - -CSteamProto::CSteamProto(const char* protoName, const TCHAR* userName) : - PROTO(protoName, userName), - hAuthProcess(1), - hMessageProcess(1), - requestsQueue(1) -{ - CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit); - - InitializeCriticalSection(&this->contact_search_lock); - - InitQueue(); - - // icons - wchar_t filePath[MAX_PATH]; - GetModuleFileName(g_hInstance, filePath, MAX_PATH); - - wchar_t sectionName[100]; - mir_sntprintf(sectionName, SIZEOF(sectionName), _T("%s/%s"), LPGENT("Protocols"), LPGENT(MODULE)); - - char settingName[100]; - mir_snprintf(settingName, SIZEOF(settingName), "%s_%s", MODULE, "main"); - - SKINICONDESC sid = {0}; - sid.cbSize = sizeof(SKINICONDESC); - sid.flags = SIDF_ALL_TCHAR; - sid.ptszDefaultFile = filePath; - sid.pszName = settingName; - sid.ptszSection = sectionName; - sid.ptszDescription = LPGENT("Protocol icon"); - sid.iDefaultIndex = -IDI_STEAM; - Skin_AddIcon(&sid); - - SetAllContactsStatus(ID_STATUS_OFFLINE); - - // services - CreateServiceFunction(MODULE"/MenuChoose", CSteamProto::MenuChooseService); - // avatar API - CreateProtoService(PS_GETAVATARINFOT, &CSteamProto::GetAvatarInfo); - CreateProtoService(PS_GETAVATARCAPS, &CSteamProto::GetAvatarCaps); - CreateProtoService(PS_GETMYAVATART, &CSteamProto::GetMyAvatar); -} - -CSteamProto::~CSteamProto() -{ - UninitQueue(); - - DeleteCriticalSection(&this->contact_search_lock); -} - -MCONTACT __cdecl CSteamProto::AddToList(int flags, PROTOSEARCHRESULT* psr) -{ - MCONTACT hContact = NULL; - ptrA steamId(mir_u2a(psr->id)); - if (psr->cbSize == sizeof(PROTOSEARCHRESULT)) - { - if (!FindContact(steamId)) - { - //hContact = AddContact(steamId, true); - //ForkThread(&CSteamProto::UpdateContactsThread, (void*)mir_strdup(steamId)); - - ptrA token(getStringA("TokenSecret")); - - PushRequest( - new SteamWebApi::GetUserSummariesRequest(token, steamId), - &CSteamProto::OnGotUserSummaries); - } - } - else if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) - { - STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT*)psr; - hContact = AddContact(steamId, true); - UpdateContact(hContact, ssr->data); - } - - return hContact; -} - -MCONTACT __cdecl CSteamProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent) -{ - return 0; -} - -int __cdecl CSteamProto::Authorize(HANDLE hDbEvent) -{ - if (IsOnline() && hDbEvent) - { - MCONTACT hContact = GetContactFromAuthEvent(hDbEvent); - if (hContact == INVALID_CONTACT_ID) - return 1; - - //ForkThread(&CSteamProto::AuthAllowThread, (void*)hContact); - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - char *who = getStringA(hContact, "SteamID"); - - PushRequest( - new SteamWebApi::ApprovePendingRequest(token, sessionId, steamId, who), - &CSteamProto::OnPendingApproved, - who); - - return 0; - } - - return 1; -} - -int __cdecl CSteamProto::AuthDeny(HANDLE hDbEvent, const TCHAR* szReason) -{ - if (IsOnline() && hDbEvent) - { - MCONTACT hContact = GetContactFromAuthEvent(hDbEvent); - if (hContact == INVALID_CONTACT_ID) - return 1; - - //ForkThread(&CSteamProto::AuthDenyThread, (void*)hContact); - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - char *who = getStringA(hContact, "SteamID"); - - PushRequest( - new SteamWebApi::IgnorePendingRequest(token, sessionId, steamId, who), - &CSteamProto::OnPendingIgnoreded, - who); - - return 0; - } - - return 1; -} - -int __cdecl CSteamProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT* pre) -{ - return 0; -} - -int __cdecl CSteamProto::AuthRequest(MCONTACT hContact, const TCHAR* szMessage) -{ - if (IsOnline() && hContact) - { - UINT hAuth = InterlockedIncrement(&hAuthProcess); - - SendAuthParam *param = (SendAuthParam*)mir_calloc(sizeof(SendAuthParam)); - param->hContact = hContact; - param->hAuth = (HANDLE)hAuth; - - //ForkThread(&CSteamProto::AddContactThread, param); - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - ptrA who(getStringA(hContact, "SteamID")); - - PushRequest( - new SteamWebApi::AddFriendRequest(token, sessionId, steamId, who), - &CSteamProto::OnFriendAdded, - param); - - return hAuth; - } - - return 1; -} - -HANDLE __cdecl CSteamProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath) -{ - return 0; -} - -int __cdecl CSteamProto::FileCancel(MCONTACT hContact, HANDLE hTransfer) -{ - return 0; -} - -int __cdecl CSteamProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason) -{ - return 0; -} - -int __cdecl CSteamProto::FileResume(HANDLE hTransfer, int* action, const TCHAR** szFilename) -{ - return 0; -} - -DWORD_PTR __cdecl CSteamProto:: GetCaps(int type, MCONTACT hContact) -{ - switch(type) - { - case PFLAGNUM_1: - return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES; - case PFLAGNUM_2: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_OUTTOLUNCH; - case PFLAGNUM_4: - return PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH | PF4_FORCEADDED | PF4_IMSENDUTF;// | PF4_IMSENDOFFLINE | PF4_SUPPORTTYPING; - case PFLAGNUM_5: - return PF2_SHORTAWAY | PF2_HEAVYDND | PF2_OUTTOLUNCH; - case PFLAG_UNIQUEIDTEXT: - return (DWORD_PTR)Translate("SteamID"); - case PFLAG_UNIQUEIDSETTING: - return (DWORD_PTR)"SteamID"; - case PFLAG_MAXLENOFMESSAGE: - return 200000; // this is guessed limit, in reality it is probably bigger - default: - return 0; - } -} - -int __cdecl CSteamProto::GetInfo(MCONTACT hContact, int infoType ) { return 0; } - -HANDLE __cdecl CSteamProto::SearchBasic(const TCHAR* id) -{ - if (!this->IsOnline()) - return 0; - - //ForkThread(&CSteamProto::SearchByIdThread, mir_wstrdup(id)); - - ptrA token(getStringA("TokenSecret")); - ptrA steamId(mir_u2a(id)); - - PushRequest( - new SteamWebApi::GetUserSummariesRequest(token, steamId), - &CSteamProto::OnSearchByIdEnded, - mir_wstrdup(id)); - - return (HANDLE)STEAM_SEARCH_BYID; -} - -HANDLE __cdecl CSteamProto::SearchByEmail(const TCHAR* email) -{ - return 0; -} - -HANDLE __cdecl CSteamProto::SearchByName(const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName) -{ - //if (!this->IsOnline()) - return 0; - - ptrA token(getStringA("TokenSecret")); - - CMString keywords; - keywords.AppendFormat(L" %s", nick); - keywords.AppendFormat(L" %s", firstName); - keywords.AppendFormat(L" %s", lastName); - keywords.Trim(); - - //ForkThread(&CSteamProto::SearchByNameThread, mir_wstrdup(keywords)); - PushRequest( - new SteamWebApi::SearchRequest(token, mir_utf8encodeW(keywords)), - &CSteamProto::OnSearchByNameStarted); - - return (HANDLE)STEAM_SEARCH_BYNAME; -} - -HWND __cdecl CSteamProto::SearchAdvanced( HWND owner ) { return 0; } - -HWND __cdecl CSteamProto::CreateExtendedSearchUI( HWND owner ){ return 0; } - -int __cdecl CSteamProto::RecvContacts(MCONTACT hContact, PROTORECVEVENT* pre) -{ - return 0; -} - -int __cdecl CSteamProto::RecvFile(MCONTACT hContact, PROTORECVFILET* pre) -{ - return 0; -} - -int __cdecl CSteamProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT* pre) -{ - return (INT_PTR)AddDBEvent(hContact, EVENTTYPE_MESSAGE, pre->timestamp, DBEF_UTF, lstrlenA(pre->szMessage), (BYTE*)pre->szMessage); -} - -int __cdecl CSteamProto::RecvUrl(MCONTACT hContact, PROTORECVEVENT *) { return 0; } - -int __cdecl CSteamProto::SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList) -{ - return 0; -} - -HANDLE __cdecl CSteamProto::SendFile(MCONTACT hContact, const TCHAR *szDescription, TCHAR **ppszFiles) -{ - return 0; -} - -int __cdecl CSteamProto::SendMsg(MCONTACT hContact, int flags, const char *msg) -{ - UINT hMessage = InterlockedIncrement(&hMessageProcess); - - if (flags & PREF_UNICODE) - msg = mir_utf8encode(msg); // FIXME: Token from FacebookRM. Is it needed? Usually we get PREF_UTF8 flag instead. And does it cause memory leak? - - SendMessageParam *param = (SendMessageParam*)mir_calloc(sizeof(SendMessageParam)); - param->hContact = hContact; - param->hMessage = (HANDLE)hMessage; - - - ptrA token(getStringA("TokenSecret")); - ptrA umqid(getStringA("UMQID")); - ptrA steamId(getStringA(hContact, "SteamID")); - - PushRequest( - new SteamWebApi::SendMessageRequest(token, umqid, steamId, msg), - &CSteamProto::OnMessageSent, - param); - - return hMessage; -} - -int __cdecl CSteamProto::SendUrl(MCONTACT hContact, int flags, const char *url) { return 0; } - -int __cdecl CSteamProto::SetApparentMode(MCONTACT hContact, int mode) { return 0; } - -int CSteamProto::SetStatus(int new_status) -{ - // Routing statuses not supported by Steam - switch (new_status) - { - case ID_STATUS_OFFLINE: - break; - - default: - new_status = ID_STATUS_ONLINE; - break; - } - - if (new_status == m_iDesiredStatus) - return 0; - - debugLog(_T("CSteamProto::SetStatus: changing status from %i to %i"), m_iStatus, new_status); - - int old_status = m_iStatus; - m_iDesiredStatus = new_status; - - if (new_status == ID_STATUS_OFFLINE) - { - //isTerminated = true; - //ForkThread(&CSteamProto::LogOutThread, NULL); - - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - - StopQueue(); - - if (!Miranda_Terminated()) - SetAllContactsStatus(ID_STATUS_OFFLINE); - } - else if (old_status == ID_STATUS_OFFLINE) - { - m_iStatus = ID_STATUS_CONNECTING; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - - //ForkThread(&CSteamProto::LogInThread, NULL); - StartQueue(); - } - - return 0; -} - -HANDLE __cdecl CSteamProto::GetAwayMsg(MCONTACT hContact) { return 0; } -int __cdecl CSteamProto::RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt) { return 0; } -int __cdecl CSteamProto::SetAwayMsg(int m_iStatus, const TCHAR *msg) { return 0; } - -int __cdecl CSteamProto::UserIsTyping(MCONTACT hContact, int type) -{ - return 0; -} - -int __cdecl CSteamProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam) -{ - switch (eventType) - { - case EV_PROTO_ONLOAD: - return this->OnModulesLoaded(wParam, lParam); - - case EV_PROTO_ONEXIT: - return this->OnPreShutdown(wParam, lParam); - - /*case EV_PROTO_ONOPTIONS: - return this->OnOptionsInit(wParam, lParam);*/ - - case EV_PROTO_ONCONTACTDELETED: - if (IsOnline()) - { - MCONTACT hContact = (MCONTACT)wParam; - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - ptrA who(getStringA(hContact, "SteamID")); - - // Don't request delete contact from server when we're not friends anyway - if (getByte(hContact, "Auth", 0) != 0) - return 0; - - PushRequest( - new SteamWebApi::RemoveFriendRequest(token, sessionId, steamId, who), - &CSteamProto::OnFriendRemoved, - (void*)hContact); - } - return 0; - - case EV_PROTO_ONMENU: - this->OnInitStatusMenu(); - break; - } - - return 1; +#include "common.h" + +CSteamProto::CSteamProto(const char* protoName, const TCHAR* userName) : + PROTO(protoName, userName), + hAuthProcess(1), + hMessageProcess(1), + requestsQueue(1) +{ + CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit); + + InitializeCriticalSection(&this->contact_search_lock); + + InitQueue(); + + m_idleTS = 0; + + // icons + wchar_t filePath[MAX_PATH]; + GetModuleFileName(g_hInstance, filePath, MAX_PATH); + + wchar_t sectionName[100]; + mir_sntprintf(sectionName, SIZEOF(sectionName), _T("%s/%s"), LPGENT("Protocols"), LPGENT(MODULE)); + + char settingName[100]; + mir_snprintf(settingName, SIZEOF(settingName), "%s_%s", MODULE, "main"); + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.flags = SIDF_ALL_TCHAR; + sid.ptszDefaultFile = filePath; + sid.pszName = settingName; + sid.ptszSection = sectionName; + sid.ptszDescription = LPGENT("Protocol icon"); + sid.iDefaultIndex = -IDI_STEAM; + Skin_AddIcon(&sid); + + // temporary DB settings + db_set_resident(m_szModuleName, "IdleTS"); + + SetAllContactsStatus(ID_STATUS_OFFLINE); + + // services + CreateServiceFunction(MODULE"/MenuChoose", CSteamProto::MenuChooseService); + // avatar API + CreateProtoService(PS_GETAVATARINFOT, &CSteamProto::GetAvatarInfo); + CreateProtoService(PS_GETAVATARCAPS, &CSteamProto::GetAvatarCaps); + CreateProtoService(PS_GETMYAVATART, &CSteamProto::GetMyAvatar); +} + +CSteamProto::~CSteamProto() +{ + UninitQueue(); + + DeleteCriticalSection(&this->contact_search_lock); +} + +MCONTACT __cdecl CSteamProto::AddToList(int flags, PROTOSEARCHRESULT* psr) +{ + MCONTACT hContact = NULL; + ptrA steamId(mir_u2a(psr->id)); + if (psr->cbSize == sizeof(PROTOSEARCHRESULT)) + { + if (!FindContact(steamId)) + { + //hContact = AddContact(steamId, true); + //ForkThread(&CSteamProto::UpdateContactsThread, (void*)mir_strdup(steamId)); + + ptrA token(getStringA("TokenSecret")); + + PushRequest( + new SteamWebApi::GetUserSummariesRequest(token, steamId), + &CSteamProto::OnGotUserSummaries); + } + } + else if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) + { + STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT*)psr; + hContact = AddContact(steamId, true); + UpdateContact(hContact, ssr->data); + } + + return hContact; +} + +MCONTACT __cdecl CSteamProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent) +{ + return 0; +} + +int __cdecl CSteamProto::Authorize(HANDLE hDbEvent) +{ + if (IsOnline() && hDbEvent) + { + MCONTACT hContact = GetContactFromAuthEvent(hDbEvent); + if (hContact == INVALID_CONTACT_ID) + return 1; + + //ForkThread(&CSteamProto::AuthAllowThread, (void*)hContact); + + ptrA token(getStringA("TokenSecret")); + ptrA sessionId(getStringA("SessionID")); + ptrA steamId(getStringA("SteamID")); + char *who = getStringA(hContact, "SteamID"); + + PushRequest( + new SteamWebApi::ApprovePendingRequest(token, sessionId, steamId, who), + &CSteamProto::OnPendingApproved, + who); + + return 0; + } + + return 1; +} + +int __cdecl CSteamProto::AuthDeny(HANDLE hDbEvent, const TCHAR* szReason) +{ + if (IsOnline() && hDbEvent) + { + MCONTACT hContact = GetContactFromAuthEvent(hDbEvent); + if (hContact == INVALID_CONTACT_ID) + return 1; + + //ForkThread(&CSteamProto::AuthDenyThread, (void*)hContact); + + ptrA token(getStringA("TokenSecret")); + ptrA sessionId(getStringA("SessionID")); + ptrA steamId(getStringA("SteamID")); + char *who = getStringA(hContact, "SteamID"); + + PushRequest( + new SteamWebApi::IgnorePendingRequest(token, sessionId, steamId, who), + &CSteamProto::OnPendingIgnoreded, + who); + + return 0; + } + + return 1; +} + +int __cdecl CSteamProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT* pre) +{ + return 0; +} + +int __cdecl CSteamProto::AuthRequest(MCONTACT hContact, const TCHAR* szMessage) +{ + if (IsOnline() && hContact) + { + UINT hAuth = InterlockedIncrement(&hAuthProcess); + + SendAuthParam *param = (SendAuthParam*)mir_calloc(sizeof(SendAuthParam)); + param->hContact = hContact; + param->hAuth = (HANDLE)hAuth; + + //ForkThread(&CSteamProto::AddContactThread, param); + + ptrA token(getStringA("TokenSecret")); + ptrA sessionId(getStringA("SessionID")); + ptrA steamId(getStringA("SteamID")); + ptrA who(getStringA(hContact, "SteamID")); + + PushRequest( + new SteamWebApi::AddFriendRequest(token, sessionId, steamId, who), + &CSteamProto::OnFriendAdded, + param); + + return hAuth; + } + + return 1; +} + +HANDLE __cdecl CSteamProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath) +{ + return 0; +} + +int __cdecl CSteamProto::FileCancel(MCONTACT hContact, HANDLE hTransfer) +{ + return 0; +} + +int __cdecl CSteamProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason) +{ + return 0; +} + +int __cdecl CSteamProto::FileResume(HANDLE hTransfer, int* action, const TCHAR** szFilename) +{ + return 0; +} + +DWORD_PTR __cdecl CSteamProto:: GetCaps(int type, MCONTACT hContact) +{ + switch(type) + { + case PFLAGNUM_1: + return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES; + case PFLAGNUM_2: + return PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_OUTTOLUNCH; + case PFLAGNUM_4: + return PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH | PF4_FORCEADDED | PF4_IMSENDUTF | PF4_SUPPORTIDLE;// | PF4_IMSENDOFFLINE | PF4_SUPPORTTYPING; + case PFLAGNUM_5: + return PF2_SHORTAWAY | PF2_HEAVYDND | PF2_OUTTOLUNCH; + case PFLAG_UNIQUEIDTEXT: + return (DWORD_PTR)Translate("SteamID"); + case PFLAG_UNIQUEIDSETTING: + return (DWORD_PTR)"SteamID"; + case PFLAG_MAXLENOFMESSAGE: + return 200000; // this is guessed limit, in reality it is probably bigger + default: + return 0; + } +} + +int __cdecl CSteamProto::GetInfo(MCONTACT hContact, int infoType ) { return 0; } + +HANDLE __cdecl CSteamProto::SearchBasic(const TCHAR* id) +{ + if (!this->IsOnline()) + return 0; + + //ForkThread(&CSteamProto::SearchByIdThread, mir_wstrdup(id)); + + ptrA token(getStringA("TokenSecret")); + ptrA steamId(mir_u2a(id)); + + PushRequest( + new SteamWebApi::GetUserSummariesRequest(token, steamId), + &CSteamProto::OnSearchByIdEnded, + mir_wstrdup(id)); + + return (HANDLE)STEAM_SEARCH_BYID; +} + +HANDLE __cdecl CSteamProto::SearchByEmail(const TCHAR* email) +{ + return 0; +} + +HANDLE __cdecl CSteamProto::SearchByName(const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName) +{ + //if (!this->IsOnline()) + return 0; + + ptrA token(getStringA("TokenSecret")); + + CMString keywords; + keywords.AppendFormat(L" %s", nick); + keywords.AppendFormat(L" %s", firstName); + keywords.AppendFormat(L" %s", lastName); + keywords.Trim(); + + //ForkThread(&CSteamProto::SearchByNameThread, mir_wstrdup(keywords)); + PushRequest( + new SteamWebApi::SearchRequest(token, mir_utf8encodeW(keywords)), + &CSteamProto::OnSearchByNameStarted); + + return (HANDLE)STEAM_SEARCH_BYNAME; +} + +HWND __cdecl CSteamProto::SearchAdvanced( HWND owner ) { return 0; } + +HWND __cdecl CSteamProto::CreateExtendedSearchUI( HWND owner ){ return 0; } + +int __cdecl CSteamProto::RecvContacts(MCONTACT hContact, PROTORECVEVENT* pre) +{ + return 0; +} + +int __cdecl CSteamProto::RecvFile(MCONTACT hContact, PROTORECVFILET* pre) +{ + return 0; +} + +int __cdecl CSteamProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT* pre) +{ + return (INT_PTR)AddDBEvent(hContact, EVENTTYPE_MESSAGE, pre->timestamp, DBEF_UTF, lstrlenA(pre->szMessage), (BYTE*)pre->szMessage); +} + +int __cdecl CSteamProto::RecvUrl(MCONTACT hContact, PROTORECVEVENT *) { return 0; } + +int __cdecl CSteamProto::SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList) +{ + return 0; +} + +HANDLE __cdecl CSteamProto::SendFile(MCONTACT hContact, const TCHAR *szDescription, TCHAR **ppszFiles) +{ + return 0; +} + +int __cdecl CSteamProto::SendMsg(MCONTACT hContact, int flags, const char *msg) +{ + UINT hMessage = InterlockedIncrement(&hMessageProcess); + + if (flags & PREF_UNICODE) + msg = mir_utf8encode(msg); // FIXME: Token from FacebookRM. Is it needed? Usually we get PREF_UTF8 flag instead. And does it cause memory leak? + + SendMessageParam *param = (SendMessageParam*)mir_calloc(sizeof(SendMessageParam)); + param->hContact = hContact; + param->hMessage = (HANDLE)hMessage; + + + ptrA token(getStringA("TokenSecret")); + ptrA umqid(getStringA("UMQID")); + ptrA steamId(getStringA(hContact, "SteamID")); + + PushRequest( + new SteamWebApi::SendMessageRequest(token, umqid, steamId, msg), + &CSteamProto::OnMessageSent, + param); + + return hMessage; +} + +int __cdecl CSteamProto::SendUrl(MCONTACT hContact, int flags, const char *url) { return 0; } + +int __cdecl CSteamProto::SetApparentMode(MCONTACT hContact, int mode) { return 0; } + +int CSteamProto::SetStatus(int new_status) +{ + // Routing statuses not supported by Steam + switch (new_status) + { + case ID_STATUS_OFFLINE: + break; + + default: + new_status = ID_STATUS_ONLINE; + break; + } + + if (new_status == m_iDesiredStatus) + return 0; + + debugLog(_T("CSteamProto::SetStatus: changing status from %i to %i"), m_iStatus, new_status); + + int old_status = m_iStatus; + m_iDesiredStatus = new_status; + + if (new_status == ID_STATUS_OFFLINE) + { + //isTerminated = true; + //ForkThread(&CSteamProto::LogOutThread, NULL); + + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); + + StopQueue(); + + if (!Miranda_Terminated()) + SetAllContactsStatus(ID_STATUS_OFFLINE); + } + else if (old_status == ID_STATUS_OFFLINE) + { + m_iStatus = ID_STATUS_CONNECTING; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); + + //ForkThread(&CSteamProto::LogInThread, NULL); + StartQueue(); + } + + return 0; +} + +HANDLE __cdecl CSteamProto::GetAwayMsg(MCONTACT hContact) { return 0; } +int __cdecl CSteamProto::RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt) { return 0; } +int __cdecl CSteamProto::SetAwayMsg(int m_iStatus, const TCHAR *msg) { return 0; } + +int __cdecl CSteamProto::UserIsTyping(MCONTACT hContact, int type) +{ + return 0; +} + +int __cdecl CSteamProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam) +{ + switch (eventType) + { + case EV_PROTO_ONLOAD: + return this->OnModulesLoaded(wParam, lParam); + + case EV_PROTO_ONEXIT: + return this->OnPreShutdown(wParam, lParam); + + /*case EV_PROTO_ONOPTIONS: + return this->OnOptionsInit(wParam, lParam);*/ + + case EV_PROTO_ONCONTACTDELETED: + if (IsOnline()) + { + MCONTACT hContact = (MCONTACT)wParam; + + ptrA token(getStringA("TokenSecret")); + ptrA sessionId(getStringA("SessionID")); + ptrA steamId(getStringA("SteamID")); + ptrA who(getStringA(hContact, "SteamID")); + + // Don't request delete contact from server when we're not friends anyway + if (getByte(hContact, "Auth", 0) != 0) + return 0; + + PushRequest( + new SteamWebApi::RemoveFriendRequest(token, sessionId, steamId, who), + &CSteamProto::OnFriendRemoved, + (void*)hContact); + } + return 0; + + case EV_PROTO_ONMENU: + this->OnInitStatusMenu(); + break; + } + + return 1; } \ No newline at end of file diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h index cfd173c37a..82dd4f925b 100644 --- a/protocols/Steam/src/steam_proto.h +++ b/protocols/Steam/src/steam_proto.h @@ -1,281 +1,286 @@ -#ifndef _STEAM_PROTO_H_ -#define _STEAM_PROTO_H_ - -#define STEAM_SEARCH_BYID 1001 -#define STEAM_SEARCH_BYNAME 1002 - -struct GuardParam -{ - char code[10]; - char domain[32]; -}; - -struct CaptchaParam -{ - BYTE *data; - size_t size; - char text[10]; -}; - -struct SendAuthParam -{ - MCONTACT hContact; - HANDLE hAuth; -}; - -struct SendMessageParam -{ - MCONTACT hContact; - HANDLE hMessage; -}; - -struct STEAM_SEARCH_RESULT -{ - PROTOSEARCHRESULT hdr; - JSONNODE *data; -}; - -enum -{ - CMI_AUTH_REQUEST, - //CMI_AUTH_GRANT, - //CMI_AUTH_REVOKE, - CMI_BLOCK, - CMI_JOIN_GAME, - SMI_BLOCKED_LIST, - CMI_MAX // this item shall be the last one -}; - -enum HTTP_STATUS -{ - HTTP_STATUS_NONE = 0, - HTTP_STATUS_OK = 200, - HTTP_STATUS_FOUND = 302, - HTTP_STATUS_BAD_REQUEST = 400, - HTTP_STATUS_UNAUTHORIZED = 401, - HTTP_STATUS_FORBIDDEN = 403, - HTTP_STATUS_NOT_FOUND = 404, - HTTP_STATUS_METHOD_NOT_ALLOWED = 405, - HTTP_STATUS_TOO_MANY_REQUESTS = 429, - HTTP_STATUS_SERVICE_UNAVAILABLE = 503, - HTTP_STATUS_INSUFICIENTE_STORAGE = 507 -}; - -typedef void (CSteamProto::*RESPONSE)(const NETLIBHTTPREQUEST *response, void *arg); - -struct QueueItem -{ - SteamWebApi::HttpRequest *request; - void *arg; - RESPONSE responseCallback; - RESPONSE responseFailedCallback; - - QueueItem(SteamWebApi::HttpRequest *request) : - request(request), arg(NULL), responseCallback(NULL), responseFailedCallback(NULL) { } - - QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response) : - request(request), arg(NULL), responseCallback(response), responseFailedCallback(NULL) { } - - QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response, RESPONSE responseFailedCallback) : - request(request), arg(NULL), responseCallback(response), responseFailedCallback(responseFailedCallback) { } - - ~QueueItem() { delete request; responseCallback = NULL; } -}; - -class CSteamProto : public PROTO -{ -public: - // PROTO_INTERFACE - CSteamProto(const char *protoName, const wchar_t *userName); - ~CSteamProto(); - - // PROTO_INTERFACE - virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT *psr); - virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, HANDLE hDbEvent); - - virtual int __cdecl Authorize(HANDLE hDbEvent); - virtual int __cdecl AuthDeny(HANDLE hDbEvent, const TCHAR *szReason); - virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT *); - virtual int __cdecl AuthRequest(MCONTACT hContact, const TCHAR * szMessage); - - virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath); - virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer); - virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason); - virtual int __cdecl FileResume(HANDLE hTransfer, int *action, const TCHAR** szFilename); - - virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL); - virtual int __cdecl GetInfo(MCONTACT hContact, int infoType); - - virtual HANDLE __cdecl SearchBasic(const TCHAR *id); - virtual HANDLE __cdecl SearchByEmail(const TCHAR *email); - virtual HANDLE __cdecl SearchByName(const TCHAR *nick, const TCHAR *firstName, const TCHAR *lastName); - virtual HWND __cdecl SearchAdvanced(HWND owner); - virtual HWND __cdecl CreateExtendedSearchUI(HWND owner); - - virtual int __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*); - virtual int __cdecl RecvFile(MCONTACT hContact, PROTORECVFILET*); - virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*); - virtual int __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*); - - virtual int __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList); - virtual HANDLE __cdecl SendFile(MCONTACT hContact, const TCHAR* szDescription, TCHAR** ppszFiles); - virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg); - virtual int __cdecl SendUrl(MCONTACT hContact, int flags, const char* url); - - virtual int __cdecl SetApparentMode(MCONTACT hContact, int mode); - virtual int __cdecl SetStatus(int iNewStatus); - - virtual HANDLE __cdecl GetAwayMsg(MCONTACT hContact); - virtual int __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt); - virtual int __cdecl SetAwayMsg(int m_iStatus, const TCHAR* msg); - - virtual int __cdecl UserIsTyping(MCONTACT hContact, int type); - - virtual int __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam); - - // instances - static CSteamProto* InitProtoInstance(const char* protoName, const wchar_t* userName); - static int UninitProtoInstance(CSteamProto* ppro); - - static CSteamProto* GetContactProtoInstance(MCONTACT hContact); - static void UninitProtoInstances(); - - // menus - static void InitMenus(); - static void UninitMenus(); - -protected: - bool isTerminated; - HANDLE m_evRequestsQueue, m_hQueueThread; - HANDLE m_pollingConnection, m_hPollingThread; - ULONG hAuthProcess; - ULONG hMessageProcess; - CRITICAL_SECTION contact_search_lock; - CRITICAL_SECTION requests_queue_lock; - LIST requestsQueue; - - // instances - static LIST InstanceList; - static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2); - - // queue - void InitQueue(); - void UninitQueue(); - - void StartQueue(); - void StopQueue(); - - void PushRequest(SteamWebApi::HttpRequest *request); - void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response); - void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response, void *arg); - - void ExecuteRequest(QueueItem *requestItem); - - void __cdecl QueueThread(void*); - - // pooling thread - void ParsePollData(JSONNODE *data); - void __cdecl PollingThread(void*); - - // account - bool IsOnline(); - bool IsMe(const char *steamId); - - void OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg); - - void OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotSession(const NETLIBHTTPREQUEST *response, void *arg); - - void OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg); - - // contacts - void SetContactStatus(MCONTACT hContact, WORD status); - void SetAllContactsStatus(WORD status); - - MCONTACT GetContactFromAuthEvent(HANDLE hEvent); - - void UpdateContact(MCONTACT hContact, JSONNODE *data); - void ProcessContact(std::map::iterator *it, MCONTACT hContact); - - void ContactIsRemoved(MCONTACT hContact); - void ContactIsFriend(MCONTACT hContact); - void ContactIsIgnored(MCONTACT hContact); - - MCONTACT FindContact(const char *steamId); - MCONTACT AddContact(const char *steamId, bool isTemporary = false); - - void OnGotFriendList(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotBlockList(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotUserSummaries(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotAvatar(const NETLIBHTTPREQUEST *response, void *arg); - - void OnFriendAdded(const NETLIBHTTPREQUEST *response, void *arg); - void OnFriendBlocked(const NETLIBHTTPREQUEST *response, void *arg); - void OnFriendRemoved(const NETLIBHTTPREQUEST *response, void *arg); - - void OnAuthRequested(const NETLIBHTTPREQUEST *response, void *arg); - - void OnPendingApproved(const NETLIBHTTPREQUEST *response, void *arg); - void OnPendingIgnoreded(const NETLIBHTTPREQUEST *response, void *arg); - - void OnSearchByIdEnded(const NETLIBHTTPREQUEST *response, void *arg); - - void OnSearchByNameStarted(const NETLIBHTTPREQUEST *response, void *arg); - void OnSearchByNameFinished(const NETLIBHTTPREQUEST *response, void *arg); - - // messages - void OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg); - - // menus - HGENMENU m_hMenuRoot; - static HANDLE hChooserMenu; - static HGENMENU contactMenuItems[CMI_MAX]; - - int __cdecl AuthRequestCommand(WPARAM, LPARAM); - int __cdecl BlockCommand(WPARAM, LPARAM); - int __cdecl JoinToGameCommand(WPARAM, LPARAM); - - INT_PTR __cdecl OpenBlockListCommand(WPARAM, LPARAM); - - static INT_PTR MenuChooseService(WPARAM wParam, LPARAM lParam); - - static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam); - int OnPrebuildContactMenu(WPARAM wParam, LPARAM); - - void OnInitStatusMenu(); - - // avatars - TCHAR* GetAvatarFilePath(MCONTACT hContact); - bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATIONT &pai); - void CheckAvatarChange(MCONTACT hContact, std::string avatarUrl); - - INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); - INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); - - //events - int OnModulesLoaded(WPARAM, LPARAM); - int OnPreShutdown(WPARAM, LPARAM); - INT_PTR __cdecl OnAccountManagerInit(WPARAM wParam, LPARAM lParam); - static int __cdecl OnOptionsInit(void *obj, WPARAM wParam, LPARAM lParam); - - // utils - static WORD SteamToMirandaStatus(int state); - static int MirandaToSteamState(int status); - - static int RsaEncrypt(const char *pszModulus, const char *data, BYTE *encrypted, DWORD &encryptedSize); - - HANDLE AddDBEvent(MCONTACT hContact, WORD type, DWORD timestamp, DWORD flags, DWORD cbBlob, PBYTE pBlob); - - static void CSteamProto::ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); - static void CSteamProto::ShowNotification(const wchar_t *caption, const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); - - // dialog procs - static INT_PTR CALLBACK GuardProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - static INT_PTR CALLBACK CaptchaProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - static INT_PTR CALLBACK MainOptionsProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - static LRESULT CALLBACK BlockListOptionsSubProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - static INT_PTR CALLBACK BlockListOptionsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); -}; - +#ifndef _STEAM_PROTO_H_ +#define _STEAM_PROTO_H_ + +#define STEAM_SEARCH_BYID 1001 +#define STEAM_SEARCH_BYNAME 1002 + +struct GuardParam +{ + char code[10]; + char domain[32]; +}; + +struct CaptchaParam +{ + BYTE *data; + size_t size; + char text[10]; +}; + +struct SendAuthParam +{ + MCONTACT hContact; + HANDLE hAuth; +}; + +struct SendMessageParam +{ + MCONTACT hContact; + HANDLE hMessage; +}; + +struct STEAM_SEARCH_RESULT +{ + PROTOSEARCHRESULT hdr; + JSONNODE *data; +}; + +enum +{ + CMI_AUTH_REQUEST, + //CMI_AUTH_GRANT, + //CMI_AUTH_REVOKE, + CMI_BLOCK, + CMI_JOIN_GAME, + SMI_BLOCKED_LIST, + CMI_MAX // this item shall be the last one +}; + +enum HTTP_STATUS +{ + HTTP_STATUS_NONE = 0, + HTTP_STATUS_OK = 200, + HTTP_STATUS_FOUND = 302, + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED = 401, + HTTP_STATUS_FORBIDDEN = 403, + HTTP_STATUS_NOT_FOUND = 404, + HTTP_STATUS_METHOD_NOT_ALLOWED = 405, + HTTP_STATUS_TOO_MANY_REQUESTS = 429, + HTTP_STATUS_SERVICE_UNAVAILABLE = 503, + HTTP_STATUS_INSUFICIENTE_STORAGE = 507 +}; + +typedef void (CSteamProto::*RESPONSE)(const NETLIBHTTPREQUEST *response, void *arg); + +struct QueueItem +{ + SteamWebApi::HttpRequest *request; + void *arg; + RESPONSE responseCallback; + RESPONSE responseFailedCallback; + + QueueItem(SteamWebApi::HttpRequest *request) : + request(request), arg(NULL), responseCallback(NULL), responseFailedCallback(NULL) { } + + QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response) : + request(request), arg(NULL), responseCallback(response), responseFailedCallback(NULL) { } + + QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response, RESPONSE responseFailedCallback) : + request(request), arg(NULL), responseCallback(response), responseFailedCallback(responseFailedCallback) { } + + ~QueueItem() { delete request; responseCallback = NULL; } +}; + +class CSteamProto : public PROTO +{ +public: + // PROTO_INTERFACE + CSteamProto(const char *protoName, const wchar_t *userName); + ~CSteamProto(); + + // PROTO_INTERFACE + virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT *psr); + virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, HANDLE hDbEvent); + + virtual int __cdecl Authorize(HANDLE hDbEvent); + virtual int __cdecl AuthDeny(HANDLE hDbEvent, const TCHAR *szReason); + virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT *); + virtual int __cdecl AuthRequest(MCONTACT hContact, const TCHAR * szMessage); + + virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath); + virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer); + virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason); + virtual int __cdecl FileResume(HANDLE hTransfer, int *action, const TCHAR** szFilename); + + virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL); + virtual int __cdecl GetInfo(MCONTACT hContact, int infoType); + + virtual HANDLE __cdecl SearchBasic(const TCHAR *id); + virtual HANDLE __cdecl SearchByEmail(const TCHAR *email); + virtual HANDLE __cdecl SearchByName(const TCHAR *nick, const TCHAR *firstName, const TCHAR *lastName); + virtual HWND __cdecl SearchAdvanced(HWND owner); + virtual HWND __cdecl CreateExtendedSearchUI(HWND owner); + + virtual int __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*); + virtual int __cdecl RecvFile(MCONTACT hContact, PROTORECVFILET*); + virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*); + virtual int __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*); + + virtual int __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList); + virtual HANDLE __cdecl SendFile(MCONTACT hContact, const TCHAR* szDescription, TCHAR** ppszFiles); + virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg); + virtual int __cdecl SendUrl(MCONTACT hContact, int flags, const char* url); + + virtual int __cdecl SetApparentMode(MCONTACT hContact, int mode); + virtual int __cdecl SetStatus(int iNewStatus); + + virtual HANDLE __cdecl GetAwayMsg(MCONTACT hContact); + virtual int __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt); + virtual int __cdecl SetAwayMsg(int m_iStatus, const TCHAR* msg); + + virtual int __cdecl UserIsTyping(MCONTACT hContact, int type); + + virtual int __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam); + + // instances + static CSteamProto* InitProtoInstance(const char* protoName, const wchar_t* userName); + static int UninitProtoInstance(CSteamProto* ppro); + + static CSteamProto* GetContactProtoInstance(MCONTACT hContact); + static void UninitProtoInstances(); + + // menus + static void InitMenus(); + static void UninitMenus(); + +protected: + bool isTerminated; + time_t m_idleTS; + HANDLE m_evRequestsQueue, m_hQueueThread; + HANDLE m_pollingConnection, m_hPollingThread; + ULONG hAuthProcess; + ULONG hMessageProcess; + CRITICAL_SECTION contact_search_lock; + CRITICAL_SECTION requests_queue_lock; + LIST requestsQueue; + + // instances + static LIST InstanceList; + static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2); + + // queue + void InitQueue(); + void UninitQueue(); + + void StartQueue(); + void StopQueue(); + + void PushRequest(SteamWebApi::HttpRequest *request); + void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response); + void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response, void *arg); + + void ExecuteRequest(QueueItem *requestItem); + + void __cdecl QueueThread(void*); + + // pooling thread + void ParsePollData(JSONNODE *data); + void __cdecl PollingThread(void*); + + // account + bool IsOnline(); + bool IsMe(const char *steamId); + + void OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg); + + void OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotSession(const NETLIBHTTPREQUEST *response, void *arg); + + void OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg); + + // contacts + void SetContactStatus(MCONTACT hContact, WORD status); + void SetAllContactsStatus(WORD status); + + MCONTACT GetContactFromAuthEvent(HANDLE hEvent); + + void UpdateContact(MCONTACT hContact, JSONNODE *data); + void ProcessContact(std::map::iterator *it, MCONTACT hContact); + + void ContactIsRemoved(MCONTACT hContact); + void ContactIsFriend(MCONTACT hContact); + void ContactIsIgnored(MCONTACT hContact); + + MCONTACT FindContact(const char *steamId); + MCONTACT AddContact(const char *steamId, bool isTemporary = false); + + void OnGotFriendList(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotBlockList(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotUserSummaries(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotAvatar(const NETLIBHTTPREQUEST *response, void *arg); + + void OnFriendAdded(const NETLIBHTTPREQUEST *response, void *arg); + void OnFriendBlocked(const NETLIBHTTPREQUEST *response, void *arg); + void OnFriendRemoved(const NETLIBHTTPREQUEST *response, void *arg); + + void OnAuthRequested(const NETLIBHTTPREQUEST *response, void *arg); + + void OnPendingApproved(const NETLIBHTTPREQUEST *response, void *arg); + void OnPendingIgnoreded(const NETLIBHTTPREQUEST *response, void *arg); + + void OnSearchByIdEnded(const NETLIBHTTPREQUEST *response, void *arg); + + void OnSearchByNameStarted(const NETLIBHTTPREQUEST *response, void *arg); + void OnSearchByNameFinished(const NETLIBHTTPREQUEST *response, void *arg); + + // messages + void OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg); + + // menus + HGENMENU m_hMenuRoot; + static HANDLE hChooserMenu; + static HGENMENU contactMenuItems[CMI_MAX]; + + int __cdecl AuthRequestCommand(WPARAM, LPARAM); + int __cdecl BlockCommand(WPARAM, LPARAM); + int __cdecl JoinToGameCommand(WPARAM, LPARAM); + + INT_PTR __cdecl OpenBlockListCommand(WPARAM, LPARAM); + + static INT_PTR MenuChooseService(WPARAM wParam, LPARAM lParam); + + static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam); + int OnPrebuildContactMenu(WPARAM wParam, LPARAM); + + void OnInitStatusMenu(); + + // avatars + TCHAR* GetAvatarFilePath(MCONTACT hContact); + bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATIONT &pai); + void CheckAvatarChange(MCONTACT hContact, std::string avatarUrl); + + INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); + INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); + INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); + + //events + int OnModulesLoaded(WPARAM, LPARAM); + int OnPreShutdown(WPARAM, LPARAM); + int __cdecl OnIdleChanged(WPARAM, LPARAM); + INT_PTR __cdecl OnAccountManagerInit(WPARAM wParam, LPARAM lParam); + static int __cdecl OnOptionsInit(void *obj, WPARAM wParam, LPARAM lParam); + + // utils + static WORD SteamToMirandaStatus(int state); + static int MirandaToSteamState(int status); + + static int RsaEncrypt(const char *pszModulus, const char *data, BYTE *encrypted, DWORD &encryptedSize); + + HANDLE AddDBEvent(MCONTACT hContact, WORD type, DWORD timestamp, DWORD flags, DWORD cbBlob, PBYTE pBlob); + + static void CSteamProto::ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); + static void CSteamProto::ShowNotification(const wchar_t *caption, const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); + + // dialog procs + static INT_PTR CALLBACK GuardProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK CaptchaProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK MainOptionsProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK BlockListOptionsSubProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK BlockListOptionsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + // helpers + inline int IdleSeconds() { return m_idleTS ? time(0) - m_idleTS : 0; } +}; + #endif //_STEAM_PROTO_H_ \ No newline at end of file -- cgit v1.2.3