2015-10-28 19:21:27 +01:00
/ *
_ _ _ ____ _ _____
/ \ _ __ ___ | | __ ( _ ) / ___ | | | _ ___ __ _ _ __ ___ | ___ | __ _ _ __ _ __ ___
/ _ \ | ' __ | / __ | | ' _ \ | | \ ___ \ | __ | / _ \ / _ ` | | ' _ ` _ \ | | _ / _ ` | | ' __ | | ' _ ` _ \
/ ___ \ | | | ( __ | | | | | | ___ ) | | | _ | __ / | ( _ | | | | | | | | | _ | | ( _ | | | | | | | | | |
/ _ / \ _ \ | _ | \ ___ | | _ | | _ | | _ | | ____ / \ __ | \ ___ | \ __ , _ | | _ | | _ | | _ | | _ | \ __ , _ | | _ | | _ | | _ | | _ |
2016-01-16 04:21:36 +01:00
Copyright 2015 - 2016 Ł ukasz "JustArchi" Domeradzki
2015-10-28 19:21:27 +01:00
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 ;
using System.Collections.Generic ;
using System.IO ;
using System.Security.Cryptography ;
2016-01-13 11:17:58 +02:00
using System.Threading ;
2015-10-25 06:16:50 +01:00
using System.Threading.Tasks ;
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
2016-03-06 14:09:08 +01:00
internal static readonly Dictionary < string , Bot > Bots = new Dictionary < string , Bot > ( ) ;
2015-12-23 09:40:42 +01:00
2016-02-22 18:34:45 +01:00
private static readonly uint LoginID = MsgClientLogon . ObfuscationMask ; // This must be the same for all ASF bots and all ASF processes
internal readonly string BotName ;
internal readonly ArchiHandler ArchiHandler ;
internal readonly ArchiWebHandler ArchiWebHandler ;
2016-03-06 02:20:41 +01:00
internal readonly BotConfig BotConfig ;
internal readonly BotDatabase BotDatabase ;
2016-02-22 18:34:45 +01:00
internal readonly SteamClient SteamClient ;
2016-03-18 14:39:59 +01:00
private readonly string SentryFile ;
private readonly Timer AcceptConfirmationsTimer ;
private readonly Timer SendItemsTimer ;
2016-01-22 11:01:33 +01:00
private readonly CallbackManager CallbackManager ;
private readonly CardsFarmer CardsFarmer ;
private readonly SteamApps SteamApps ;
private readonly SteamFriends SteamFriends ;
private readonly SteamUser SteamUser ;
private readonly Trading Trading ;
2015-10-25 06:16:50 +01:00
2016-03-26 22:51:19 +01:00
internal bool KeepRunning { get ; private set ; }
2015-10-31 03:27:58 +01:00
2016-03-18 14:39:59 +01:00
private bool InvalidPassword , LoggedInElsewhere ;
2016-03-06 02:20:41 +01:00
private string AuthCode , TwoFactorAuth ;
2016-01-07 22:29:55 +01:00
2016-03-07 02:39:55 +01:00
internal static async Task RefreshCMs ( uint cellID ) {
2016-01-24 17:38:45 +01:00
bool initialized = false ;
2016-02-21 22:21:17 +01:00
for ( byte i = 0 ; i < 3 & & ! initialized ; i + + ) {
2016-01-24 17:38:45 +01:00
try {
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Refreshing list of CMs..." ) ;
2016-03-07 02:39:55 +01:00
await SteamDirectory . Initialize ( cellID ) . ConfigureAwait ( false ) ;
2016-01-24 17:38:45 +01:00
initialized = true ;
2016-01-25 20:08:30 +01:00
} catch ( Exception e ) {
Logging . LogGenericException ( e ) ;
2016-02-21 22:21:17 +01:00
await Utilities . SleepAsync ( 1000 ) . ConfigureAwait ( false ) ;
2016-01-24 17:38:45 +01:00
}
}
2016-02-21 22:19:55 +01:00
if ( initialized ) {
Logging . LogGenericInfo ( "Success!" ) ;
} else {
2016-02-21 22:21:17 +01:00
Logging . LogGenericWarning ( "Failed to initialize list of CMs after 3 tries, ASF will use built-in SK2 list, it may take a while to connect" ) ;
2016-02-21 22:19:55 +01:00
}
2016-01-24 17:38:45 +01:00
}
2016-03-18 09:02:09 +01:00
private static bool IsOwner ( ulong steamID ) {
if ( steamID = = 0 ) {
return false ;
}
return steamID = = Program . GlobalConfig . SteamOwnerID ;
}
2016-02-22 18:34:45 +01:00
private static bool IsValidCdKey ( string key ) {
if ( string . IsNullOrEmpty ( key ) ) {
return false ;
}
// 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 ;
}
2016-02-12 16:06:57 +01:00
internal Bot ( string botName ) {
2016-02-26 22:39:03 +01:00
if ( string . IsNullOrEmpty ( botName ) ) {
2015-11-01 02:04:44 +01:00
return ;
}
2015-10-25 06:16:50 +01:00
BotName = botName ;
2016-02-22 18:34:45 +01:00
string botPath = Path . Combine ( Program . ConfigDirectory , botName ) ;
2015-10-25 06:16:50 +01:00
2016-03-06 02:20:41 +01:00
BotConfig = BotConfig . Load ( botPath + ".json" ) ;
if ( BotConfig = = null ) {
2016-03-26 22:12:55 +01:00
Logging . LogGenericError ( "Your bot config is invalid, refusing to start this bot instance!" , botName ) ;
2015-10-25 06:16:50 +01:00
return ;
}
2015-10-28 19:21:27 +01:00
2016-03-06 02:20:41 +01:00
if ( ! BotConfig . Enabled ) {
2016-02-26 22:39:03 +01:00
return ;
}
2016-02-05 20:10:15 +01:00
2016-03-26 22:12:55 +01:00
BotDatabase = BotDatabase . Load ( botPath + ".db" ) ;
if ( BotDatabase = = null ) {
Logging . LogGenericError ( "Bot database could not be loaded, refusing to start this bot instance!" , botName ) ;
return ;
}
2016-03-06 14:09:08 +01:00
bool alreadyExists ;
lock ( Bots ) {
alreadyExists = Bots . ContainsKey ( botName ) ;
if ( ! alreadyExists ) {
Bots [ botName ] = this ;
}
}
if ( alreadyExists ) {
return ;
}
2016-03-06 02:20:41 +01:00
SentryFile = botPath + ".bin" ;
2016-03-18 14:39:59 +01:00
if ( BotDatabase . SteamGuardAccount = = null ) {
// Support and convert SDA files
string maFilePath = botPath + ".maFile" ;
if ( File . Exists ( maFilePath ) ) {
ImportAuthenticator ( maFilePath ) ;
}
2016-03-07 15:42:38 +01:00
}
2015-10-31 03:27:58 +01:00
// Initialize
2016-03-19 11:33:39 +01:00
SteamClient = new SteamClient ( Program . GlobalConfig . SteamProtocol ) ;
2015-10-31 03:27:58 +01:00
2016-03-13 21:22:52 +01:00
if ( Program . GlobalConfig . Debug & & ! Debugging . NetHookAlreadyInitialized & & Directory . Exists ( Program . DebugDirectory ) ) {
2016-03-07 18:12:05 +01:00
try {
SteamClient . DebugNetworkListener = new NetHookNetworkListener ( Program . DebugDirectory ) ;
Debugging . NetHookAlreadyInitialized = true ;
} catch ( Exception e ) {
Logging . LogGenericException ( e , botName ) ;
}
}
2015-10-31 03:27:58 +01:00
ArchiHandler = new ArchiHandler ( ) ;
SteamClient . AddHandler ( ArchiHandler ) ;
CallbackManager = new CallbackManager ( SteamClient ) ;
CallbackManager . Subscribe < SteamClient . ConnectedCallback > ( OnConnected ) ;
CallbackManager . Subscribe < SteamClient . DisconnectedCallback > ( OnDisconnected ) ;
2016-01-22 10:56:06 +01:00
SteamApps = SteamClient . GetHandler < SteamApps > ( ) ;
CallbackManager . Subscribe < SteamApps . FreeLicenseCallback > ( OnFreeLicense ) ;
2016-03-27 23:07:00 +02:00
CallbackManager . Subscribe < SteamApps . GuestPassListCallback > ( OnGuestPassList ) ;
2016-01-22 10:56:06 +01:00
2015-10-31 03:27:58 +01:00
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
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-03-29 14:33:05 +02:00
CallbackManager . Subscribe < SteamUser . WebAPIUserNonceCallback > ( OnWebAPIUserNonce ) ;
2015-10-31 03:27:58 +01:00
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 ) ;
2016-03-06 02:20:41 +01:00
ArchiWebHandler = new ArchiWebHandler ( this ) ;
2015-10-31 03:27:58 +01:00
CardsFarmer = new CardsFarmer ( this ) ;
Trading = new Trading ( this ) ;
2016-04-01 20:18:21 +02:00
if ( AcceptConfirmationsTimer = = null & & BotConfig . AcceptConfirmationsPeriod > 0 ) {
2016-03-10 21:17:48 +01:00
AcceptConfirmationsTimer = new Timer (
2016-03-14 18:24:03 +01:00
async e = > await AcceptConfirmations ( ) . ConfigureAwait ( false ) ,
2016-03-10 21:17:48 +01:00
null ,
2016-03-10 22:54:59 +01:00
TimeSpan . FromMinutes ( BotConfig . AcceptConfirmationsPeriod ) , // Delay
TimeSpan . FromMinutes ( BotConfig . AcceptConfirmationsPeriod ) // Period
2016-03-10 21:17:48 +01:00
) ;
}
2016-04-01 20:18:21 +02:00
if ( SendItemsTimer = = null & & BotConfig . SendTradePeriod > 0 ) {
2016-01-14 02:24:55 +01:00
SendItemsTimer = new Timer (
2016-03-18 09:02:09 +01:00
async e = > await ResponseSendTrade ( BotConfig . SteamMasterID ) . ConfigureAwait ( false ) ,
2016-01-14 02:24:55 +01:00
null ,
2016-03-06 02:20:41 +01:00
TimeSpan . FromHours ( BotConfig . SendTradePeriod ) , // Delay
TimeSpan . FromHours ( BotConfig . SendTradePeriod ) // Period
2016-01-14 02:48:56 +01:00
) ;
2016-01-14 02:24:55 +01:00
}
2016-02-05 20:11:04 +01:00
2016-03-06 02:20:41 +01:00
if ( ! BotConfig . StartOnLaunch ) {
2016-02-05 20:11:04 +01:00
return ;
}
2016-01-14 02:24:55 +01:00
2015-10-31 03:27:58 +01:00
// Start
2016-03-22 11:21:45 +01:00
Start ( ) . Forget ( ) ;
2015-10-25 06:16:50 +01:00
}
2016-03-14 18:24:03 +01:00
internal async Task AcceptConfirmations ( Confirmation . ConfirmationType allowedConfirmationType = Confirmation . ConfirmationType . Unknown ) {
2016-03-06 02:20:41 +01:00
if ( BotDatabase . SteamGuardAccount = = null ) {
2015-12-11 22:53:28 +01:00
return ;
}
2016-03-11 19:42:15 +01:00
try {
if ( ! await BotDatabase . SteamGuardAccount . RefreshSessionAsync ( ) . ConfigureAwait ( false ) ) {
return ;
}
2016-03-10 00:40:30 +01:00
2016-03-11 19:42:15 +01:00
Confirmation [ ] confirmations = await BotDatabase . SteamGuardAccount . FetchConfirmationsAsync ( ) . ConfigureAwait ( false ) ;
if ( confirmations = = null ) {
return ;
}
2015-12-13 15:25:00 +01:00
2016-03-10 00:40:30 +01:00
foreach ( Confirmation confirmation in confirmations ) {
2016-03-14 18:24:03 +01:00
if ( allowedConfirmationType ! = Confirmation . ConfirmationType . Unknown & & confirmation . ConfType ! = allowedConfirmationType ) {
2016-03-14 18:13:33 +01:00
continue ;
2015-12-13 15:25:00 +01:00
}
2016-03-14 18:13:33 +01:00
BotDatabase . SteamGuardAccount . AcceptConfirmation ( confirmation ) ;
2015-12-11 22:53:28 +01:00
}
2015-12-13 15:25:00 +01:00
} catch ( SteamGuardAccount . WGTokenInvalidException ) {
2016-01-24 18:08:27 +01:00
Logging . LogGenericWarning ( "Accepting confirmation: Failed!" , BotName ) ;
Logging . LogGenericWarning ( "Confirmation could not be accepted because of invalid token exception" , BotName ) ;
Logging . LogGenericWarning ( "If issue persists, consider removing and readding ASF 2FA" , BotName ) ;
2016-03-11 19:42:15 +01:00
} catch ( Exception e ) {
Logging . LogGenericException ( e , BotName ) ;
2015-12-11 22:53:28 +01:00
}
}
2016-02-28 04:15:52 +01:00
internal void ResetGamesPlayed ( ) {
2016-03-08 03:18:50 +01:00
if ( ! string . IsNullOrEmpty ( BotConfig . CustomGamePlayedWhileIdle ) ) {
ArchiHandler . PlayGame ( BotConfig . CustomGamePlayedWhileIdle ) ;
2016-02-28 04:15:52 +01:00
} else {
2016-03-06 02:20:41 +01:00
ArchiHandler . PlayGames ( BotConfig . GamesPlayedWhileIdle ) ;
2016-02-28 04:15:52 +01:00
}
}
2016-03-29 14:33:05 +02:00
internal async Task < bool > RefreshSession ( ) {
2016-03-22 08:53:55 +01:00
if ( ! SteamClient . IsConnected ) {
2016-03-29 14:33:05 +02:00
return false ;
2016-03-22 08:53:55 +01:00
}
2016-03-29 14:33:05 +02:00
var userNonce = await SteamUser . RequestWebAPIUserNonce ( ) ;
if ( userNonce = = null | | userNonce . Result ! = EResult . OK | | string . IsNullOrEmpty ( userNonce . Nonce ) ) {
Start ( ) . Forget ( ) ;
return false ;
}
if ( ! ArchiWebHandler . Init ( SteamClient , userNonce . Nonce , BotConfig . SteamParentalPIN ) ) {
Start ( ) . Forget ( ) ;
return false ;
}
return true ;
2015-12-22 16:51:37 +01:00
}
2016-02-24 06:20:35 +01:00
internal async Task OnFarmingFinished ( bool farmedSomething ) {
2016-03-06 02:20:41 +01:00
if ( farmedSomething & & BotConfig . SendOnFarmingFinished ) {
2016-03-18 09:02:09 +01:00
await ResponseSendTrade ( BotConfig . SteamMasterID ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
}
2016-03-18 14:39:59 +01:00
2016-03-06 02:20:41 +01:00
if ( BotConfig . ShutdownOnFarmingFinished ) {
2016-03-22 20:18:47 +01:00
Stop ( ) ;
2016-02-24 06:20:35 +01:00
}
}
2016-03-18 09:02:09 +01:00
internal async Task < string > Response ( ulong steamID , string message ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( message ) ) {
2016-02-24 06:20:35 +01:00
return null ;
}
if ( ! message . StartsWith ( "!" ) ) {
2016-03-18 09:02:09 +01:00
return await ResponseRedeem ( steamID , BotName , message , true ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
}
if ( ! message . Contains ( " " ) ) {
switch ( message ) {
case "!2fa" :
2016-03-18 09:02:09 +01:00
return Response2FA ( steamID ) ;
2016-02-24 06:20:35 +01:00
case "!2faoff" :
2016-03-18 09:02:09 +01:00
return Response2FAOff ( steamID ) ;
2016-03-10 00:40:30 +01:00
case "!2faok" :
2016-03-18 09:02:09 +01:00
return await Response2FAOK ( steamID ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
case "!exit" :
2016-03-18 09:02:09 +01:00
return ResponseExit ( steamID ) ;
2016-03-11 19:42:15 +01:00
case "!farm" :
2016-03-22 11:10:34 +01:00
return ResponseFarm ( steamID ) ;
2016-03-26 02:47:25 +01:00
case "!help" :
return ResponseHelp ( steamID ) ;
2016-03-11 19:48:14 +01:00
case "!loot" :
2016-03-18 09:02:09 +01:00
return await ResponseSendTrade ( steamID ) . ConfigureAwait ( false ) ;
2016-03-24 14:18:07 +01:00
case "!pause" :
return await ResponsePause ( steamID ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
case "!rejoinchat" :
2016-03-18 09:02:09 +01:00
return ResponseRejoinChat ( steamID ) ;
2016-02-24 06:20:35 +01:00
case "!restart" :
2016-03-18 09:02:09 +01:00
return ResponseRestart ( steamID ) ;
2016-02-24 06:20:35 +01:00
case "!status" :
2016-03-18 09:02:09 +01:00
return ResponseStatus ( steamID ) ;
2016-02-24 06:20:35 +01:00
case "!statusall" :
2016-03-18 09:02:09 +01:00
return ResponseStatusAll ( steamID ) ;
2016-02-24 06:20:35 +01:00
case "!stop" :
2016-03-22 20:18:47 +01:00
return ResponseStop ( steamID ) ;
2016-03-11 19:48:14 +01:00
case "!update" :
2016-03-18 09:02:09 +01:00
return await ResponseUpdate ( steamID ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
default :
2016-03-18 14:39:59 +01:00
return ResponseUnknown ( steamID ) ;
2016-02-24 06:20:35 +01:00
}
} else {
string [ ] args = message . Split ( ' ' ) ;
switch ( args [ 0 ] ) {
case "!2fa" :
2016-03-18 09:02:09 +01:00
return Response2FA ( steamID , args [ 1 ] ) ;
2016-02-24 06:20:35 +01:00
case "!2faoff" :
2016-03-18 09:02:09 +01:00
return Response2FAOff ( steamID , args [ 1 ] ) ;
2016-03-10 00:40:30 +01:00
case "!2faok" :
2016-03-18 09:02:09 +01:00
return await Response2FAOK ( steamID , args [ 1 ] ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
case "!addlicense" :
if ( args . Length > 2 ) {
2016-03-18 09:02:09 +01:00
return await ResponseAddLicense ( steamID , args [ 1 ] , args [ 2 ] ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
} else {
2016-03-18 09:02:09 +01:00
return await ResponseAddLicense ( steamID , BotName , args [ 1 ] ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
}
2016-03-11 19:39:25 +01:00
case "!farm" :
2016-03-22 11:10:34 +01:00
return ResponseFarm ( steamID , args [ 1 ] ) ;
2016-03-26 02:47:25 +01:00
case "!help" :
return ResponseHelp ( steamID , args [ 1 ] ) ;
2016-03-11 19:48:14 +01:00
case "!loot" :
2016-03-18 09:02:09 +01:00
return await ResponseSendTrade ( steamID , args [ 1 ] ) . ConfigureAwait ( false ) ;
2016-03-15 04:20:28 +01:00
case "!owns" :
if ( args . Length > 2 ) {
2016-03-18 09:02:09 +01:00
return await ResponseOwns ( steamID , args [ 1 ] , args [ 2 ] ) . ConfigureAwait ( false ) ;
2016-03-15 04:20:28 +01:00
} else {
2016-03-18 09:02:09 +01:00
return await ResponseOwns ( steamID , BotName , args [ 1 ] ) . ConfigureAwait ( false ) ;
2016-03-15 04:20:28 +01:00
}
2016-03-24 14:18:07 +01:00
case "!pause" :
return await ResponsePause ( steamID , args [ 1 ] ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
case "!play" :
if ( args . Length > 2 ) {
2016-03-18 09:02:09 +01:00
return await ResponsePlay ( steamID , args [ 1 ] , args [ 2 ] ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
} else {
2016-03-18 09:02:09 +01:00
return await ResponsePlay ( steamID , BotName , args [ 1 ] ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
}
case "!redeem" :
if ( args . Length > 2 ) {
2016-03-18 09:02:09 +01:00
return await ResponseRedeem ( steamID , args [ 1 ] , args [ 2 ] , false ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
} else {
2016-03-18 09:02:09 +01:00
return await ResponseRedeem ( steamID , BotName , args [ 1 ] , false ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
}
case "!start" :
2016-03-18 09:02:09 +01:00
return await ResponseStart ( steamID , args [ 1 ] ) . ConfigureAwait ( false ) ;
2016-02-24 06:20:35 +01:00
case "!status" :
2016-03-18 09:02:09 +01:00
return ResponseStatus ( steamID , args [ 1 ] ) ;
2016-03-11 19:48:14 +01:00
case "!stop" :
2016-03-22 20:18:47 +01:00
return ResponseStop ( steamID , args [ 1 ] ) ;
2016-02-24 06:20:35 +01:00
default :
2016-03-18 14:39:59 +01:00
return ResponseUnknown ( steamID ) ;
2016-02-24 06:20:35 +01:00
}
}
}
private async Task Start ( ) {
2016-02-05 20:10:15 +01:00
if ( ! KeepRunning ) {
KeepRunning = true ;
2016-03-06 22:14:02 +01:00
Task . Run ( ( ) = > HandleCallbacks ( ) ) . Forget ( ) ;
2016-02-05 20:10:15 +01:00
}
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 ) ;
}
2016-03-22 20:18:47 +01:00
Logging . LogGenericInfo ( "Starting..." , BotName ) ;
2015-11-04 04:31:27 +01:00
SteamClient . Connect ( ) ;
2015-10-25 06:16:50 +01:00
}
2016-03-22 20:18:47 +01:00
private void Stop ( ) {
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Stopping..." , BotName ) ;
2016-01-04 00:02:18 +01:00
KeepRunning = false ;
2016-03-22 20:20:04 +01:00
if ( SteamClient . IsConnected ) {
SteamClient . Disconnect ( ) ;
}
2016-01-04 00:02:18 +01:00
Program . OnBotShutdown ( ) ;
}
2015-12-12 08:04:41 +01:00
2016-03-26 02:47:25 +01:00
private bool IsMaster ( ulong steamID ) {
if ( steamID = = 0 ) {
return false ;
}
return steamID = = BotConfig . SteamMasterID | | IsOwner ( steamID ) ;
}
2016-03-12 05:58:51 +01:00
private void ImportAuthenticator ( string maFilePath ) {
if ( BotDatabase . SteamGuardAccount ! = null | | ! File . Exists ( maFilePath ) ) {
return ;
}
Logging . LogGenericInfo ( "Converting SDA .maFile into ASF format..." , BotName ) ;
try {
BotDatabase . SteamGuardAccount = JsonConvert . DeserializeObject < SteamGuardAccount > ( File . ReadAllText ( maFilePath ) ) ;
File . Delete ( maFilePath ) ;
Logging . LogGenericInfo ( "Success!" , BotName ) ;
} catch ( Exception e ) {
Logging . LogGenericException ( e , BotName ) ;
return ;
}
// If this is SDA file, then we should already have everything ready
if ( BotDatabase . SteamGuardAccount . Session ! = null ) {
Logging . LogGenericInfo ( "Successfully finished importing mobile authenticator!" , BotName ) ;
return ;
}
// But here we're dealing with WinAuth authenticator
Logging . LogGenericInfo ( "ASF requires a few more steps to complete authenticator import..." , BotName ) ;
InitializeLoginAndPassword ( ) ;
UserLogin userLogin = new UserLogin ( BotConfig . SteamLogin , BotConfig . SteamPassword ) ;
LoginResult loginResult ;
while ( ( loginResult = userLogin . DoLogin ( ) ) ! = LoginResult . LoginOkay ) {
switch ( loginResult ) {
case LoginResult . Need2FA :
2016-03-22 17:26:39 +01:00
userLogin . TwoFactorCode = Program . GetUserInput ( Program . EUserInputType . TwoFactorAuthentication , BotName ) ;
2016-03-12 05:58:51 +01:00
break ;
default :
Logging . LogGenericError ( "Unhandled situation: " + loginResult , BotName ) ;
return ;
}
}
if ( userLogin . Session = = null ) {
BotDatabase . SteamGuardAccount = null ;
Logging . LogGenericError ( "Session is invalid, linking can't be completed!" , BotName ) ;
return ;
}
BotDatabase . SteamGuardAccount . FullyEnrolled = true ;
BotDatabase . SteamGuardAccount . Session = userLogin . Session ;
if ( string . IsNullOrEmpty ( BotDatabase . SteamGuardAccount . DeviceID ) ) {
2016-03-22 17:26:39 +01:00
BotDatabase . SteamGuardAccount . DeviceID = Program . GetUserInput ( Program . EUserInputType . DeviceID , BotName ) ;
2016-03-12 05:58:51 +01:00
}
BotDatabase . Save ( ) ;
Logging . LogGenericInfo ( "Successfully finished importing mobile authenticator!" , BotName ) ;
}
2016-03-24 14:18:07 +01:00
private async Task < string > ResponsePause ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-24 14:18:07 +01:00
return null ;
}
if ( CardsFarmer . ManualMode ) {
await CardsFarmer . SwitchToManualMode ( false ) . ConfigureAwait ( false ) ;
return "Automatic farming is enabled again!" ;
} else {
await CardsFarmer . SwitchToManualMode ( true ) . ConfigureAwait ( false ) ;
return "Automatic farming is now stopped!" ;
}
}
private static async Task < string > ResponsePause ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
return await bot . ResponsePause ( steamID ) . ConfigureAwait ( false ) ;
}
2016-03-18 09:02:09 +01:00
private string ResponseStatus ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-02-05 20:10:15 +01:00
if ( CardsFarmer . CurrentGamesFarming . Count > 0 ) {
2016-03-21 16:31:59 +01:00
return "Bot " + BotName + " is farming appIDs: " + string . Join ( ", " , CardsFarmer . CurrentGamesFarming ) + " and has a total of " + CardsFarmer . GamesToFarm . Count + " games left to farm." ;
} else if ( SteamClient . IsConnected ) {
return "Bot " + BotName + " is not farming anything." ;
} else if ( KeepRunning ) {
return "Bot " + BotName + " is not connected." ;
2016-02-05 20:10:15 +01:00
} else {
2016-03-21 16:31:59 +01:00
return "Bot " + BotName + " is not running." ;
2016-02-05 20:10:15 +01:00
}
}
2016-03-18 09:02:09 +01:00
private static string ResponseStatus ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-01-03 22:23:30 +01:00
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-03-18 09:02:09 +01:00
return bot . ResponseStatus ( steamID ) ;
2016-01-10 19:35:03 +01:00
}
2016-01-10 20:22:46 +02:00
2016-03-18 09:02:09 +01:00
private static string ResponseStatusAll ( ulong steamID ) {
if ( steamID = = 0 ) {
return null ;
}
if ( ! IsOwner ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-01-10 19:31:21 +01:00
StringBuilder result = new StringBuilder ( Environment . NewLine ) ;
2016-02-05 20:10:15 +01:00
2016-03-21 16:31:59 +01:00
byte runningBotsCount = 0 ;
2016-01-10 19:35:03 +01:00
foreach ( Bot bot in Bots . Values ) {
2016-03-18 09:02:09 +01:00
result . Append ( bot . ResponseStatus ( steamID ) + Environment . NewLine ) ;
2016-02-05 20:10:15 +01:00
if ( bot . KeepRunning ) {
runningBotsCount + + ;
}
2016-01-10 19:39:12 +02:00
}
2016-01-10 19:35:03 +01:00
2016-03-26 19:39:46 +01:00
result . Append ( "There are " + runningBotsCount + "/" + Bots . Count + " bots running." ) ;
2016-01-10 20:22:46 +02:00
return result . ToString ( ) ;
2016-01-10 19:39:12 +02:00
}
2016-03-18 09:02:09 +01:00
private async Task < string > ResponseSendTrade ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-03-06 02:20:41 +01:00
if ( BotConfig . SteamMasterID = = 0 ) {
2016-01-14 01:30:12 +01:00
return "Trade couldn't be send because SteamMasterID is not defined!" ;
2016-01-13 11:17:58 +02:00
}
2016-01-14 01:30:12 +01:00
2016-01-26 23:05:53 +01:00
await Trading . LimitInventoryRequestsAsync ( ) . ConfigureAwait ( false ) ;
2016-03-10 02:21:28 +01:00
List < Steam . Item > inventory = await ArchiWebHandler . GetMyTradableInventory ( ) . ConfigureAwait ( false ) ;
2016-01-26 23:05:53 +01:00
2016-01-14 02:48:56 +01:00
if ( inventory = = null | | inventory . Count = = 0 ) {
2016-01-14 01:30:12 +01:00
return "Nothing to send, inventory seems empty!" ;
2016-01-13 11:17:58 +02:00
}
2016-01-14 01:30:12 +01:00
2016-03-06 02:27:43 +01:00
if ( await ArchiWebHandler . SendTradeOffer ( inventory , BotConfig . SteamMasterID , BotConfig . SteamTradeToken ) . ConfigureAwait ( false ) ) {
2016-03-14 18:24:03 +01:00
await AcceptConfirmations ( Confirmation . ConfirmationType . Trade ) . ConfigureAwait ( false ) ;
2016-01-14 01:30:12 +01:00
return "Trade offer sent successfully!" ;
} else {
return "Trade offer failed due to error!" ;
2016-01-13 11:17:58 +02:00
}
}
2016-03-18 09:02:09 +01:00
private static async Task < string > ResponseSendTrade ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-01-04 00:02:18 +01:00
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
}
2016-03-18 09:02:09 +01:00
return await bot . ResponseSendTrade ( steamID ) . ConfigureAwait ( false ) ;
2016-02-05 20:10:15 +01:00
}
2016-03-18 09:02:09 +01:00
private string Response2FA ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-03-06 02:20:41 +01:00
if ( BotDatabase . 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-03-06 02:20:41 +01:00
return "2FA Token: " + BotDatabase . SteamGuardAccount . GenerateSteamGuardCode ( ) + " (expires in " + timeLeft + " seconds)" ;
2015-12-11 22:53:28 +01:00
}
2016-03-18 09:02:09 +01:00
private static string Response2FA ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-01-04 00:02:18 +01:00
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
}
2016-03-18 09:02:09 +01:00
return bot . Response2FA ( steamID ) ;
2016-02-05 20:10:15 +01:00
}
2016-03-18 09:02:09 +01:00
private string Response2FAOff ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-03-06 02:20:41 +01:00
if ( BotDatabase . 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
}
2016-02-05 20:10:15 +01:00
if ( 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-03-18 09:02:09 +01:00
private static string Response2FAOff ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-02-05 20:10:15 +01:00
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
2016-03-18 09:02:09 +01:00
return bot . Response2FAOff ( steamID ) ;
2016-02-05 20:10:15 +01:00
}
2016-03-18 09:02:09 +01:00
private async Task < string > Response2FAOK ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-03-10 00:40:30 +01:00
if ( BotDatabase . SteamGuardAccount = = null ) {
return "That bot doesn't have ASF 2FA enabled!" ;
}
2016-03-14 18:24:03 +01:00
await AcceptConfirmations ( ) . ConfigureAwait ( false ) ;
2016-03-10 00:40:30 +01:00
return "Done!" ;
}
2016-03-18 09:02:09 +01:00
private static async Task < string > Response2FAOK ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-03-10 00:40:30 +01:00
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
2016-03-18 09:02:09 +01:00
return await bot . Response2FAOK ( steamID ) . ConfigureAwait ( false ) ;
2016-03-10 00:40:30 +01:00
}
2016-03-18 09:02:09 +01:00
private static string ResponseExit ( ulong steamID ) {
if ( steamID = = 0 ) {
return null ;
}
if ( ! IsOwner ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-04-02 13:08:43 +02:00
Program . Exit ( 0 ) ;
return "Done!" ;
2016-03-18 09:02:09 +01:00
}
2016-03-22 11:10:34 +01:00
private string ResponseFarm ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-03-21 03:39:35 +01:00
if ( ! SteamClient . IsConnected ) {
return "This bot instance is not connected!" ;
}
2016-03-22 11:21:45 +01:00
CardsFarmer . RestartFarming ( ) . Forget ( ) ;
2016-03-11 19:39:25 +01:00
return "Done!" ;
}
2016-03-22 11:10:34 +01:00
private static string ResponseFarm ( ulong steamID , string botName ) {
2016-03-18 09:02:09 +01:00
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-03-11 19:39:25 +01:00
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
2016-03-22 11:10:34 +01:00
return bot . ResponseFarm ( steamID ) ;
2016-03-11 19:39:25 +01:00
}
2016-03-26 02:47:25 +01:00
private string ResponseHelp ( ulong steamID ) {
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-02-03 21:53:30 +01:00
return null ;
}
2016-03-26 02:47:25 +01:00
return "https://github.com/" + Program . GithubRepo + "/wiki/Commands" ;
}
private static string ResponseHelp ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
return bot . ResponseHelp ( steamID ) ;
}
private async Task < string > ResponseRedeem ( ulong steamID , string message , bool validate ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( message ) | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-01-10 20:36:56 +01:00
StringBuilder response = new StringBuilder ( ) ;
using ( StringReader reader = new StringReader ( message ) ) {
2016-01-25 19:15:22 +01:00
string key = reader . ReadLine ( ) ;
2016-01-25 09:42:59 +02:00
IEnumerator < Bot > iterator = Bots . Values . GetEnumerator ( ) ;
Bot currentBot = this ;
while ( key ! = null ) {
if ( currentBot = = null ) {
break ;
}
2016-02-03 21:53:30 +01:00
2016-01-11 04:49:12 +01:00
if ( validate & & ! IsValidCdKey ( key ) ) {
2016-02-09 10:26:51 +01:00
key = reader . ReadLine ( ) ;
2016-01-10 20:36:56 +01:00
continue ;
}
2016-01-04 00:02:18 +01:00
2016-03-30 13:10:00 +02:00
ArchiHandler . PurchaseResponseCallback result = await currentBot . ArchiHandler . RedeemKey ( key ) . ConfigureAwait ( false ) ;
2016-01-10 20:36:56 +01:00
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-25 09:42:59 +02:00
response . Append ( Environment . NewLine + "<" + currentBot . BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string . Join ( "" , items ) ) ;
2016-03-06 02:20:41 +01:00
if ( BotConfig . DistributeKeys ) {
2016-01-25 09:42:59 +02:00
do {
if ( iterator . MoveNext ( ) ) {
currentBot = iterator . Current ;
} else {
currentBot = null ;
}
2016-01-25 19:15:22 +01:00
} while ( currentBot = = this ) ;
2016-01-25 09:42:59 +02:00
2016-03-06 02:20:41 +01:00
if ( ! BotConfig . ForwardKeysToOtherBots ) {
2016-01-25 09:42:59 +02:00
key = reader . ReadLine ( ) ;
}
break ;
}
2016-03-06 02:20:41 +01:00
if ( ! BotConfig . ForwardKeysToOtherBots ) {
2016-01-25 09:42:59 +02:00
key = reader . ReadLine ( ) ;
2016-01-10 20:36:56 +01:00
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 ;
}
2016-03-30 13:10:00 +02:00
ArchiHandler . PurchaseResponseCallback otherResult = await bot . ArchiHandler . RedeemKey ( key ) . ConfigureAwait ( false ) ;
2016-01-10 20:36:56 +01:00
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
}
}
2016-01-25 09:42:59 +02:00
key = reader . ReadLine ( ) ;
2016-01-10 20:36:56 +01:00
break ;
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . OK :
2016-01-25 09:42:59 +02:00
response . Append ( Environment . NewLine + "<" + currentBot . BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string . Join ( "" , items ) ) ;
2016-03-06 02:20:41 +01:00
if ( BotConfig . DistributeKeys ) {
2016-01-25 09:42:59 +02:00
do {
if ( iterator . MoveNext ( ) ) {
currentBot = iterator . Current ;
} else {
currentBot = null ;
}
2016-01-25 19:15:22 +01:00
} while ( currentBot = = this ) ;
2016-01-25 09:42:59 +02:00
}
key = reader . ReadLine ( ) ;
2016-01-10 20:36:56 +01:00
break ;
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . DuplicatedKey :
case ArchiHandler . PurchaseResponseCallback . EPurchaseResult . InvalidKey :
2016-01-25 09:42:59 +02:00
response . Append ( Environment . NewLine + "<" + currentBot . BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string . Join ( "" , items ) ) ;
2016-03-06 02:20:41 +01:00
if ( BotConfig . DistributeKeys & & ! BotConfig . ForwardKeysToOtherBots ) {
2016-01-25 09:42:59 +02:00
do {
if ( iterator . MoveNext ( ) ) {
currentBot = iterator . Current ;
} else {
currentBot = null ;
}
2016-01-25 19:15:22 +01:00
} while ( currentBot = = this ) ;
2016-01-25 09:42:59 +02:00
}
key = reader . ReadLine ( ) ;
2016-01-25 19:15:22 +01:00
break ;
2016-01-10 20:36:56 +01:00
}
}
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 ( ) ;
}
2016-03-18 09:02:09 +01:00
private static async Task < string > ResponseRedeem ( ulong steamID , string botName , string message , bool validate ) {
if ( steamID = = 0 | | 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-03-18 09:02:09 +01:00
return await bot . ResponseRedeem ( steamID , message , validate ) . ConfigureAwait ( false ) ;
2016-01-02 17:22:35 +01:00
}
2016-03-18 09:02:09 +01:00
private static string ResponseRejoinChat ( ulong steamID ) {
if ( steamID = = 0 ) {
return null ;
}
if ( ! IsOwner ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-02-24 06:06:09 +01:00
foreach ( Bot bot in Bots . Values ) {
bot . JoinMasterChat ( ) ;
}
return "Done!" ;
}
2016-03-18 09:02:09 +01:00
private static string ResponseRestart ( ulong steamID ) {
if ( steamID = = 0 ) {
return null ;
}
if ( ! IsOwner ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
Program . Restart ( ) ;
2016-04-02 13:08:43 +02:00
return "Done!" ;
2016-03-18 09:02:09 +01:00
}
private async Task < string > ResponseAddLicense ( ulong steamID , HashSet < uint > gameIDs ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | gameIDs = = null | | gameIDs . Count = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-02-16 08:08:06 +01:00
StringBuilder result = new StringBuilder ( ) ;
foreach ( uint gameID in gameIDs ) {
2016-03-30 13:10:00 +02:00
SteamApps . FreeLicenseCallback callback = await SteamApps . RequestFreeLicense ( gameID ) ;
if ( callback = = null ) {
2016-02-16 08:08:06 +01:00
continue ;
}
result . AppendLine ( "Result: " + callback . Result + " | Granted apps: " + string . Join ( ", " , callback . GrantedApps ) + " " + string . Join ( ", " , callback . GrantedPackages ) ) ;
}
return result . ToString ( ) ;
2016-02-05 20:10:15 +01:00
}
2016-03-18 09:02:09 +01:00
private static async Task < string > ResponseAddLicense ( ulong steamID , string botName , string games ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) | | string . IsNullOrEmpty ( games ) ) {
2016-01-22 10:56:06 +01:00
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
2016-02-16 08:08:06 +01:00
string [ ] gameIDs = games . Split ( ',' ) ;
HashSet < uint > gamesToRedeem = new HashSet < uint > ( ) ;
foreach ( string game in gameIDs ) {
uint gameID ;
if ( ! uint . TryParse ( game , out gameID ) ) {
continue ;
}
gamesToRedeem . Add ( gameID ) ;
}
if ( gamesToRedeem . Count = = 0 ) {
return "Couldn't parse any games given!" ;
2016-01-22 10:56:06 +01:00
}
2016-03-18 09:02:09 +01:00
return await bot . ResponseAddLicense ( steamID , gamesToRedeem ) . ConfigureAwait ( false ) ;
2016-02-05 20:10:15 +01:00
}
2016-03-18 09:02:09 +01:00
private async Task < string > ResponseOwns ( ulong steamID , string games ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | string . IsNullOrEmpty ( games ) | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-03-15 04:20:28 +01:00
Dictionary < uint , string > ownedGames = await ArchiWebHandler . GetOwnedGames ( ) . ConfigureAwait ( false ) ;
if ( ownedGames = = null | | ownedGames . Count = = 0 ) {
return "List of owned games is empty!" ;
}
// Check if this is uint
uint appID ;
if ( uint . TryParse ( games , out appID ) ) {
string ownedName ;
if ( ownedGames . TryGetValue ( appID , out ownedName ) ) {
return "Owned already: " + appID + " | " + ownedName ;
} else {
return "Not owned yet: " + appID ;
}
}
StringBuilder response = new StringBuilder ( ) ;
// This is a string
foreach ( KeyValuePair < uint , string > game in ownedGames ) {
if ( game . Value . IndexOf ( games , StringComparison . OrdinalIgnoreCase ) < 0 ) {
continue ;
}
response . AppendLine ( Environment . NewLine + "Owned already: " + game . Key + " | " + game . Value ) ;
}
if ( response . Length > 0 ) {
return response . ToString ( ) ;
} else {
return "Not owned yet: " + games ;
}
}
2016-03-18 09:02:09 +01:00
private static async Task < string > ResponseOwns ( ulong steamID , string botName , string games ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) | | string . IsNullOrEmpty ( games ) ) {
2016-03-15 04:20:28 +01:00
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
2016-03-18 09:02:09 +01:00
return await bot . ResponseOwns ( steamID , games ) . ConfigureAwait ( false ) ;
2016-03-15 04:20:28 +01:00
}
2016-03-18 09:02:09 +01:00
private async Task < string > ResponsePlay ( ulong steamID , HashSet < uint > gameIDs ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | gameIDs = = null | | gameIDs . Count = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-02-13 23:21:47 +01:00
if ( gameIDs . Contains ( 0 ) ) {
2016-03-24 14:18:07 +01:00
if ( CardsFarmer . ManualMode ) {
2016-02-28 04:15:52 +01:00
ResetGamesPlayed ( ) ;
2016-03-24 14:18:07 +01:00
await CardsFarmer . SwitchToManualMode ( false ) . ConfigureAwait ( false ) ;
2016-02-13 23:31:58 +01:00
}
2016-02-13 23:21:47 +01:00
} else {
2016-03-24 14:18:07 +01:00
if ( ! CardsFarmer . ManualMode ) {
await CardsFarmer . SwitchToManualMode ( true ) . ConfigureAwait ( false ) ;
}
2016-02-13 23:21:47 +01:00
ArchiHandler . PlayGames ( gameIDs ) ;
}
2016-02-05 20:10:15 +01:00
return "Done!" ;
2016-01-22 10:56:06 +01:00
}
2016-03-18 09:02:09 +01:00
private static async Task < string > ResponsePlay ( ulong steamID , string botName , string games ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) | | string . IsNullOrEmpty ( games ) ) {
2016-01-22 10:45:01 +01:00
return null ;
}
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
}
2016-02-13 23:21:47 +01:00
string [ ] gameIDs = games . Split ( ',' ) ;
HashSet < uint > gamesToPlay = new HashSet < uint > ( ) ;
foreach ( string game in gameIDs ) {
uint gameID ;
if ( ! uint . TryParse ( game , out gameID ) ) {
continue ;
}
gamesToPlay . Add ( gameID ) ;
}
if ( gamesToPlay . Count = = 0 ) {
return "Couldn't parse any games given!" ;
2016-01-22 10:45:01 +01:00
}
2016-03-18 09:02:09 +01:00
return await bot . ResponsePlay ( steamID , gamesToPlay ) . ConfigureAwait ( false ) ;
2016-02-05 20:10:15 +01:00
}
2016-01-22 10:45:01 +01:00
2016-03-18 09:02:09 +01:00
private async Task < string > ResponseStart ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-02-05 20:10:15 +01:00
if ( KeepRunning ) {
return "That bot instance is already running!" ;
}
await Start ( ) . ConfigureAwait ( false ) ;
2016-01-22 10:45:01 +01:00
return "Done!" ;
}
2016-03-18 09:02:09 +01:00
private static async Task < string > ResponseStart ( ulong steamID , string botName ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-01-04 00:02:18 +01:00
return null ;
2015-11-01 02:04:44 +01:00
}
2016-02-05 20:10:15 +01:00
Bot bot ;
if ( ! Bots . TryGetValue ( botName , out bot ) ) {
return "Couldn't find any bot named " + botName + "!" ;
2015-11-01 02:04:44 +01:00
}
2016-03-18 09:02:09 +01:00
return await bot . ResponseStart ( steamID ) . ConfigureAwait ( false ) ;
2016-02-05 20:10:15 +01:00
}
2016-03-22 20:18:47 +01:00
private string ResponseStop ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
2016-02-05 20:10:15 +01:00
if ( ! KeepRunning ) {
return "That bot instance is already inactive!" ;
2015-11-01 02:04:44 +01:00
}
2016-02-05 20:10:15 +01:00
2016-03-22 20:18:47 +01:00
Stop ( ) ;
2016-02-05 20:10:15 +01:00
return "Done!" ;
2015-11-01 02:04:44 +01:00
}
2016-03-22 20:18:47 +01:00
private static string ResponseStop ( ulong steamID , string botName ) {
2016-03-18 09:02:09 +01:00
if ( steamID = = 0 | | string . IsNullOrEmpty ( botName ) ) {
2016-01-04 00:02:18 +01:00
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 ) ) {
2016-02-05 20:10:15 +01:00
return "Couldn't find any bot named " + botName + "!" ;
2015-11-01 02:04:44 +01:00
}
2016-03-22 20:18:47 +01:00
return bot . ResponseStop ( steamID ) ;
2016-03-18 09:02:09 +01:00
}
2016-03-18 14:39:59 +01:00
private string ResponseUnknown ( ulong steamID ) {
2016-03-26 02:47:25 +01:00
if ( steamID = = 0 | | ! IsMaster ( steamID ) ) {
2016-03-18 14:39:59 +01:00
return null ;
}
return "ERROR: Unknown command!" ;
}
2016-03-18 09:02:09 +01:00
private static async Task < string > ResponseUpdate ( ulong steamID ) {
if ( steamID = = 0 ) {
return null ;
}
if ( ! IsOwner ( steamID ) ) {
2016-03-18 14:13:04 +01:00
return null ;
2016-03-18 09:02:09 +01:00
}
await Program . CheckForUpdate ( ) . ConfigureAwait ( false ) ;
return "Done!" ;
2015-11-01 02:04:44 +01:00
}
2016-02-22 18:34:45 +01:00
private void HandleCallbacks ( ) {
TimeSpan timeSpan = TimeSpan . FromMilliseconds ( CallbackSleep ) ;
2016-03-03 16:11:46 +01:00
while ( KeepRunning | | SteamClient . IsConnected ) {
2016-03-30 01:41:53 +02:00
try {
CallbackManager . RunWaitCallbacks ( timeSpan ) ;
} catch ( Exception e ) {
Logging . LogGenericException ( e , BotName ) ;
}
2016-02-22 18:34:45 +01:00
}
}
2016-03-18 20:35:42 +01:00
private async Task HandleMessage ( ulong chatID , ulong steamID , string message ) {
if ( chatID = = 0 | | steamID = = 0 | | string . IsNullOrEmpty ( message ) ) {
2016-01-04 00:02:18 +01:00
return ;
}
2016-03-18 20:35:42 +01:00
SendMessage ( chatID , await Response ( steamID , message ) . ConfigureAwait ( false ) ) ;
2016-01-04 00:02:18 +01:00
}
2016-02-22 18:34:45 +01:00
private void SendMessage ( ulong steamID , string message ) {
if ( steamID = = 0 | | string . IsNullOrEmpty ( message ) ) {
return ;
}
2016-03-10 01:20:17 +01:00
if ( new SteamID ( steamID ) . IsChatAccount ) {
2016-02-22 18:34:45 +01:00
SteamFriends . SendChatRoomMessage ( steamID , EChatEntryType . ChatMsg , message ) ;
2016-03-10 01:20:17 +01:00
} else {
SteamFriends . SendChatMessage ( steamID , EChatEntryType . ChatMsg , message ) ;
2016-02-22 18:34:45 +01:00
}
}
2016-03-10 01:20:17 +01:00
private void LinkMobileAuthenticator ( ) {
2016-03-06 02:20:41 +01:00
if ( BotDatabase . SteamGuardAccount ! = null ) {
2016-03-10 01:20:17 +01:00
return ;
2016-02-22 18:34:45 +01:00
}
Logging . LogGenericInfo ( "Linking new ASF MobileAuthenticator..." , BotName ) ;
2016-03-12 05:58:51 +01:00
InitializeLoginAndPassword ( ) ;
2016-03-06 02:20:41 +01:00
UserLogin userLogin = new UserLogin ( BotConfig . SteamLogin , BotConfig . SteamPassword ) ;
2016-02-22 18:34:45 +01:00
LoginResult loginResult ;
while ( ( loginResult = userLogin . DoLogin ( ) ) ! = LoginResult . LoginOkay ) {
switch ( loginResult ) {
case LoginResult . NeedEmail :
2016-03-22 17:26:39 +01:00
userLogin . EmailCode = Program . GetUserInput ( Program . EUserInputType . SteamGuard , BotName ) ;
2016-02-22 18:34:45 +01:00
break ;
default :
Logging . LogGenericError ( "Unhandled situation: " + loginResult , BotName ) ;
2016-03-10 01:20:17 +01:00
return ;
2016-02-22 18:34:45 +01:00
}
}
AuthenticatorLinker authenticatorLinker = new AuthenticatorLinker ( userLogin . Session ) ;
AuthenticatorLinker . LinkResult linkResult ;
while ( ( linkResult = authenticatorLinker . AddAuthenticator ( ) ) ! = AuthenticatorLinker . LinkResult . AwaitingFinalization ) {
switch ( linkResult ) {
case AuthenticatorLinker . LinkResult . MustProvidePhoneNumber :
2016-03-22 17:26:39 +01:00
authenticatorLinker . PhoneNumber = Program . GetUserInput ( Program . EUserInputType . PhoneNumber , BotName ) ;
2016-02-22 18:34:45 +01:00
break ;
default :
Logging . LogGenericError ( "Unhandled situation: " + linkResult , BotName ) ;
2016-03-10 01:20:17 +01:00
return ;
2016-02-22 18:34:45 +01:00
}
}
2016-03-06 02:20:41 +01:00
BotDatabase . SteamGuardAccount = authenticatorLinker . LinkedAccount ;
2016-02-22 18:34:45 +01:00
2016-03-22 17:26:39 +01:00
AuthenticatorLinker . FinalizeResult finalizeResult = authenticatorLinker . FinalizeAddAuthenticator ( Program . GetUserInput ( Program . EUserInputType . SMS , BotName ) ) ;
2016-02-22 18:34:45 +01:00
if ( finalizeResult ! = AuthenticatorLinker . FinalizeResult . Success ) {
Logging . LogGenericError ( "Unhandled situation: " + finalizeResult , BotName ) ;
DelinkMobileAuthenticator ( ) ;
2016-03-10 01:20:17 +01:00
return ;
2016-02-22 18:34:45 +01:00
}
2016-04-01 17:14:03 +02:00
// Ensure that we also save changes made by finalization step (if any)
BotDatabase . Save ( ) ;
2016-02-22 18:34:45 +01:00
Logging . LogGenericInfo ( "Successfully linked ASF as new mobile authenticator for this account!" , BotName ) ;
2016-03-22 17:26:39 +01:00
Program . GetUserInput ( Program . EUserInputType . RevocationCode , BotName , BotDatabase . SteamGuardAccount . RevocationCode ) ;
2016-02-22 18:34:45 +01:00
}
private bool DelinkMobileAuthenticator ( ) {
2016-03-06 02:20:41 +01:00
if ( BotDatabase . SteamGuardAccount = = null ) {
2016-02-22 18:34:45 +01:00
return false ;
}
2016-03-06 02:20:41 +01:00
bool result = BotDatabase . SteamGuardAccount . DeactivateAuthenticator ( ) ;
2016-02-22 18:34:45 +01:00
2016-03-06 02:20:41 +01:00
if ( result ) {
BotDatabase . SteamGuardAccount = null ;
2016-02-22 18:34:45 +01:00
}
return result ;
}
2016-02-24 06:06:09 +01:00
private void JoinMasterChat ( ) {
2016-03-06 02:20:41 +01:00
if ( BotConfig . SteamMasterClanID = = 0 ) {
2016-02-24 06:06:09 +01:00
return ;
}
2016-03-06 02:20:41 +01:00
SteamFriends . JoinChat ( BotConfig . SteamMasterClanID ) ;
2016-02-24 06:06:09 +01:00
}
2016-03-12 05:58:51 +01:00
private void InitializeLoginAndPassword ( ) {
if ( string . IsNullOrEmpty ( BotConfig . SteamLogin ) ) {
2016-03-22 17:26:39 +01:00
BotConfig . SteamLogin = Program . GetUserInput ( Program . EUserInputType . Login , BotName ) ;
2016-03-12 05:58:51 +01:00
}
if ( string . IsNullOrEmpty ( BotConfig . SteamPassword ) & & string . IsNullOrEmpty ( BotDatabase . LoginKey ) ) {
2016-03-22 17:26:39 +01:00
BotConfig . SteamPassword = Program . GetUserInput ( Program . EUserInputType . Password , BotName ) ;
2016-03-12 05:58:51 +01:00
}
}
2015-10-25 06:16:50 +01:00
private void OnConnected ( SteamClient . ConnectedCallback callback ) {
if ( callback = = null ) {
return ;
}
if ( callback . Result ! = EResult . OK ) {
2016-01-24 18:08:27 +01:00
Logging . LogGenericError ( "Unable to connect to Steam: " + callback . Result , BotName ) ;
2015-10-25 06:16:50 +01:00
return ;
}
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Connected to Steam!" , BotName ) ;
2015-10-25 06:16:50 +01:00
2016-03-03 16:11:46 +01:00
if ( ! KeepRunning ) {
Logging . LogGenericInfo ( "Disconnecting..." , BotName ) ;
SteamClient . Disconnect ( ) ;
return ;
}
2015-10-25 06:16:50 +01:00
byte [ ] sentryHash = null ;
if ( File . Exists ( SentryFile ) ) {
2016-02-12 16:51:06 +01:00
try {
byte [ ] sentryFileContent = File . ReadAllBytes ( SentryFile ) ;
sentryHash = CryptoHelper . SHAHash ( sentryFileContent ) ;
} catch ( Exception e ) {
Logging . LogGenericException ( e , BotName ) ;
}
2015-10-25 06:16:50 +01:00
}
2016-03-12 05:58:51 +01:00
InitializeLoginAndPassword ( ) ;
2015-10-28 23:29:50 +01:00
2016-03-13 22:58:52 +01:00
Logging . LogGenericInfo ( "Logging in..." , BotName ) ;
2016-03-14 20:38:17 +01:00
// TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed
if ( Program . GlobalConfig . HackIgnoreMachineID ) {
Logging . LogGenericWarning ( "Using workaround for broken GenerateMachineID()!" , BotName ) ;
ArchiHandler . HackedLogOn ( new SteamUser . LogOnDetails {
Username = BotConfig . SteamLogin ,
Password = BotConfig . SteamPassword ,
AuthCode = AuthCode ,
LoginID = LoginID ,
LoginKey = BotDatabase . LoginKey ,
TwoFactorCode = TwoFactorAuth ,
SentryFileHash = sentryHash ,
ShouldRememberPassword = true
} ) ;
return ;
}
2015-12-21 10:06:37 +01:00
SteamUser . LogOn ( new SteamUser . LogOnDetails {
2016-03-06 02:20:41 +01:00
Username = BotConfig . SteamLogin ,
Password = BotConfig . SteamPassword ,
2015-12-16 01:20:54 +01:00
AuthCode = AuthCode ,
2015-12-21 10:06:37 +01:00
LoginID = LoginID ,
2016-03-06 02:20:41 +01:00
LoginKey = BotDatabase . LoginKey ,
2015-12-16 01:20:54 +01:00
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
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Disconnected from Steam!" , BotName ) ;
2016-03-22 20:18:47 +01:00
CardsFarmer . StopFarming ( ) . Forget ( ) ;
2015-12-22 16:51:37 +01:00
2016-03-22 20:18:47 +01:00
// If we initiated disconnect, do not attempt to reconnect
if ( callback . UserInitiated ) {
2015-12-23 10:58:14 +01:00
return ;
}
2016-03-22 20:18:47 +01:00
if ( ! KeepRunning ) {
2015-11-01 02:04:44 +01:00
return ;
}
2015-12-23 10:58:14 +01:00
if ( InvalidPassword ) {
InvalidPassword = false ;
2016-03-06 02:20:41 +01:00
if ( ! string . IsNullOrEmpty ( BotDatabase . LoginKey ) ) { // InvalidPassword means usually that login key has expired, if we used it
BotDatabase . LoginKey = null ;
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Removed expired login key" , BotName ) ;
2015-12-23 10:58:14 +01:00
} else { // If we didn't use login key, InvalidPassword usually means we got captcha or other network-based throttling
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Will retry after 25 minutes..." , BotName ) ;
2015-12-23 10:58:14 +01:00
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 ;
2016-03-22 17:26:39 +01:00
if ( Program . GlobalConfig . AccountPlayingDelay = = 0 ) {
2016-03-22 20:18:47 +01:00
Stop ( ) ;
2016-03-22 17:26:39 +01:00
return ;
}
2016-03-10 21:44:45 +01:00
Logging . LogGenericInfo ( "Account is being used elsewhere, ASF will try to resume farming in " + Program . GlobalConfig . AccountPlayingDelay + " minutes..." , BotName ) ;
2016-03-07 23:10:07 +01:00
await Utilities . SleepAsync ( Program . GlobalConfig . AccountPlayingDelay * 60 * 1000 ) . ConfigureAwait ( false ) ;
2015-12-09 20:55:43 +01:00
}
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Reconnecting..." , BotName ) ;
2015-12-22 16:51:37 +01:00
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 ( ) ;
}
2016-01-22 10:56:06 +01:00
private void OnFreeLicense ( SteamApps . FreeLicenseCallback callback ) {
if ( callback = = null ) {
return ;
}
}
2016-03-27 23:07:00 +02:00
private async void OnGuestPassList ( SteamApps . GuestPassListCallback callback ) {
2016-03-27 23:18:01 +02:00
if ( callback = = null | | callback . Result ! = EResult . OK | | callback . CountGuestPassesToRedeem = = 0 | | callback . GuestPasses . Count = = 0 | | ! BotConfig . AcceptGifts ) {
2016-03-27 23:07:00 +02:00
return ;
}
bool acceptedSomething = false ;
foreach ( KeyValue guestPass in callback . GuestPasses ) {
ulong gid = guestPass [ "gid" ] . AsUnsignedLong ( ) ;
if ( gid = = 0 ) {
continue ;
}
Logging . LogGenericInfo ( "Accepting gift: " + gid + "..." , BotName ) ;
if ( await ArchiWebHandler . AcceptGift ( gid ) . ConfigureAwait ( false ) ) {
acceptedSomething = true ;
Logging . LogGenericInfo ( "Success!" , BotName ) ;
} else {
Logging . LogGenericInfo ( "Failed!" , BotName ) ;
}
}
if ( acceptedSomething ) {
CardsFarmer . RestartFarming ( ) . Forget ( ) ;
}
}
2015-12-21 19:28:59 +01:00
private void OnChatInvite ( SteamFriends . ChatInviteCallback callback ) {
2016-03-26 02:47:25 +01:00
if ( callback = = null | | ! IsMaster ( callback . PatronID ) ) {
2015-12-21 19:28:59 +01:00
return ;
}
SteamFriends . JoinChat ( callback . ChatRoomID ) ;
}
private async void OnChatMsg ( SteamFriends . ChatMsgCallback callback ) {
2016-03-26 02:47:25 +01:00
if ( callback = = null | | callback . ChatMsgType ! = EChatEntryType . ChatMsg ) {
2015-12-21 19:28:59 +01:00
return ;
}
2016-02-12 16:21:33 +01:00
switch ( callback . Message ) {
case "!leave" :
2016-03-26 02:47:25 +01:00
if ( ! IsMaster ( callback . ChatterID ) ) {
break ;
}
2016-02-12 16:21:33 +01:00
SteamFriends . LeaveChat ( callback . ChatRoomID ) ;
break ;
default :
2016-03-18 20:35:42 +01:00
await HandleMessage ( callback . ChatRoomID , callback . ChatterID , callback . Message ) . ConfigureAwait ( false ) ;
2016-02-12 16:21:33 +01:00
break ;
}
2015-12-21 19:28:59 +01:00
}
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 ;
}
2016-02-12 16:51:06 +01:00
switch ( friend . SteamID . AccountType ) {
2015-10-25 06:16:50 +01:00
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 :
2016-03-18 09:02:09 +01:00
if ( ! IsMaster ( friend . SteamID ) ) {
break ;
2015-10-25 06:16:50 +01:00
}
2016-03-26 02:47:25 +01:00
2016-03-18 09:02:09 +01:00
SteamFriends . AddFriend ( friend . SteamID ) ;
2015-10-25 06:16:50 +01:00
break ;
}
}
}
2015-10-31 05:27:30 +01:00
private async void OnFriendMsg ( SteamFriends . FriendMsgCallback callback ) {
2016-03-26 02:47:25 +01:00
if ( callback = = null | | callback . EntryType ! = EChatEntryType . ChatMsg ) {
2015-10-25 06:16:50 +01:00
return ;
2015-12-21 19:28:59 +01:00
}
2016-03-18 20:35:42 +01:00
await HandleMessage ( callback . Sender , callback . Sender , callback . Message ) . ConfigureAwait ( false ) ;
2015-12-21 10:55:55 +01:00
}
private async void OnFriendMsgHistory ( SteamFriends . FriendMsgHistoryCallback callback ) {
2016-03-26 02:47:25 +01:00
if ( callback = = null | | callback . Result ! = EResult . OK | | callback . Messages . Count = = 0 | | ! IsMaster ( callback . SteamID ) ) {
2015-11-01 02:04:44 +01:00
return ;
}
2015-12-21 10:55:55 +01:00
// Get last message
2016-02-12 16:51:06 +01:00
var lastMessage = callback . Messages [ callback . Messages . Count - 1 ] ;
2015-12-21 10:55:55 +01:00
// 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
2016-03-18 20:35:42 +01:00
await HandleMessage ( callback . SteamID , callback . SteamID , lastMessage . Message ) . ConfigureAwait ( false ) ;
2015-10-25 06:16:50 +01:00
}
private void OnAccountInfo ( SteamUser . AccountInfoCallback callback ) {
if ( callback = = null ) {
return ;
}
2016-03-06 02:20:41 +01:00
if ( ! BotConfig . 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 ;
}
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Logged off of Steam: " + callback . Result , BotName ) ;
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 ;
}
2016-02-12 16:51:06 +01:00
switch ( callback . Result ) {
2015-10-25 06:16:50 +01:00
case EResult . AccountLogonDenied :
2016-03-22 17:26:39 +01:00
AuthCode = Program . GetUserInput ( Program . EUserInputType . SteamGuard , BotName ) ;
2015-10-25 06:16:50 +01:00
break ;
case EResult . AccountLoginDeniedNeedTwoFactor :
2016-03-06 02:20:41 +01:00
if ( BotDatabase . SteamGuardAccount = = null ) {
2016-03-22 17:26:39 +01:00
TwoFactorAuth = Program . GetUserInput ( Program . EUserInputType . TwoFactorAuthentication , BotName ) ;
2015-12-11 22:53:28 +01:00
} else {
2016-03-06 02:20:41 +01:00
TwoFactorAuth = BotDatabase . SteamGuardAccount . GenerateSteamGuardCode ( ) ;
2015-12-11 22:53:28 +01:00
}
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 ;
2016-02-12 16:51:06 +01:00
Logging . LogGenericWarning ( "Unable to login to Steam: " + callback . Result , BotName ) ;
2015-11-26 01:22:56 +01:00
break ;
2015-10-25 06:16:50 +01:00
case EResult . OK :
2016-01-24 18:08:27 +01:00
Logging . LogGenericInfo ( "Successfully logged on!" , BotName ) ;
2015-10-28 20:01:43 +01:00
2016-03-07 02:39:55 +01:00
if ( callback . CellID ! = 0 ) {
Program . GlobalDatabase . CellID = callback . CellID ;
}
2016-03-18 14:39:59 +01:00
if ( BotDatabase . SteamGuardAccount = = null ) {
// Support and convert SDA files
string maFilePath = Path . Combine ( Program . ConfigDirectory , callback . ClientSteamID . ConvertToUInt64 ( ) + ".maFile" ) ;
if ( File . Exists ( maFilePath ) ) {
ImportAuthenticator ( maFilePath ) ;
} else if ( TwoFactorAuth = = null & & BotConfig . UseAsfAsMobileAuthenticator ) {
LinkMobileAuthenticator ( ) ;
}
2015-12-11 22:53:28 +01:00
}
2015-12-06 19:38:09 +01:00
// Reset one-time-only access tokens
2016-03-18 14:39:59 +01:00
AuthCode = TwoFactorAuth = null ;
2015-12-06 19:38:09 +01:00
2016-02-28 04:15:52 +01:00
ResetGamesPlayed ( ) ;
2016-03-06 02:20:41 +01:00
if ( string . IsNullOrEmpty ( BotConfig . SteamParentalPIN ) ) {
2016-03-22 17:26:39 +01:00
BotConfig . SteamParentalPIN = Program . GetUserInput ( Program . EUserInputType . SteamParentalPIN , BotName ) ;
2015-10-29 01:01:31 +01:00
}
2016-03-29 14:33:05 +02:00
if ( ! ArchiWebHandler . Init ( SteamClient , callback . WebAPIUserNonce , BotConfig . SteamParentalPIN ) ) {
if ( ! await RefreshSession ( ) . ConfigureAwait ( false ) ) {
return ;
}
2015-12-25 17:49:00 +01:00
}
2015-10-25 06:16:50 +01:00
2016-03-10 21:44:45 +01:00
if ( BotConfig . DismissInventoryNotifications ) {
2016-03-22 11:21:45 +01:00
ArchiWebHandler . MarkInventory ( ) . Forget ( ) ;
2016-03-10 21:44:45 +01:00
}
2016-03-06 02:20:41 +01:00
if ( BotConfig . SteamMasterClanID ! = 0 ) {
2016-03-18 14:47:52 +01:00
Task . Run ( async ( ) = > {
await ArchiWebHandler . JoinClan ( BotConfig . SteamMasterClanID ) . ConfigureAwait ( false ) ;
JoinMasterChat ( ) ;
} ) . Forget ( ) ;
2015-10-28 19:21:27 +01:00
}
2015-10-25 06:16:50 +01:00
2016-03-09 05:02:07 +01:00
if ( Program . GlobalConfig . Statistics ) {
2016-03-18 14:47:52 +01:00
Task . Run ( async ( ) = > {
await ArchiWebHandler . JoinClan ( ArchiSCFarmGroup ) . ConfigureAwait ( false ) ;
SteamFriends . JoinChat ( ArchiSCFarmGroup ) ;
} ) . Forget ( ) ;
2015-10-29 16:38:16 +01:00
}
2016-03-18 14:47:52 +01:00
Task . Run ( ( ) = > Trading . CheckTrades ( ) ) . Forget ( ) ;
2015-12-13 15:25:00 +01:00
2016-03-22 11:21:45 +01:00
CardsFarmer . StartFarming ( ) . Forget ( ) ;
2015-10-25 06:16:50 +01:00
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 :
2016-02-12 16:51:06 +01:00
Logging . LogGenericWarning ( "Unable to login to Steam: " + callback . Result , BotName ) ;
2015-10-25 06:16:50 +01:00
break ;
2015-12-23 10:58:14 +01:00
default : // Unexpected result, shutdown immediately
2016-02-12 16:51:06 +01:00
Logging . LogGenericWarning ( "Unable to login to Steam: " + callback . Result , BotName ) ;
2016-03-22 20:18:47 +01:00
Stop ( ) ;
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 ;
}
2016-03-06 02:20:41 +01:00
BotDatabase . LoginKey = callback . LoginKey ;
2015-12-11 22:53:28 +01:00
SteamUser . AcceptNewLoginKey ( callback ) ;
}
2015-10-25 06:16:50 +01:00
private void OnMachineAuth ( SteamUser . UpdateMachineAuthCallback callback ) {
if ( callback = = null ) {
return ;
}
2016-03-30 13:10:00 +02:00
int fileSize ;
byte [ ] sentryHash ;
2016-02-20 17:07:05 +01:00
2016-03-30 13:10:00 +02:00
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 ;
2016-02-12 16:51:06 +01:00
2016-03-30 13:10:00 +02:00
fileStream . Seek ( 0 , SeekOrigin . Begin ) ;
using ( SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider ( ) ) {
sentryHash = sha . ComputeHash ( fileStream ) ;
2015-10-25 06:16:50 +01:00
}
2016-02-12 16:51:06 +01:00
}
2016-03-30 13:10:00 +02:00
// 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
} ) ;
2015-10-25 06:16:50 +01:00
}
2016-03-29 14:33:05 +02:00
private void OnWebAPIUserNonce ( SteamUser . WebAPIUserNonceCallback callback ) {
if ( callback = = null ) {
return ;
}
}
2016-02-28 03:40:59 +01:00
private async void OnNotifications ( ArchiHandler . NotificationsCallback callback ) {
if ( callback = = null | | callback . Notifications = = null ) {
2015-10-25 06:16:50 +01:00
return ;
}
2016-01-02 17:22:35 +01:00
bool checkTrades = false ;
2016-02-28 03:40:59 +01:00
bool markInventory = false ;
2016-01-02 17:22:35 +01:00
foreach ( var notification in callback . Notifications ) {
switch ( notification . NotificationType ) {
2016-02-28 03:40:59 +01:00
case ArchiHandler . NotificationsCallback . Notification . ENotificationType . Items :
markInventory = true ;
break ;
2016-01-02 17:22:35 +01:00
case ArchiHandler . NotificationsCallback . Notification . ENotificationType . Trading :
checkTrades = true ;
break ;
}
}
if ( checkTrades ) {
2016-03-24 14:18:07 +01:00
Trading . CheckTrades ( ) . Forget ( ) ;
2015-10-25 06:16:50 +01:00
}
2016-02-28 03:40:59 +01:00
2016-03-06 14:15:59 +01:00
if ( markInventory & & BotConfig . DismissInventoryNotifications ) {
2016-02-28 03:40:59 +01:00
await ArchiWebHandler . MarkInventory ( ) . ConfigureAwait ( false ) ;
}
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 ;
}
2016-03-06 02:20:41 +01:00
if ( ! BotConfig . HandleOfflineMessages ) {
2015-12-20 19:48:58 +01:00
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
2016-03-09 18:50:54 +01:00
private void OnPurchaseResponse ( ArchiHandler . PurchaseResponseCallback callback ) {
2015-10-25 06:16:50 +01:00
if ( callback = = null ) {
return ;
}
2016-02-12 16:51:06 +01:00
if ( callback . 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
2016-03-22 11:21:45 +01:00
CardsFarmer . RestartFarming ( ) . Forget ( ) ;
2015-10-25 06:16:50 +01:00
}
}
}
}