diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 63996608c..a878b0ba4 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -21,7 +21,9 @@ limitations under the License. */ - +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Linq; using HtmlAgilityPack; using SteamKit2; using System; @@ -371,6 +373,54 @@ namespace ArchiSteamFarm { return response != null; // Steam API doesn't respond with any error code, assume any response is a success } + internal async Task> GetInventory() { + List result = new List(); + try { + JObject jobj = await WebBrowser.UrlGetToJObject("http://steamcommunity.com/my/inventory/json/753/6", Cookie).ConfigureAwait(false); + IList results = jobj.SelectTokens("$.rgInventory.*").ToList(); + foreach (JToken res in results) { + result.Add(JsonConvert.DeserializeObject(res.ToString())); + } + } catch (Exception) { + //just return empty list on error + } + return result; + } + + internal async Task SendTradeOffer(List itemsSend, string masterid,string token=null) { + string sessionID; + if (!Cookie.TryGetValue("sessionid", out sessionID)) { + return false; + } + + SteamTradeItemList items = new SteamTradeItemList(); + foreach (var item in itemsSend) { + items.assets.Add(new SteamTradeItem(753, 6, Int32.Parse(item.amount), item.id)); + } + + SteamTradeOfferRequest trade = new SteamTradeOfferRequest(true, 2, items, new SteamTradeItemList()); + + string referer = String.Format("https://steamcommunity.com/tradeoffer/new/?partner={0}", ((Int32)Int64.Parse(masterid)).ToString()); + + if (!string.IsNullOrEmpty(token)) { + referer += String.Format("&token={0}",token); + } + + Dictionary postData = new Dictionary() { + {"sessionid", sessionID}, + {"serverid","1" }, + {"partner",masterid }, + {"tradeoffermessage","sent by ASF" }, + {"json_tradeoffer",JsonConvert.SerializeObject(trade) }, + {"trade_offer_create_params",string.IsNullOrEmpty(token)?"":String.Format("{{ \"trade_offer_access_token\":\"{0}\" }}", token) } + }; + HttpResponseMessage response = await WebBrowser.UrlPost("https://steamcommunity.com/tradeoffer/new/send", postData, Cookie, referer).ConfigureAwait(false); + if (response == null) { + return false; + } + return response.IsSuccessStatusCode; + } + internal async Task GetBadgePage(int page) { if (SteamID == 0 || page == 0) { return null; diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs old mode 100755 new mode 100644 index a4b14da98..7910196c6 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -31,6 +31,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; +using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Text; @@ -56,6 +57,7 @@ namespace ArchiSteamFarm { internal readonly SteamFriends SteamFriends; internal readonly SteamUser SteamUser; internal readonly Trading Trading; + private Timer Timer; private bool KeepRunning = true; private bool InvalidPassword = false; @@ -70,6 +72,7 @@ namespace ArchiSteamFarm { internal string SteamPassword { get; private set; } = "null"; internal string SteamNickname { get; private set; } = "null"; internal string SteamApiKey { get; private set; } = "null"; + internal string SteamTradeToken {get; private set; } = "null"; internal string SteamParentalPIN { get; private set; } = "0"; internal ulong SteamMasterID { get; private set; } = 0; internal ulong SteamMasterClanID { get; private set; } = 0; @@ -79,6 +82,8 @@ namespace ArchiSteamFarm { internal bool ForwardKeysToOtherBots { get; private set; } = false; internal bool UseAsfAsMobileAuthenticator { get; private set; } = false; internal bool ShutdownOnFarmingFinished { get; private set; } = false; + internal bool SendOnFarmingFinished { get; private set; } = false; + internal uint SendTradePeriod {get; private set; } = 0; internal HashSet Blacklist { get; private set; } = new HashSet(); internal bool Statistics { get; private set; } = true; @@ -305,6 +310,9 @@ namespace ArchiSteamFarm { case "SteamApiKey": SteamApiKey = value; break; + case "SteamTradeToken": + SteamTradeToken = value; + break; case "SteamParentalPIN": SteamParentalPIN = value; break; @@ -332,6 +340,12 @@ namespace ArchiSteamFarm { case "ShutdownOnFarmingFinished": ShutdownOnFarmingFinished = bool.Parse(value); break; + case "SendOnFarmingFinished": + SendOnFarmingFinished = bool.Parse(value); + break; + case "SendTradePeriod": + SendTradePeriod = uint.Parse(value); + break; case "Blacklist": Blacklist.Clear(); foreach (string appID in value.Split(',')) { @@ -411,6 +425,9 @@ namespace ArchiSteamFarm { } internal async Task OnFarmingFinished() { + if (SendOnFarmingFinished) { + await ResponseSendTrade(BotName).ConfigureAwait(false); + } if (ShutdownOnFarmingFinished) { await Shutdown().ConfigureAwait(false); } @@ -467,6 +484,35 @@ namespace ArchiSteamFarm { return result.ToString(); } + internal static async Task ResponseSendTrade(string botName) { + Bot bot; + string token=null; + if (string.IsNullOrEmpty(botName)) { + return "Error, no name specified"; + } + if (!Bots.TryGetValue(botName, out bot)) { + return "Couldn't find any bot named " + botName + "!"; + } + if (bot.SendTradePeriod!=0) { + bot.Timer.Change(TimeSpan.FromHours(bot.SendTradePeriod),Timeout.InfiniteTimeSpan); + } + if (bot.SteamMasterID==0) { + return "No master set"; + } + if ((!string.IsNullOrEmpty(bot.SteamTradeToken))&&(!bot.SteamTradeToken.Equals("null"))) { + token=bot.SteamTradeToken; + } + List inv = await bot.ArchiWebHandler.GetInventory().ConfigureAwait(false); + if (inv.Count == 0) { + return "Nothing to send"; + } + if (await bot.ArchiWebHandler.SendTradeOffer(inv, bot.SteamMasterID.ToString(),token).ConfigureAwait(false)) { + await bot.AcceptAllConfirmations().ConfigureAwait(false); + return "Trade offer sent"; + } + return "Error sending trade offer"; + } + internal static string Response2FA(string botName) { if (string.IsNullOrEmpty(botName)) { return null; @@ -673,6 +719,8 @@ namespace ArchiSteamFarm { return ResponseStatusAll(); case "!stop": return await ResponseStop(BotName).ConfigureAwait(false); + case "!loot": + return await ResponseSendTrade(BotName).ConfigureAwait(false); default: return "Unrecognized command: " + message; } @@ -700,6 +748,8 @@ namespace ArchiSteamFarm { return await ResponseStop(args[1]).ConfigureAwait(false); case "!status": return ResponseStatus(args[1]); + case "!loot": + return await ResponseSendTrade(args[1]).ConfigureAwait(false); default: return "Unrecognized command: " + args[0]; } @@ -991,6 +1041,15 @@ namespace ArchiSteamFarm { Trading.CheckTrades(); await CardsFarmer.StartFarming().ConfigureAwait(false); + + if (SendTradePeriod!=0) { + Timer = new Timer( + async e => await ResponseSendTrade(BotName).ConfigureAwait(false), + null, + TimeSpan.FromHours(SendTradePeriod), // Delay + Timeout.InfiniteTimeSpan // Period + ); + } break; case EResult.NoConnection: case EResult.ServiceUnavailable: diff --git a/ArchiSteamFarm/SteamInventoryItem.cs b/ArchiSteamFarm/SteamInventoryItem.cs new file mode 100644 index 000000000..60158c527 --- /dev/null +++ b/ArchiSteamFarm/SteamInventoryItem.cs @@ -0,0 +1,12 @@ + +namespace ArchiSteamFarm +{ + public class SteamInventoryItem + { + public string id { get; set; } + public string classid { get; set; } + public string instanceid { get; set; } + public string amount { get; set; } + public int pos { get; set; } + } +} diff --git a/ArchiSteamFarm/SteamTradeItem.cs b/ArchiSteamFarm/SteamTradeItem.cs new file mode 100644 index 000000000..f2090d792 --- /dev/null +++ b/ArchiSteamFarm/SteamTradeItem.cs @@ -0,0 +1,15 @@ + +namespace ArchiSteamFarm { + public class SteamTradeItem { + public int appid { get; set; } + public int contextid { get; set; } + public int amount { get; set; } + public string assetid { get; set; } + public SteamTradeItem (int aid, int cid, int am, string asset) { + appid = aid; + contextid = cid; + amount = am; + assetid = asset; + } + } +} diff --git a/ArchiSteamFarm/SteamTradeItemList.cs b/ArchiSteamFarm/SteamTradeItemList.cs new file mode 100644 index 000000000..2173a32e2 --- /dev/null +++ b/ArchiSteamFarm/SteamTradeItemList.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace ArchiSteamFarm { + public class SteamTradeItemList { + public List assets { get; set; } + public List currency { get; set; } + public bool ready { get; set; } + public SteamTradeItemList() { + assets = new List(); + currency = new List(); + ready = false; + } + } +} diff --git a/ArchiSteamFarm/SteamTradeOfferRequest.cs b/ArchiSteamFarm/SteamTradeOfferRequest.cs new file mode 100644 index 000000000..5540c1194 --- /dev/null +++ b/ArchiSteamFarm/SteamTradeOfferRequest.cs @@ -0,0 +1,15 @@ + +namespace ArchiSteamFarm { + public class SteamTradeOfferRequest { + public bool newversion { get; set; } + public int version { get; set; } + public SteamTradeItemList me { get; set; } + public SteamTradeItemList them { get; set; } + public SteamTradeOfferRequest (bool nv, int v, SteamTradeItemList m, SteamTradeItemList t) { + newversion = nv; + version = v; + me = m; + them = t; + } + } +} diff --git a/ArchiSteamFarm/config/example.xml b/ArchiSteamFarm/config/example.xml index 24e98bcd3..a73bbc747 100644 --- a/ArchiSteamFarm/config/example.xml +++ b/ArchiSteamFarm/config/example.xml @@ -1,7 +1,7 @@ - + @@ -104,6 +104,23 @@ + + + + + + + + + + + + + + + + +