1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
|
#ifndef _STEAM_PROTO_H_
#define _STEAM_PROTO_H_
#define STEAM_SEARCH_BYID 1001
#define STEAM_SEARCH_BYNAME 1002
#define STEAM_PROTOCOL_VERSION 65580
#define STEAM_PROTOCOL_MASK 0x80000000
// Global settings for all accounts: hosts' list
#define DBKEY_HOSTS_COUNT "HostsCount"
#define DBKEY_HOSTS_DATE "HostsDate"
#define DBKEY_LASTMSG "LastMessageTS"
#define DBKEY_CLIENT_ID "ClientID"
#define DBKEY_STEAM_ID "SteamID"
#define DBKEY_ACCOUNT_NAME "Username"
// Steam services
#define PollAuthSessionStatus "Authentication.PollAuthSessionStatus#1"
#define GetPasswordRSAPublicKey "Authentication.GetPasswordRSAPublicKey#1"
#define BeginAuthSessionViaCredentials "Authentication.BeginAuthSessionViaCredentials#1"
#define UpdateAuthSessionWithSteamGuardCode "Authentication.UpdateAuthSessionWithSteamGuardCode#1"
#define GetOwnAuthorizedDevices "DeviceAuth.GetOwnAuthorizedDevices#1"
#define FriendSendMessage "FriendMessages.SendMessage#1"
#define FriendGetActiveSessions "FriendMessages.GetActiveMessageSessions#1"
#define FriendGetRecentMessages "FriendMessages.GetRecentMessages#1"
#define FriendGetIncomingMessage "FriendMessagesClient.IncomingMessage#1"
#define NotificationReceived "SteamNotificationClient.NotificationsReceived#1"
struct SendAuthParam
{
MCONTACT hContact;
HANDLE hAuth;
};
struct STEAM_SEARCH_RESULT
{
PROTOSEARCHRESULT psr;
const JSONNode *data;
};
enum
{
CMI_BLOCK,
CMI_UNBLOCK,
CMI_JOIN_GAME,
CMI_MAX // this item shall be the last one
};
typedef void (CSteamProto::*MsgCallback)(const uint8_t *pBuf, size_t cbLen);
typedef void (CSteamProto::*HttpCallback)(const MHttpResponse &, void *);
typedef void (CSteamProto::*JsonCallback)(const JSONNode &, void *);
struct HttpRequest : public MTHttpRequest<CSteamProto>
{
HttpRequest(int iRequestType, const char *pszUrl);
MHttpRequest* Get();
};
struct ProtoRequest
{
ProtoRequest(int64_t _1, MsgCallback _2) :
id(_1),
pCallback(_2)
{}
int64_t id;
MsgCallback pCallback;
};
struct COwnMessage
{
COwnMessage(MCONTACT _1, int _2) :
hContact(_1),
iMessageId(_2)
{}
int iMessageId, timestamp = 0;
MCONTACT hContact;
uint64_t iSourceId = -1;
};
class CSteamProto : public PROTO<CSteamProto>
{
friend struct CMPlugin;
friend class CSteamGuardDialog;
friend class CSteamPasswordEditor;
friend class CSteamOptionsMain;
friend class CSteamOptionsBlockList;
friend class PollRequest;
friend class WebSocket<CSteamProto>;
class CProtoImpl
{
friend class CSteamProto;
CSteamProto &m_proto;
CTimer m_heartBeat;
void OnHeartBeat(CTimer *)
{
m_proto.SendHeartBeat();
}
CProtoImpl(CSteamProto &pro) :
m_proto(pro),
m_heartBeat(Miranda_GetSystemWindow(), UINT_PTR(this)+1)
{
m_heartBeat.OnEvent = Callback(this, &CProtoImpl::OnHeartBeat);
}
}
m_impl;
ptrW m_password;
bool m_bTerminated;
time_t m_idleTS;
uint64_t m_iSteamId, m_iClientId, m_iSessionId;
MBinBuffer m_requestId;
int64_t GetId(const char *pszSetting);
void SetId(const char *pszSetting, int64_t id);
int64_t GetId(MCONTACT, const char *pszSetting);
void SetId(MCONTACT, const char *pszSetting, int64_t id);
// polling
CMStringA m_szRefreshToken, m_szAccessToken;
ULONG hAuthProcess = 1;
ULONG hMessageProcess = 1;
mir_cs m_addContactLock;
mir_cs m_setStatusLock;
// connection
WebSocket<CSteamProto> *m_ws;
void __cdecl ServerThread(void *);
bool ServerThreadStub(const char *szHost);
void ProcessMulti(const uint8_t *buf, size_t cbLen);
void ProcessMessage(const uint8_t *buf, size_t cbLen);
void ProcessServiceResponse(const uint8_t *buf, size_t cbLen, const CMsgProtoBufHeader &hdr);
void WSSend(EMsg msgType, const ProtobufCppMessage &msg);
void WSSendRaw(EMsg msgType, const MBinBuffer &buf);
void WSSendHeader(EMsg msgType, const CMsgProtoBufHeader &hdr, const ProtobufCppMessage &msg);
int64_t WSSendService(const char *pszServiceName, const ProtobufCppMessage &msg, bool bAnon = false);
// requests
bool SendRequest(HttpRequest *request);
bool SendRequest(HttpRequest *request, HttpCallback callback, void *param = nullptr);
bool SendRequest(HttpRequest *request, JsonCallback callback, void *param = nullptr);
void SendAppInfoRequest(uint32_t appId);
void SendDeviceListRequest();
void SendHeartBeat();
void SendLogout();
void SendPersonaStatus(int iStatus);
void SendPollRequest();
// login
bool IsOnline();
void Login();
void Logout();
static INT_PTR CALLBACK EnterTotpCode(void *param);
static INT_PTR CALLBACK EnterEmailCode(void *param);
void OnBeginSession(const CAuthenticationBeginAuthSessionViaCredentialsResponse &pResponse, const CMsgProtoBufHeader &hdr);
void OnClientLogon(const CMsgClientLogonResponse &pResponse, const CMsgProtoBufHeader &hdr);
void OnClientLogoff(const CMsgClientLoggedOff &pResponse, const CMsgProtoBufHeader &hdr);
void OnGotAppInfo(const CMsgClientPICSProductInfoResponse &pResponse, const CMsgProtoBufHeader &hdr);
void OnGotDeviceList(const CDeviceAuthGetOwnAuthorizedDevicesResponse &pResponse, const CMsgProtoBufHeader &hdr);
void OnGotRsaKey(const CAuthenticationGetPasswordRSAPublicKeyResponse &pResponse, const CMsgProtoBufHeader &hdr);
void OnGotConfirmationCode(const CAuthenticationUpdateAuthSessionWithSteamGuardCodeResponse &pResponse, const CMsgProtoBufHeader &hdr);
void OnPollSession(const CAuthenticationPollAuthSessionStatusResponse &pResponse, const CMsgProtoBufHeader &hdr);
void OnGotHosts(const JSONNode &root, void *);
void DeleteAuthSettings();
void SendConfirmationCode(bool, const char *pszCode);
// avatars
wchar_t *GetAvatarFilePath(MCONTACT hContact);
bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATION &pai);
void CheckAvatarChange(MCONTACT hContact, const char *avatarHash);
INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM);
INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM);
INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM);
// contacts
void SetAllContactStatuses(int status);
void SetContactStatus(MCONTACT hContact, uint16_t status);
void SendUserInfoRequest(uint64_t id);
void SendUserInfoRequest(const std::vector<uint64_t> &ids);
void SendUserAddRequest(uint64_t id);
void SendUserRemoveRequest(MCONTACT hContact);
void SendUserIgnoreRequest(MCONTACT hContact, bool bIgnore);
MCONTACT GetContactFromAuthEvent(MEVENT hEvent);
void UpdateContactRelationship(MCONTACT hContact, FriendRelationship);
void ContactIsRemoved(MCONTACT hContact);
void ContactIsFriend(MCONTACT hContact);
void ContactIsBlocked(MCONTACT hContact);
void ContactIsUnblocked(MCONTACT hContact);
void ContactIsAskingAuth(MCONTACT hContact);
void OnGotFriendList(const CMsgClientFriendsList &reply, const CMsgProtoBufHeader &hdr);
void OnGotFriendInfo(const CMsgClientPersonaState &reply, const CMsgProtoBufHeader &hdr);
MCONTACT GetContact(int64_t steamId);
MCONTACT AddContact(int64_t steamId, const wchar_t *nick = nullptr, bool isTemporary = false);
void OnGotBlockList(const JSONNode &root, void *);
void OnGotAvatar(const MHttpResponse &response, void *arg);
void OnPendingApproved(const JSONNode &root, void *arg);
void OnPendingIgnoreded(const JSONNode &root, void *arg);
void OnSearchResults(const MHttpResponse &response, void *arg);
void OnSearchByNameStarted(const MHttpResponse &response, void *arg);
// history
void SendHistoryRequest(uint64_t accountId, uint32_t startTime);
void OnGotRecentMessages(const CFriendMessagesGetRecentMessagesResponse &reply, const CMsgProtoBufHeader &hdr);
void OnGotConversations(const CFriendsMessagesGetActiveMessageSessionsResponse &reply, const CMsgProtoBufHeader &hdr);
void OnGotHistoryMessages(const CMsgClientChatGetFriendMessageHistoryResponse &reply, const CMsgProtoBufHeader &hdr);
// menus
static int hChooserMenu;
static HGENMENU contactMenuItems[CMI_MAX];
INT_PTR __cdecl AuthRequestCommand(WPARAM, LPARAM);
INT_PTR __cdecl AuthRevokeCommand(WPARAM, LPARAM);
int __cdecl BlockCommand(WPARAM, LPARAM);
int __cdecl UnblockCommand(WPARAM, LPARAM);
int __cdecl JoinToGameCommand(WPARAM, LPARAM);
INT_PTR __cdecl OpenBlockListCommand(WPARAM, LPARAM);
static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam);
int OnPrebuildContactMenu(WPARAM wParam, LPARAM);
void OnInitStatusMenu();
// notifications
void OnGotNotification(const CSteamNotificationNotificationsReceivedNotification &reply, const CMsgProtoBufHeader &hdr);
// messages
mir_cs m_csOwnMessages;
OBJLIST<COwnMessage> m_arOwnMessages;
int64_t SendFriendMessage(EChatEntryType, int64_t steamId, const char *pszMessage);
void OnGotIncomingMessage(const CFriendMessagesIncomingMessageNotification &reply, const CMsgProtoBufHeader &hdr);
void OnMessageSent(const CFriendMessagesSendMessageResponse &reply, const CMsgProtoBufHeader &hdr);
int __cdecl OnPreCreateMessage(WPARAM, LPARAM lParam);
void SendFriendActiveSessions();
// xstatuses
INT_PTR __cdecl OnGetXStatusEx(WPARAM wParam, LPARAM lParam);
INT_PTR __cdecl OnGetXStatusIcon(WPARAM wParam, LPARAM lParam);
INT_PTR __cdecl OnRequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam);
HICON GetXStatusIcon(int status, UINT flags);
int GetContactXStatus(MCONTACT hContact);
void __cdecl GetAwayMsgThread(void *arg);
// events
int __cdecl OnIdleChanged(WPARAM, LPARAM);
int __cdecl OnOptionsInit(WPARAM wParam, LPARAM lParam);
INT_PTR __cdecl OnGetEventTextChatStates(WPARAM wParam, LPARAM lParam);
// helpers
inline int IdleSeconds()
{
// Based on idle time we report Steam server will mark us as online/away/snooze
switch (m_iStatus) {
case ID_STATUS_AWAY:
return STEAM_API_IDLEOUT_AWAY;
case ID_STATUS_NA:
return STEAM_API_IDLEOUT_SNOOZE;
default:
return 0;
}
// ... or we can report real idle info
// return m_idleTS ? time(0) - m_idleTS : 0;
}
public:
// constructor
CSteamProto(const char *protoName, const wchar_t *userName);
~CSteamProto();
// options
CMOption<wchar_t*> m_wszGroupName; // default group for this account's contacts
CMOption<wchar_t*> m_wszDeviceName; // how do you see this account in the Device List
// PROTO_INTERFACE
MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr) override;
MCONTACT AddToListByEvent(int flags, int iContact, MEVENT hDbEvent) override;
int Authorize(MEVENT hDbEvent) override;
int AuthRecv(MCONTACT, DB::EventInfo &dbei) override;
int AuthDeny(MEVENT hDbEvent, const wchar_t *szReason) override;
int AuthRequest(MCONTACT hContact, const wchar_t *szMessage) override;
INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override;
HANDLE GetAwayMsg(MCONTACT hContact) override;
HANDLE SearchBasic(const wchar_t *id) override;
HANDLE SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) override;
int SendMsg(MCONTACT hContact, MEVENT hReplyEvent, const char *msg) override;
int SetStatus(int iNewStatus) override;
int UserIsTyping(MCONTACT hContact, int type) override;
bool OnContactDeleted(MCONTACT, uint32_t flags) override;
MWindow OnCreateAccMgrUI(MWindow) override;
void OnModulesLoaded() override;
// menus
static void InitMenus();
};
struct CMPlugin : public ACCPROTOPLUGIN<CSteamProto>
{
CMPlugin();
void InitSteamServices();
std::map<EMsg, const ProtobufCMessageDescriptor *> messages;
std::map<std::string, const ProtobufCServiceDescriptor *> services;
typedef void (CSteamProto:: *ServiceResponseHandler)(const ProtobufCMessage &msg, const CMsgProtoBufHeader &hdr);
std::map<EMsg, ServiceResponseHandler> messageHandlers;
std::map<std::string, ServiceResponseHandler> serviceHandlers;
int Load() override;
};
int OnReloadIcons(WPARAM wParam, LPARAM lParam);
void SetContactExtraIcon(MCONTACT hContact, int status);
#endif //_STEAM_PROTO_H_
|