summaryrefslogtreecommitdiff
path: root/protocols/Steam
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Steam')
-rw-r--r--protocols/Steam/src/api/enums.h176
-rw-r--r--protocols/Steam/src/steam_proto.cpp708
2 files changed, 442 insertions, 442 deletions
diff --git a/protocols/Steam/src/api/enums.h b/protocols/Steam/src/api/enums.h
index 087b99c5fa..2cf767e37f 100644
--- a/protocols/Steam/src/api/enums.h
+++ b/protocols/Steam/src/api/enums.h
@@ -1,88 +1,88 @@
-#ifndef _STEAM_ENUMS_H_
-#define _STEAM_ENUMS_H_
-
-enum VisibilityState
-{
- Private = 1,
- FriendsOnly = 2,
- FriendsOfFriends = 3,
- UsersOnly = 4,
- Public = 5,
-};
-
-enum PersonaState
-{
- Offline = 0,
- Online = 1,
- Busy = 2,
- Away = 3,
- Snooze = 4,
- LookingToTrade = 5,
- LookingToPlay = 6,
- Invisible = 7,
-};
-
-enum class PersonaStateFlag : int
-{
- None = 0,
- HasRichPresence = 1,
- InJoinableGame = 2,
- ClientTypeWeb = 256,
- ClientTypeMobile = 512,
- ClientTypeBigPicture = 1024,
- ClientTypeVR = 2048,
-};
-
-inline PersonaStateFlag operator &(PersonaStateFlag lhs, PersonaStateFlag rhs)
-{
- return static_cast<PersonaStateFlag> (
- static_cast<std::underlying_type<PersonaStateFlag>::type>(lhs) &
- static_cast<std::underlying_type<PersonaStateFlag>::type>(rhs));
-}
-
-enum class PersonaStatusFlag : int
-{
- Status = 1,
- PlayerName = 2,
- QueryPort = 4,
- SourceID = 8,
- Presence = 16,
- Metadata = 32,
- LastSeen = 64,
- ClanInfo = 128,
- GameExtraInfo = 256,
- GameDataBlob = 512,
- ClanTag = 1024,
- Facebook = 2048,
- Unknown = 4096,
-};
-
-inline PersonaStatusFlag operator &(PersonaStatusFlag lhs, PersonaStatusFlag rhs)
-{
- return static_cast<PersonaStatusFlag> (
- static_cast<std::underlying_type<PersonaStatusFlag>::type>(lhs) &
- static_cast<std::underlying_type<PersonaStatusFlag>::type>(rhs));
-}
-
-enum class PersonaRelationshipAction : int
-{
- // friend removed from contact list
- Remove = 0,
- // friend added you to ignore list
- Ignore = 1,
- // friend requested auth
- AuthRequest = 2,
- // friend added you to contact list
- AddToList = 3,
- // friend got (or approved?) your auth request
- AuthRequested = 4,
-};
-
-template<typename T>
-bool contains_flag(T x, T y) {
- return (static_cast<typename std::underlying_type<T>::type>(x)
- & static_cast<typename std::underlying_type<T>::type>(y))
- == static_cast<typename std::underlying_type<T>::type>(y);
-}
-
-#endif //_STEAM_ENUMS_H_
+#ifndef _STEAM_ENUMS_H_
+#define _STEAM_ENUMS_H_
+
+enum VisibilityState
+{
+ Private = 1,
+ FriendsOnly = 2,
+ FriendsOfFriends = 3,
+ UsersOnly = 4,
+ Public = 5,
+};
+
+enum PersonaState
+{
+ Offline = 0,
+ Online = 1,
+ Busy = 2,
+ Away = 3,
+ Snooze = 4,
+ LookingToTrade = 5,
+ LookingToPlay = 6,
+ Invisible = 7,
+};
+
+enum class PersonaStateFlag : int
+{
+ None = 0,
+ HasRichPresence = 1,
+ InJoinableGame = 2,
+ ClientTypeWeb = 256,
+ ClientTypeMobile = 512,
+ ClientTypeBigPicture = 1024,
+ ClientTypeVR = 2048,
+};
+
+inline PersonaStateFlag operator &(PersonaStateFlag lhs, PersonaStateFlag rhs)
+{
+ return static_cast<PersonaStateFlag> (
+ static_cast<std::underlying_type<PersonaStateFlag>::type>(lhs) &
+ static_cast<std::underlying_type<PersonaStateFlag>::type>(rhs));
+}
+
+enum class PersonaStatusFlag : int
+{
+ Status = 1,
+ PlayerName = 2,
+ QueryPort = 4,
+ SourceID = 8,
+ Presence = 16,
+ Metadata = 32,
+ LastSeen = 64,
+ ClanInfo = 128,
+ GameExtraInfo = 256,
+ GameDataBlob = 512,
+ ClanTag = 1024,
+ Facebook = 2048,
+ Unknown = 4096,
+};
+
+inline PersonaStatusFlag operator &(PersonaStatusFlag lhs, PersonaStatusFlag rhs)
+{
+ return static_cast<PersonaStatusFlag> (
+ static_cast<std::underlying_type<PersonaStatusFlag>::type>(lhs) &
+ static_cast<std::underlying_type<PersonaStatusFlag>::type>(rhs));
+}
+
+enum class PersonaRelationshipAction : int
+{
+ // friend removed from contact list
+ Remove = 0,
+ // friend added you to ignore list
+ Ignore = 1,
+ // friend requested auth
+ AuthRequest = 2,
+ // friend added you to contact list
+ AddToList = 3,
+ // friend got (or approved?) your auth request
+ AuthRequested = 4,
+};
+
+template<typename T>
+bool contains_flag(T x, T y) {
+ return (static_cast<typename std::underlying_type<T>::type>(x)
+ & static_cast<typename std::underlying_type<T>::type>(y))
+ == static_cast<typename std::underlying_type<T>::type>(y);
+}
+
+#endif //_STEAM_ENUMS_H_
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp
index a6bac4aafb..f185171edd 100644
--- a/protocols/Steam/src/steam_proto.cpp
+++ b/protocols/Steam/src/steam_proto.cpp
@@ -1,354 +1,354 @@
-#include "stdafx.h"
-
-CSteamProto::CSteamProto(const char *protoName, const wchar_t *userName) :
- PROTO<CSteamProto>(protoName, userName),
- m_requestQueue(1), hAuthProcess(1), hMessageProcess(1)
-{
- CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit);
-
- m_hRequestsQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- // default group
- m_defaultGroup = getWStringA("DefaultGroup");
- if (m_defaultGroup == nullptr)
- m_defaultGroup = mir_wstrdup(L"Steam");
-
- // icons
- wchar_t filePath[MAX_PATH];
- GetModuleFileName(g_plugin.getInst(), filePath, MAX_PATH);
-
- wchar_t sectionName[100];
- mir_snwprintf(sectionName, L"%s/%s", LPGENW("Protocols"), _A2W(MODULE));
-
- char settingName[100];
- mir_snprintf(settingName, "%s_%s", MODULE, "main");
-
- SKINICONDESC sid = {};
- sid.flags = SIDF_ALL_UNICODE;
- sid.defaultFile.w = filePath;
- sid.pszName = settingName;
- sid.section.w = sectionName;
- sid.description.w = LPGENW("Protocol icon");
- sid.iDefaultIndex = -IDI_STEAM;
- g_plugin.addIcon(&sid);
-
- mir_snprintf(settingName, "%s_%s", MODULE, "gaming");
- sid.description.w = LPGENW("Gaming icon");
- sid.iDefaultIndex = -IDI_GAMING;
- g_plugin.addIcon(&sid);
-
- // temporary DB settings
- db_set_resident(m_szModuleName, "XStatusId");
- db_set_resident(m_szModuleName, "XStatusName");
- db_set_resident(m_szModuleName, "XStatusMsg");
- db_set_resident(m_szModuleName, "IdleTS");
- db_set_resident(m_szModuleName, "GameID");
- db_set_resident(m_szModuleName, "ServerIP");
- db_set_resident(m_szModuleName, "ServerID");
-
- SetAllContactStatuses(ID_STATUS_OFFLINE);
-
- // avatar API
- CreateProtoService(PS_GETAVATARINFO, &CSteamProto::GetAvatarInfo);
- CreateProtoService(PS_GETAVATARCAPS, &CSteamProto::GetAvatarCaps);
- CreateProtoService(PS_GETMYAVATAR, &CSteamProto::GetMyAvatar);
-
- // custom status API
- CreateProtoService(PS_GETCUSTOMSTATUSEX, &CSteamProto::OnGetXStatusEx);
- CreateProtoService(PS_GETCUSTOMSTATUSICON, &CSteamProto::OnGetXStatusIcon);
- CreateProtoService(PS_GETADVANCEDSTATUSICON, &CSteamProto::OnRequestAdvStatusIconIdx);
-
- // menus
- CreateProtoService(PS_MENU_REQAUTH, &CSteamProto::AuthRequestCommand);
- CreateProtoService(PS_MENU_REVOKEAUTH, &CSteamProto::AuthRevokeCommand);
-
- // custom db events API
- CreateProtoService(STEAM_DB_GETEVENTTEXT_CHATSTATES, &CSteamProto::OnGetEventTextChatStates);
-
- // hooks
- HookProtoEvent(ME_OPT_INITIALISE, &CSteamProto::OnOptionsInit);
-
- // netlib support
- NETLIBUSER nlu = {};
- nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
- nlu.szDescriptiveName.w = m_tszUserName;
- nlu.szSettingsModule = m_szModuleName;
- m_hNetlibUser = Netlib_RegisterUser(&nlu);
-
- debugLogA(__FUNCTION__":Setting protocol / module name to '%s'", m_szModuleName);
-
- if (uint32_t iGlobalValue = getDword(DB_KEY_LASTMSGTS)) {
- for (auto &cc : AccContacts())
- setDword(cc, DB_KEY_LASTMSGTS, iGlobalValue);
- delSetting(DB_KEY_LASTMSGTS);
- }
-}
-
-CSteamProto::~CSteamProto()
-{
- if (m_hRequestsQueueEvent) {
- CloseHandle(m_hRequestsQueueEvent);
- m_hRequestsQueueEvent = nullptr;
- }
-}
-
-MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT *psr)
-{
- MCONTACT hContact = AddContact(T2Utf(psr->id.w), psr->nick.w, true);
-
- if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) {
- STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT *)psr;
- UpdateContactDetails(hContact, *ssr->data);
- }
-
- return hContact;
-}
-
-MCONTACT CSteamProto::AddToListByEvent(int, int, MEVENT hDbEvent)
-{
- DB::EventInfo dbei;
- dbei.cbBlob = -1;
- if (db_event_get(hDbEvent, &dbei))
- return 0;
- if (mir_strcmp(dbei.szModule, m_szModuleName))
- return 0;
- if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
- return 0;
-
- DB::AUTH_BLOB blob(dbei.pBlob);
- return AddContact(blob.get_email(), Utf2T(blob.get_nick()));
-}
-
-int CSteamProto::Authorize(MEVENT hDbEvent)
-{
- if (IsOnline() && hDbEvent) {
- MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
- if (hContact == INVALID_CONTACT_ID)
- return 1;
-
- ptrA token(getStringA("TokenSecret"));
- ptrA sessionId(getStringA("SessionID"));
- ptrA steamId(getStringA("SteamID"));
- char *who = getStringA(hContact, "SteamID");
-
- PushRequest(
- new ApprovePendingRequest(token, sessionId, steamId, who),
- &CSteamProto::OnPendingApproved,
- who);
-
- return 0;
- }
-
- return 1;
-}
-
-int CSteamProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT *pre)
-{
- // remember to not create this event again, unless authorization status changes again
- setByte(hContact, "AuthAsked", 1);
- return Proto_AuthRecv(m_szModuleName, pre);
-}
-
-int CSteamProto::AuthDeny(MEVENT hDbEvent, const wchar_t*)
-{
- if (IsOnline() && hDbEvent) {
- MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
- if (hContact == INVALID_CONTACT_ID)
- return 1;
-
- ptrA token(getStringA("TokenSecret"));
- ptrA sessionId(getStringA("SessionID"));
- ptrA steamId(getStringA("SteamID"));
- char *who = getStringA(hContact, "SteamID");
-
- PushRequest(
- new IgnorePendingRequest(token, sessionId, steamId, who),
- &CSteamProto::OnPendingIgnoreded,
- who);
-
- return 0;
- }
-
- return 1;
-}
-
-int CSteamProto::AuthRequest(MCONTACT hContact, const wchar_t*)
-{
- if (IsOnline() && hContact) {
- UINT hAuth = InterlockedIncrement(&hAuthProcess);
-
- SendAuthParam *param = (SendAuthParam*)mir_calloc(sizeof(SendAuthParam));
- param->hContact = hContact;
- param->hAuth = (HANDLE)hAuth;
-
- ptrA token(getStringA("TokenSecret"));
- ptrA sessionId(getStringA("SessionID"));
- ptrA steamId(getStringA("SteamID"));
- ptrA who(getStringA(hContact, "SteamID"));
-
- PushRequest(
- new AddFriendRequest(token, sessionId, steamId, who),
- &CSteamProto::OnFriendAdded,
- param);
-
- return hAuth;
- }
-
- return 1;
-}
-
-INT_PTR CSteamProto::GetCaps(int type, MCONTACT)
-{
- switch (type) {
- case PFLAGNUM_1:
- return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES | PF1_MODEMSGRECV;
- case PFLAGNUM_2:
- return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT | PF2_INVISIBLE;
- case PFLAGNUM_4:
- return PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH | PF4_SUPPORTIDLE | PF4_SUPPORTTYPING;// | PF4_IMSENDOFFLINE;
- case PFLAGNUM_5:
- return PF2_HEAVYDND | PF2_FREECHAT;
- case PFLAG_UNIQUEIDTEXT:
- return (INT_PTR)TranslateT("SteamID");
- default:
- return 0;
- }
-}
-
-HANDLE CSteamProto::SearchBasic(const wchar_t* id)
-{
- if (!this->IsOnline())
- return nullptr;
-
- ptrA steamId(mir_u2a(id));
- PushRequest(new GetUserSummariesRequest(this, steamId), &CSteamProto::OnSearchResults, (HANDLE)STEAM_SEARCH_BYID);
-
- return (HANDLE)STEAM_SEARCH_BYID;
-}
-
-HANDLE CSteamProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName)
-{
- if (!IsOnline())
- return nullptr;
-
- // Combine all fields to single text
- wchar_t keywordsT[200];
- mir_snwprintf(keywordsT, L"%s %s %s", nick, firstName, lastName);
-
- ptrA token(getStringA("TokenSecret"));
- ptrA keywords(mir_utf8encodeW(rtrimw(keywordsT)));
-
- PushRequest(
- new SearchRequest(token, keywords),
- &CSteamProto::OnSearchByNameStarted,
- (HANDLE)STEAM_SEARCH_BYNAME);
-
- return (HANDLE)STEAM_SEARCH_BYNAME;
-}
-
-int CSteamProto::SendMsg(MCONTACT hContact, int, const char *message)
-{
- if (!IsOnline()) {
- ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, nullptr, (LPARAM)TranslateT("You cannot send messages when you are offline."));
- return 0;
- }
-
- return OnSendMessage(hContact, message);
-}
-
-int CSteamProto::SetStatus(int new_status)
-{
- // Routing statuses not supported by Steam
- switch (new_status) {
- case ID_STATUS_OFFLINE:
- case ID_STATUS_AWAY:
- case ID_STATUS_NA:
- case ID_STATUS_INVISIBLE:
- break;
-
- case ID_STATUS_DND:
- case ID_STATUS_OCCUPIED:
- new_status = ID_STATUS_NA;
- break;
-
- default:
- new_status = ID_STATUS_ONLINE;
- break;
- }
-
- {
- mir_cslock lock(m_setStatusLock);
- if (new_status == m_iDesiredStatus)
- return 0;
- }
-
- debugLogA(__FUNCTION__ ": 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) {
- // Reset relogin flag
- isLoginAgain = false;
-
- m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
-
- if (!Miranda_IsTerminated())
- SetAllContactStatuses(ID_STATUS_OFFLINE);
-
- Logout();
- }
- else if (m_hRequestQueueThread == nullptr && !IsStatusConnecting(m_iStatus)) {
- m_iStatus = ID_STATUS_CONNECTING;
- m_isTerminated = false;
- ForkThread(&CSteamProto::RequestQueueThread);
-
- Login();
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
- }
- else if (IsOnline()) {
- m_iStatus = new_status;
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
- }
- return 0;
-}
-
-void CSteamProto::GetAwayMsgThread(void *arg)
-{
- // Maybe not needed, but better to be sure that this won't happen faster than core handling return value of GetAwayMsg()
- Sleep(50);
-
- MCONTACT hContact = (UINT_PTR)arg;
- CMStringW message(db_get_wsm(hContact, "CList", "StatusMsg"));
-
- // if contact has no status message, get xstatus message
- if (message.IsEmpty()) {
- ptrW xStatusName(getWStringA(hContact, "XStatusName"));
- ptrW xStatusMsg(getWStringA(hContact, "XStatusMsg"));
-
- if (xStatusName)
- message.AppendFormat(L"%s: %s", xStatusName.get(), xStatusMsg.get());
- else
- message.Append(xStatusMsg);
- }
-
- ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)message.c_str());
-}
-
-HANDLE CSteamProto::GetAwayMsg(MCONTACT hContact)
-{
- ForkThread(&CSteamProto::GetAwayMsgThread, (void*)hContact);
- return (HANDLE)1;
-}
-
-void CSteamProto::OnContactDeleted(MCONTACT hContact)
-{
- // remove only authorized contacts
- if (!getByte(hContact, "Auth", 0)) {
- ptrA token(getStringA("TokenSecret"));
- ptrA sessionId(getStringA("SessionID"));
- ptrA steamId(getStringA("SteamID"));
- char *who = getStringA(hContact, "SteamID");
- PushRequest(new RemoveFriendRequest(token, sessionId, steamId, who), &CSteamProto::OnFriendRemoved, (void*)who);
- }
-}
+#include "stdafx.h"
+
+CSteamProto::CSteamProto(const char *protoName, const wchar_t *userName) :
+ PROTO<CSteamProto>(protoName, userName),
+ m_requestQueue(1), hAuthProcess(1), hMessageProcess(1)
+{
+ CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit);
+
+ m_hRequestsQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ // default group
+ m_defaultGroup = getWStringA("DefaultGroup");
+ if (m_defaultGroup == nullptr)
+ m_defaultGroup = mir_wstrdup(L"Steam");
+
+ // icons
+ wchar_t filePath[MAX_PATH];
+ GetModuleFileName(g_plugin.getInst(), filePath, MAX_PATH);
+
+ wchar_t sectionName[100];
+ mir_snwprintf(sectionName, L"%s/%s", LPGENW("Protocols"), _A2W(MODULE));
+
+ char settingName[100];
+ mir_snprintf(settingName, "%s_%s", MODULE, "main");
+
+ SKINICONDESC sid = {};
+ sid.flags = SIDF_ALL_UNICODE;
+ sid.defaultFile.w = filePath;
+ sid.pszName = settingName;
+ sid.section.w = sectionName;
+ sid.description.w = LPGENW("Protocol icon");
+ sid.iDefaultIndex = -IDI_STEAM;
+ g_plugin.addIcon(&sid);
+
+ mir_snprintf(settingName, "%s_%s", MODULE, "gaming");
+ sid.description.w = LPGENW("Gaming icon");
+ sid.iDefaultIndex = -IDI_GAMING;
+ g_plugin.addIcon(&sid);
+
+ // temporary DB settings
+ db_set_resident(m_szModuleName, "XStatusId");
+ db_set_resident(m_szModuleName, "XStatusName");
+ db_set_resident(m_szModuleName, "XStatusMsg");
+ db_set_resident(m_szModuleName, "IdleTS");
+ db_set_resident(m_szModuleName, "GameID");
+ db_set_resident(m_szModuleName, "ServerIP");
+ db_set_resident(m_szModuleName, "ServerID");
+
+ SetAllContactStatuses(ID_STATUS_OFFLINE);
+
+ // avatar API
+ CreateProtoService(PS_GETAVATARINFO, &CSteamProto::GetAvatarInfo);
+ CreateProtoService(PS_GETAVATARCAPS, &CSteamProto::GetAvatarCaps);
+ CreateProtoService(PS_GETMYAVATAR, &CSteamProto::GetMyAvatar);
+
+ // custom status API
+ CreateProtoService(PS_GETCUSTOMSTATUSEX, &CSteamProto::OnGetXStatusEx);
+ CreateProtoService(PS_GETCUSTOMSTATUSICON, &CSteamProto::OnGetXStatusIcon);
+ CreateProtoService(PS_GETADVANCEDSTATUSICON, &CSteamProto::OnRequestAdvStatusIconIdx);
+
+ // menus
+ CreateProtoService(PS_MENU_REQAUTH, &CSteamProto::AuthRequestCommand);
+ CreateProtoService(PS_MENU_REVOKEAUTH, &CSteamProto::AuthRevokeCommand);
+
+ // custom db events API
+ CreateProtoService(STEAM_DB_GETEVENTTEXT_CHATSTATES, &CSteamProto::OnGetEventTextChatStates);
+
+ // hooks
+ HookProtoEvent(ME_OPT_INITIALISE, &CSteamProto::OnOptionsInit);
+
+ // netlib support
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
+ nlu.szDescriptiveName.w = m_tszUserName;
+ nlu.szSettingsModule = m_szModuleName;
+ m_hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ debugLogA(__FUNCTION__":Setting protocol / module name to '%s'", m_szModuleName);
+
+ if (uint32_t iGlobalValue = getDword(DB_KEY_LASTMSGTS)) {
+ for (auto &cc : AccContacts())
+ setDword(cc, DB_KEY_LASTMSGTS, iGlobalValue);
+ delSetting(DB_KEY_LASTMSGTS);
+ }
+}
+
+CSteamProto::~CSteamProto()
+{
+ if (m_hRequestsQueueEvent) {
+ CloseHandle(m_hRequestsQueueEvent);
+ m_hRequestsQueueEvent = nullptr;
+ }
+}
+
+MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT *psr)
+{
+ MCONTACT hContact = AddContact(T2Utf(psr->id.w), psr->nick.w, true);
+
+ if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) {
+ STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT *)psr;
+ UpdateContactDetails(hContact, *ssr->data);
+ }
+
+ return hContact;
+}
+
+MCONTACT CSteamProto::AddToListByEvent(int, int, MEVENT hDbEvent)
+{
+ DB::EventInfo dbei;
+ dbei.cbBlob = -1;
+ if (db_event_get(hDbEvent, &dbei))
+ return 0;
+ if (mir_strcmp(dbei.szModule, m_szModuleName))
+ return 0;
+ if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
+ return 0;
+
+ DB::AUTH_BLOB blob(dbei.pBlob);
+ return AddContact(blob.get_email(), Utf2T(blob.get_nick()));
+}
+
+int CSteamProto::Authorize(MEVENT hDbEvent)
+{
+ if (IsOnline() && hDbEvent) {
+ MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
+ if (hContact == INVALID_CONTACT_ID)
+ return 1;
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+
+ PushRequest(
+ new ApprovePendingRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnPendingApproved,
+ who);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+int CSteamProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT *pre)
+{
+ // remember to not create this event again, unless authorization status changes again
+ setByte(hContact, "AuthAsked", 1);
+ return Proto_AuthRecv(m_szModuleName, pre);
+}
+
+int CSteamProto::AuthDeny(MEVENT hDbEvent, const wchar_t*)
+{
+ if (IsOnline() && hDbEvent) {
+ MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
+ if (hContact == INVALID_CONTACT_ID)
+ return 1;
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+
+ PushRequest(
+ new IgnorePendingRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnPendingIgnoreded,
+ who);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+int CSteamProto::AuthRequest(MCONTACT hContact, const wchar_t*)
+{
+ if (IsOnline() && hContact) {
+ UINT hAuth = InterlockedIncrement(&hAuthProcess);
+
+ SendAuthParam *param = (SendAuthParam*)mir_calloc(sizeof(SendAuthParam));
+ param->hContact = hContact;
+ param->hAuth = (HANDLE)hAuth;
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ ptrA who(getStringA(hContact, "SteamID"));
+
+ PushRequest(
+ new AddFriendRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnFriendAdded,
+ param);
+
+ return hAuth;
+ }
+
+ return 1;
+}
+
+INT_PTR CSteamProto::GetCaps(int type, MCONTACT)
+{
+ switch (type) {
+ case PFLAGNUM_1:
+ return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES | PF1_MODEMSGRECV;
+ case PFLAGNUM_2:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT | PF2_INVISIBLE;
+ case PFLAGNUM_4:
+ return PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH | PF4_SUPPORTIDLE | PF4_SUPPORTTYPING;// | PF4_IMSENDOFFLINE;
+ case PFLAGNUM_5:
+ return PF2_HEAVYDND | PF2_FREECHAT;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)TranslateT("SteamID");
+ default:
+ return 0;
+ }
+}
+
+HANDLE CSteamProto::SearchBasic(const wchar_t* id)
+{
+ if (!this->IsOnline())
+ return nullptr;
+
+ ptrA steamId(mir_u2a(id));
+ PushRequest(new GetUserSummariesRequest(this, steamId), &CSteamProto::OnSearchResults, (HANDLE)STEAM_SEARCH_BYID);
+
+ return (HANDLE)STEAM_SEARCH_BYID;
+}
+
+HANDLE CSteamProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName)
+{
+ if (!IsOnline())
+ return nullptr;
+
+ // Combine all fields to single text
+ wchar_t keywordsT[200];
+ mir_snwprintf(keywordsT, L"%s %s %s", nick, firstName, lastName);
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA keywords(mir_utf8encodeW(rtrimw(keywordsT)));
+
+ PushRequest(
+ new SearchRequest(token, keywords),
+ &CSteamProto::OnSearchByNameStarted,
+ (HANDLE)STEAM_SEARCH_BYNAME);
+
+ return (HANDLE)STEAM_SEARCH_BYNAME;
+}
+
+int CSteamProto::SendMsg(MCONTACT hContact, int, const char *message)
+{
+ if (!IsOnline()) {
+ ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, nullptr, (LPARAM)TranslateT("You cannot send messages when you are offline."));
+ return 0;
+ }
+
+ return OnSendMessage(hContact, message);
+}
+
+int CSteamProto::SetStatus(int new_status)
+{
+ // Routing statuses not supported by Steam
+ switch (new_status) {
+ case ID_STATUS_OFFLINE:
+ case ID_STATUS_AWAY:
+ case ID_STATUS_NA:
+ case ID_STATUS_INVISIBLE:
+ break;
+
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ new_status = ID_STATUS_NA;
+ break;
+
+ default:
+ new_status = ID_STATUS_ONLINE;
+ break;
+ }
+
+ {
+ mir_cslock lock(m_setStatusLock);
+ if (new_status == m_iDesiredStatus)
+ return 0;
+ }
+
+ debugLogA(__FUNCTION__ ": 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) {
+ // Reset relogin flag
+ isLoginAgain = false;
+
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+
+ if (!Miranda_IsTerminated())
+ SetAllContactStatuses(ID_STATUS_OFFLINE);
+
+ Logout();
+ }
+ else if (m_hRequestQueueThread == nullptr && !IsStatusConnecting(m_iStatus)) {
+ m_iStatus = ID_STATUS_CONNECTING;
+ m_isTerminated = false;
+ ForkThread(&CSteamProto::RequestQueueThread);
+
+ Login();
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+ }
+ else if (IsOnline()) {
+ m_iStatus = new_status;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+ }
+ return 0;
+}
+
+void CSteamProto::GetAwayMsgThread(void *arg)
+{
+ // Maybe not needed, but better to be sure that this won't happen faster than core handling return value of GetAwayMsg()
+ Sleep(50);
+
+ MCONTACT hContact = (UINT_PTR)arg;
+ CMStringW message(db_get_wsm(hContact, "CList", "StatusMsg"));
+
+ // if contact has no status message, get xstatus message
+ if (message.IsEmpty()) {
+ ptrW xStatusName(getWStringA(hContact, "XStatusName"));
+ ptrW xStatusMsg(getWStringA(hContact, "XStatusMsg"));
+
+ if (xStatusName)
+ message.AppendFormat(L"%s: %s", xStatusName.get(), xStatusMsg.get());
+ else
+ message.Append(xStatusMsg);
+ }
+
+ ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)message.c_str());
+}
+
+HANDLE CSteamProto::GetAwayMsg(MCONTACT hContact)
+{
+ ForkThread(&CSteamProto::GetAwayMsgThread, (void*)hContact);
+ return (HANDLE)1;
+}
+
+void CSteamProto::OnContactDeleted(MCONTACT hContact)
+{
+ // remove only authorized contacts
+ if (!getByte(hContact, "Auth", 0)) {
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+ PushRequest(new RemoveFriendRequest(token, sessionId, steamId, who), &CSteamProto::OnFriendRemoved, (void*)who);
+ }
+}