2015-10-28 19:21:27 +01:00
/ *
_ _ _ ____ _ _____
/ \ _ __ ___ | | __ ( _ ) / ___ | | | _ ___ __ _ _ __ ___ | ___ | __ _ _ __ _ __ ___
/ _ \ | ' __ | / __ | | ' _ \ | | \ ___ \ | __ | / _ \ / _ ` | | ' _ ` _ \ | | _ / _ ` | | ' __ | | ' _ ` _ \
/ ___ \ | | | ( __ | | | | | | ___ ) | | | _ | __ / | ( _ | | | | | | | | | _ | | ( _ | | | | | | | | | |
/ _ / \ _ \ | _ | \ ___ | | _ | | _ | | _ | | ____ / \ __ | \ ___ | \ __ , _ | | _ | | _ | | _ | | _ | \ __ , _ | | _ | | _ | | _ | | _ |
Copyright 2015 Ł ukasz "JustArchi" Domeradzki
Contact : JustArchi @JustArchi . net
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2015-12-11 22:53:28 +01:00
using Newtonsoft.Json ;
using SteamAuth ;
2015-10-28 19:21:27 +01:00
using SteamKit2 ;
2015-12-21 10:24:29 +01:00
using SteamKit2.Internal ;
2015-10-25 06:16:50 +01:00
using System ;
2015-11-18 14:28:46 +01:00
using System.Collections.Concurrent ;
2015-10-25 06:16:50 +01:00
using System.Collections.Generic ;
using System.IO ;
using System.Security.Cryptography ;
using System.Threading.Tasks ;
using System.Xml ;
2016-01-10 20:22:46 +02:00
using System.Text ;
2015-10-25 06:16:50 +01:00
namespace ArchiSteamFarm {
2015-11-27 16:25:03 +01:00
internal sealed class Bot {
2015-12-21 10:06:37 +01:00
private const ulong ArchiSCFarmGroup = 103582791440160998 ;
2015-10-28 19:21:27 +01:00
private const ushort CallbackSleep = 500 ; // In miliseconds
2015-10-25 06:16:50 +01:00
2015-12-21 10:24:29 +01:00
private static readonly uint LoginID = MsgClientLogon . ObfuscationMask ; // This must be the same for all ASF bots and all ASF processes
2015-10-25 06:16:50 +01:00
2016-01-03 22:23:30 +01:00
internal static readonly ConcurrentDictionary < string , Bot > Bots = new ConcurrentDictionary < string , Bot > ( ) ;
2015-12-23 09:40:42 +01:00
internal static readonly HashSet < uint > GlobalBlacklist = new HashSet < uint > { 303700 , 335590 , 368020 , 425280 } ;
2015-12-11 22:53:28 +01:00
private readonly string ConfigFile , LoginKeyFile , MobileAuthenticatorFile , SentryFile ;
2015-11-20 14:47:16 +01:00
internal readonly string BotName ;
2015-12-18 14:54:14 +01:00
internal readonly ArchiHandler ArchiHandler ;
internal readonly ArchiWebHandler ArchiWebHandler ;
internal readonly CallbackManager CallbackManager ;
internal readonly CardsFarmer CardsFarmer ;
internal readonly SteamClient SteamClient ;
internal readonly SteamFriends SteamFriends ;
internal readonly SteamUser SteamUser ;
internal readonly Trading Trading ;
2015-10-25 06:16:50 +01:00
2015-12-23 10:58:14 +01:00
private bool KeepRunning = true ;
private bool InvalidPassword = false ;
2015-12-09 20:55:43 +01:00
private bool LoggedInElsewhere = false ;
2015-12-11 22:53:28 +01:00
private string AuthCode , LoginKey , TwoFactorAuth ;
2015-10-25 06:16:50 +01:00
2015-12-11 22:53:28 +01:00
internal SteamGuardAccount SteamGuardAccount { get ; private set ; }
2015-10-25 06:16:50 +01:00
// Config variables
2015-10-31 09:17:56 +01:00
internal bool Enabled { get ; private set ; } = false ;
2015-10-31 03:27:58 +01:00
internal string SteamLogin { get ; private set ; } = "null" ;
internal string SteamPassword { get ; private set ; } = "null" ;
internal string SteamNickname { get ; private set ; } = "null" ;
internal string SteamApiKey { get ; private set ; } = "null" ;
internal string SteamParentalPIN { get ; private set ; } = "0" ;
2015-11-04 04:46:55 +01:00
internal ulong SteamMasterID { get ; private set ; } = 0 ;
2015-10-31 03:27:58 +01:00
internal ulong SteamMasterClanID { get ; private set ; } = 0 ;
2015-11-21 18:27:30 +01:00
internal bool CardDropsRestricted { get ; private set ; } = false ;
2015-12-20 19:48:58 +01:00
internal bool FarmOffline { get ; private set ; } = false ;
internal bool HandleOfflineMessages { get ; private set ; } = false ;
2016-01-10 20:36:56 +01:00
internal bool ForwardKeysToOtherBots { get ; private set ; } = false ;
2015-12-11 22:53:28 +01:00
internal bool UseAsfAsMobileAuthenticator { get ; private set ; } = false ;
2015-10-31 06:09:03 +01:00
internal bool ShutdownOnFarmingFinished { get ; private set ; } = false ;
2015-12-23 09:40:42 +01:00
internal HashSet < uint > Blacklist { get ; private set ; } = new HashSet < uint > ( ) ;
2015-10-31 03:27:58 +01:00
internal bool Statistics { get ; private set ; } = true ;
2015-11-25 16:49:01 +01:00
private static bool IsValidCdKey ( string key ) {
if ( string . IsNullOrEmpty ( key ) ) {
return false ;
}
2016-01-10 22:25:15 +01:00
// Steam keys are offered in many formats: https://support.steampowered.com/kb_article.php?ref=7480-WUSF-3601
// It's pointless to implement them all, so we'll just do a simple check if key is supposed to be valid
// Every valid key, apart from Prey one has at least two dashes
return Utilities . GetCharCountInString ( key , '-' ) > = 2 ;
2015-11-25 16:49:01 +01:00
}
2016-01-07 22:29:55 +01:00
internal static string GetAnyBotName ( ) {
foreach ( string botName in Bots . Keys ) {
return botName ;
}
return null ;
}
2015-11-25 16:49:01 +01:00
2015-10-31 03:27:58 +01:00
internal static int GetRunningBotsCount ( ) {
2015-11-18 14:28:46 +01:00
return Bots . Count ;
2015-11-18 14:30:05 +01:00
}
2015-10-31 03:27:58 +01:00
2015-10-31 05:27:30 +01:00
internal static async Task ShutdownAllBots ( ) {
List < Task > tasks = new List < Task > ( ) ;
2015-11-18 14:28:46 +01:00
foreach ( Bot bot in Bots . Values ) {
tasks . Add ( Task . Run ( async ( ) = > await bot . Shutdown ( ) . ConfigureAwait ( false ) ) ) ;
2015-10-31 03:27:58 +01:00
}
2015-10-31 05:27:30 +01:00
await Task . WhenAll ( tasks ) . ConfigureAwait ( false ) ;
2015-10-31 03:27:58 +01:00
}
2015-10-25 06:16:50 +01:00
2015-10-28 19:21:27 +01:00
internal Bot ( string botName ) {
2015-11-01 02:04:44 +01:00
if ( Bots . ContainsKey ( botName ) ) {
return ;
}
2015-10-25 06:16:50 +01:00
BotName = botName ;
2016-01-01 12:46:49 +01:00
ConfigFile = Path . Combine ( Program . ConfigDirectory , BotName + ".xml" ) ;
LoginKeyFile = Path . Combine ( Program . ConfigDirectory , BotName + ".key" ) ;
MobileAuthenticatorFile = Path . Combine ( Program . ConfigDirectory , BotName + ".auth" ) ;
SentryFile = Path . Combine ( Program . ConfigDirectory , BotName + ".bin" ) ;
2015-10-25 06:16:50 +01:00
2015-11-01 02:04:44 +01:00
if ( ! ReadConfig ( ) ) {
return ;
}
2015-10-25 06:16:50 +01:00
if ( ! Enabled ) {
return ;
}
2015-10-28 19:21:27 +01:00
2015-11-18 14:28:46 +01:00
Bots . AddOrUpdate ( BotName , this , ( key , value ) = > this ) ;
2015-10-31 03:27:58 +01:00
// Initialize
SteamClient = new SteamClient ( ) ;
ArchiHandler = new ArchiHandler ( ) ;
SteamClient . AddHandler ( ArchiHandler ) ;
CallbackManager = new CallbackManager ( SteamClient ) ;
CallbackManager . Subscribe < SteamClient . ConnectedCallback > ( OnConnected ) ;
CallbackManager . Subscribe < SteamClient . DisconnectedCallback > ( OnDisconnected ) ;
SteamFriends = SteamClient . GetHandler < SteamFriends > ( ) ;
2015-12-21 19:28:59 +01:00
CallbackManager . Subscribe < SteamFriends . ChatInviteCallback > ( OnChatInvite ) ;
CallbackManager . Subscribe < SteamFriends . ChatMsgCallback > ( OnChatMsg ) ;
2015-10-31 03:27:58 +01:00
CallbackManager . Subscribe < SteamFriends . FriendsListCallback > ( OnFriendsList ) ;
CallbackManager . Subscribe < SteamFriends . FriendMsgCallback > ( OnFriendMsg ) ;
2015-12-21 10:55:55 +01:00
CallbackManager . Subscribe < SteamFriends . FriendMsgHistoryCallback > ( OnFriendMsgHistory ) ;
2015-10-31 03:27:58 +01:00
2015-12-11 22:53:28 +01:00
if ( UseAsfAsMobileAuthenticator & & File . Exists ( MobileAuthenticatorFile ) ) {
SteamGuardAccount = JsonConvert . DeserializeObject < SteamGuardAccount > ( File . ReadAllText ( MobileAuthenticatorFile ) ) ;
}
2015-10-31 03:27:58 +01:00
SteamUser = SteamClient . GetHandler < SteamUser > ( ) ;
CallbackManager . Subscribe < SteamUser . AccountInfoCallback > ( OnAccountInfo ) ;
CallbackManager . Subscribe < SteamUser . LoggedOffCallback > ( OnLoggedOff ) ;
CallbackManager . Subscribe < SteamUser . LoggedOnCallback > ( OnLoggedOn ) ;
2015-12-11 22:53:28 +01:00
CallbackManager . Subscribe < SteamUser . LoginKeyCallback > ( OnLoginKey ) ;
2015-10-31 03:27:58 +01:00
CallbackManager . Subscribe < SteamUser . UpdateMachineAuthCallback > ( OnMachineAuth ) ;
2016-01-02 17:22:35 +01:00
CallbackManager . Subscribe < ArchiHandler . NotificationsCallback > ( OnNotifications ) ;
2015-12-20 19:48:58 +01:00
CallbackManager . Subscribe < ArchiHandler . OfflineMessageCallback > ( OnOfflineMessage ) ;
2015-10-31 03:27:58 +01:00
CallbackManager . Subscribe < ArchiHandler . PurchaseResponseCallback > ( OnPurchaseResponse ) ;
ArchiWebHandler = new ArchiWebHandler ( this , SteamApiKey ) ;
CardsFarmer = new CardsFarmer ( this ) ;
Trading = new Trading ( this ) ;
2016-01-07 22:08:06 +01:00
// Before attempting to connect, initialize our list of CMs
SteamDirectory . Initialize ( ) . Wait ( ) ;
2015-10-31 03:27:58 +01:00
// Start
2015-12-22 16:51:37 +01:00
var handleCallbacks = Task . Run ( ( ) = > HandleCallbacks ( ) ) ;
var start = Task . Run ( async ( ) = > await Start ( ) . ConfigureAwait ( false ) ) ;
2015-10-25 06:16:50 +01:00
}
2015-12-17 22:04:13 +01:00
internal async Task AcceptAllConfirmations ( ) {
2015-12-11 22:53:28 +01:00
if ( SteamGuardAccount = = null ) {
return ;
}
2015-12-17 22:04:13 +01:00
await SteamGuardAccount . RefreshSessionAsync ( ) . ConfigureAwait ( false ) ;
2015-12-13 15:25:00 +01:00
try {
2015-12-17 22:04:13 +01:00
foreach ( Confirmation confirmation in await SteamGuardAccount . FetchConfirmationsAsync ( ) . ConfigureAwait ( false ) ) {
2015-12-13 15:25:00 +01:00
if ( SteamGuardAccount . AcceptConfirmation ( confirmation ) ) {
Logging . LogGenericInfo ( BotName , "Accepting confirmation: Success!" ) ;
} else {
Logging . LogGenericWarning ( BotName , "Accepting confirmation: Failed!" ) ;
}
2015-12-11 22:53:28 +01:00
}
2015-12-13 15:25:00 +01:00
} catch ( SteamGuardAccount . WGTokenInvalidException ) {
Logging . LogGenericWarning ( BotName , "Accepting confirmation: Failed!" ) ;
Logging . LogGenericWarning ( BotName , "Confirmation could not be accepted because of invalid token exception" ) ;
Logging . LogGenericWarning ( BotName , "If issue persists, consider removing and readding ASF 2FA" ) ;
2015-12-11 22:53:28 +01:00
}
}
private bool LinkMobileAuthenticator ( ) {
if ( SteamGuardAccount ! = null ) {
return false ;
}
Logging . LogGenericNotice ( BotName , "Linking new ASF MobileAuthenticator..." ) ;
UserLogin userLogin = new UserLogin ( SteamLogin , SteamPassword ) ;
LoginResult loginResult ;
while ( ( loginResult = userLogin . DoLogin ( ) ) ! = LoginResult . LoginOkay ) {
switch ( loginResult ) {
case LoginResult . NeedEmail :
userLogin . EmailCode = Program . GetUserInput ( BotName , Program . EUserInputType . SteamGuard ) ;
break ;
default :
Logging . LogGenericError ( BotName , "Unhandled situation: " + loginResult ) ;
return false ;
}
}
AuthenticatorLinker authenticatorLinker = new AuthenticatorLinker ( userLogin . Session ) ;
2015-12-13 13:51:58 +01:00
AuthenticatorLinker . LinkResult linkResult ;
while ( ( linkResult = authenticatorLinker . AddAuthenticator ( ) ) ! = AuthenticatorLinker . LinkResult . AwaitingFinalization ) {
switch ( linkResult ) {
case AuthenticatorLinker . LinkResult . MustProvidePhoneNumber :
2015-12-11 22:53:28 +01:00
authenticatorLinker . PhoneNumber = Program . GetUserInput ( BotName , Program . EUserInputType . PhoneNumber ) ;
2015-12-13 13:51:58 +01:00
break ;
default :
Logging . LogGenericError ( BotName , "Unhandled situation: " + linkResult ) ;
return false ;
}
2015-12-11 22:53:28 +01:00
}
SteamGuardAccount = authenticatorLinker . LinkedAccount ;
try {
File . WriteAllText ( MobileAuthenticatorFile , JsonConvert . SerializeObject ( SteamGuardAccount ) ) ;
} catch ( Exception e ) {
Logging . LogGenericException ( BotName , e ) ;
return false ;
}
AuthenticatorLinker . FinalizeResult finalizeResult = authenticatorLinker . FinalizeAddAuthenticator ( Program . GetUserInput ( BotName , Program . EUserInputType . SMS ) ) ;
if ( finalizeResult ! = AuthenticatorLinker . FinalizeResult . Success ) {
Logging . LogGenericError ( BotName , "Unhandled situation: " + finalizeResult ) ;
DelinkMobileAuthenticator ( ) ;
return false ;
}
Logging . LogGenericInfo ( BotName , "Successfully linked ASF as new mobile authenticator for this account!" ) ;
Program . GetUserInput ( BotName , Program . EUserInputType . RevocationCode , SteamGuardAccount . RevocationCode ) ;
return true ;
}
private bool DelinkMobileAuthenticator ( ) {
if ( SteamGuardAccount = = null ) {
return false ;
}
bool result = SteamGuardAccount . DeactivateAuthenticator ( ) ;
SteamGuardAccount = null ;
File . Delete ( MobileAuthenticatorFile ) ;
return result ;
}
2015-11-01 02:04:44 +01:00
private bool ReadConfig ( ) {
if ( ! File . Exists ( ConfigFile ) ) {
return false ;
}
2015-11-04 04:51:52 +01:00
try {
using ( XmlReader reader = XmlReader . Create ( ConfigFile ) ) {
while ( reader . Read ( ) ) {
if ( reader . NodeType ! = XmlNodeType . Element ) {
continue ;
}
string key = reader . Name ;
if ( string . IsNullOrEmpty ( key ) ) {
continue ;
}
string value = reader . GetAttribute ( "value" ) ;
if ( string . IsNullOrEmpty ( value ) ) {
continue ;
}
switch ( key ) {
case "Enabled" :
Enabled = bool . Parse ( value ) ;
break ;
case "SteamLogin" :
SteamLogin = value ;
break ;
case "SteamPassword" :
SteamPassword = value ;
break ;
case "SteamNickname" :
SteamNickname = value ;
break ;
case "SteamApiKey" :
SteamApiKey = value ;
break ;
case "SteamParentalPIN" :
SteamParentalPIN = value ;
break ;
case "SteamMasterID" :
SteamMasterID = ulong . Parse ( value ) ;
break ;
case "SteamMasterClanID" :
SteamMasterClanID = ulong . Parse ( value ) ;
break ;
2015-12-11 22:53:28 +01:00
case "UseAsfAsMobileAuthenticator" :
UseAsfAsMobileAuthenticator = bool . Parse ( value ) ;
break ;
2015-11-21 18:27:30 +01:00
case "CardDropsRestricted" :
CardDropsRestricted = bool . Parse ( value ) ;
break ;
2015-12-20 19:48:58 +01:00
case "FarmOffline" :
FarmOffline = bool . Parse ( value ) ;
2015-12-20 19:01:05 +01:00
break ;
2015-12-20 19:48:58 +01:00
case "HandleOfflineMessages" :
HandleOfflineMessages = bool . Parse ( value ) ;
2015-12-20 19:50:54 +01:00
break ;
2016-01-10 20:36:56 +01:00
case "ForwardKeysToOtherBots" :
ForwardKeysToOtherBots = bool . Parse ( value ) ;
break ;
2015-12-20 19:50:54 +01:00
case "ShutdownOnFarmingFinished" :
2015-11-04 04:51:52 +01:00
ShutdownOnFarmingFinished = bool . Parse ( value ) ;
break ;
case "Blacklist" :
2015-11-04 04:55:00 +01:00
Blacklist . Clear ( ) ;
2015-11-04 04:51:52 +01:00
foreach ( string appID in value . Split ( ',' ) ) {
Blacklist . Add ( uint . Parse ( appID ) ) ;
}
break ;
case "Statistics" :
Statistics = bool . Parse ( value ) ;
break ;
default :
Logging . LogGenericWarning ( BotName , "Unrecognized config value: " + key + "=" + value ) ;
break ;
}
2015-10-28 22:34:53 +01:00
}
2015-10-25 06:16:50 +01:00
}
2015-11-18 14:28:46 +01:00
} catch ( Exception e ) {
2015-11-04 04:51:52 +01:00
Logging . LogGenericException ( BotName , e ) ;
Logging . LogGenericError ( BotName , "Your config for this bot instance is invalid, it won't run!" ) ;
return false ;
2015-10-25 06:16:50 +01:00
}
2015-11-01 02:04:44 +01:00
return true ;
2015-10-25 06:16:50 +01:00
}
2015-12-22 16:51:37 +01:00
internal async Task Restart ( ) {
await Stop ( ) . ConfigureAwait ( false ) ;
await Start ( ) . ConfigureAwait ( false ) ;
}
2015-11-04 04:42:13 +01:00
internal async Task Start ( ) {
2015-12-22 16:51:37 +01:00
if ( SteamClient . IsConnected ) {
2015-10-25 06:16:50 +01:00
return ;
}
2015-11-04 04:42:13 +01:00
Logging . LogGenericInfo ( BotName , "Starting..." ) ;
2015-12-06 19:38:09 +01:00
// 2FA tokens are expiring soon, use limiter only when we don't have any pending
if ( TwoFactorAuth = = null ) {
await Program . LimitSteamRequestsAsync ( ) . ConfigureAwait ( false ) ;
}
2015-11-04 04:31:27 +01:00
SteamClient . Connect ( ) ;
2015-10-25 06:16:50 +01:00
}
2015-10-31 05:27:30 +01:00
internal async Task Stop ( ) {
2015-12-22 16:51:37 +01:00
if ( ! SteamClient . IsConnected ) {
2015-10-25 06:16:50 +01:00
return ;
}
2015-12-22 16:51:37 +01:00
await Utilities . SleepAsync ( 0 ) ; // TODO: This is here only to make VS happy, for now
Logging . LogGenericInfo ( BotName , "Stopping..." ) ;
2015-11-01 02:08:41 +01:00
SteamClient . Disconnect ( ) ;
2015-10-31 03:50:08 +01:00
}
2015-10-31 03:27:58 +01:00
2016-01-04 00:02:18 +01:00
internal async Task Shutdown ( ) {
KeepRunning = false ;
await Stop ( ) . ConfigureAwait ( false ) ;
2015-12-12 08:04:41 +01:00
Bot bot ;
2016-01-04 00:02:18 +01:00
Bots . TryRemove ( BotName , out bot ) ;
Program . OnBotShutdown ( ) ;
}
2015-12-12 08:04:41 +01:00
2016-01-04 00:02:18 +01:00
internal static async Task < bool > Shutdown ( string botName ) {
2015-12-12 08:04:41 +01:00
if ( string . IsNullOrEmpty ( botName ) ) {
2016-01-04 00:02:18 +01:00
return false ;
2015-11-01 02:04:44 +01:00
}
2016-01-04 00:02:18 +01:00
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return false ;
}
2015-11-01 02:04:44 +01:00
2016-01-04 00:02:18 +01:00
await bot . Shutdown ( ) . ConfigureAwait ( false ) ;
2015-11-01 02:04:44 +01:00
return true ;
}
2015-10-31 05:27:30 +01:00
internal async Task OnFarmingFinished ( ) {
2015-10-31 03:27:58 +01:00
if ( ShutdownOnFarmingFinished ) {
2015-10-31 05:27:30 +01:00
await Shutdown ( ) . ConfigureAwait ( false ) ;
2015-10-31 03:27:58 +01:00
}
2015-10-25 06:16:50 +01:00
}
private void HandleCallbacks ( ) {
TimeSpan timeSpan = TimeSpan . FromMilliseconds ( CallbackSleep ) ;
2015-12-23 10:58:14 +01:00
while ( KeepRunning ) {
2015-10-25 06:16:50 +01:00
CallbackManager . RunWaitCallbacks ( timeSpan ) ;
}
}
2015-12-21 19:28:59 +01:00
private void SendMessage ( ulong steamID , string message ) {
2015-11-01 02:04:44 +01:00
if ( steamID = = 0 | | string . IsNullOrEmpty ( message ) ) {
return ;
}
2015-12-21 19:28:59 +01:00
// TODO: I really need something better
if ( steamID < 110300000000000000 ) {
SteamFriends . SendChatMessage ( steamID , EChatEntryType . ChatMsg , message ) ;
} else {
SteamFriends . SendChatRoomMessage ( steamID , EChatEntryType . ChatMsg , message ) ;
}
2015-11-01 02:04:44 +01:00
}
2016-01-03 22:23:30 +01:00
internal static string ResponseStatus ( string botName ) {
if ( string . IsNullOrEmpty ( botName ) ) {
return null ;
2016-01-10 18:50:17 +02:00
}
2015-11-18 22:10:24 +01:00
2016-01-10 19:31:21 +01:00
Bot bot ;
2016-01-03 22:23:30 +01:00
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
2016-01-10 19:31:21 +01:00
return "Couldn't find any bot named " + botName + "!" ;
2015-11-18 22:10:24 +01:00
}
2016-01-10 19:31:21 +01:00
2016-01-10 19:35:03 +01:00
return bot . ResponseStatus ( ) ;
}
2016-01-10 20:22:46 +02:00
2016-01-10 19:35:03 +01:00
internal string ResponseStatus ( ) {
if ( CardsFarmer . CurrentGamesFarming . Count > 0 ) {
return "Bot " + BotName + " is currently farming appIDs: " + string . Join ( ", " , CardsFarmer . CurrentGamesFarming ) + " and has a total of " + CardsFarmer . GamesToFarm . Count + " games left to farm." ;
} else {
return "Bot " + BotName + " is not farming." ;
2016-01-10 18:34:30 +02:00
}
2015-11-01 02:04:44 +01:00
}
2016-01-10 19:39:12 +02:00
internal static string ResponseStatusAll ( ) {
2016-01-10 19:31:21 +01:00
StringBuilder result = new StringBuilder ( Environment . NewLine ) ;
2016-01-10 19:35:03 +01:00
foreach ( Bot bot in Bots . Values ) {
result . Append ( bot . ResponseStatus ( ) + Environment . NewLine ) ;
2016-01-10 19:39:12 +02:00
}
2016-01-10 19:35:03 +01:00
2016-01-10 20:22:46 +02:00
result . Append ( "Currently " + Bots . Count + " bots are running." ) ;
return result . ToString ( ) ;
2016-01-10 19:39:12 +02:00
}
2016-01-04 00:02:18 +01:00
internal static string Response2FA ( string botName ) {
if ( string . IsNullOrEmpty ( botName ) ) {
return null ;
2015-12-11 22:53:28 +01:00
}
Bot bot ;
2016-01-04 00:02:18 +01:00
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
2015-12-11 22:53:28 +01:00
}
if ( bot . SteamGuardAccount = = null ) {
2016-01-04 00:02:18 +01:00
return "That bot doesn't have ASF 2FA enabled!" ;
2015-12-11 22:53:28 +01:00
}
long timeLeft = 30 - TimeAligner . GetSteamTime ( ) % 30 ;
2016-01-04 00:02:18 +01:00
return "2FA Token: " + bot . SteamGuardAccount . GenerateSteamGuardCode ( ) + " (expires in " + timeLeft + " seconds)" ;
2015-12-11 22:53:28 +01:00
}
2016-01-04 00:02:18 +01:00
internal static string Response2FAOff ( string botName ) {
if ( string . IsNullOrEmpty ( botName ) ) {
return null ;
2015-12-11 22:53:28 +01:00
}
Bot bot ;
2016-01-04 00:02:18 +01:00
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
2015-12-11 22:53:28 +01:00
}
if ( bot . SteamGuardAccount = = null ) {
2016-01-04 00:02:18 +01:00
return "That bot doesn't have ASF 2FA enabled!" ;
2015-12-11 22:53:28 +01:00
}
if ( bot . DelinkMobileAuthenticator ( ) ) {
2016-01-04 00:02:18 +01:00
return "Done! Bot is no longer using ASF 2FA" ;
2015-12-11 22:53:28 +01:00
} else {
2016-01-04 00:02:18 +01:00
return "Something went wrong during delinking mobile authenticator!" ;
2015-12-11 22:53:28 +01:00
}
}
2016-01-10 20:36:56 +01:00
internal async Task < string > ResponseRedeem ( string message ) {
StringBuilder response = new StringBuilder ( ) ;
using ( StringReader reader = new StringReader ( message ) ) {
2016-01-10 20:53:32 +01:00
string key ;
while ( ( key = reader . ReadLine ( ) ) ! = null ) {
if ( ! IsValidCdKey ( key ) ) {
2016-01-10 20:36:56 +01:00
continue ;
}
2016-01-04 00:02:18 +01:00
2016-01-10 20:36:56 +01:00
ArchiHandler . PurchaseResponseCallback result ;
try {
2016-01-10 20:53:32 +01:00
result = await ArchiHandler . RedeemKey ( key ) ;
2016-01-10 20:36:56 +01:00
} catch ( Exception e ) {
Logging . LogGenericException ( BotName , e ) ;
break ;
}
if ( result = = null ) {
break ;
}
var purchaseResult = result . PurchaseResult ;
var items = result . Items ;
switch ( purchaseResult ) {
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . AlreadyOwned :
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . BaseGameRequired :
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . OnCooldown :
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . RegionLocked :
2016-01-10 20:53:32 +01:00
response . Append ( Environment . NewLine + "<" + BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string . Join ( "" , items ) ) ;
2016-01-10 20:36:56 +01:00
if ( ! ForwardKeysToOtherBots ) {
break ;
}
2016-01-10 20:45:53 +01:00
bool alreadyHandled = false ;
2016-01-10 20:36:56 +01:00
foreach ( Bot bot in Bots . Values ) {
2016-01-10 20:45:53 +01:00
if ( alreadyHandled ) {
break ;
}
2016-01-10 20:36:56 +01:00
if ( bot = = this ) {
continue ;
}
ArchiHandler . PurchaseResponseCallback otherResult ;
try {
2016-01-10 20:53:32 +01:00
otherResult = await bot . ArchiHandler . RedeemKey ( key ) ;
2016-01-10 20:36:56 +01:00
} catch ( Exception e ) {
Logging . LogGenericException ( bot . BotName , e ) ;
break ; // We're done with this key
}
if ( otherResult = = null ) {
break ; // We're done with this key
}
var otherPurchaseResult = otherResult . PurchaseResult ;
var otherItems = otherResult . Items ;
2016-01-10 20:45:53 +01:00
switch ( otherPurchaseResult ) {
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . OK :
alreadyHandled = true ; // We're done with this key
2016-01-10 20:53:32 +01:00
response . Append ( Environment . NewLine + "<" + bot . BotName + "> Key: " + key + " | Status: " + otherPurchaseResult + " | Items: " + string . Join ( "" , otherItems ) ) ;
2016-01-10 20:45:53 +01:00
break ;
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . DuplicatedKey :
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . InvalidKey :
alreadyHandled = true ; // This key doesn't work, don't try to redeem it anymore
2016-01-10 20:53:32 +01:00
response . Append ( Environment . NewLine + "<" + bot . BotName + "> Key: " + key + " | Status: " + otherPurchaseResult + " | Items: " + string . Join ( "" , otherItems ) ) ;
break ;
default :
response . Append ( Environment . NewLine + "<" + bot . BotName + "> Key: " + key + " | Status: " + otherPurchaseResult + " | Items: " + string . Join ( "" , otherItems ) ) ;
2016-01-10 20:45:53 +01:00
break ;
2016-01-10 20:36:56 +01:00
}
}
break ;
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . OK :
2016-01-10 20:53:32 +01:00
response . Append ( Environment . NewLine + "<" + BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string . Join ( "" , items ) ) ;
2016-01-10 20:36:56 +01:00
break ;
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . DuplicatedKey :
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . InvalidKey :
2016-01-10 20:53:32 +01:00
response . Append ( Environment . NewLine + "<" + BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string . Join ( "" , items ) ) ;
2016-01-10 20:36:56 +01:00
break ;
}
}
2016-01-02 17:22:35 +01:00
}
2016-01-10 20:36:56 +01:00
if ( response . Length = = 0 ) {
2016-01-04 00:02:18 +01:00
return null ;
2016-01-02 17:22:35 +01:00
}
2016-01-10 20:36:56 +01:00
return response . ToString ( ) ;
}
internal static async Task < string > ResponseRedeem ( string botName , string message ) {
if ( string . IsNullOrEmpty ( botName ) | | string . IsNullOrEmpty ( message ) ) {
2016-01-04 00:02:18 +01:00
return null ;
2016-01-02 17:22:35 +01:00
}
2016-01-10 20:36:56 +01:00
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
2016-01-02 17:22:35 +01:00
2016-01-10 20:36:56 +01:00
return await bot . ResponseRedeem ( message ) . ConfigureAwait ( false ) ;
2016-01-02 17:22:35 +01:00
}
2016-01-04 00:02:18 +01:00
internal static string ResponseStart ( string botName ) {
if ( string . IsNullOrEmpty ( botName ) ) {
return null ;
2015-11-01 02:04:44 +01:00
}
2015-12-12 08:04:41 +01:00
if ( Bots . ContainsKey ( botName ) ) {
2016-01-04 00:02:18 +01:00
return "That bot instance is already running!" ;
2015-11-01 02:04:44 +01:00
}
2015-12-12 08:04:41 +01:00
new Bot ( botName ) ;
if ( Bots . ContainsKey ( botName ) ) {
2016-01-04 00:02:18 +01:00
return "Done!" ;
2015-11-01 02:04:44 +01:00
} else {
2016-01-04 00:02:18 +01:00
return "That bot instance failed to start, make sure that XML config exists and bot is active!" ;
2015-11-01 02:04:44 +01:00
}
}
2016-01-04 00:02:18 +01:00
internal static async Task < string > ResponseStop ( string botName ) {
if ( string . IsNullOrEmpty ( botName ) ) {
return null ;
2015-11-01 02:04:44 +01:00
}
2016-01-04 00:02:18 +01:00
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "That bot instance is already inactive!" ;
2015-11-01 02:04:44 +01:00
}
2015-12-12 08:04:41 +01:00
if ( await Shutdown ( botName ) . ConfigureAwait ( false ) ) {
2016-01-04 00:02:18 +01:00
return "Done!" ;
2015-11-01 02:04:44 +01:00
} else {
2016-01-04 00:02:18 +01:00
return "That bot instance failed to shutdown!" ;
2015-11-01 02:04:44 +01:00
}
}
2016-01-04 00:02:18 +01:00
internal async Task < string > HandleMessage ( string message ) {
if ( string . IsNullOrEmpty ( message ) ) {
return null ;
2015-12-21 10:55:55 +01:00
}
2016-01-10 20:36:56 +01:00
if ( ! message . StartsWith ( "!" ) ) {
2016-01-04 00:02:18 +01:00
return await ResponseRedeem ( BotName , message ) . ConfigureAwait ( false ) ;
2015-12-21 10:55:55 +01:00
}
if ( ! message . Contains ( " " ) ) {
switch ( message ) {
case "!2fa" :
2016-01-04 00:02:18 +01:00
return Response2FA ( BotName ) ;
2015-12-21 10:55:55 +01:00
case "!2faoff" :
2016-01-04 00:02:18 +01:00
return Response2FAOff ( BotName ) ;
2015-12-21 10:55:55 +01:00
case "!exit" :
await ShutdownAllBots ( ) . ConfigureAwait ( false ) ;
2016-01-04 00:02:18 +01:00
return "Done" ;
2015-12-21 10:55:55 +01:00
case "!restart" :
await Program . Restart ( ) . ConfigureAwait ( false ) ;
2016-01-04 00:02:18 +01:00
return "Done" ;
2015-12-21 10:55:55 +01:00
case "!status" :
2016-01-10 19:35:03 +01:00
return ResponseStatus ( ) ;
2016-01-10 19:39:12 +02:00
case "!statusall" :
return ResponseStatusAll ( ) ;
2015-12-21 10:55:55 +01:00
case "!stop" :
2016-01-04 00:02:18 +01:00
return await ResponseStop ( BotName ) . ConfigureAwait ( false ) ;
default :
return "Unrecognized command: " + message ;
2015-12-21 10:55:55 +01:00
}
} else {
string [ ] args = message . Split ( ' ' ) ;
switch ( args [ 0 ] ) {
case "!2fa" :
2016-01-04 00:02:18 +01:00
return Response2FA ( args [ 1 ] ) ;
2015-12-21 10:55:55 +01:00
case "!2faoff" :
2016-01-04 00:02:18 +01:00
return Response2FAOff ( args [ 1 ] ) ;
2015-12-21 10:55:55 +01:00
case "!redeem" :
2016-01-04 00:02:18 +01:00
string botName ;
string key ;
if ( args . Length > 2 ) {
botName = args [ 1 ] ;
key = args [ 2 ] ;
} else {
botName = BotName ;
key = args [ 1 ] ;
}
return await ResponseRedeem ( botName , key ) . ConfigureAwait ( false ) ;
2015-12-21 10:55:55 +01:00
case "!start" :
2016-01-04 00:02:18 +01:00
return ResponseStart ( args [ 1 ] ) ;
2015-12-21 10:55:55 +01:00
case "!stop" :
2016-01-04 00:02:18 +01:00
return await ResponseStop ( args [ 1 ] ) . ConfigureAwait ( false ) ;
2015-12-21 10:55:55 +01:00
case "!status" :
2016-01-04 00:02:18 +01:00
return ResponseStatus ( args [ 1 ] ) ;
default :
return "Unrecognized command: " + args [ 0 ] ;
2015-12-21 10:55:55 +01:00
}
}
}
2016-01-04 00:02:18 +01:00
private async Task HandleMessage ( ulong steamID , string message ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( message ) ) {
return ;
}
SendMessage ( steamID , await HandleMessage ( message ) . ConfigureAwait ( false ) ) ;
}
2015-10-25 06:16:50 +01:00
private void OnConnected ( SteamClient . ConnectedCallback callback ) {
if ( callback = = null ) {
return ;
}
if ( callback . Result ! = EResult . OK ) {
Logging . LogGenericError ( BotName , "Unable to connect to Steam: " + callback . Result ) ;
return ;
}
Logging . LogGenericInfo ( BotName , "Connected to Steam!" ) ;
2015-12-11 22:53:28 +01:00
if ( File . Exists ( LoginKeyFile ) ) {
LoginKey = File . ReadAllText ( LoginKeyFile ) ;
}
2015-10-25 06:16:50 +01:00
byte [ ] sentryHash = null ;
if ( File . Exists ( SentryFile ) ) {
byte [ ] sentryFileContent = File . ReadAllBytes ( SentryFile ) ;
sentryHash = CryptoHelper . SHAHash ( sentryFileContent ) ;
}
2015-10-31 03:27:58 +01:00
if ( SteamLogin . Equals ( "null" ) ) {
SteamLogin = Program . GetUserInput ( BotName , Program . EUserInputType . Login ) ;
2015-10-28 23:29:50 +01:00
}
2015-12-11 22:53:28 +01:00
if ( SteamPassword . Equals ( "null" ) & & string . IsNullOrEmpty ( LoginKey ) ) {
2015-10-31 03:27:58 +01:00
SteamPassword = Program . GetUserInput ( BotName , Program . EUserInputType . Password ) ;
2015-10-28 23:29:50 +01:00
}
2015-12-21 10:06:37 +01:00
SteamUser . LogOn ( new SteamUser . LogOnDetails {
2015-12-16 01:20:54 +01:00
Username = SteamLogin ,
Password = SteamPassword ,
AuthCode = AuthCode ,
2015-12-21 10:06:37 +01:00
LoginID = LoginID ,
2015-12-16 01:20:54 +01:00
LoginKey = LoginKey ,
TwoFactorCode = TwoFactorAuth ,
SentryFileHash = sentryHash ,
ShouldRememberPassword = true
2015-12-16 20:01:40 +01:00
} ) ;
2015-10-25 06:16:50 +01:00
}
2015-11-01 02:04:44 +01:00
private async void OnDisconnected ( SteamClient . DisconnectedCallback callback ) {
2015-10-25 06:16:50 +01:00
if ( callback = = null ) {
return ;
}
2015-10-28 22:34:53 +01:00
2015-12-22 16:51:37 +01:00
Logging . LogGenericInfo ( BotName , "Disconnected from Steam!" ) ;
await CardsFarmer . StopFarming ( ) . ConfigureAwait ( false ) ;
2015-12-23 10:58:14 +01:00
if ( ! KeepRunning ) {
return ;
}
2015-12-22 16:51:37 +01:00
// If we initiated disconnect, do not attempt to reconnect
if ( callback . UserInitiated ) {
2015-11-01 02:04:44 +01:00
return ;
}
2015-12-23 10:58:14 +01:00
if ( InvalidPassword ) {
InvalidPassword = false ;
if ( ! string . IsNullOrEmpty ( LoginKey ) ) { // InvalidPassword means usually that login key has expired, if we used it
LoginKey = null ;
File . Delete ( LoginKeyFile ) ;
Logging . LogGenericInfo ( BotName , "Removed expired login key" ) ;
} else { // If we didn't use login key, InvalidPassword usually means we got captcha or other network-based throttling
Logging . LogGenericInfo ( BotName , "Will retry after 25 minutes..." ) ;
await Utilities . SleepAsync ( 25 * 60 * 1000 ) . ConfigureAwait ( false ) ; // Captcha disappears after around 20 minutes, so we make it 25
}
} else if ( LoggedInElsewhere ) {
2015-12-09 20:55:43 +01:00
LoggedInElsewhere = false ;
2015-12-22 16:51:37 +01:00
Logging . LogGenericWarning ( BotName , "Account is being used elsewhere, will try reconnecting in 30 minutes..." ) ;
await Utilities . SleepAsync ( 30 * 60 * 1000 ) . ConfigureAwait ( false ) ;
2015-12-09 20:55:43 +01:00
}
2015-12-22 16:51:37 +01:00
Logging . LogGenericInfo ( BotName , "Reconnecting..." ) ;
2015-12-21 09:28:59 +01:00
// 2FA tokens are expiring soon, use limiter only when we don't have any pending
if ( TwoFactorAuth = = null ) {
await Program . LimitSteamRequestsAsync ( ) . ConfigureAwait ( false ) ;
}
2015-10-25 06:16:50 +01:00
SteamClient . Connect ( ) ;
}
2015-12-21 19:28:59 +01:00
private void OnChatInvite ( SteamFriends . ChatInviteCallback callback ) {
if ( callback = = null ) {
return ;
}
ulong steamID = callback . PatronID ;
if ( steamID ! = SteamMasterID ) {
return ;
}
SteamFriends . JoinChat ( callback . ChatRoomID ) ;
}
private async void OnChatMsg ( SteamFriends . ChatMsgCallback callback ) {
if ( callback = = null ) {
return ;
}
if ( callback . ChatMsgType ! = EChatEntryType . ChatMsg ) {
return ;
}
ulong steamID = callback . ChatterID ;
if ( steamID ! = SteamMasterID ) {
return ;
}
await HandleMessage ( callback . ChatRoomID , callback . Message ) . ConfigureAwait ( false ) ;
}
2015-10-25 06:16:50 +01:00
private void OnFriendsList ( SteamFriends . FriendsListCallback callback ) {
if ( callback = = null ) {
return ;
}
foreach ( var friend in callback . FriendList ) {
if ( friend . Relationship ! = EFriendRelationship . RequestRecipient ) {
continue ;
}
SteamID steamID = friend . SteamID ;
switch ( steamID . AccountType ) {
case EAccountType . Clan :
2015-12-16 20:09:31 +01:00
// TODO: Accept clan invites from master?
2015-10-25 06:16:50 +01:00
break ;
default :
if ( steamID = = SteamMasterID ) {
SteamFriends . AddFriend ( steamID ) ;
}
break ;
}
}
}
2015-10-31 05:27:30 +01:00
private async void OnFriendMsg ( SteamFriends . FriendMsgCallback callback ) {
2015-10-25 06:16:50 +01:00
if ( callback = = null ) {
return ;
}
if ( callback . EntryType ! = EChatEntryType . ChatMsg ) {
return ;
}
2015-12-21 19:28:59 +01:00
ulong steamID = callback . Sender ;
if ( steamID ! = SteamMasterID ) {
return ;
}
await HandleMessage ( steamID , callback . Message ) . ConfigureAwait ( false ) ;
2015-12-21 10:55:55 +01:00
}
private async void OnFriendMsgHistory ( SteamFriends . FriendMsgHistoryCallback callback ) {
if ( callback = = null ) {
2015-10-25 06:16:50 +01:00
return ;
}
2015-12-21 10:55:55 +01:00
if ( callback . Result ! = EResult . OK ) {
2015-10-25 06:16:50 +01:00
return ;
}
2015-12-21 10:55:55 +01:00
ulong steamID = callback . SteamID ;
if ( steamID ! = SteamMasterID ) {
2015-11-01 02:04:44 +01:00
return ;
2015-10-25 06:16:50 +01:00
}
2015-10-31 05:27:30 +01:00
2015-12-21 10:55:55 +01:00
var messages = callback . Messages ;
if ( messages . Count = = 0 ) {
2015-11-01 02:04:44 +01:00
return ;
}
2015-12-21 10:55:55 +01:00
// Get last message
var lastMessage = messages [ messages . Count - 1 ] ;
// If message is read already, return
if ( ! lastMessage . Unread ) {
return ;
2015-10-31 05:27:30 +01:00
}
2015-12-21 10:55:55 +01:00
// If message is too old, return
if ( DateTime . UtcNow . Subtract ( lastMessage . Timestamp ) . TotalMinutes > 1 ) {
return ;
}
// Handle the message
await HandleMessage ( steamID , lastMessage . Message ) . ConfigureAwait ( false ) ;
2015-10-25 06:16:50 +01:00
}
private void OnAccountInfo ( SteamUser . AccountInfoCallback callback ) {
if ( callback = = null ) {
return ;
}
2015-12-20 19:48:58 +01:00
if ( ! FarmOffline ) {
2015-12-20 19:01:05 +01:00
SteamFriends . SetPersonaState ( EPersonaState . Online ) ;
}
2015-10-25 06:16:50 +01:00
}
private void OnLoggedOff ( SteamUser . LoggedOffCallback callback ) {
if ( callback = = null ) {
return ;
}
Logging . LogGenericInfo ( BotName , "Logged off of Steam: " + callback . Result ) ;
2015-12-09 20:55:43 +01:00
switch ( callback . Result ) {
case EResult . AlreadyLoggedInElsewhere :
case EResult . LoggedInElsewhere :
2015-12-16 20:01:40 +01:00
case EResult . LogonSessionReplaced :
2015-12-09 20:55:43 +01:00
LoggedInElsewhere = true ;
break ;
}
2015-10-25 06:16:50 +01:00
}
private async void OnLoggedOn ( SteamUser . LoggedOnCallback callback ) {
if ( callback = = null ) {
return ;
}
EResult result = callback . Result ;
switch ( result ) {
case EResult . AccountLogonDenied :
2015-10-28 23:29:50 +01:00
AuthCode = Program . GetUserInput ( SteamLogin , Program . EUserInputType . SteamGuard ) ;
2015-10-25 06:16:50 +01:00
break ;
case EResult . AccountLoginDeniedNeedTwoFactor :
2015-12-11 22:53:28 +01:00
if ( SteamGuardAccount = = null ) {
TwoFactorAuth = Program . GetUserInput ( SteamLogin , Program . EUserInputType . TwoFactorAuthentication ) ;
} else {
TwoFactorAuth = SteamGuardAccount . GenerateSteamGuardCode ( ) ;
}
2015-10-25 06:16:50 +01:00
break ;
2015-11-26 01:22:56 +01:00
case EResult . InvalidPassword :
2015-12-23 10:58:14 +01:00
InvalidPassword = true ;
2015-12-16 09:39:03 +01:00
Logging . LogGenericWarning ( BotName , "Unable to login to Steam: " + result ) ;
2015-11-26 01:22:56 +01:00
break ;
2015-10-25 06:16:50 +01:00
case EResult . OK :
Logging . LogGenericInfo ( BotName , "Successfully logged on!" ) ;
2015-10-28 20:01:43 +01:00
2015-12-11 22:53:28 +01:00
if ( UseAsfAsMobileAuthenticator & & TwoFactorAuth = = null & & SteamGuardAccount = = null ) {
LinkMobileAuthenticator ( ) ;
}
2015-12-06 19:38:09 +01:00
// Reset one-time-only access tokens
AuthCode = null ;
TwoFactorAuth = null ;
2015-10-31 03:27:58 +01:00
if ( ! SteamNickname . Equals ( "null" ) ) {
2015-12-21 10:00:29 +01:00
await SteamFriends . SetPersonaName ( SteamNickname ) ;
2015-10-28 20:01:43 +01:00
}
2015-10-31 03:27:58 +01:00
if ( SteamParentalPIN . Equals ( "null" ) ) {
SteamParentalPIN = Program . GetUserInput ( BotName , Program . EUserInputType . SteamParentalPIN ) ;
2015-10-29 01:01:31 +01:00
}
2015-12-25 17:49:00 +01:00
if ( ! await ArchiWebHandler . Init ( SteamClient , callback . WebAPIUserNonce , callback . VanityURL , SteamParentalPIN ) . ConfigureAwait ( false ) ) {
await Restart ( ) . ConfigureAwait ( false ) ;
return ;
}
2015-10-25 06:16:50 +01:00
2015-12-06 20:12:44 +01:00
if ( SteamMasterClanID ! = 0 ) {
await ArchiWebHandler . JoinClan ( SteamMasterClanID ) . ConfigureAwait ( false ) ;
SteamFriends . JoinChat ( SteamMasterClanID ) ;
2015-10-28 19:21:27 +01:00
}
2015-10-25 06:16:50 +01:00
2015-10-29 16:38:16 +01:00
if ( Statistics ) {
2015-12-21 10:06:37 +01:00
await ArchiWebHandler . JoinClan ( ArchiSCFarmGroup ) . ConfigureAwait ( false ) ;
SteamFriends . JoinChat ( ArchiSCFarmGroup ) ;
2015-10-29 16:38:16 +01:00
}
2015-12-13 15:25:00 +01:00
Trading . CheckTrades ( ) ;
2015-10-25 06:16:50 +01:00
await CardsFarmer . StartFarming ( ) . ConfigureAwait ( false ) ;
break ;
2015-12-23 16:34:57 +01:00
case EResult . NoConnection :
2015-12-02 17:17:47 +01:00
case EResult . ServiceUnavailable :
2015-10-28 20:01:43 +01:00
case EResult . Timeout :
case EResult . TryAnotherCM :
2015-12-23 10:58:14 +01:00
Logging . LogGenericWarning ( BotName , "Unable to login to Steam: " + result ) ;
2015-10-25 06:16:50 +01:00
break ;
2015-12-23 10:58:14 +01:00
default : // Unexpected result, shutdown immediately
2015-11-26 01:22:56 +01:00
Logging . LogGenericWarning ( BotName , "Unable to login to Steam: " + result ) ;
2015-10-31 05:27:30 +01:00
await Shutdown ( ) . ConfigureAwait ( false ) ;
2015-10-28 20:01:43 +01:00
break ;
2015-10-25 06:16:50 +01:00
}
}
2015-12-11 22:53:28 +01:00
private void OnLoginKey ( SteamUser . LoginKeyCallback callback ) {
if ( callback = = null ) {
return ;
}
File . WriteAllText ( LoginKeyFile , callback . LoginKey ) ;
SteamUser . AcceptNewLoginKey ( callback ) ;
}
2015-10-25 06:16:50 +01:00
private void OnMachineAuth ( SteamUser . UpdateMachineAuthCallback callback ) {
if ( callback = = null ) {
return ;
}
int fileSize ;
byte [ ] sentryHash ;
using ( FileStream fileStream = File . Open ( SentryFile , FileMode . OpenOrCreate , FileAccess . ReadWrite ) ) {
fileStream . Seek ( callback . Offset , SeekOrigin . Begin ) ;
fileStream . Write ( callback . Data , 0 , callback . BytesToWrite ) ;
fileSize = ( int ) fileStream . Length ;
fileStream . Seek ( 0 , SeekOrigin . Begin ) ;
using ( SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider ( ) ) {
sentryHash = sha . ComputeHash ( fileStream ) ;
}
}
// Inform the steam servers that we're accepting this sentry file
SteamUser . SendMachineAuthResponse ( new SteamUser . MachineAuthDetails {
JobID = callback . JobID ,
FileName = callback . FileName ,
BytesWritten = callback . BytesToWrite ,
FileSize = fileSize ,
Offset = callback . Offset ,
Result = EResult . OK ,
LastError = 0 ,
OneTimePassword = callback . OneTimePassword ,
SentryFileHash = sentryHash ,
} ) ;
}
2016-01-02 17:22:35 +01:00
private void OnNotifications ( ArchiHandler . NotificationsCallback callback ) {
2015-10-25 06:16:50 +01:00
if ( callback = = null ) {
return ;
}
2016-01-02 17:22:35 +01:00
bool checkTrades = false ;
foreach ( var notification in callback . Notifications ) {
switch ( notification . NotificationType ) {
case ArchiHandler . NotificationsCallback . Notification . ENotificationType . Trading :
checkTrades = true ;
break ;
}
}
if ( checkTrades ) {
Trading . CheckTrades ( ) ;
2015-10-25 06:16:50 +01:00
}
}
2015-12-20 19:48:58 +01:00
private void OnOfflineMessage ( ArchiHandler . OfflineMessageCallback callback ) {
if ( callback = = null ) {
return ;
}
if ( ! HandleOfflineMessages ) {
return ;
}
2015-12-21 10:55:55 +01:00
SteamFriends . RequestOfflineMessages ( ) ;
2015-12-20 19:50:54 +01:00
}
2015-12-20 19:48:58 +01:00
2015-10-25 06:16:50 +01:00
private async void OnPurchaseResponse ( ArchiHandler . PurchaseResponseCallback callback ) {
if ( callback = = null ) {
return ;
}
var purchaseResult = callback . PurchaseResult ;
if ( purchaseResult = = ArchiHandler . PurchaseResponseCallback . EPurchaseResult . OK ) {
2015-12-22 18:32:48 +01:00
// We will restart CF module to recalculate current status and decide about new optimal approach
await CardsFarmer . RestartFarming ( ) . ConfigureAwait ( false ) ;
2015-10-25 06:16:50 +01:00
}
}
}
}