/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// using System; using System.Globalization; using System.IO; using System.Threading; using System.Collections.Generic; using OpenMetaverse; using OpenMetaverse.Messages.Linden; using System.Linq; namespace Rake { internal class Rake { private static readonly GridClient Client = new GridClient(); private static string _firstName = string.Empty; private static string _lastName = string.Empty; private static string _password = string.Empty; private static readonly Thread RakeThread = new Thread(ProcessInventory); private static readonly List StabilizeChecks = new List(); private static AutoResetEvent _folders = new AutoResetEvent(false); private static readonly KeyValuePair[] Grids = new[] { new KeyValuePair('1', "https://login.agni.lindenlab.com/cgi-bin/login.cgi") , new KeyValuePair('2', "http://os.bio-se.info:9000/") , new KeyValuePair('3', "Manual override.") }; private static bool _overwriteExisting = true; private static readonly List Logo = new List { " ,v+s. ,.\n", " ,z~ Vs ,gW`Vi\n", " _Y` VWs __gmW@@@ ].\n", " g/\\g=YM` V@WmW@@@@@@@@@@@@@@@@@@@@@@@@@ [\n", " Z+/~ _d 7e. Y@@@@@~~~~~~V***@@@@@@@@@@@@@b b\n", " _m@@@Wv.Vm. @@@@@ 'VM@@@@@@@@@@Wm*\n", " gW@@@*fT@i '@ Y@@@@ Y@@@@@@@@@Wm_\n", " ,g@@@*~ ,/. ,/` d@@@@ ]@@@@W 'VM@@@Ws\n", " ,_m@@@*` /Z gf ,@@@@A*f~~~~~+=s_. g@@@@@P '*@f'Ms\n", " K~~******==*f~M[\f` ,g@Af~ ,mms. Y@@@@@Af 'M/\\4W.\n", " !z i/ '+m@@*~` ,gW@@@@@s. i@@@@@| Vbv*W.\n", " gW| M. -' _g=~~M@@@@@@@@@@@@@@@@@m_ 'N-Z@.\n", " i@@W_-. '*s. ,_mK` MK` ]@@@@@@@@*fVN2~ 'M\\_W\n", " ,@@@f'*eK__s__2_gmm@*Y!Vtms ]5__W@@@A*M@@. 'Vc. 'bgVb\n", " W@@P [,._z\\z 'Vmz` M@@@A` ]@@[ '+_ -gs@i\n", " i@Af '8M` K ,_=Y=s M@P @@b '\\s M~VW\n", " Wf ,-'`|~`-. gf,vf~\\s_/ V '* @@@b Vs ][~@i\n", "i` .' . i -'c ,P,_ ' '- !i @@@@._Y~Ve_. 'N. b ~[\n", "! ] i~-L-'. '. ![~V ! b vf**MK. V@D__ Ms @M@[\n", "s ] !,-7-,` ,v=e b i P ,/ ~N. '+ '` ]@b ]_,b\n", "@. `,-` ! - P A !i / [ K . , Y. ,W@@i W-i[\n", "]W_ '=,_L .-`t !s Ys v i[ 'VMf ,g@mm@m____gW@@@@[ A 4[\n", "]@*+=g[ 'i,g=Yc 4@['c _- . ,@[ Yms_d@@@@@@@@@@@@@@@[ ,[ @[\n", " @_ ~- '` ,W[ ]W_v` v g@@ ]@@@@@@@@@@@@@@@@@@A d g@`\n", " ]@@D- __gmmm,_L@@` !A~ ,-' g@@@! ]@@~M@@@@@@@@@@@@Af i[-WP\n", " 5_mm@~ i!]@@@A ds [,gW@@@A` ]@@ 'M@@@@@@**f~ ,AsdA\n", " M@@@s ] ]@@A` g@@@W- `]@@@A~ ]@@ 'M@@@@@ ,P-gW`\n", " M@@@b !['*f g@@Af`_- ,f~ ]@@. 'M@@@@W. ,g@WmA`\n", " V@@@W. 'e__Z~!@K_mmz=f` Wizardry ]@@b '@@@@@@Wsg@@@@f\n", " 'M@@@W. iA '`i and ]@@@i Y@@@@@@@@@@@b.\n", " 'M@@@Ws___zP/ Vs Steamworks ]@@@@s '@@@@@@@@@@@@@Ws.\n", " 'V@@@@A` 'N_ ]@@@@@@s_@@@@@@@@@@@@@@@A!\n", " ~*Mb. _ 'V=e_. ]@@@@@@@@@@@@@@@@@@*~`\n", " '~*Wmmm_______.____ !@@@@@@@@@@@@*f~~`\n", " ~V**@@@@@@@@@@Wmgmmm@@W@@@@@A~~~~`\n", " '~~~********M@@********\n", " \n", " v.\"Dancing hogs in managed states.\" \n\n" }; public static void Main() { foreach (var row in Logo) { new List(new int[(Console.WindowWidth - 70) / 2]).ForEach(i => Console.Write(" ")); Console.Write(row); } Settings.LOG_LEVEL = Helpers.LogLevel.None; Client.Settings.STORE_LAND_PATCHES = true; Client.Settings.ALWAYS_DECODE_OBJECTS = true; Client.Settings.ALWAYS_REQUEST_OBJECTS = true; Client.Settings.SEND_AGENT_UPDATES = true; Client.Settings.USE_ASSET_CACHE = false; Client.Settings.FETCH_MISSING_INVENTORY = true; Client.Network.LoginProgress += HandleLoginProgress; Client.Appearance.AppearanceSet += HandleAppearanceSet; Client.Network.SimConnected += HandleSimulatorConnected; Client.Network.EventQueueRunning += HandleEventQueueRunning; Console.Write("[Rake] : First Name : "); var line = Console.ReadLine(); if (line != null) _firstName = line.Trim(); Console.Write("[Rake] : Last Name : "); line = Console.ReadLine(); if (line != null) _lastName = line.Trim(); Console.Write("[Rake] : Password : "); var info = Console.ReadKey(true); var rnd = new Random(); while (info.Key != ConsoleKey.Enter) { if (info.Key != ConsoleKey.Backspace) { new List(new int[rnd.Next(1, 3)]).ForEach(i => Console.Write("*")); _password += info.KeyChar; } else if (!string.IsNullOrEmpty(_password)) { _password = _password.Substring(0, _password.Length - 1); var pos = Console.CursorLeft; Console.SetCursorPosition(pos - 1, Console.CursorTop); Console.Write(" "); Console.SetCursorPosition(pos - 1, Console.CursorTop); } info = Console.ReadKey(true); } Console.WriteLine(); invalid_overwrite: Console.Write("[Rake] : Overwrite files? [y/n] : "); info = Console.ReadKey(true); Console.WriteLine(info.KeyChar); switch (info.KeyChar) { case 'y': case 'Y': _overwriteExisting = true; break; case 'n': case 'N': _overwriteExisting = false; break; default: goto invalid_overwrite; } invalid_grid: foreach (var grid in Grids) { Console.WriteLine("{0}. {1}", grid.Key, grid.Value); } Console.Write("[Rake] : Select grid: "); info = Console.ReadKey(true); if (Grids.Count(g => g.Key.Equals(info.KeyChar)) == 0) { Console.WriteLine(); goto invalid_grid; } switch (info.KeyChar) { case '3': Console.WriteLine(); Console.Write("[Rake] : Please type a login URI : "); line = Console.ReadLine(); if (line != null) Client.Settings.LOGIN_SERVER = line.Trim(); break; default: Client.Settings.LOGIN_SERVER = Grids.First(g => g.Key.Equals(info.KeyChar)).Value; break; } Console.Write(info.KeyChar); Console.WriteLine(); new List(new int[Console.WindowWidth]).ForEach(i => Console.Write("-")); var login = new LoginParams(Client, _firstName, _lastName, _password, "[WaS] Rake", "1.0"); Console.Write("[Rake] : Starting login..."); Client.Network.BeginLogin(login); RakeThread.Start(); } private static void HandleEventQueueRunning(object sender, EventQueueRunningEventArgs e) { Client.Network.EventQueueRunning -= HandleEventQueueRunning; Console.Write("\n[Rake] : Event queue started..."); StabilizeChecks.Add(true); } private static void HandleSimulatorConnected(object sender, SimConnectedEventArgs e) { Client.Network.SimConnected -= HandleSimulatorConnected; Console.Write("\n[Rake] : Simulator connected..."); StabilizeChecks.Add(true); } private static void HandleAppearanceSet(object sender, AppearanceSetEventArgs e) { if (!e.Success) return; Client.Appearance.AppearanceSet -= HandleAppearanceSet; Console.Write("\n[Rake] : Appearance set..."); StabilizeChecks.Add(true); } private static void HandleLoginProgress(object sender, LoginProgressEventArgs e) { if (e.Status == LoginStatus.Success) { Console.Write("\n[Rake] : Login ok..."); StabilizeChecks.Add(true); } switch (e.Status) { case LoginStatus.Failed: Console.Write("\n[Rake] : Failed Login...\n"); break; } } private static void ProcessInventory() { Console.Write("\n[Rake] : Stabilizing, please wait..."); while (StabilizeChecks.Count < 4) { switch (Client.Network.LoginStatusCode) { case LoginStatus.Failed: return; } Thread.Sleep(1000); Console.Write("."); } Console.Write("\n[Rake] : Raking: "); RakeInventory(Client.Inventory.Store.RootFolder); Console.WriteLine(); new List(new int[Console.WindowWidth]).ForEach(i => Console.Write("-")); Console.WriteLine("[Rake] : All operations completed."); Client.Network.Logout(); } private static void RakeInventory(InventoryBase root) { _folders = new AutoResetEvent(false); Client.Inventory.FolderUpdated += delegate(object sender, FolderUpdatedEventArgs e) { if (e.Success) _folders.Set(); }; _folders.Reset(); Client.Inventory.RequestFolderContents(root.UUID, Client.Self.AgentID, true, true, InventorySortOrder.ByName); _folders.WaitOne(60000, false); var inventoryBases = Client.Inventory.FolderContents(root.UUID, Client.Self.AgentID, true, true, InventorySortOrder.ByName, 60000); if (inventoryBases == null) return; foreach (var ib in inventoryBases) { Thread.Sleep(Client.Network.CurrentSim.Stats.LastLag + (int)Math.Round(new ViewerStatsMessage().AgentPing)); var done = new AutoResetEvent(false); if (ib is InventoryFolder) { var folder = ib as InventoryFolder; Console.Write("-"); RakeInventory(folder); continue; } if (!(ib is InventoryItem)) continue; var item = ib as InventoryItem; switch (item.AssetType) { case AssetType.Bodypart: break; case AssetType.Texture: #region Texture Rake var imageTexture = ib as InventoryTexture; var imageSnapshot = ib as InventorySnapshot; string textureFileName; UUID textureAssetUUID; if (imageTexture != null) { textureFileName = Path.GetInvalidFileNameChars().Aggregate(imageTexture.Name + ".jp2", (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty)); textureAssetUUID = imageTexture.AssetUUID; goto download_texture; } if (imageSnapshot != null) { textureFileName = Path.GetInvalidFileNameChars().Aggregate(imageSnapshot.Name + ".jp2", (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty)); textureAssetUUID = imageSnapshot.AssetUUID; goto download_texture; } break; download_texture: if (!_overwriteExisting && FindFile(textureFileName, Path.Combine(_firstName + " " + _lastName, "Assets", "Images"))) { Console.Write("."); break; } Client.Assets.RequestImage(textureAssetUUID, ImageType.Normal, (state, asset) => { if (state != TextureRequestState.Finished) return; var texturePath = Path.Combine(_firstName + " " + _lastName, "Assets", "Images", Path.GetInvalidFileNameChars().Aggregate(root.Name, (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty))); if (!Directory.Exists(texturePath)) Directory.CreateDirectory(texturePath); File.WriteAllBytes(Path.Combine(texturePath, textureFileName), asset.AssetData); Console.Write("T"); done.Set(); }, false); done.WaitOne(60000, false); #endregion Texture Rake break; case AssetType.Notecard: #region Notecard Rake var notecard = (InventoryNotecard)ib; var notecardNormal = Path.GetInvalidFileNameChars().Aggregate(notecard.Name + ".rtf", (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty)); if (!_overwriteExisting && FindFile(notecardNormal, Path.Combine(_firstName + " " + _lastName, "Assets", "Notecards"))) { Console.Write("."); break; } Client.Assets.RequestInventoryAsset(notecard.AssetUUID, notecard.UUID, UUID.Zero, Client.Self.AgentID, AssetType.Notecard, true, (transfer, asset) => { if (!transfer.Success) { Console.Write("!"); done.Set(); return; } var notecardPath = Path.Combine(_firstName + " " + _lastName, "Assets", "Notecards", Path.GetInvalidFileNameChars().Aggregate(root.Name, (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty))); if (!Directory.Exists(notecardPath)) Directory.CreateDirectory(notecardPath); File.WriteAllBytes(Path.Combine(notecardPath, notecardNormal), asset.AssetData); Console.Write("N"); done.Set(); }); done.WaitOne(60000, false); #endregion Notecard Rake break; case AssetType.Animation: #region Animation Rake var animation = (InventoryAnimation)ib; var animationNormal = Path.GetInvalidFileNameChars().Aggregate(animation.Name + ".animatn", (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty)); if (!_overwriteExisting && FindFile(animationNormal, Path.Combine(_firstName + " " + _lastName, "Assets", "Animations"))) { Console.Write("."); break; } Client.Assets.RequestInventoryAsset(animation.AssetUUID, animation.UUID, UUID.Zero, Client.Self.AgentID, AssetType.Animation, true, (transfer, asset) => { if (!transfer.Success) { Console.Write("!"); done.Set(); return; } var animationPath = Path.Combine(_firstName + " " + _lastName, "Assets", "Animations", Path.GetInvalidFileNameChars().Aggregate(root.Name, (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty))); if (!Directory.Exists(animationPath)) Directory.CreateDirectory(animationPath); File.WriteAllBytes(Path.Combine(animationPath, animationNormal), asset.AssetData); Console.Write("A"); done.Set(); }); done.WaitOne(60000, false); #endregion Animation Rake break; case AssetType.LSLText: #region Script Rake var script = (InventoryLSL)ib; if (script.Permissions.OwnerMask != PermissionMask.All) break; var scriptNormal = Path.GetInvalidFileNameChars().Aggregate(script.Name + ".lsl", (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty)); if (!_overwriteExisting && FindFile(scriptNormal, Path.Combine(_firstName + " " + _lastName, "Assets", "Scripts"))) { Console.Write("."); break; } Client.Assets.RequestInventoryAsset(script.AssetUUID, script.UUID, UUID.Zero, Client.Self.AgentID, AssetType.LSLText, true, (transfer, asset) => { if (!transfer.Success) { Console.Write("!"); done.Set(); return; } var scriptPath = Path.Combine(_firstName + " " + _lastName, "Assets", "Scripts", Path.GetInvalidFileNameChars().Aggregate(root.Name, (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), string.Empty))); if (!Directory.Exists(scriptPath)) Directory.CreateDirectory(scriptPath); File.WriteAllBytes(Path.Combine(scriptPath, scriptNormal), asset.AssetData); Console.Write("S"); done.Set(); }); done.WaitOne(60000, false); #endregion Script Rake break; } } } private static bool FindFile(string file, string directory) { try { foreach (var d in Directory.GetDirectories(directory)) { if (Directory.GetFiles(d).Any(f => f.Equals(file))) { return true; } FindFile(file, d); } } catch (Exception) { return false; } return false; } } }