From 2cf03f42571d428d6d2cbb126424ea58deada054 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sat, 14 Oct 2006 04:10:33 +0000 Subject: [PATCH] Moving the trunk to the directory "old" git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@276 52acb1d6-8a22-11de-b505-999d5b087335 --- old/libsecondlife-cs/AssemblyInfo.cs | 58 + old/libsecondlife-cs/AssetSystem/Asset.cs | 55 + .../AssetSystem/AssetImage.cs | 27 + .../AssetSystem/AssetManager.cs | 461 ++++++ .../AssetSystem/AssetNotecard.cs | 75 + .../AssetSystem/ImageManager.cs | 255 ++++ .../AssetSystem/NotecardAsset.cs | 76 + old/libsecondlife-cs/Avatar.cs | 702 +++++++++ old/libsecondlife-cs/EstateTools.cs | 62 + old/libsecondlife-cs/GridManager.cs | 160 ++ old/libsecondlife-cs/Inventory.cs | 41 + .../InventorySystem/InventoryBase.cs | 46 + .../InventorySystem/InventoryFolder.cs | 159 ++ .../InventorySystem/InventoryImage.cs | 145 ++ .../InventorySystem/InventoryItem.cs | 421 ++++++ .../InventorySystem/InventoryManager.cs | 683 +++++++++ .../InventorySystem/InventoryNotecard.cs | 142 ++ old/libsecondlife-cs/JSON/JSONArray.cs | 172 +++ old/libsecondlife-cs/JSON/JSONFacade.cs | 26 + old/libsecondlife-cs/JSON/JSONObject.cs | 293 ++++ old/libsecondlife-cs/JSON/JSONTokener.cs | 340 +++++ old/libsecondlife-cs/NetworkManager.cs | 1305 +++++++++++++++++ old/libsecondlife-cs/ObjectManager.cs | 572 ++++++++ old/libsecondlife-cs/Packet.cs | 849 +++++++++++ old/libsecondlife-cs/Packets/AssetPackets.cs | 183 +++ .../Packets/CommunicationPackets.cs | 107 ++ old/libsecondlife-cs/Packets/EstatePackets.cs | 122 ++ old/libsecondlife-cs/Packets/ImagePackets.cs | 32 + .../Packets/InventoryPackets.cs | 742 ++++++++++ .../Packets/InventoryPacketsOld.cs | 131 ++ .../Packets/NetworkPackets.cs | 96 ++ old/libsecondlife-cs/Packets/ObjectPackets.cs | 79 + old/libsecondlife-cs/Packets/ParcelPackets.cs | 282 ++++ old/libsecondlife-cs/Packets/SimPackets.cs | 164 +++ .../Packets/TransferPackets.cs | 74 + old/libsecondlife-cs/Parcel.cs | 809 ++++++++++ old/libsecondlife-cs/Prims.cs | 221 +++ old/libsecondlife-cs/ProtocolManager.cs | 598 ++++++++ old/libsecondlife-cs/README.Mono | 39 + old/libsecondlife-cs/Region.cs | 254 ++++ old/libsecondlife-cs/SecondLife.cs | 381 +++++ old/libsecondlife-cs/Types.cs | 618 ++++++++ old/libsecondlife-cs/Utils/ImageTools.cs | 117 ++ old/libsecondlife-cs/Utils/InventoryApp.cs | 101 ++ old/libsecondlife-cs/Utils/Utils.cs | 88 ++ old/libsecondlife-cs/Utils/fubar.txt | 0 old/libsecondlife-cs/XmlRpcCS/Logger.cs | 46 + .../XmlRpcCS/XmlRpcDeserializer.cs | 180 +++ .../XmlRpcCS/XmlRpcErrorCodes.cs | 19 + .../XmlRpcCS/XmlRpcException.cs | 38 + .../XmlRpcCS/XmlRpcRequest.cs | 96 ++ .../XmlRpcCS/XmlRpcRequestDeserializer.cs | 64 + .../XmlRpcCS/XmlRpcRequestSerializer.cs | 38 + .../XmlRpcCS/XmlRpcResponse.cs | 73 + .../XmlRpcCS/XmlRpcResponseDeserializer.cs | 51 + .../XmlRpcCS/XmlRpcResponseSerializer.cs | 57 + .../XmlRpcCS/XmlRpcSerializer.cs | 109 ++ .../XmlRpcCS/XmlRpcXmlTokens.cs | 76 + old/libsecondlife-cs/build | 24 + .../examples/CreateNotecard/App.ico | Bin 0 -> 1078 bytes .../examples/CreateNotecard/AssemblyInfo.cs | 58 + .../examples/CreateNotecard/CreateNotecard.cs | 105 ++ .../CreateNotecard/CreateNotecard.csproj | 107 ++ .../examples/ImageTool/App.ico | Bin 0 -> 1078 bytes .../examples/ImageTool/AssemblyInfo.cs | 58 + .../examples/ImageTool/ImageTool.cs | 111 ++ .../examples/ImageTool/ImageTool.csproj | 106 ++ .../examples/ImageTool/Readme.txt | 5 + .../examples/InventoryDump/App.ico | Bin 0 -> 1078 bytes .../examples/InventoryDump/AssemblyInfo.cs | 58 + .../examples/InventoryDump/InventoryDump.cs | 74 + .../InventoryDump/InventoryDump.csproj | 107 ++ .../examples/ParcelDownload/ParcelDownload.cs | 95 ++ .../ParcelDownload/ParcelDownload.csproj | 104 ++ old/libsecondlife-cs/examples/examples.build | 89 ++ .../examples/name2key/name2key.cs | 123 ++ .../examples/name2key/name2key.csproj | 105 ++ .../examples/primexport/frmPrimExport.cs | 364 +++++ .../examples/primexport/frmPrimExport.resx | 120 ++ .../examples/primexport/primexport.cs | 45 + .../examples/primexport/primexport.csproj | 116 ++ .../examples/slaccountant/App.ico | Bin 0 -> 1078 bytes .../examples/slaccountant/AssemblyInfo.cs | 58 + .../examples/slaccountant/frmSLAccountant.cs | 642 ++++++++ .../slaccountant/frmSLAccountant.resx | 328 +++++ .../examples/slaccountant/slaccountant.csproj | 117 ++ .../examples/sldump/sldump.cs | 121 ++ .../examples/sldump/sldump.csproj | 105 ++ old/libsecondlife-cs/libsecondlife.build | 68 + old/libsecondlife-cs/libsecondlife.csproj | 265 ++++ old/libsecondlife-cs/libsecondlife.sln | 79 + .../mapgenerator/Properties/AssemblyInfo.cs | 33 + .../mapgenerator/mapgenerator.cs | 392 +++++ .../mapgenerator/mapgenerator.csproj | 53 + .../mapgenerator/mapgenerator.sln | 20 + old/libsecondlife-cs/tests/DebugServer.cs | 141 ++ old/libsecondlife-cs/tests/Tests.cs | 102 ++ .../tests/libsecondlife.Tests.csproj | 61 + .../tests/libsecondlife.Tests.sln | 20 + 99 files changed, 17789 insertions(+) create mode 100644 old/libsecondlife-cs/AssemblyInfo.cs create mode 100644 old/libsecondlife-cs/AssetSystem/Asset.cs create mode 100644 old/libsecondlife-cs/AssetSystem/AssetImage.cs create mode 100644 old/libsecondlife-cs/AssetSystem/AssetManager.cs create mode 100644 old/libsecondlife-cs/AssetSystem/AssetNotecard.cs create mode 100644 old/libsecondlife-cs/AssetSystem/ImageManager.cs create mode 100644 old/libsecondlife-cs/AssetSystem/NotecardAsset.cs create mode 100644 old/libsecondlife-cs/Avatar.cs create mode 100644 old/libsecondlife-cs/EstateTools.cs create mode 100644 old/libsecondlife-cs/GridManager.cs create mode 100644 old/libsecondlife-cs/Inventory.cs create mode 100644 old/libsecondlife-cs/InventorySystem/InventoryBase.cs create mode 100644 old/libsecondlife-cs/InventorySystem/InventoryFolder.cs create mode 100644 old/libsecondlife-cs/InventorySystem/InventoryImage.cs create mode 100644 old/libsecondlife-cs/InventorySystem/InventoryItem.cs create mode 100644 old/libsecondlife-cs/InventorySystem/InventoryManager.cs create mode 100644 old/libsecondlife-cs/InventorySystem/InventoryNotecard.cs create mode 100644 old/libsecondlife-cs/JSON/JSONArray.cs create mode 100644 old/libsecondlife-cs/JSON/JSONFacade.cs create mode 100644 old/libsecondlife-cs/JSON/JSONObject.cs create mode 100644 old/libsecondlife-cs/JSON/JSONTokener.cs create mode 100644 old/libsecondlife-cs/NetworkManager.cs create mode 100644 old/libsecondlife-cs/ObjectManager.cs create mode 100644 old/libsecondlife-cs/Packet.cs create mode 100644 old/libsecondlife-cs/Packets/AssetPackets.cs create mode 100644 old/libsecondlife-cs/Packets/CommunicationPackets.cs create mode 100644 old/libsecondlife-cs/Packets/EstatePackets.cs create mode 100644 old/libsecondlife-cs/Packets/ImagePackets.cs create mode 100644 old/libsecondlife-cs/Packets/InventoryPackets.cs create mode 100644 old/libsecondlife-cs/Packets/InventoryPacketsOld.cs create mode 100644 old/libsecondlife-cs/Packets/NetworkPackets.cs create mode 100644 old/libsecondlife-cs/Packets/ObjectPackets.cs create mode 100644 old/libsecondlife-cs/Packets/ParcelPackets.cs create mode 100644 old/libsecondlife-cs/Packets/SimPackets.cs create mode 100644 old/libsecondlife-cs/Packets/TransferPackets.cs create mode 100644 old/libsecondlife-cs/Parcel.cs create mode 100644 old/libsecondlife-cs/Prims.cs create mode 100644 old/libsecondlife-cs/ProtocolManager.cs create mode 100644 old/libsecondlife-cs/README.Mono create mode 100644 old/libsecondlife-cs/Region.cs create mode 100644 old/libsecondlife-cs/SecondLife.cs create mode 100644 old/libsecondlife-cs/Types.cs create mode 100644 old/libsecondlife-cs/Utils/ImageTools.cs create mode 100644 old/libsecondlife-cs/Utils/InventoryApp.cs create mode 100644 old/libsecondlife-cs/Utils/Utils.cs create mode 100644 old/libsecondlife-cs/Utils/fubar.txt create mode 100644 old/libsecondlife-cs/XmlRpcCS/Logger.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcDeserializer.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcErrorCodes.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcException.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcRequest.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestDeserializer.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestSerializer.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcResponse.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseDeserializer.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseSerializer.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcSerializer.cs create mode 100644 old/libsecondlife-cs/XmlRpcCS/XmlRpcXmlTokens.cs create mode 100644 old/libsecondlife-cs/build create mode 100644 old/libsecondlife-cs/examples/CreateNotecard/App.ico create mode 100644 old/libsecondlife-cs/examples/CreateNotecard/AssemblyInfo.cs create mode 100644 old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.cs create mode 100644 old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.csproj create mode 100644 old/libsecondlife-cs/examples/ImageTool/App.ico create mode 100644 old/libsecondlife-cs/examples/ImageTool/AssemblyInfo.cs create mode 100644 old/libsecondlife-cs/examples/ImageTool/ImageTool.cs create mode 100644 old/libsecondlife-cs/examples/ImageTool/ImageTool.csproj create mode 100644 old/libsecondlife-cs/examples/ImageTool/Readme.txt create mode 100644 old/libsecondlife-cs/examples/InventoryDump/App.ico create mode 100644 old/libsecondlife-cs/examples/InventoryDump/AssemblyInfo.cs create mode 100644 old/libsecondlife-cs/examples/InventoryDump/InventoryDump.cs create mode 100644 old/libsecondlife-cs/examples/InventoryDump/InventoryDump.csproj create mode 100644 old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.cs create mode 100644 old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.csproj create mode 100644 old/libsecondlife-cs/examples/examples.build create mode 100644 old/libsecondlife-cs/examples/name2key/name2key.cs create mode 100644 old/libsecondlife-cs/examples/name2key/name2key.csproj create mode 100644 old/libsecondlife-cs/examples/primexport/frmPrimExport.cs create mode 100644 old/libsecondlife-cs/examples/primexport/frmPrimExport.resx create mode 100644 old/libsecondlife-cs/examples/primexport/primexport.cs create mode 100644 old/libsecondlife-cs/examples/primexport/primexport.csproj create mode 100644 old/libsecondlife-cs/examples/slaccountant/App.ico create mode 100644 old/libsecondlife-cs/examples/slaccountant/AssemblyInfo.cs create mode 100644 old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs create mode 100644 old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.resx create mode 100644 old/libsecondlife-cs/examples/slaccountant/slaccountant.csproj create mode 100644 old/libsecondlife-cs/examples/sldump/sldump.cs create mode 100644 old/libsecondlife-cs/examples/sldump/sldump.csproj create mode 100644 old/libsecondlife-cs/libsecondlife.build create mode 100644 old/libsecondlife-cs/libsecondlife.csproj create mode 100644 old/libsecondlife-cs/libsecondlife.sln create mode 100644 old/libsecondlife-cs/mapgenerator/Properties/AssemblyInfo.cs create mode 100644 old/libsecondlife-cs/mapgenerator/mapgenerator.cs create mode 100644 old/libsecondlife-cs/mapgenerator/mapgenerator.csproj create mode 100644 old/libsecondlife-cs/mapgenerator/mapgenerator.sln create mode 100644 old/libsecondlife-cs/tests/DebugServer.cs create mode 100644 old/libsecondlife-cs/tests/Tests.cs create mode 100644 old/libsecondlife-cs/tests/libsecondlife.Tests.csproj create mode 100644 old/libsecondlife-cs/tests/libsecondlife.Tests.sln diff --git a/old/libsecondlife-cs/AssemblyInfo.cs b/old/libsecondlife-cs/AssemblyInfo.cs new file mode 100644 index 00000000..9a6f924c --- /dev/null +++ b/old/libsecondlife-cs/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("libsecondlife")] +[assembly: AssemblyDescription("Networking layer for the Second Life world")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Second Life Reverse Engineering Team")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("(c) 2006 Second Life Reverse Engineering Team")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("0.0.5.0")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/old/libsecondlife-cs/AssetSystem/Asset.cs b/old/libsecondlife-cs/AssetSystem/Asset.cs new file mode 100644 index 00000000..3e9a6bf0 --- /dev/null +++ b/old/libsecondlife-cs/AssetSystem/Asset.cs @@ -0,0 +1,55 @@ +using System; + +using libsecondlife; +using libsecondlife.Utils; + +namespace libsecondlife.AssetSystem +{ + /// + /// Summary description for Asset. + /// + public class Asset + { + public const sbyte ASSET_TYPE_NOTECARD = 7; + public const sbyte ASSET_TYPE_IMAGE = 0; + + public LLUUID AssetID; + + public sbyte Type; + public bool Tempfile; + + + private byte[] assetdata; + public byte[] AssetData + { + get { return assetdata; } + set + { + assetdata = value; + } + } + + + public Asset(LLUUID assetID, sbyte type, bool tempfile, byte[] assetData) + { + AssetID = assetID; + Type = (sbyte)type; + Tempfile = tempfile; + AssetData = assetData; + } + + public Asset(LLUUID assetID, sbyte type, byte[] assetData) + { + AssetID = assetID; + Type = (sbyte)type; + Tempfile = false; + AssetData = assetData; + } + + + public string AssetDataToString() + { + return MiscUtils.ByteArrayToString((byte[])AssetData); + } + } +} diff --git a/old/libsecondlife-cs/AssetSystem/AssetImage.cs b/old/libsecondlife-cs/AssetSystem/AssetImage.cs new file mode 100644 index 00000000..37ec8f56 --- /dev/null +++ b/old/libsecondlife-cs/AssetSystem/AssetImage.cs @@ -0,0 +1,27 @@ +using System; + +using libsecondlife; + +namespace libsecondlife.AssetSystem +{ + /// + /// Summary description for AssetNotecard. + /// + public class AssetImage : Asset + { + public byte[] J2CData + { + get + { + return base.AssetData; + } + } + + public AssetImage(LLUUID assetID, byte[] assetData) : base( assetID, Asset.ASSET_TYPE_IMAGE, false, assetData ) + { + } + + + + } +} diff --git a/old/libsecondlife-cs/AssetSystem/AssetManager.cs b/old/libsecondlife-cs/AssetSystem/AssetManager.cs new file mode 100644 index 00000000..c686a932 --- /dev/null +++ b/old/libsecondlife-cs/AssetSystem/AssetManager.cs @@ -0,0 +1,461 @@ +using System; +using System.Collections; + +using libsecondlife; + +using libsecondlife.InventorySystem; + +using libsecondlife.Packets; + +namespace libsecondlife.AssetSystem +{ + /// + /// Summary description for AssetManager. + /// + public class AssetManager + { + public const int SINK_FEE_IMAGE = 1; + + private SecondLife slClient; + + private Hashtable htUploadRequests = new Hashtable(); + private Hashtable htDownloadRequests = new Hashtable(); + + private class TransferRequest + { + public bool Completed; + public bool Status; + public string StatusMsg; + + public int Size; + public int Received; + public int LastPacket; + public byte[] AssetData; + } + + internal AssetManager( SecondLife client ) + { + slClient = client; + + // Used to upload small assets, or as an initial start packet for large transfers + PacketCallback AssetUploadCompleteCallback = new PacketCallback(AssetUploadCompleteCallbackHandler); + slClient.Network.RegisterCallback("AssetUploadComplete", AssetUploadCompleteCallback); + + // Transfer Packets for downloading large assets + PacketCallback TransferInfoCallback = new PacketCallback(TransferInfoCallbackHandler); + slClient.Network.RegisterCallback("TransferInfo", TransferInfoCallback); + + PacketCallback TransferPacketCallback = new PacketCallback(TransferPacketCallbackHandler); + slClient.Network.RegisterCallback("TransferPacket", TransferPacketCallback); + + // XFer packets for uploading large assets + PacketCallback ConfirmXferPacketCallback = new PacketCallback(ConfirmXferPacketCallbackHandler); + slClient.Network.RegisterCallback("ConfirmXferPacket", ConfirmXferPacketCallback); + + PacketCallback RequestXferCallback = new PacketCallback(RequestXferCallbackHandler); + slClient.Network.RegisterCallback("RequestXfer", RequestXferCallback); + + } + + + /* + ----- MoneyTransferRequest ----- + MoneyData + AggregatePermInventory: 0 + AggregatePermNextOwner: 0 + DestID: 00000000000000000000000000000000 + Amount: 10 + Flags: 0 + SourceID: 25472683cb324516904a6cd0ecabf128 + TransactionType: 1101 + AgentData + AgentID: 25472683cb324516904a6cd0ecabf128 + SessionID: 7395ab89cadf4f638c5f28630c0e75d2 + + */ + public void SinkFee( int sinkType ) + { + switch( sinkType ) + { + case SINK_FEE_IMAGE: + slClient.Avatar.GiveMoney( new LLUUID(), 10, "Image Upload" ); + break; + default: + throw new Exception("AssetManager: Unknown sinktype (" + sinkType + ")"); + } + } + + public void UploadAsset( Asset asset ) + { + Packet packet; + TransferRequest tr = new TransferRequest(); + tr.Completed = false; + htUploadRequests[asset.AssetID] = tr; + + if( asset.AssetData.Length > 500 ) + { + packet = AssetPackets.AssetUploadRequestHeaderOnly(slClient.Protocol, asset); + slClient.Network.SendPacket(packet); + Console.WriteLine(packet); + tr.AssetData = asset.AssetData; + } + else + { + packet = AssetPackets.AssetUploadRequest(slClient.Protocol, asset); + slClient.Network.SendPacket(packet); + Console.WriteLine(packet); + } + + while( tr.Completed == false ) + { + slClient.Tick(); + } + + if( tr.Status == false ) + { + throw new Exception( tr.StatusMsg ); + } else { + if( asset.Type == Asset.ASSET_TYPE_IMAGE ) + { + SinkFee( SINK_FEE_IMAGE ); + } + } + } + + public void GetInventoryAsset( InventoryItem item ) + { + LLUUID TransferID = LLUUID.GenerateUUID(); + + TransferRequest tr = new TransferRequest(); + tr.Completed = false; + tr.Size = int.MaxValue; // Number of bytes expected + tr.Received = 0; // Number of bytes received + tr.LastPacket = getUnixtime(); // last time we recevied a packet for this request + + htDownloadRequests[TransferID] = tr; + + Packet packet = AssetPackets.TransferRequest(slClient.Protocol, slClient.Network.SessionID, slClient.Network.AgentID, TransferID, item ); + slClient.Network.SendPacket(packet); + + while( tr.Completed == false ) + { + slClient.Tick(); + } + + item.SetAssetData( tr.AssetData ); + } + + + public void AssetUploadCompleteCallbackHandler(Packet packet, Simulator simulator) + { + + ArrayList blocks = packet.Blocks(); + + LLUUID AssetID = ""; + bool Success = false; + + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("AssetBlock") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "Success": + Success = bool.Parse(field.Data.ToString()); + break; + case "UUID": + AssetID = new LLUUID(field.Data.ToString()); + break; + } + } + + } + } + + TransferRequest tr = (TransferRequest)htUploadRequests[AssetID]; + if( Success ) + { + tr.Completed = true; + tr.Status = true; + tr.StatusMsg = "Success"; + } + else + { + tr.Completed = true; + tr.Status = false; + tr.StatusMsg = "Server returned failed"; + } + } + + /* + ---- TransferInfo ---- + -- TransferInfo -- + TransferID: 5eb06365fb85d94c853a15352da57574 + Size: 88 + ChannelType: 2 + TargetType: 0 + Status: 0 + + Low 00194 - TransferInfo - Untrusted - Unencoded + 0770 TransferInfo (01) + 0072 TransferID (LLUUID / 1) + 0584 Size (S32 / 1) + 0912 ChannelType (S32 / 1) + 1049 TargetType (S32 / 1) + 1062 Status (S32 / 1) + + */ + public void TransferInfoCallbackHandler(Packet packet, Simulator simulator) + { + + ArrayList blocks = packet.Blocks(); + + LLUUID TransferID = ""; + int Size = 0; + int Status = 0; + + + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("TransferInfo") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "Size": + Size = (int)field.Data; + break; + case "TransferID": + TransferID = (LLUUID)field.Data; + break; + case "Status": + Status = (int)field.Data; + break; + } + } + + } + } + + TransferRequest tr = (TransferRequest)htDownloadRequests[TransferID]; + if( tr == null ) + { + return; + } + + if( Status == -2 ) + { + tr.Completed = true; + tr.Status = false; + tr.StatusMsg = "Asset Status -2 :: Likely Status Not Found"; + + tr.Size = 1; + tr.AssetData = new byte[1]; + + } + else + { + tr.Size = Size; + tr.AssetData = new byte[Size]; + } + } + + /* + ----- TransferPacket ----- + TransferData + TransferID: cc75b93dd4d8c25f6cf56c22f1b3b26c + Data: 4c 69 6e 64 65 6e 20 74 65 78 74 20 76 65 72 73 Linden text vers + Data: 69 6f 6e 20 31 0a 7b 0a 4c 4c 45 6d 62 65 64 64 ion 1.{.LLEmbedd + Data: 65 64 49 74 65 6d 73 20 76 65 72 73 69 6f 6e 20 edItems version + Data: 31 0a 7b 0a 63 6f 75 6e 74 20 30 0a 7d 0a 54 65 1.{.count 0.}.Te + Data: 78 74 20 6c 65 6e 67 74 68 20 39 32 0a 0a 45 61 xt length 92..Ea + Data: 72 6c 79 20 41 6c 65 72 74 20 57 65 62 73 69 74 rly Alert Websit + Data: 65 0a 68 74 74 70 3a 2f 2f 65 61 72 6c 79 61 6c e.http://earlyal + Data: 65 72 74 2e 66 75 6c 6c 63 6f 6c 6c 2e 65 64 75 ert.fullcoll.edu + Data: 0a 46 75 6c 6c 65 72 74 6f 6e 20 43 6f 6c 6c 65 .Fullerton Colle + Data: 67 65 0a 43 6f 75 6e 73 65 6c 69 6e 67 20 44 65 ge.Counseling De + Data: 70 61 72 74 6d 65 6e 74 0a 7d 0a 00 partment.}.. + Packet: 0 + ChannelType: 2 + Status: 1 + + */ + public void TransferPacketCallbackHandler(Packet packet, Simulator simulator) + { + + LLUUID TransferID = ""; + byte[] Data = null; + + ArrayList blocks = packet.Blocks(); + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("TransferData") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "TransferID": + TransferID = new LLUUID(field.Data.ToString()); + break; + case "Data": + Data = (byte[])field.Data; + break; + } + } + + } + } + + // Append data to data received. + TransferRequest tr = (TransferRequest)htDownloadRequests[TransferID]; + if( tr == null ) + { + return; + } + + Array.Copy(Data, 0, tr.AssetData, tr.Received, Data.Length); + tr.Received += Data.Length; + + // If we've gotten all the data, mark it completed. + if( tr.Received >= tr.Size ) + { + tr.Completed = true; + } + + } + + /* + High 00021 - ConfirmXferPacket - Untrusted - Zerocoded + 0804 XferID (01) + 0030 ID (U64 / 1) + 0785 Packet (U32 / 1) + + ----- ConfirmXferPacket ----- + XferID + ID: 4089841211943505063 + Packet: 0 + + */ + + public void ConfirmXferPacketCallbackHandler(Packet packet, Simulator simulator) + { + + U64 XferID = new U64(); + uint PacketNum = 0; + + ArrayList blocks = packet.Blocks(); + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("XferID") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "ID": + XferID = (U64)field.Data; + break; + case "Packet": + PacketNum = (uint)field.Data; + break; + } + } + + } + } + } + + + /* + Low 00197 - RequestXfer - Untrusted - Unencoded + 0804 XferID (01) + 0030 ID (U64 / 1) + 0183 UseBigPackets (BOOL / 1) + 0351 DeleteOnCompletion (BOOL / 1) + 0687 FilePath (U8 / 1) + 0817 Filename (Variable / 1) + 0997 VFileID (LLUUID / 1) + 1333 VFileType (S16 / 1) + + ----- RequestXfer ----- + XferID + ID: 12874913228238730530 + UseBigPackets: False + DeleteOnCompletion: False + FilePath: 0 + Filename: + VFileID: b16097032e253a9d5220ba07c1a1b28a + VFileType: 7 + */ + public void RequestXferCallbackHandler(Packet packet, Simulator simulator) + { + + U64 XferID = new U64(); + LLUUID AssetID = ""; + + ArrayList blocks = packet.Blocks(); + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("XferID") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "ID": + XferID = (U64)field.Data; + break; + case "VFileID": + AssetID = (LLUUID)field.Data; + break; + } + } + + } + } + + + TransferRequest tr = (TransferRequest)htUploadRequests[AssetID]; + + byte[] packetData = new byte[1004]; + + // FIXME: Apply endianness patch + Array.Copy(BitConverter.GetBytes((int)tr.AssetData.Length), 0, packetData, 0, 4); + Array.Copy(tr.AssetData, 0, packetData, 4, 1000); + + packet = AssetPackets.SendXferPacket(slClient.Protocol, XferID, packetData, 0); + slClient.Network.SendPacket(packet); + + + // TODO: This for loop should be removed and these uploads should take place in + // a call back handler for ConfirmXferPacket + int numPackets = tr.AssetData.Length / 1000; + for( uint i = 1; i + /// Summary description for AssetNotecard. + /// + public class AssetNotecard : Asset + { + private string _Body = ""; + public string Body + { + get { return _Body; } + set + { + _Body = value.Replace("\r", ""); + setAsset( _Body ); + } + } + + public AssetNotecard(LLUUID assetID, string body) : base( assetID, Asset.ASSET_TYPE_NOTECARD, false, null ) + { + _Body = body; + setAsset( body ); + } + + public AssetNotecard(LLUUID assetID, byte[] assetData) : base( assetID, Asset.ASSET_TYPE_NOTECARD, false, null ) + { + base.AssetData = assetData; + + string temp = System.Text.Encoding.UTF8.GetString(assetData).Trim(); + + // TODO: Calculate the correct header size to look for + // it's usually around 80 or so... + if( temp.Length > 50 ) + { + // Trim trailing null terminator + temp = temp.Substring(0,temp.Length-1); + + // Remove the header + temp = temp.Substring(temp.IndexOf("}") + 2); + temp = temp.Substring(temp.IndexOf('\n') + 1); + + // Remove trailing close brace + temp = temp.Substring(0,temp.Length-2); + } + _Body = temp; + } + + private void setAsset( string body ) + { + // Format the string body into Linden text + string lindenText = "Linden text version 1\n"; + lindenText += "{\n"; + lindenText += "LLEmbeddedItems version 1\n"; + lindenText += "{\n"; + lindenText += "count 0\n"; + lindenText += "}\n"; + lindenText += "Text length " + body.Length + "\n"; + lindenText += body; + lindenText += "}\n"; + + + + // Assume this is a string, add 1 for the null terminator + byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes((string)lindenText); + byte[] assetData = new byte[stringBytes.Length + 1]; + Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length); + + base.AssetData = assetData; + } + } +} diff --git a/old/libsecondlife-cs/AssetSystem/ImageManager.cs b/old/libsecondlife-cs/AssetSystem/ImageManager.cs new file mode 100644 index 00000000..5d82cd91 --- /dev/null +++ b/old/libsecondlife-cs/AssetSystem/ImageManager.cs @@ -0,0 +1,255 @@ +using System; +using System.Collections; + +using libsecondlife; + +using libsecondlife.InventorySystem; + +using libsecondlife.Packets; + +namespace libsecondlife.AssetSystem +{ + /// + /// Summary description for AssetManager. + /// + public class ImageManager + { + private SecondLife slClient; + + private Hashtable htDownloadRequests = new Hashtable(); + + private class TransferRequest + { + public bool Completed; + public bool Status; + public string StatusMsg; + + public uint Size; + public uint Received; + public int LastPacket; + public byte[] AssetData; + + public TransferRequest() + { + Completed = false; + + Status = false; + StatusMsg = ""; + + AssetData = null; + } + } + + public ImageManager( SecondLife client ) + { + slClient = client; + + // Used to upload small assets, or as an initial start packet for large transfers + PacketCallback ImageDataCallback = new PacketCallback(ImageDataCallbackHandler); + slClient.Network.RegisterCallback("ImageData", ImageDataCallback); + + // Transfer Packets for downloading large assets + PacketCallback ImagePacketCallback = new PacketCallback(ImagePacketCallbackHandler); + slClient.Network.RegisterCallback("ImagePacket", ImagePacketCallback); + + } + + public byte[] RequestImage( LLUUID ImageID ) + { + TransferRequest tr = new TransferRequest(); + tr.Completed = false; + tr.Size = int.MaxValue; // Number of bytes expected + tr.Received = 0; // Number of bytes received + tr.LastPacket = getUnixtime(); // last time we recevied a packet for this request + + htDownloadRequests[ImageID] = tr; + + Packet packet = ImagePackets.RequestImage(slClient.Protocol, ImageID ); + slClient.Network.SendPacket(packet); + + while( tr.Completed == false ) + { + slClient.Tick(); + } + + if( tr.Status == true ) + { + return tr.AssetData; + } + else + { + throw new Exception( "RequestImage: " + tr.StatusMsg ); + } + + } + + + /* + High 00010 - ImageData - Trusted - Zerocoded + 0233 ImageID (01) + 0030 ID (LLUUID / 1) + 0085 Packets (U16 / 1) + 0584 Size (U32 / 1) + 1203 Codec (U8 / 1) + 1334 ImageData (01) + 0527 Data (Variable / 2) + + ---- ImageData ---- + -- ImageID -- + ID: 8955674724cb43ed920b47caed15465f + Packets: 25344 + Size: 98282 + Codec: 2 + -- ImageData -- + Data: FF 4F FF 51 00 2F 00 00 00 00 02 00 00 00 02 00 .O.Q./.......... + */ + + public void ImageDataCallbackHandler(Packet packet, Simulator simulator) + { +// Console.WriteLine( packet ); + + LLUUID ImageID = null; + ushort Packets = 0; + uint Size = 0; + byte[] Data = null; + + ArrayList blocks = packet.Blocks(); + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("ImageID") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "ID": + ImageID = (LLUUID)field.Data; + break; + case "Packets": + Packets = (ushort)field.Data; + break; + case "Size": + Size = (uint)field.Data; + break; + + case "Codec": + // Not used + break; + } + } + } + if( block.Layout.Name.Equals("ImageData") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "Data": + Data = (byte[])field.Data; + break; + } + } + } + } + + TransferRequest tr = (TransferRequest)htDownloadRequests[ImageID]; + if( tr == null ) + { + return; + } + + tr.Size = Size; + tr.AssetData = new byte[tr.Size]; + + Array.Copy(Data, 0, tr.AssetData, tr.Received, Data.Length); + tr.Received += (uint)Data.Length; + + // If we've gotten all the data, mark it completed. + if( tr.Received >= tr.Size ) + { + tr.Completed = true; + tr.Status = true; + } + + + } + + /* + High 00011 - ImagePacket - Trusted - Zerocoded + 0233 ImageID (01) + 0030 ID (LLUUID / 1) + 0785 Packet (U16 / 1) + 1334 ImageData (01) + 0527 Data (Variable / 2) + + ---- ImagePacket ---- + -- ImageID -- + ID: f252794e1b0fbe2f0f10020a437a9e40 + Packet: 256 + -- ImageData -- + Data: 80 80 F9 B7 A8 5E 6A 5E 34 1C E1 8E 25 C5 6B 18 .....^j^4...%.k. + + */ + + public void ImagePacketCallbackHandler(Packet packet, Simulator simulator) + { + LLUUID ImageID = null; + byte[] Data = null; + + ArrayList blocks = packet.Blocks(); + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("ImageID") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "ID": + ImageID = (LLUUID)field.Data; + break; + case "Packet": + // Not Used + break; + } + } + } + if( block.Layout.Name.Equals("ImageData") ) + { + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "Data": + Data = (byte[])field.Data; + break; + } + } + } + } + + TransferRequest tr = (TransferRequest)htDownloadRequests[ImageID]; + if( tr == null ) + { + return; + } + + Array.Copy(Data, 0, tr.AssetData, tr.Received, Data.Length); + tr.Received += (uint)Data.Length; + + // If we've gotten all the data, mark it completed. + if( tr.Received >= tr.Size ) + { + tr.Completed = true; + tr.Status = true; + } + } + + + public static int getUnixtime() + { + TimeSpan ts = (DateTime.UtcNow - new DateTime(1970,1,1,0,0,0)); + return (int)ts.TotalSeconds; + } + } +} diff --git a/old/libsecondlife-cs/AssetSystem/NotecardAsset.cs b/old/libsecondlife-cs/AssetSystem/NotecardAsset.cs new file mode 100644 index 00000000..46d9f425 --- /dev/null +++ b/old/libsecondlife-cs/AssetSystem/NotecardAsset.cs @@ -0,0 +1,76 @@ +using System; + +using libsecondlife; + +namespace libsecondlife.AssetSystem +{ + /// + /// Summary description for NotecardAsset. + /// + public class NotecardAsset : Asset + { + private string _Body = ""; + public string Body + { + get { return _Body; } + set + { + Console.WriteLine("Setting notecard body to: " + value); + _Body = value; + setAsset( _Body ); + } + } + + public NotecardAsset(LLUUID assetID, string body) : base( assetID, Asset.ASSET_TYPE_NOTECARD, false, null ) + { + _Body = body; + setAsset( body ); + } + + public NotecardAsset(LLUUID assetID, byte[] assetData) : base( assetID, Asset.ASSET_TYPE_NOTECARD, false, null ) + { + base.AssetData = assetData; + + string temp = System.Text.Encoding.UTF8.GetString(assetData).Trim(); + + // TODO: Calculate the correct header size to look for + // it's usually around 80 or so... + if( temp.Length > 50 ) + { + // Trim trailing null terminator + temp = temp.Substring(0,temp.Length-1); + + // Remove the header + temp = temp.Substring(temp.IndexOf("}") + 2); + temp = temp.Substring(temp.IndexOf('\n') + 1); + + // Remove trailing close brace + temp = temp.Substring(0,temp.Length-2); + } + _Body = temp; + } + + private void setAsset( string body ) + { + // Format the string body into Linden text + string lindenText = "Linden text version 1\n"; + lindenText += "{\n"; + lindenText += "LLEmbeddedItems version 1\n"; + lindenText += "{\n"; + lindenText += "count 0\n"; + lindenText += "}\n"; + lindenText += "Text length " + body.Length + "\n"; + lindenText += body; + lindenText += "}\n"; + + + + // Assume this is a string, add 1 for the null terminator + byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes((string)lindenText); + byte[] assetData = new byte[stringBytes.Length + 1]; + Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length); + + base.AssetData = assetData; + } + } +} diff --git a/old/libsecondlife-cs/Avatar.cs b/old/libsecondlife-cs/Avatar.cs new file mode 100644 index 00000000..b39ef8a0 --- /dev/null +++ b/old/libsecondlife-cs/Avatar.cs @@ -0,0 +1,702 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Timers; +using System.Net; +using System.Collections; + +namespace libsecondlife +{ + public delegate void ChatCallback(string message, byte audible, byte chattype, byte sourcetype, + string name, LLUUID sourceid, LLUUID ownerid, LLVector3 position); + + public delegate void InstantMessageCallback(LLUUID FromAgentID, LLUUID ToAgentID, + uint ParentEstateID, LLUUID RegionID, LLVector3 Position, byte Offline, byte Dialog, + LLUUID ID, uint Timestamp, string AgentName, string Message, string Bucket); + + public delegate void FriendNotificationCallback(LLUUID AgentID, bool Online); + + public delegate void TeleportCallback(string message); + + public class Avatar + { + public LLUUID ID; + public uint LocalID; + public string Name; + public string GroupName; + public bool Online; + public LLVector3 Position; + public LLQuaternion Rotation; + public Region CurrentRegion; + } + + public class MainAvatar + { + public LLUUID ID; + public uint LocalID; + public string FirstName; + public string LastName; + public string TeleportMessage; + public LLVector3 Position; + public LLQuaternion Rotation; + // Should we even keep LookAt around? It's just for setting the initial + // rotation after login AFAIK + public LLVector3d LookAt; + public LLVector3d HomePosition; + public LLVector3d HomeLookAt; + + private SecondLife Client; + private int TeleportStatus; + private Timer TeleportTimer; + private bool TeleportTimeout; + + public event ChatCallback OnChat; + public event InstantMessageCallback OnInstantMessage; + public event FriendNotificationCallback OnFriendNotification; + public event TeleportCallback OnTeleport; + + public MainAvatar(SecondLife client) + { + Client = client; + TeleportMessage = ""; + + // Create emtpy vectors for now + HomeLookAt = HomePosition = LookAt = new LLVector3d(); + Position = new LLVector3(); + Rotation = new LLQuaternion(); + + // Coarse location callback + PacketCallback callback = new PacketCallback(CoarseLocationHandler); + Client.Network.RegisterCallback("CoarseLocationUpdate", callback); + + // Teleport callbacks + callback = new PacketCallback(TeleportHandler); + Client.Network.RegisterCallback("TeleportStart", callback); + Client.Network.RegisterCallback("TeleportProgress", callback); + Client.Network.RegisterCallback("TeleportFailed", callback); + Client.Network.RegisterCallback("TeleportFinish", callback); + + // Instant Message callback + callback = new PacketCallback(InstantMessageHandler); + Client.Network.RegisterCallback("ImprovedInstantMessage", callback); + + // Chat callback + callback = new PacketCallback(ChatHandler); + Client.Network.RegisterCallback("ChatFromSimulator", callback); + + // Friend notification callback + callback = new PacketCallback(FriendNotificationHandler); + Client.Network.RegisterCallback("OnlineNotification", callback); + Client.Network.RegisterCallback("OfflineNotification", callback); + + TeleportTimer = new Timer(8000); + TeleportTimer.Elapsed += new ElapsedEventHandler(TeleportTimerEvent); + TeleportTimeout = false; + } + + private void FriendNotificationHandler(Packet packet, Simulator simulator) + { + // If the agent is online... + if (packet.Layout.Name == "OnlineNotification") + { + LLUUID AgentID = new LLUUID(); + + ArrayList blocks; + + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "AgentID") + { + AgentID = (LLUUID)field.Data; + + Client.AddAvatar(AgentID); + Client.AvatarsMutex.WaitOne(); + ((Avatar)Client.Avatars[AgentID]).Online = true; + Client.AvatarsMutex.ReleaseMutex(); + + if (OnFriendNotification != null) + { + OnFriendNotification(AgentID, true); + } + } + } + } + + return; + } + + // If the agent is Offline... + if (packet.Layout.Name == "OfflineNotification") + { + LLUUID AgentID = new LLUUID(); + + ArrayList blocks; + + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "AgentID") + { + AgentID = (LLUUID)field.Data; + + Client.AddAvatar(AgentID); + Client.AvatarsMutex.WaitOne(); + ((Avatar)Client.Avatars[AgentID]).Online = false; + Client.AvatarsMutex.ReleaseMutex(); + + if (OnFriendNotification != null) + { + OnFriendNotification(AgentID, false); + } + } + } + } + + return; + } + } + + private void CoarseLocationHandler(Packet packet, Simulator simulator) + { + LLVector3d position = new LLVector3d(); + + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "X") + { + position.X = Convert.ToDouble((byte)field.Data); + } + else if (field.Layout.Name == "Y") + { + position.Y = Convert.ToDouble((byte)field.Data); + } + else if (field.Layout.Name == "Z") + { + position.Z = Convert.ToDouble((byte)field.Data); + } + } + } + + // Check if the avatar position hasn't been updated + if (Position.X == 0 && Position.Y == 0 && Position.Z == 0) + { + Position.X = (float)position.X; + Position.Y = (float)position.Y; + Position.Z = (float)position.Z; + + // Send an AgentUpdate packet with the new camera location + packet = Packets.Sim.AgentUpdate(Client.Protocol, Client.Network.AgentID, + 56.0F, Position, 0, 0); + Client.Network.SendPacket(packet); + + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["ID"] = Client.Avatar.ID; + fields["CircuitCode"] = Client.Network.CurrentSim.CircuitCode; + fields["GenCounter"] = (uint)0; + blocks[fields] = "Sender"; + + fields = new Hashtable(); + fields["VerticalAngle"] = (float)6.28318531F; + blocks[fields] = "FOVBlock"; + + packet = PacketBuilder.BuildPacket("AgentFOV", Client.Protocol, blocks, Helpers.MSG_RELIABLE); + } + } + + private void InstantMessageHandler(Packet packet, Simulator simulator) + { + if (packet.Layout.Name == "ImprovedInstantMessage") + { + LLUUID FromAgentID = new LLUUID(); + LLUUID ToAgentID = new LLUUID(); + uint ParentEstateID = 0; + LLUUID RegionID = new LLUUID(); + LLVector3 position = new LLVector3(); + byte Offline = 0; + byte Dialog = 0; + LLUUID ID = new LLUUID(); + uint Timestamp = 0; + string AgentName = ""; + string Message = ""; + string Bucket = ""; + + ArrayList blocks; + + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "AgentID") + { + FromAgentID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "ToAgentID") + { + ToAgentID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "ParentEstateID") + { + ParentEstateID = (uint)field.Data; + } + else if (field.Layout.Name == "RegionID") + { + RegionID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "Position") + { + position = (LLVector3)field.Data; + } + else if (field.Layout.Name == "Offline") + { + Offline = (byte)field.Data; + } + else if (field.Layout.Name == "Dialog") + { + Dialog = (byte)field.Data; + } + else if (field.Layout.Name == "ID") + { + ID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "Timestamp") + { + Timestamp = (uint)field.Data; + } + else if (field.Layout.Name == "FromAgentName") + { + AgentName = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "Message") + { + Message = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "BinaryBucket") + { + Bucket = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + } + } + + if (OnInstantMessage != null) + { + OnInstantMessage(FromAgentID, ToAgentID, ParentEstateID, RegionID, position, + Offline, Dialog, ID, Timestamp, AgentName, Message, Bucket); + } + } + } + + /** + As of 9/26/2006 + --------------- + // ChatFromSimulator + // Chat text to appear on a user's screen + // Position is region local. + // Viewer can optionally use position to animate + // If audible is CHAT_NOT_AUDIBLE, message will not be valid + { + ChatFromSimulator Low Trusted Unencoded + { + ChatData Single + { FromName Variable 1 } + { SourceID LLUUID } // agent id or object id + { OwnerID LLUUID } // object's owner + { SourceType U8 } + { ChatType U8 } + { Audible U8 } + { Position LLVector3 } + { Message Variable 2 } // UTF-8 text + } + } + */ + + private void ChatHandler(Packet packet, Simulator simulator) + { + if (packet.Layout.Name == "ChatFromSimulator") + { + string name = ""; + LLUUID sourceID = new LLUUID(); + LLUUID ownerID = new LLUUID(); + byte sourcetype = 0; + byte chattype = 0; + byte audible = 0; + LLVector3 position = new LLVector3(); + string message = ""; + + ArrayList blocks; + + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "SourceID") + { + sourceID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "OwnerID") + { + ownerID = (LLUUID)field.Data; + } + + else if (field.Layout.Name == "FromName") + { + name = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "SourceType") + { + sourcetype = (byte)field.Data; + } + else if (field.Layout.Name == "ChatType") + { + chattype = (byte)field.Data; + } + else if (field.Layout.Name == "Audible") + { + audible = (byte)field.Data; + } + else if (field.Layout.Name == "Message") + { + message = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "Position") + { + position = (LLVector3)field.Data; + } + } + } + + if (OnChat != null) + { + OnChat(message, audible, chattype, sourcetype, name, sourceID, ownerID, position); + } + } + } + + public void InstantMessage(LLUUID target, string message) + { + string name = FirstName + " " + LastName; + + InstantMessage(name, LLUUID.GenerateUUID(), target, message, null); + } + + public void InstantMessage(LLUUID target, string message, LLUUID converstationID) + { + string name = FirstName + " " + LastName; + + InstantMessage(name, converstationID, target, message, null); + } + + public void InstantMessage(string fromName, LLUUID sessionID, LLUUID target, string message, LLUUID[] conferenceIDs) + { + TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); + uint now = (uint)(t.TotalSeconds); + + byte[] binaryBucket; + + if (conferenceIDs != null && conferenceIDs.Length > 0) + { + binaryBucket = new byte[16 * conferenceIDs.Length]; + + for (int i = 0; i < conferenceIDs.Length; ++i) + { + Array.Copy(conferenceIDs[i].Data, 0, binaryBucket, 16 * i, 16); + } + } + else + { + binaryBucket = new byte[0]; + } + + if( Client.CurrentRegion == null ) + { + throw new Exception("Cannot send instant messages until CurrentRegion is not null."); + } + + // Build the packet + Packet packet = Packets.Communication.ImprovedInstantMessage(Client.Protocol, target, Client.Network.AgentID, 0, + Client.CurrentRegion.ID, new LLVector3((float)Position.X, (float)Position.Y, (float)Position.Z), + 0, 0, sessionID, now, fromName, message, binaryBucket, Client.Network.SessionID); + + // Send the message + Client.Network.SendPacket(packet); + } + + public void Say(string message, int channel) + { + LLUUID CommandID = new LLUUID(); + LLVector3 Position = new LLVector3(0.0F, 0.0F, 0.0F); + + Packet packet = Packets.Communication.ChatFromViewer(Client.Protocol, Client.Avatar.ID, Client.Network.SessionID, + message, (byte)1, channel, 0, CommandID, 20, Position); + + Client.Network.SendPacket(packet); + } + + public void Shout(string message, int channel) + { + LLUUID CommandID = new LLUUID(); + LLVector3 Position = new LLVector3(0.0F, 0.0F, 0.0F); + + Packet packet = Packets.Communication.ChatFromViewer(Client.Protocol, Client.Avatar.ID, Client.Network.SessionID, + message, (byte)2, channel, 0, CommandID, 100, Position); + + Client.Network.SendPacket(packet); + } + + public void GiveMoney(LLUUID target, int amount, string description) + { + // 5001 - transaction type for av to av money transfers + GiveMoney(target, amount, description, 5001); + } + + public void GiveMoney(LLUUID target, int amount, string description, int transactiontype) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AggregatePermInventory"] = (byte)0; + fields["AggregatePermNextOwner"] = (byte)0; + fields["DestID"] = target; + fields["Amount"] = amount; + fields["Description"] = description; + fields["Flags"] = (byte)0; + fields["SourceID"] = Client.Network.AgentID; + fields["TransactionType"] = transactiontype; + blocks[fields] = "MoneyData"; + + fields = new Hashtable(); + fields["AgentID"] = Client.Network.AgentID; + fields["SessionID"] = Client.Network.SessionID; + blocks[fields] = "AgentData"; + + Packet packet = PacketBuilder.BuildPacket("MoneyTransferRequest", Client.Protocol, blocks, + Helpers.MSG_RELIABLE); + + Client.Network.SendPacket(packet); + } + + public bool Teleport(U64 regionHandle, LLVector3 position) + { + return Teleport(regionHandle, position, new LLVector3(position.X + 1.0F, position.Y, position.Z)); + } + + public bool Teleport(U64 regionHandle, LLVector3 position, LLVector3 lookAt) + { + TeleportStatus = 0; + // LLVector3 lookAt = new LLVector3(position.X + 1.0F, position.Y, position.Z); + + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + fields["RegionHandle"] = regionHandle; + fields["LookAt"] = lookAt; + fields["Position"] = position; + blocks[fields] = "Info"; + fields = new Hashtable(); + fields["AgentID"] = Client.Network.AgentID; + fields["SessionID"] = Client.Network.SessionID; + blocks[fields] = "AgentData"; + Packet packet = PacketBuilder.BuildPacket("TeleportLocationRequest", Client.Protocol, blocks, + Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + + Client.Log("Teleporting to region " + regionHandle.ToString(), Helpers.LogLevel.Info); + + // Start the timeout check + TeleportTimeout = false; + TeleportTimer.Start(); + + Client.Network.SendPacket(packet); + + while (TeleportStatus == 0 && !TeleportTimeout) + { + Client.Tick(); + } + + TeleportTimer.Stop(); + + if (TeleportTimeout) + { + if (OnTeleport != null) + { + OnTeleport("Teleport timed out."); + } + } + else + { + if (OnTeleport != null) + { + OnTeleport(TeleportMessage); + } + } + + return (TeleportStatus == 1); + } + + public bool Teleport(string simName, LLVector3 position) + { + return Teleport(simName, position, new LLVector3(position.X + 1.0F, position.Y, position.Z)); + } + + public bool Teleport(string simName, LLVector3 position, LLVector3 lookAt) + { + Client.Grid.AddSim(simName); + int attempts = 0; + + while (attempts++ < 5) + { + if (Client.Grid.Regions.ContainsKey(simName)) + { + return Teleport(((GridRegion)Client.Grid.Regions[simName]).RegionHandle, position, lookAt); + } + else + { + System.Threading.Thread.Sleep(1000); + Client.Grid.AddSim(simName); + Client.Tick(); + } + } + if (OnTeleport != null) + { + OnTeleport("Unable to resolve name: " + simName); + } + return false; + } + + private void TeleportHandler(Packet packet, Simulator simulator) + { + ArrayList blocks; + + if (packet.Layout.Name == "TeleportStart") + { + TeleportMessage = "Teleport started"; + } + else if (packet.Layout.Name == "TeleportProgress") + { + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "Message") + { + TeleportMessage = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + return; + } + } + } + } + else if (packet.Layout.Name == "TeleportFailed") + { + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "Reason") + { + TeleportMessage = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + TeleportStatus = -1; + return; + } + } + } + } + else if (packet.Layout.Name == "TeleportFinish") + { + TeleportMessage = "Teleport finished"; + + ushort port = 0; + IPAddress ip = null; + U64 regionHandle; + + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "SimPort") + { + port = (ushort)field.Data; + } + else if (field.Layout.Name == "SimIP") + { + ip = (IPAddress)field.Data; + } + else if (field.Layout.Name == "RegionHandle") + { + regionHandle = (U64)field.Data; + } + } + } + + if (Client.Network.Connect(ip, port, Client.Network.CurrentSim.CircuitCode, true) != null) + { + // Move the avatar in to this sim + Packet movePacket = Packets.Sim.CompleteAgentMovement(Client.Protocol, Client.Network.AgentID, + Client.Network.SessionID, Client.Network.CurrentSim.CircuitCode); + Client.Network.SendPacket(movePacket); + + Client.Log("Connected to new sim " + Client.Network.CurrentSim.IPEndPoint.ToString(), + Helpers.LogLevel.Info); + + // Sleep a little while so we can collect parcel information + System.Threading.Thread.Sleep(1000); + + Client.CurrentRegion = Client.Network.CurrentSim.Region; + TeleportStatus = 1; + return; + } + else + { + TeleportStatus = -1; + return; + } + } + } + + private void TeleportTimerEvent(object source, System.Timers.ElapsedEventArgs ea) + { + TeleportTimeout = true; + } + } +} diff --git a/old/libsecondlife-cs/EstateTools.cs b/old/libsecondlife-cs/EstateTools.cs new file mode 100644 index 00000000..cac6bfd1 --- /dev/null +++ b/old/libsecondlife-cs/EstateTools.cs @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +using System; + +namespace libsecondlife +{ + /// + /// Summary description for EstateTools. + /// + public class EstateTools + { + private SecondLife Client; + + public EstateTools(SecondLife client) + { + Client = client; + } + + public void KickUser(LLUUID prey) + { + Client.Network.SendPacket(Packets.Estate.EstateKick(Client.Protocol,Client.Avatar.ID,Client.Network.SessionID,prey)); + } + + public void BanUser(LLUUID prey) + { + Client.Network.SendPacket(Packets.Estate.EstateBan(Client.Protocol,Client.Avatar.ID,Client.Network.SessionID,prey)); + } + + public void UnBanUser(LLUUID prey) + { + Client.Network.SendPacket(Packets.Estate.EstateUnBan(Client.Protocol,Client.Avatar.ID,Client.Network.SessionID,prey)); + } + + public void TeleportHomeUser(LLUUID prey) + { + Client.Network.SendPacket(Packets.Estate.EstateTeleportUser(Client.Protocol,Client.Avatar.ID,Client.Network.SessionID,prey)); + } + } +} diff --git a/old/libsecondlife-cs/GridManager.cs b/old/libsecondlife-cs/GridManager.cs new file mode 100644 index 00000000..861f2472 --- /dev/null +++ b/old/libsecondlife-cs/GridManager.cs @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife +{ + /// + /// Class for regions on the world map + /// + public class GridRegion + { + public int X; + public int Y; + public string Name; + public byte Access; + public uint RegionFlags; + public byte WaterHeight; + public byte Agents; + public LLUUID MapImageID; + public U64 RegionHandle; // Used for teleporting + + public GridRegion() + { + + } + } + + /// + /// Manages grid-wide tasks such as the world map + /// + public class GridManager + { + public Hashtable Regions; + SecondLife Client; + + public GridManager(SecondLife client) + { + Client = client; + Regions = new Hashtable(); + PacketCallback callback = new PacketCallback(MapBlockReplyHandler); + Client.Network.RegisterCallback("MapBlockReply", callback); + } + + public void AddSim(string name) + { + if(!Regions.ContainsKey(name)) + { + Client.Network.SendPacket(Packets.Sim.MapNameRequest(Client.Protocol,Client.Avatar.ID,0,0,false,name)); +// Client.Network.SendPacket(Packets.Sim.MapNameRequest(Client.Protocol,Client.Avatar.ID,2,0,false,name)); +// Client.Network.SendPacket(Packets.Sim.MapNameRequest(Client.Protocol,Client.Avatar.ID,512,0,false,name)); + } + } + + public void AddAllSims() + { +// uint flags = 2; +// Client.Network.SendPacket(Packets.Sim.MapBlockRequest(Client.Protocol,Client.Avatar.ID,flags,0,false,0,65535,0,65535)); + uint flags = 0; + Client.Network.SendPacket(Packets.Sim.MapBlockRequest(Client.Protocol,Client.Avatar.ID,flags,0,false,0,65535,0,65535)); + } + + public GridRegion GetSim(string name) + { + if(Regions.ContainsKey(name)) + return (GridRegion)Regions[name]; + + AddSim(name); + System.Threading.Thread.Sleep(1000); + + if(Regions.ContainsKey(name)) + return (GridRegion)Regions[name]; + else + { + /* TODO: Put some better handling inplace here with some retry code */ + Client.Log("Error returned sim that didnt exist",Helpers.LogLevel.Warning); + return new GridRegion(); + } + } + + private void MapBlockReplyHandler(Packet packet, Simulator simulator) + { + GridRegion region; + + foreach (Block block in packet.Blocks()) + { + if(block.Layout.Name == "Data") + { + region = new GridRegion(); + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "X") + { + if(System.BitConverter.IsLittleEndian) + { + ushort temp = (ushort)field.Data; + region.X = ((temp << 8) & 0xFF00) | ((temp >> 8) & 0x00FF); + } + else + { + region.X = (ushort)field.Data; + } + } + else if(field.Layout.Name == "Y") + { + if(System.BitConverter.IsLittleEndian) + { + ushort temp = (ushort)field.Data; + region.Y = ((temp << 8) & 0xFF00) | ((temp >> 8) & 0x00FF); + } + else + { + region.Y = (ushort)field.Data; + } + } + else if(field.Layout.Name == "Name") + region.Name = Helpers.FieldToString(field.Data); + else if(field.Layout.Name == "RegionFlags") + region.RegionFlags = (uint)field.Data; + else if(field.Layout.Name == "WaterHeight") + region.WaterHeight = (byte)field.Data; + else if(field.Layout.Name == "Agents") + region.Agents = (byte)field.Data; + else if(field.Layout.Name == "MapImageID") + region.MapImageID = (LLUUID)field.Data; + } + + region.RegionHandle = new U64(region.X * 256,region.Y * 256); + + if(region.Name != "" && (region.X != 0 && region.Y != 0)) + Regions[region.Name] = region; + } + } + } + } +} diff --git a/old/libsecondlife-cs/Inventory.cs b/old/libsecondlife-cs/Inventory.cs new file mode 100644 index 00000000..94d00aff --- /dev/null +++ b/old/libsecondlife-cs/Inventory.cs @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife +{ + public class Inventory + { + private SecondLife Client; + + public Inventory(SecondLife client) + { + Client = client; + } + } +} diff --git a/old/libsecondlife-cs/InventorySystem/InventoryBase.cs b/old/libsecondlife-cs/InventorySystem/InventoryBase.cs new file mode 100644 index 00000000..72d065d5 --- /dev/null +++ b/old/libsecondlife-cs/InventorySystem/InventoryBase.cs @@ -0,0 +1,46 @@ +using System; + +using libsecondlife; +using libsecondlife.AssetSystem; + +namespace libsecondlife.InventorySystem +{ + /// + /// Summary description for Class1. + /// + abstract public class InventoryBase + { + protected InventoryManager iManager; + + internal string _Name; + + internal InventoryBase(InventoryManager manager) + { + if( manager == null ) + { + throw new Exception( "Inventory Manager cannot be null" ); + } + iManager = manager; + } + + abstract public string toXML( bool outputAssets ); + + protected string xmlSafe ( string str ) + { + if( str != null ) + { + string clean = str.Replace("&","&"); + clean = clean.Replace("<","<"); + clean = clean.Replace(">",">"); + clean = clean.Replace("'","'"); + clean = clean.Replace("\"","""); + return clean; + } + else + { + return ""; + } + } + + } +} diff --git a/old/libsecondlife-cs/InventorySystem/InventoryFolder.cs b/old/libsecondlife-cs/InventorySystem/InventoryFolder.cs new file mode 100644 index 00000000..d892da32 --- /dev/null +++ b/old/libsecondlife-cs/InventorySystem/InventoryFolder.cs @@ -0,0 +1,159 @@ +using System.Collections; +using System; +using libsecondlife; + +namespace libsecondlife.InventorySystem +{ + /// + /// Summary description for InventoryFolder. + /// + public class InventoryFolder : InventoryBase + { + public string Name + { + get { return _Name; } + set + { + _Name = value; + base.iManager.FolderRename( this ); + } + } + + + private LLUUID _FolderID; + public LLUUID FolderID + { + get { return _FolderID; } + } + + private LLUUID _ParentID; + public LLUUID ParentID + { + get { return _ParentID; } + set + { + InventoryFolder ifParent = iManager.getFolder( this.ParentID ); + ifParent.alContents.Remove( this ); + + ifParent = iManager.getFolder( value ); + ifParent.alContents.Add( this ); + + this._ParentID = value; + + base.iManager.FolderMove( this, value ); + } + } + + internal sbyte _Type; + public sbyte Type + { + get { return _Type; } + } + + public ArrayList alContents = new ArrayList(); + + internal InventoryFolder( InventoryManager manager ) : base(manager) + { + _Name = ""; + _FolderID = new LLUUID(); + _ParentID = new LLUUID(); + _Type = -1; + } + + internal InventoryFolder( InventoryManager manager, String name, LLUUID folderID, LLUUID parentID ) : base(manager) + { + this._Name = name; + this._FolderID = folderID; + this._ParentID = parentID; + this._Type = 0; + } + + internal InventoryFolder( InventoryManager manager, String name, LLUUID folderID, LLUUID parentID, sbyte Type ) : base(manager) + { + this._Name = name; + this._FolderID = folderID; + this._ParentID = parentID; + this._Type = Type; + } + + internal InventoryFolder( InventoryManager manager, Hashtable htData ) : base(manager) + { + this._Name = (string)htData["name"]; + this._FolderID = new LLUUID( (string)htData["folder_id"] ); + this._ParentID = new LLUUID( (string)htData["parent_id"] ); + this._Type = sbyte.Parse( htData["type_default"].ToString() ); + } + + + public InventoryFolder CreateFolder( string name ) + { + return base.iManager.FolderCreate( name, FolderID ); + } + + public void Delete() + { + iManager.getFolder( this.ParentID ).alContents.Remove(this); + iManager.FolderRemove(this); + } + + public void MoveTo( InventoryFolder newParent ) + { + MoveTo( newParent.FolderID ); + } + + public void MoveTo( LLUUID newParentID ) + { + this.ParentID = newParentID; + } + + public InventoryNotecard NewNotecard( string name, string description, string body ) + { + return base.iManager.NewNotecard( name, description, body, this.FolderID ); + } + + public InventoryImage NewImage( string name, string description, byte[] j2cdata ) + { + return base.iManager.NewImage( name, description, j2cdata, this.FolderID ); + } + + public ArrayList GetItemByName( string name ) + { + ArrayList items = new ArrayList(); + foreach( InventoryBase ib in alContents ) + { + if( ib is InventoryFolder ) + { + items.AddRange( ((InventoryFolder)ib).GetItemByName(name) ); + } else if ( ib is InventoryItem ) { + if( ((InventoryItem)ib).Name.Equals( name ) ) + { + items.Add( ib ); + } + } + } + + return items; + } + + override public string toXML( bool outputAssets ) + { + string output = " + /// Summary description for InventoryNotecard. + /// + public class InventoryImage : InventoryItem + { + + public byte[] J2CData + { + get + { + if( Asset != null ) + { + return ((AssetImage)Asset).J2CData; + } + else + { + if( (AssetID != null) && (AssetID != new LLUUID()) ) + { + base.iManager.AssetManager.GetInventoryAsset( this ); + return ((AssetImage)Asset).J2CData; + } + } + + return null; + } + + set + { + base._Asset = new AssetImage( LLUUID.GenerateUUID(), value ); + base.iManager.AssetManager.UploadAsset( Asset ); + this.AssetID = Asset.AssetID; + } + + } + + internal InventoryImage( InventoryManager manager, string name, string description, LLUUID id, LLUUID folderID, LLUUID uuidOwnerCreater ) + : base(manager, name, description, id, folderID, 0, 0, uuidOwnerCreater) + { + + } + + internal InventoryImage( InventoryManager manager, InventoryItem ii ) + : base( manager, ii._Name, ii._Description, ii._ItemID, ii._FolderID, ii._InvType, ii._Type, ii._CreatorID) + { + if( (ii.InvType != 0) || (ii.Type != Asset.ASSET_TYPE_IMAGE) ) + { + throw new Exception("The InventoryItem cannot be converted to a Image/Texture, wrong InvType/Type."); + } + + this.iManager = manager; + this._Asset = ii._Asset; + this._AssetID = ii._AssetID; + this._BaseMask = ii._BaseMask; + this._CRC = ii._CRC; + this._CreationDate = ii._CreationDate; + this._EveryoneMask = ii._EveryoneMask; + this._Flags = ii._Flags; + this._GroupID = ii._GroupID; + this._GroupMask = ii._GroupMask; + this._GroupOwned = ii._GroupOwned; + this._InvType = ii._InvType; + this._NextOwnerMask = ii._NextOwnerMask; + this._OwnerID = ii._OwnerID; + this._OwnerMask = ii._OwnerMask; + this._SalePrice = ii._SalePrice; + this._SaleType = ii._SaleType; + this._Type = ii._Type; + } + + + override internal void SetAssetData( byte[] assetData ) + { + if( Asset == null ) + { + if( AssetID != null ) + { + _Asset = new AssetImage( AssetID, assetData ); + } + else + { + _Asset = new AssetImage( LLUUID.GenerateUUID(), assetData ); + AssetID = _Asset.AssetID; + } + } + else + { + Asset.AssetData = assetData; + } + + } + + override public string toXML( bool outputAssets ) + { + string output = " + /// Summary description for InventoryFolder. + /// + public class InventoryItem : InventoryBase + { + private const uint FULL_MASK_PERMISSIONS = 2147483647; + + public string Name + { + get{ return base._Name; } + set + { + _Name = value; + UpdateItem(); + } + } + + internal LLUUID _FolderID = new LLUUID(); + public LLUUID FolderID + { + get{ return _FolderID; } + set + { + InventoryFolder iTargetFolder = base.iManager.getFolder( value ); + if( iTargetFolder == null ) + { + throw new Exception("Target Folder [" + value + "] does not exist."); + } + + base.iManager.getFolder( this.FolderID ).alContents.Remove( this ); + iTargetFolder.alContents.Add( this ); + + _FolderID = value; + UpdateItem(); + } + } + + internal LLUUID _ItemID = new LLUUID(); + public LLUUID ItemID + { + get{ return _ItemID; } + } + + internal sbyte _InvType = 0; + public sbyte InvType + { + get{ return _InvType; } + } + + internal sbyte _Type = 0; + public sbyte Type + { + get{ return _Type; } + set + { + _Type = value; + UpdateItem(); + } + } + + + internal string _Description = ""; + public string Description + { + get{ return _Description; } + set + { + _Description = value; + UpdateItem(); + } + } + + internal uint _CRC = 0; + public uint CRC + { + get { return _CRC; } + set + { + _CRC = value; + } + } + + + internal LLUUID _OwnerID = new LLUUID(); + public LLUUID OwnerID + { + get { return _OwnerID; } + } + + internal LLUUID _CreatorID = new LLUUID(); + public LLUUID CreatorID + { + get { return _CreatorID; } + } + + internal Asset _Asset; + public Asset Asset + { + get { + if( _Asset != null ) + { + return _Asset; + } + else + { + if( (AssetID != null) && (AssetID != new LLUUID()) ) + { + base.iManager.AssetManager.GetInventoryAsset( this ); + return Asset; + } + } + return null; + } + } + + internal LLUUID _AssetID = new LLUUID(); + public LLUUID AssetID + { + get { return _AssetID; } + set + { + _AssetID = value; + UpdateItem(); + } + } + + + internal LLUUID _GroupID = new LLUUID(); + public LLUUID GroupID + { + get { return _GroupID; } + set + { + _GroupID = value; + UpdateItem(); + } + } + + internal bool _GroupOwned = false; + public bool GroupOwned + { + get { return _GroupOwned; } + set + { + _GroupOwned = value; + UpdateItem(); + } + } + + internal int _CreationDate = (int)((TimeSpan)(DateTime.UtcNow - new DateTime(1970, 1, 1))).TotalSeconds; + public int CreationDate + { + get { return _CreationDate; } + } + + internal byte _SaleType = 0; + public byte SaleType + { + get { return _SaleType; } + set + { + _SaleType = value; + UpdateItem(); + } + } + + internal uint _BaseMask = FULL_MASK_PERMISSIONS; + public uint BaseMask + { + get { return _BaseMask; } + } + + internal int _SalePrice = 0; + public int SalePrice + { + get { return _SalePrice; } + set + { + _SalePrice = value; + UpdateItem(); + } + } + + internal uint _EveryoneMask = 0; + public uint EveryoneMask + { + get { return _EveryoneMask; } + set + { + _EveryoneMask = value; + UpdateItem(); + } + } + + internal uint _Flags = 0; + public uint Flags + { + get { return _Flags; } + set + { + _Flags = value; + UpdateItem(); + } + } + + internal uint _NextOwnerMask = FULL_MASK_PERMISSIONS; + public uint NextOwnerMask + { + get { return _NextOwnerMask; } + set + { + _NextOwnerMask = value; + UpdateItem(); + } + } + + internal uint _GroupMask = 0; + public uint GroupMask + { + get { return _GroupMask; } + set + { + _GroupMask = value; + UpdateItem(); + } + } + + internal uint _OwnerMask = FULL_MASK_PERMISSIONS; + public uint OwnerMask + { + get { return _OwnerMask; } + } + + + + internal InventoryItem(InventoryManager manager) : base(manager) + { + } + + internal InventoryItem( InventoryManager manager, string name, LLUUID id, LLUUID folderID, sbyte invType, sbyte type, LLUUID uuidOwnerCreater ) : base(manager) + { + _Name = name; + _ItemID = id; + _FolderID = folderID; + _InvType = invType; + _Type = type; + _OwnerID = uuidOwnerCreater; + _CreatorID = uuidOwnerCreater; + + UpdateCRC(); + } + + internal InventoryItem( InventoryManager manager, string name, string description, LLUUID id, LLUUID folderID, sbyte invType, sbyte type, LLUUID uuidOwnerCreater ) : base(manager) + { + _Name = name; + _Description = description; + _ItemID = id; + _FolderID = folderID; + _InvType = invType; + _Type = type; + _OwnerID = uuidOwnerCreater; + _CreatorID = uuidOwnerCreater; + + UpdateCRC(); + } + + public override bool Equals(object o) + { + if( (o is InventoryItem) == false ) + { + return false; + } + + return this._ItemID == ((InventoryItem)o)._ItemID; + } + + public override int GetHashCode() + { + return this._ItemID.GetHashCode(); + } + + public int CompareTo(object obj) + { + if(obj is InventoryBase) + { + InventoryBase temp = (InventoryBase) obj; + return this._Name.CompareTo(temp._Name); + } + throw new ArgumentException("object is not an InventoryItem"); + } + + private void UpdateItem() + { + UpdateCRC(); + base.iManager.ItemUpdate( this ); + } + + private void UpdateCRC() + { + _CRC = Packets.InventoryPackets.InventoryUpdateCRC(this); + } + + public void MoveTo( InventoryFolder targetFolder ) + { + this.FolderID = targetFolder.FolderID; + } + public void MoveTo( LLUUID targetFolderID ) + { + this.FolderID = targetFolderID; + } + + public void CopyTo( LLUUID targetFolder ) + { + base.iManager.ItemCopy( this.ItemID, targetFolder ); + } + + public void GiveTo( LLUUID ToAgentID ) + { + base.iManager.ItemGiveTo( this, ToAgentID ); + } + + public void Delete() + { + base.iManager.getFolder( this.FolderID ).alContents.Remove( this ); + base.iManager.ItemRemove( this ); + + } + + public void ClearAssetTest() + { + _Asset = null; + } + + virtual internal void SetAssetData( byte[] assetData ) + { + if( _Asset == null ) + { + if( AssetID != null ) + { + _Asset = new Asset( AssetID, Type, assetData ); + } else { + _Asset = new Asset( LLUUID.GenerateUUID(), Type, assetData ); + AssetID = _Asset.AssetID; + } + } else { + _Asset.AssetData = assetData; + } + } + + override public string toXML( bool outputAssets ) + { + string output = " + /// Summary description for Inventory. + /// + public class InventoryManager + { + // Reference to the SLClient Library + private SecondLife slClient; + + // Reference to the Asset Manager + private static AssetManager slAssetManager; + internal AssetManager AssetManager + { + get{ return slAssetManager; } + } + + + // UUID of Root Inventory Folder + private LLUUID uuidRootFolder; + + // Setup a hashtable to easily lookup folders by UUID + private Hashtable htFoldersByUUID = new Hashtable(); + + // Setup a Hashtable to track download progress + private Hashtable htFolderDownloadStatus; + private ArrayList alFolderRequestQueue; + + private int iLastPacketRecieved; + + private class DescendentRequest + { + public LLUUID FolderID; + + public int Expected = int.MaxValue; + public int Received = 0; + public int LastReceived = 0; + + public bool FetchFolders = true; + public bool FetchItems = true; + + public DescendentRequest( LLUUID folderID ) + { + FolderID = folderID; + LastReceived = MiscUtils.getUnixtime(); + } + + public DescendentRequest( LLUUID folderID, bool fetchFolders, bool fetchItems ) + { + FolderID = folderID; + FetchFolders = fetchFolders; + FetchItems = fetchItems; + LastReceived = MiscUtils.getUnixtime(); + } + + } + + // Each InventorySystem needs to be initialized with a client (for network access to SL) + // and root folder. The root folder can be the root folder of an object OR an agent. + public InventoryManager( SecondLife client, LLUUID rootFolder ) + { + slClient = client; + if( slAssetManager == null ) + { + slAssetManager = new AssetManager( slClient ); + } + + uuidRootFolder = rootFolder; + + resetFoldersByUUID(); + + // Setup the callback + PacketCallback InventoryDescendentsCallback = new PacketCallback(InventoryDescendentsHandler); + slClient.Network.RegisterCallback("InventoryDescendents", InventoryDescendentsCallback); + } + + // Used primarily for debugging and testing + public AssetManager getAssetManager() + { + Console.WriteLine("It is not recommended that you access the asset manager directly"); + return AssetManager; + } + + private void resetFoldersByUUID() + { + // Init folder structure with root + htFoldersByUUID = new Hashtable(); + + InventoryFolder ifRootFolder = new InventoryFolder(this, "My Inventory", uuidRootFolder, null); + htFoldersByUUID[uuidRootFolder] = ifRootFolder; + } + + public InventoryFolder getRootFolder() + { + return (InventoryFolder)htFoldersByUUID[uuidRootFolder]; + } + + public InventoryFolder getFolder( LLUUID folderID ) + { + return (InventoryFolder)htFoldersByUUID[folderID]; + } + + public InventoryFolder getFolder( String sFolderPath ) + { + string sSecretConst = "+@#%$#$%^%^%$^$%SV$#%FR$G"; + sFolderPath = sFolderPath.Replace("//",sSecretConst); + + char[] seperators = new char[1]; + seperators[0] = '/'; + string[] sFolderPathParts = sFolderPath.Split(seperators); + for( int i = 0; i 0) || (alFolderRequestQueue.Count > 0) ) + { + if( htFolderDownloadStatus.Count == 0 ) + { + DescendentRequest dr = (DescendentRequest)alFolderRequestQueue[0]; + alFolderRequestQueue.RemoveAt(0); + RequestFolder( dr ); + } + + if( (MiscUtils.getUnixtime() - iLastPacketRecieved) > 10 ) + { + Console.WriteLine("Time-out while waiting for packets (" + (MiscUtils.getUnixtime() - iLastPacketRecieved) + " seconds since last packet)"); + Console.WriteLine("Current Status:"); + + // have to make a seperate list otherwise we run into modifying the original array + // while still enumerating it. + ArrayList alRestartList = new ArrayList(); + + if (htFolderDownloadStatus[0] != null) + { + Console.WriteLine(htFolderDownloadStatus[0].GetType()); + } + + foreach( DescendentRequest dr in htFolderDownloadStatus ) + { + Console.WriteLine( dr.FolderID + " " + dr.Expected + " / " + dr.Received + " / " + dr.LastReceived ); + + alRestartList.Add( dr ); + } + + iLastPacketRecieved = MiscUtils.getUnixtime(); + foreach( DescendentRequest dr in alRestartList ) + { + RequestFolder( dr ); + } + + } + slClient.Tick(); + + } + } + + + + + + /* + Low 00333 - InventoryDescendents - Untrusted - Unencoded + 1044 ItemData (Variable) + 0047 GroupOwned (BOOL / 1) + 0149 CRC (U32 / 1) + 0159 CreationDate (S32 / 1) + 0345 SaleType (U8 / 1) + 0395 BaseMask (U32 / 1) + 0506 Name (Variable / 1) + 0562 InvType (S8 / 1) + 0630 Type (S8 / 1) + 0680 AssetID (LLUUID / 1) + 0699 GroupID (LLUUID / 1) + 0716 SalePrice (S32 / 1) + 0719 OwnerID (LLUUID / 1) + 0736 CreatorID (LLUUID / 1) + 0968 ItemID (LLUUID / 1) + 1025 FolderID (LLUUID / 1) + 1084 EveryoneMask (U32 / 1) + 1101 Description (Variable / 1) + 1189 Flags (U32 / 1) + 1348 NextOwnerMask (U32 / 1) + 1452 GroupMask (U32 / 1) + 1505 OwnerMask (U32 / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + 0366 Descendents (S32 / 1) + 0418 Version (S32 / 1) + 0719 OwnerID (LLUUID / 1) + 1025 FolderID (LLUUID / 1) + 1298 FolderData (Variable) + 0506 Name (Variable / 1) + 0558 ParentID (LLUUID / 1) + 0630 Type (S8 / 1) + 1025 FolderID (LLUUID / 1) + */ + public void InventoryDescendentsHandler(Packet packet, Simulator simulator) + { +// Console.WriteLine("Status|Queue :: " + htFolderDownloadStatus.Count + "/" + qFolderRequestQueue.Count); + iLastPacketRecieved = MiscUtils.getUnixtime(); + + ArrayList blocks = packet.Blocks(); + + InventoryItem invItem; + InventoryFolder invFolder; + + LLUUID uuidFolderID = new LLUUID(); + + int iDescendentsExpected = int.MaxValue; + int iDescendentsReceivedThisBlock = 0; + + foreach (Block block in blocks) + { + if( block.Layout.Name.Equals("ItemData") ) + { + invItem = new InventoryItem(this); + + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "Name": + invItem._Name = System.Text.Encoding.UTF8.GetString( (byte[])field.Data).Trim(); + invItem._Name = invItem.Name.Replace("\0", ""); + break; + case "Description": + invItem._Description = System.Text.Encoding.UTF8.GetString( (byte[])field.Data).Trim(); + invItem._Description = invItem.Description.Replace("\0", ""); + break; + + case "InvType": + invItem._InvType = sbyte.Parse(field.Data.ToString()); + break; + case "Type": + invItem._Type = sbyte.Parse(field.Data.ToString()); + break; + + case "SaleType": + invItem._SaleType = byte.Parse(field.Data.ToString()); + break; + + case "GroupOwned": + invItem._GroupOwned = bool.Parse(field.Data.ToString()); + break; + + case "FolderID": + invItem._FolderID = new LLUUID(field.Data.ToString()); + break; + case "ItemID": + invItem._ItemID = new LLUUID(field.Data.ToString()); + break; + case "AssetID": + invItem._AssetID = new LLUUID(field.Data.ToString()); + break; + case "GroupID": + invItem._GroupID = new LLUUID(field.Data.ToString()); + break; + case "OwnerID": + invItem._OwnerID = new LLUUID(field.Data.ToString()); + break; + case "CreatorID": + invItem._CreatorID = new LLUUID(field.Data.ToString()); + break; + + case "CRC": + invItem._CRC = uint.Parse(field.Data.ToString()); + break; + case "Flags": + invItem._Flags = uint.Parse(field.Data.ToString()); + break; + + case "BaseMask": + invItem._BaseMask = uint.Parse(field.Data.ToString()); + break; + case "EveryoneMask": + invItem._EveryoneMask = uint.Parse(field.Data.ToString()); + break; + case "NextOwnerMask": + invItem._NextOwnerMask = uint.Parse(field.Data.ToString()); + break; + case "GroupMask": + invItem._GroupMask = uint.Parse(field.Data.ToString()); + break; + case "OwnerMask": + invItem._OwnerMask = uint.Parse(field.Data.ToString()); + break; + + case "CreationDate": + invItem._CreationDate = int.Parse(field.Data.ToString()); + break; + case "SalePrice": + invItem._SalePrice = int.Parse(field.Data.ToString()); + break; + + default: + break; + } + } + + // There is always an item block, even if there isn't any items + // the "filler" block will not have a name + if( (invItem.Name != null) && !invItem.Name.Equals("") ) + { + iDescendentsReceivedThisBlock++; + + InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invItem.FolderID]; + + if( ifolder.alContents.Contains( invItem ) == false ) + { + if( (invItem.InvType == 7) && (invItem.Type == Asset.ASSET_TYPE_NOTECARD) ) + { + InventoryItem temp = new InventoryNotecard( this, invItem ); + invItem = temp; + } + + if( (invItem.InvType == 0) && (invItem.Type == Asset.ASSET_TYPE_IMAGE) ) + { + InventoryItem temp = new InventoryImage( this, invItem ); + invItem = temp; + } + + ifolder.alContents.Add(invItem); + } + } + } + + // Count number of folder descendents received + if( block.Layout.Name.Equals("FolderData") ) + { + String name = ""; + LLUUID folderid = new LLUUID(); + LLUUID parentid = new LLUUID(); + sbyte type = 0; + + foreach (Field field in block.Fields ) + { + switch( field.Layout.Name ) + { + case "Name": + name = System.Text.Encoding.UTF8.GetString( (byte[])field.Data).Trim(); + name = name.Replace("\0", ""); + break; + case "FolderID": + folderid = new LLUUID(field.Data.ToString()); + break; + case "ParentID": + parentid = new LLUUID(field.Data.ToString()); + break; + case "Type": + type = sbyte.Parse(field.Data.ToString()); + break; + default: + break; + } + } + + invFolder = new InventoryFolder(this, name, folderid, parentid); + + // There is always an folder block, even if there isn't any folders + // the "filler" block will not have a name + if( (invFolder.Name != null) && !invFolder.Name.Equals("") ) + { + iDescendentsReceivedThisBlock++; + + // Add folder to Parent + InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invFolder.ParentID]; + if( ifolder.alContents.Contains(invFolder) == false ) + { + ifolder.alContents.Add(invFolder); + } + + + // Add folder to UUID Lookup + htFoldersByUUID[invFolder.FolderID] = invFolder; + + + // It's not the root, should be safe to "recurse" + if( !invFolder.FolderID.Equals( uuidRootFolder ) ) + { + bool alreadyQueued = false; + foreach( DescendentRequest dr in alFolderRequestQueue ) + { + if( dr.FolderID == invFolder.FolderID ) + { + alreadyQueued = true; + break; + } + } + + if( !alreadyQueued ) + { + alFolderRequestQueue.Add( new DescendentRequest( invFolder.FolderID ) ); + } + } + } + } + + // Check how many descendents we're actually supposed to receive + if( block.Layout.Name.Equals("AgentData") ) + { + foreach (Field field in block.Fields ) + { + if( field.Layout.Name.Equals("Descendents") ) + { + iDescendentsExpected = int.Parse(field.Data.ToString()); + } + if( field.Layout.Name.Equals("FolderID") ) + { + uuidFolderID = field.Data.ToString(); +// Console.WriteLine("Recieved a packet for : " + uuidFolderID); + } + } + } + } + + // Update download status for this folder + if( iDescendentsReceivedThisBlock >= iDescendentsExpected ) + { + // We received all the descendents we're expecting for this folder + // in this packet, so go ahead and remove folder from status list. + htFolderDownloadStatus.Remove(uuidFolderID); + } + else + { + + // This one packet didn't have all the descendents we're expecting + // so update the total we're expecting, and update the total downloaded + DescendentRequest dr = (DescendentRequest)htFolderDownloadStatus[uuidFolderID]; + dr.Expected = iDescendentsExpected; + dr.Received += iDescendentsReceivedThisBlock; + dr.LastReceived = MiscUtils.getUnixtime(); + + if( dr.Received >= dr.Expected ) + { + // Looks like after updating, we have all the descendents, + // remove from folder status. + htFolderDownloadStatus.Remove(uuidFolderID); + } + else + { + htFolderDownloadStatus[uuidFolderID] = dr; +// Console.WriteLine( uuidFolderID + " is expecting " + (iDescendentsExpected - iStatus[1]) + " more packets." ); + } + } + } + } +} diff --git a/old/libsecondlife-cs/InventorySystem/InventoryNotecard.cs b/old/libsecondlife-cs/InventorySystem/InventoryNotecard.cs new file mode 100644 index 00000000..c9c6fc52 --- /dev/null +++ b/old/libsecondlife-cs/InventorySystem/InventoryNotecard.cs @@ -0,0 +1,142 @@ +using System; + +using libsecondlife; +using libsecondlife.AssetSystem; + +namespace libsecondlife.InventorySystem +{ + /// + /// Summary description for InventoryNotecard. + /// + public class InventoryNotecard : InventoryItem + { + public string Body + { + get + { + if( Asset != null ) + { + return ((AssetNotecard)Asset).Body; + } else { + if( (AssetID != null) && (AssetID != new LLUUID()) ) + { + base.iManager.AssetManager.GetInventoryAsset( this ); + return ((AssetNotecard)Asset).Body; + } + } + + return null; + } + + set + { + base._Asset = new AssetNotecard( LLUUID.GenerateUUID(), value ); + base.iManager.AssetManager.UploadAsset( Asset ); + this.AssetID = Asset.AssetID; + + } + } + + + internal InventoryNotecard( InventoryManager manager, string name, string description, LLUUID id, LLUUID folderID, LLUUID uuidOwnerCreater ) + : base(manager, name, description, id, folderID, 7, 7, uuidOwnerCreater) + { + + } + + internal InventoryNotecard( InventoryManager manager, InventoryItem ii ) + : base( manager, ii._Name, ii._Description, ii._ItemID, ii._FolderID, ii._InvType, ii._Type, ii._CreatorID) + { + if( (ii.InvType != 7) || (ii.Type != Asset.ASSET_TYPE_NOTECARD) ) + { + throw new Exception("The InventoryItem cannot be converted to a Notecard, wrong InvType/Type."); + } + + this.iManager = manager; + this._Asset = ii._Asset; + this._AssetID = ii._AssetID; + this._BaseMask = ii._BaseMask; + this._CRC = ii._CRC; + this._CreationDate = ii._CreationDate; + this._EveryoneMask = ii._EveryoneMask; + this._Flags = ii._Flags; + this._GroupID = ii._GroupID; + this._GroupMask = ii._GroupMask; + this._GroupOwned = ii._GroupOwned; + this._InvType = ii._InvType; + this._NextOwnerMask = ii._NextOwnerMask; + this._OwnerID = ii._OwnerID; + this._OwnerMask = ii._OwnerMask; + this._SalePrice = ii._SalePrice; + this._SaleType = ii._SaleType; + this._Type = ii._Type; + } + + override internal void SetAssetData( byte[] assetData ) + { + if( _Asset == null ) + { + if( AssetID != null ) + { + _Asset = new AssetNotecard( AssetID, assetData ); + } + else + { + _Asset = new AssetNotecard( LLUUID.GenerateUUID(), assetData ); + AssetID = _Asset.AssetID; + } + } + else + { + _Asset.AssetData = assetData; + } + + } + + override public string toXML( bool outputAssets ) + { + string output = " + /// + /// A JSONArray is an ordered sequence of values. Its external form is a string + /// wrapped in square brackets with commas between the values. The internal form + /// is an object having get() and opt() methods for accessing the values by + /// index, and put() methods for adding or replacing values. The values can be + /// any of these types: Boolean, JSONArray, JSONObject, Number, String, or the + /// JSONObject.NULL object. + /// + /// + /// The constructor can convert a JSON external form string into an + /// internal form Java object. The toString() method creates an external + /// form string. + /// + /// + /// A get() method returns a value if one can be found, and throws an exception + /// if one cannot be found. An opt() method returns a default value instead of + /// throwing an exception, and so is useful for obtaining optional values. + /// + /// + /// The generic get() and opt() methods return an object which you can cast or + /// query for type. There are also typed get() and opt() methods that do typing + /// checking and type coersion for you. + /// + /// + /// The texts produced by the toString() methods are very strict. + /// The constructors are more forgiving in the texts they will accept. + /// + /// + /// + /// An extra comma may appear just before the closing bracket. + /// Strings may be quoted with single quotes. + /// Strings do not need to be quoted at all if they do not contain leading + /// or trailing spaces, and if they do not contain any of these characters: + /// { } [ ] / \ : , + /// Numbers may have the 0- (octal) or 0x- (hex) prefix. + /// + /// + /// + /// Public Domain 2002 JSON.org + /// @author JSON.org + /// @version 0.1 + /// + /// Ported to C# by Are Bjolseth, teleplan.no + /// TODO: + /// 1. Implement Custom exceptions + /// 2. Add indexer JSONObject[i] = object, and object = JSONObject[i]; + /// 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"] + /// 4. Add unit testing + /// 5. Add log4net + /// 6. Make get/put methods private, to force use of indexer instead? + /// + public class JSONArray + { + /// The ArrayList where the JSONArray's properties are kept. + private ArrayList myArrayList; + + + /// + /// Construct an empty JSONArray + /// + public JSONArray() + { + myArrayList = new ArrayList(); + } + + /// + /// Construct a JSONArray from a JSONTokener. + /// + /// A JSONTokener + public JSONArray(JSONTokener x) : this() + { + if (x.nextClean() != '[') + { + throw new Exception("A JSONArray must start with '['"); + } + if (x.nextClean() == ']') + { + return; + } + x.back(); + while (true) + { + myArrayList.Add(x.nextObject()); + switch (x.nextClean()) + { + case ',': + if (x.nextClean() == ']') + { + return; + } + x.back(); + break; + case ']': + return; + default: + throw new Exception("Expected a ',' or ']'"); + } + } + } + + /// + /// Alternate to Java get/put method, by using indexer + /// + public object this[int i] + { + get + { + return opt(i); + } + set + { + //myArrayList[i] = value; + put(i, value); + } + } + + /// + /// Get the optional object value associated with an index. + /// + /// index subscript + /// object at that index. + public object opt(int i) + { + if (i < 0 || i >= myArrayList.Count) + throw new ArgumentOutOfRangeException("int i", i, "Index out of bounds!"); + + return myArrayList[i]; + } + + /// + /// Put or replace a boolean value in the JSONArray. + /// + /// + /// The subscript. If the index is greater than the length of + /// the JSONArray, then null elements will be added as necessary to pad it out. + /// + /// An object value. + /// this (JSONArray) + public JSONArray put(int i, object val) + { + if (i < 0) + { + throw new ArgumentOutOfRangeException("i", i, "Negative indexes illegal"); + } + else if (val == null) + { + throw new ArgumentNullException("val", "Object cannt be null"); + } + else if (i < myArrayList.Count) + { + myArrayList.Insert(i, val); + } + // NOTE! Since i is >= Count, fill null vals before index i, then append new object at i + else + { + while (i != myArrayList.Count) + { + myArrayList.Add(null); + } + myArrayList.Add(val); + } + return this; + } + } +} diff --git a/old/libsecondlife-cs/JSON/JSONFacade.cs b/old/libsecondlife-cs/JSON/JSONFacade.cs new file mode 100644 index 00000000..045e0489 --- /dev/null +++ b/old/libsecondlife-cs/JSON/JSONFacade.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Reflection; +using System.Text; + +namespace Nii.JSON +{ + /// + /// Summary description for JsonFacade. + /// + public sealed class JsonFacade + { + /// + /// Parse JSON formatted string and return a Hashtable + /// + /// + /// + public static IDictionary fromJSON(string sJSON) + { + JSONObject jsob = new JSONObject(sJSON); + IDictionary idict = jsob.getDictionary(); + return idict; + } + } +} diff --git a/old/libsecondlife-cs/JSON/JSONObject.cs b/old/libsecondlife-cs/JSON/JSONObject.cs new file mode 100644 index 00000000..47597c80 --- /dev/null +++ b/old/libsecondlife-cs/JSON/JSONObject.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Text; +using System.Globalization; + +/* + * A JSONObject is an unordered collection of name/value pairs. Its + * external form is a string wrapped in curly braces with colons between the + * names and values, and commas between the values and names. The internal form + * is an object having get() and opt() methods for accessing the values by name, + * and put() methods for adding or replacing values by name. The values can be + * any of these types: Boolean, JSONArray, JSONObject, Number, String, or the + * JSONObject.NULL object. + *

+ * The constructor can convert an external form string into an internal form + * Java object. The toString() method creates an external form string. + *

+ * A get() method returns a value if one can be found, and throws an exception + * if one cannot be found. An opt() method returns a default value instead of + * throwing an exception, and so is useful for obtaining optional values. + *

+ * The generic get() and opt() methods return an object, which you can cast or + * query for type. There are also typed get() and opt() methods that do typing + * checking and type coersion for you. + *

+ * The texts produced by the toString() methods are very strict. + * The constructors are more forgiving in the texts they will accept. + *

    + *
  • An extra comma may appear just before the closing brace.
  • + *
  • Strings may be quoted with single quotes.
  • + *
  • Strings do not need to be quoted at all if they do not contain leading + * or trailing spaces, and if they do not contain any of these characters: + * { } [ ] / \ : ,
  • + *
  • Numbers may have the 0- (octal) or 0x- (hex) prefix.
  • + *
+ *

+ * Public Domain 2002 JSON.org + * @author JSON.org + * @version 0.1 + *

+ * Ported to C# by Are Bjolseth, teleplan.no + * TODO: + * 1. Implement Custom exceptions + * 2. Add indexer JSONObject[i] = object, and object = JSONObject[i]; + * 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"] + * 4. Add unit testing + * 5. Add log4net + */ +namespace Nii.JSON +{ + ///

+ /// + /// A JSONArray is an ordered sequence of values. Its external form is a string + /// wrapped in square brackets with commas between the values. The internal form + /// is an object having get() and opt() methods for accessing the values by + /// index, and put() methods for adding or replacing values. The values can be + /// any of these types: Boolean, JSONArray, JSONObject, Number, String, or the + /// JSONObject.NULL object. + /// + /// + /// The constructor can convert a JSON external form string into an + /// internal form Java object. The toString() method creates an external + /// form string. + /// + /// + /// A get() method returns a value if one can be found, and throws an exception + /// if one cannot be found. An opt() method returns a default value instead of + /// throwing an exception, and so is useful for obtaining optional values. + /// + /// + /// The generic get() and opt() methods return an object which you can cast or + /// query for type. There are also typed get() and opt() methods that do typing + /// checking and type coersion for you. + /// + /// + /// The texts produced by the toString() methods are very strict. + /// The constructors are more forgiving in the texts they will accept. + /// + /// + /// + /// An extra comma may appear just before the closing bracket. + /// Strings may be quoted with single quotes. + /// Strings do not need to be quoted at all if they do not contain leading + /// or trailing spaces, and if they do not contain any of these characters: + /// { } [ ] / \ : , + /// Numbers may have the 0- (octal) or 0x- (hex) prefix. + /// + /// + /// + /// Public Domain 2002 JSON.org + /// @author JSON.org + /// @version 0.1 + /// + /// Ported to C# by Are Bjolseth, teleplan.no + /// TODO: + /// 1. Implement Custom exceptions + /// 2. Add indexer JSONObject[i] = object, and object = JSONObject[i]; + /// 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"] + /// 4. Add unit testing + /// 5. Add log4net + /// 6. Make get/put methods private, to force use of indexer instead? + /// + public class JSONObject + { + /// + /// Make a Null object + /// JSONObject.NULL is equivalent to the value that JavaScript calls null, + /// whilst C#'s null is equivalent to the value that JavaScript calls undefined. + /// + public struct JSONNull + { + /* + public object clone() + { + return this; + } + */ + /* + public bool equals(object obj) + { + return (obj == null) || (obj == this); + } + */ + /// + /// Overriden to return "null" + /// + /// null + public override string ToString() + { + //return base.ToString (); + return "null"; + } + } + + ///The hash map where the JSONObject's properties are kept. + private Hashtable myHashMap; + + ///A shadow list of keys to enable access by sequence of insertion + private ArrayList myKeyIndexList; + + /// + /// It is sometimes more convenient and less ambiguous to have a NULL + /// object than to use C#'s null value. + /// JSONObject.NULL.toString() returns "null". + /// + public static readonly JSONNull NULL = new JSONNull(); + + + /// + /// Construct an empty JSONObject. + /// + public JSONObject() + { + myHashMap = new Hashtable(); + myKeyIndexList = new ArrayList(); + } + + /// + /// Construct a JSONObject from a JSONTokener. + /// + /// A JSONTokener object containing the source string. + public JSONObject(JSONTokener x) : this() + { + char c; + string key; + if (x.next() == '%') + { + x.unescape(); + } + x.back(); + if (x.nextClean() != '{') + { + throw new Exception("A JSONObject must begin with '{'"); + } + while (true) + { + c = x.nextClean(); + switch (c) + { + case (char)0: + throw new Exception("A JSONObject must end with '}'"); + case '}': + return; + default: + x.back(); + key = x.nextObject().ToString(); + break; + } + if (x.nextClean() != ':') + { + throw new Exception("Expected a ':' after a key"); + } + object obj = x.nextObject(); + myHashMap.Add(key, obj); + myKeyIndexList.Add(key); + switch (x.nextClean()) + { + case ',': + if (x.nextClean() == '}') + { + return; + } + x.back(); + break; + case '}': + return; + default: + throw new Exception("Expected a ',' or '}'"); + } + } + } + + + /// + /// Construct a JSONObject from a string. + /// + /// A string beginning with '{' and ending with '}'. + public JSONObject(string sJSON) : this(new JSONTokener(sJSON)) + { + + } + + /// + /// C# convenience method + /// + /// The Hashtable + public IDictionary getDictionary() + { + return myHashMap; + } + + // OMITTED - all put methods can be replaced by a indexer in C# + // - =================================================== + // public JSONObject put(String key, boolean value) + // public JSONObject put(String key, double value) + // public JSONObject put(String key, int value) + + /// + /// Put a key/value pair in the JSONObject. If the value is null, + /// then the key will be removed from the JSONObject if it is present. + /// + /// A key string. + /// + /// An object which is the value. It should be of one of these + /// types: Boolean, Double, Integer, JSONArray, JSONObject, String, or the + /// JSONObject.NULL object. + /// + /// JSONObject + public JSONObject put(string key, object val) + { + if (key == null) + { + throw new ArgumentNullException("key", "key cannot be null"); + } + if (val != null) + { + if (!myHashMap.ContainsKey(key)) + { + myHashMap.Add(key,val); + myKeyIndexList.Add(key); + } + else + { + myHashMap[key]=val; + } + } + else + { + remove(key); + } + return this; + } + + /// + /// Remove a object assosiateted with the given key + /// + /// + /// + public object remove(string key) + { + if (myHashMap.ContainsKey(key)) + { + // TODO - does it really work ??? + object obj = myHashMap[key]; + myHashMap.Remove(key); + myKeyIndexList.Remove(key); + return obj; + } + return null; + } + } +} diff --git a/old/libsecondlife-cs/JSON/JSONTokener.cs b/old/libsecondlife-cs/JSON/JSONTokener.cs new file mode 100644 index 00000000..ee77f670 --- /dev/null +++ b/old/libsecondlife-cs/JSON/JSONTokener.cs @@ -0,0 +1,340 @@ +using System; +using System.Text; +using System.Globalization; + +namespace Nii.JSON +{ + /// + /// + /// A JSONTokener takes a source string and extracts characters and tokens from + /// it. It is used by the JSONObject and JSONArray constructors to parse + /// JSON source strings. + /// + /// + /// Public Domain 2002 JSON.org + /// @author JSON.org + /// @version 0.1 + /// + /// Ported to C# by Are Bjolseth, teleplan.no + /// + /// + /// Implement Custom exceptions + /// Add unit testing + /// Add log4net + /// + /// + /// + public class JSONTokener + { + /// The index of the next character. + private int myIndex; + /// The source string being tokenized. + private string mySource; + + /// + /// Construct a JSONTokener from a string. + /// + /// A source string. + public JSONTokener(string s) + { + myIndex = 0; + mySource = s; + } + + /// + /// Back up one character. This provides a sort of lookahead capability, + /// so that you can test for a digit or letter before attempting to parse + /// the next number or identifier. + /// + public void back() + { + if (myIndex > 0) + myIndex -= 1; + } + + /// + /// Get the hex value of a character (base16). + /// + /// + /// A character between '0' and '9' or between 'A' and 'F' or + /// between 'a' and 'f'. + /// + /// An int between 0 and 15, or -1 if c was not a hex digit. + public static int dehexchar(char c) + { + if (c >= '0' && c <= '9') + { + return c - '0'; + } + if (c >= 'A' && c <= 'F') + { + return c + 10 - 'A'; + } + if (c >= 'a' && c <= 'f') + { + return c + 10 - 'a'; + } + return -1; + } + + /// + /// Determine if the source string still contains characters that next() can consume. + /// + /// true if not yet at the end of the source. + public bool more() + { + return myIndex < mySource.Length; + } + + /// + /// Get the next character in the source string. + /// + /// The next character, or 0 if past the end of the source string. + public char next() + { + char c = more() ? mySource[myIndex] : (char)0; + myIndex +=1; + return c; + } + + /// + /// Get the next n characters. + /// + /// The number of characters to take. + /// A string of n characters. + public string next(int n) + { + int i = myIndex; + int j = i + n; + if (j >= mySource.Length) + { + string msg = "Substring bounds error"; + throw (new Exception(msg)); + } + myIndex += n; + return mySource.Substring(i,j); + } + + /// + /// Get the next char in the string, skipping whitespace + /// and comments (slashslash and slashstar). + /// + /// A character, or 0 if there are no more characters. + public char nextClean() + { + while (true) + { + char c = next(); + if (c == '/') + { + switch (next()) + { + case '/': + do + { + c = next(); + } while (c != '\n' && c != '\r' && c != 0); + break; + case '*': + while (true) + { + c = next(); + if (c == 0) + { + throw (new Exception("Unclosed comment.")); + } + if (c == '*') + { + if (next() == '/') + { + break; + } + back(); + } + } + break; + default: + back(); + return '/'; + } + } + else if (c == 0 || c > ' ') + { + return c; + } + } + } + + /// + /// Return the characters up to the next close quote character. + /// Backslash processing is done. The formal JSON format does not + /// allow strings in single quotes, but an implementation is allowed to + /// accept them. + /// + /// The quoting character, either " or ' + /// A String. + public string nextString(char quote) + { + char c; + StringBuilder sb = new StringBuilder(); + while (true) + { + c = next(); + if ((c == 0x00) || (c == 0x0A) || (c == 0x0D)) + { + throw (new Exception("Unterminated string")); + } + // CTRL chars + if (c == '\\') + { + c = next(); + switch (c) + { + case 'b': //Backspace + sb.Append('\b'); + break; + case 't': //Horizontal tab + sb.Append('\t'); + break; + case 'n': //newline + sb.Append('\n'); + break; + case 'f': //Form feed + sb.Append('\f'); + break; + case 'r': // Carriage return + sb.Append('\r'); + break; + case 'u': + //sb.append((char)Integer.parseInt(next(4), 16)); // 16 == radix, ie. hex + int iascii = int.Parse(next(4),System.Globalization.NumberStyles.HexNumber); + sb.Append((char)iascii); + break; + default: + sb.Append(c); + break; + } + } + else + { + if (c == quote) + { + return sb.ToString(); + } + sb.Append(c); + } + }//END-while + } + + /// + /// Get the next value as object. The value can be a Boolean, Double, Integer, + /// JSONArray, JSONObject, or String, or the JSONObject.NULL object. + /// + /// An object. + public object nextObject() + { + char c = nextClean(); + string s; + + if (c == '"' || c == '\'') + { + return nextString(c); + } + // Object + if (c == '{') + { + back(); + return new JSONObject(this); + } + + // JSON Array + if (c == '[') + { + back(); + return new JSONArray(this); + } + + StringBuilder sb = new StringBuilder(); + + char b = c; + while (c >= ' ' && c != ':' && c != ',' && c != ']' && c != '}' && c != '/') + { + sb.Append(c); + c = next(); + } + back(); + + s = sb.ToString().Trim(); + if (s == "true") + return bool.Parse("true"); + if (s == "false") + return bool.Parse("false"); + if (s == "null") + return JSONObject.NULL; + + if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') + { + try + { + return Convert.ToInt32(s); + } + catch + { + } + try + { + return Convert.ToDouble(s, NumberFormatInfo.InvariantInfo); + } + catch + { + } + } + if (s == "") + { + throw (new Exception("Missing value")); + } + return s; + } + + /// + /// Unescape the source text. Convert %hh sequences to single characters, + /// and convert plus to space. There are Web transport systems that insist on + /// doing unnecessary URL encoding. This provides a way to undo it. + /// + public void unescape() + { + mySource = unescape(mySource); + } + + /// + /// Convert %hh sequences to single characters, and convert plus to space. + /// + /// A string that may contain plus and %hh sequences. + /// The unescaped string. + public static string unescape(string s) + { + int len = s.Length; + StringBuilder sb = new StringBuilder(); + for (int i=0; i < len; i++) + { + char c = s[i]; + if (c == '+') + { + c = ' '; + } + else if (c == '%' && (i + 2 < len)) + { + int d = dehexchar(s[i+1]); + int e = dehexchar(s[i+2]); + if (d >= 0 && e >= 0) + { + c = (char)(d*16 + e); + i += 2; + } + } + sb.Append(c); + } + return sb.ToString(); + } + } +} diff --git a/old/libsecondlife-cs/NetworkManager.cs b/old/libsecondlife-cs/NetworkManager.cs new file mode 100644 index 00000000..0a9b625b --- /dev/null +++ b/old/libsecondlife-cs/NetworkManager.cs @@ -0,0 +1,1305 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Text; +using System.Timers; +using System.Collections; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Security.Cryptography; +using Nwc.XmlRpc; +using Nii.JSON; + +namespace libsecondlife +{ + public delegate void PacketCallback(Packet packet, Simulator simulator); + public delegate void SimDisconnected(Simulator simulator, DisconnectType reason); + public delegate void Disconnected(DisconnectType reason, string message); + + public enum DisconnectType + { + ClientInitiated, + ServerInitiated, + NetworkTimeout + } + + /// + /// This exception is thrown whenever a network operation is attempted + /// without a network connection. + /// + public class NotConnectedException : ApplicationException { } + + internal class AcceptAllCertificatePolicy : ICertificatePolicy + { + public AcceptAllCertificatePolicy() + { + } + + public bool CheckValidationResult(ServicePoint sPoint, + System.Security.Cryptography.X509Certificates.X509Certificate cert, + WebRequest wRequest,int certProb) + { + // Always accept + return true; + } + } + + /// + /// Simulator is a wrapper for a network connection to a simulator and the + /// Region class representing the block of land in the metaverse. + /// + public class Simulator + { + /// + /// The Region class that this Simulator wraps + /// + public Region Region; + + /// + /// The ID number associated with this particular connection to the + /// simulator, used to emulate TCP connections. This is used + /// internally for packets that have a CircuitCode field. + /// + public uint CircuitCode + { + get { return circuitCode; } + } + + /// + /// The IP address and port of the server. + /// + public IPEndPoint IPEndPoint + { + get { return ipEndPoint; } + } + + /// + /// A boolean representing whether there is a working connection to the + /// simulator or not. + /// + public bool Connected + { + get { return connected; } + } + + /// + /// Used internally to track sim disconnections, do not modify this + /// variable. + /// + public bool DisconnectCandidate; + + private SecondLife Client; + private ProtocolManager Protocol; + private NetworkManager Network; + private Hashtable Callbacks; + private ushort Sequence; + private byte[] RecvBuffer; + private Mutex RecvBufferMutex = new Mutex(false, "RecvBufferMutex"); + private Socket Connection; + private AsyncCallback ReceivedData; + private Hashtable NeedAck; + private Mutex NeedAckMutex; + private SortedList Inbox; + private Mutex InboxMutex; + private bool connected; + private uint circuitCode; + private IPEndPoint ipEndPoint; + private EndPoint endPoint; + + public Simulator(SecondLife client, Hashtable callbacks, uint circuit, + IPAddress ip, int port) + { + Initialize(client, callbacks, circuit, ip, port); + } + + private void Initialize(SecondLife client, Hashtable callbacks, uint circuit, + IPAddress ip, int port) + { + Client = client; + Protocol = client.Protocol; + Network = client.Network; + Callbacks = callbacks; + Region = new Region(client); + circuitCode = circuit; + Sequence = 0; + RecvBuffer = new byte[2048]; + Connection = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + connected = false; + DisconnectCandidate = false; + + // Initialize the hashtable for reliable packets waiting on ACKs from the server + NeedAck = new Hashtable(); + + // Initialize the list of sequence numbers we've received so far + Inbox = new SortedList(); + + NeedAckMutex = new Mutex(false, "NeedAckMutex"); + InboxMutex = new Mutex(false, "InboxMutex"); + + Client.Log("Connecting to " + ip.ToString() + ":" + port, Helpers.LogLevel.Info); + + try + { + // Setup the callback + ReceivedData = new AsyncCallback(OnReceivedData); + + // Create an endpoint that we will be communicating with (need it in two + // types due to .NET weirdness) + ipEndPoint = new IPEndPoint(ip, port); + endPoint = (EndPoint)ipEndPoint; + + // Associate this simulator's socket with the given ip/port and start listening + Connection.Connect(endPoint); + Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null); + + // Send the UseCircuitCode packet to initiate the connection + Packet packet = Packets.Network.UseCircuitCode(Protocol, Network.AgentID, + Network.SessionID, CircuitCode); + + // Send the initial packet out + SendPacket(packet, true); + + // Track the current time for timeout purposes + int start = Environment.TickCount; + + while (true) + { + if (connected || Environment.TickCount - start > 5000) + { + return; + } + Thread.Sleep(10); + } + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + } + + public void Disconnect() + { + // Send the CloseCircuit notice + Packet packet = new Packet("CloseCircuit", Protocol, 8); + + try + { + Connection.Send(packet.Data); + } + catch (SocketException) + { + // There's a high probability of this failing if the network is + // disconnected, so don't even bother logging the error + } + + try + { + // Shut the socket communication down + Connection.Shutdown(SocketShutdown.Both); + } + catch (SocketException e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + + connected = false; + } + + public void SendPacket(Packet packet, bool incrementSequence) + { + byte[] buffer; + int bytes; + + if (!connected && packet.Layout.Name != "UseCircuitCode") + { + Client.Log("Trying to send a " + packet.Layout.Name + " packet when the socket is closed", + Helpers.LogLevel.Warning); + + throw new NotConnectedException(); + } + + if (incrementSequence) + { + // Set the sequence number here since we are manually serializing the packet + packet.Sequence = ++Sequence; + + if ((packet.Data[0] & Helpers.MSG_RELIABLE) != 0) + { + // Keep track of when this packet was sent out + packet.TickCount = Environment.TickCount; + + #region NeedAckMutex + NeedAckMutex.WaitOne(); + if (!NeedAck.ContainsKey(packet.Sequence)) + { + NeedAck.Add(packet.Sequence, packet); + } + else + { + Client.Log("Attempted to add a duplicate sequence number (" + + packet.Sequence + ") to the NeedAck hashtable for packet type " + + packet.Layout.Name, Helpers.LogLevel.Warning); + } + NeedAckMutex.ReleaseMutex(); + #endregion NeedAckMutex + } + } + + // Zerocode if needed + if ((packet.Data[0] & Helpers.MSG_ZEROCODED) != 0) + { + byte[] zeroBuffer = new byte[4096]; + bytes = Helpers.ZeroEncode(packet.Data, packet.Data.Length, zeroBuffer); + buffer = zeroBuffer; + } + else + { + // Normal packet, no zerocoding required + buffer = packet.Data; + bytes = buffer.Length; + } + + #region AppendACKS + // Append any ACKs that need to be sent out to this packet + /*if (AckOutbox.Count != 0 && incrementSequence && + packet.Layout.Name != "PacketAck" && + packet.Layout.Name != "LogoutRequest") + { + // Claim the mutex on the AckOutbox + #region AckOutboxMutex + AckOutboxMutex.WaitOne(); + + // Append each ACK needing to be sent out to this packet + foreach (uint ack in AckOutbox) + { + // FIXME: The ack must be little-endian, I don't think BitConverter will work + Array.Copy(BitConverter.GetBytes(ack), 0, buffer, bytes, 4); + bytes += 4; + } + + // Last byte is the number of ACKs + buffer[bytes] = (byte)AckOutbox.Count; + bytes += 1; + + AckOutbox.Clear(); + + // Release the mutex + AckOutboxMutex.ReleaseMutex(); + #endregion AckOutboxMutex + + // Set the flag that this packet has ACKs appended to it + buffer[0] += Helpers.MSG_APPENDED_ACKS; + }*/ + #endregion AppendACKS + + try + { + Connection.Send(buffer, bytes, SocketFlags.None); + } + catch (SocketException e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + } + + public void SendPacket(byte[] payload) + { + if (!connected) + { + throw new NotConnectedException(); + } + + try + { + Connection.Send(payload, payload.Length, SocketFlags.None); + } + catch (SocketException e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + } + + private void SendACK(uint id) + { + try + { + Packet packet = new Packet("PacketAck", Protocol, 13); + packet.Data[8] = 1; + Array.Copy(BitConverter.GetBytes(id), 0, packet.Data, 9, 4); + + // Set the sequence number + packet.Sequence = ++Sequence; + + // Bypass SendPacket and send the ACK directly + int numSent = Connection.Send(packet.Data); + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + } + + private void OnReceivedData(IAsyncResult result) + { + Packet packet = null; + int numBytes; + + // If we're receiving data the sim connection is open + connected = true; + + #region RecvBufferMutex + try + { + RecvBufferMutex.WaitOne(); + + // Update the disconnect flag so this sim doesn't time out + DisconnectCandidate = false; + + // Retrieve the incoming packet + try + { + numBytes = Connection.EndReceiveFrom(result, ref endPoint); + } + catch (SocketException) + { + Client.Log("Socket error, shutting down " + this.Region.Name + + " (" + endPoint.ToString() + ")", Helpers.LogLevel.Warning); + + connected = false; + RecvBufferMutex.ReleaseMutex(); + Network.DisconnectSim(this); + + return; + } + + if ((RecvBuffer[0] & Helpers.MSG_APPENDED_ACKS) != 0) + { + // Grab the ACKs that are appended to this packet + byte numAcks = RecvBuffer[numBytes - 1]; + + Client.Log("Found " + numAcks + " appended acks", Helpers.LogLevel.Info); + + #region NeedAckMutex + try + { + NeedAckMutex.WaitOne(); + + for (int i = 1; i <= numAcks; ++i) + { + ushort ack = (ushort)BitConverter.ToUInt32(RecvBuffer, (numBytes - i * 4) - 1); + NeedAck.Remove(ack); + } + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + NeedAckMutex.ReleaseMutex(); + } + #endregion NeedAckMutex + + // Adjust the packet length + numBytes = (numBytes - numAcks * 4) - 1; + } + + // Zerodecode this packet if necessary + // TODO: It would be nice if the Packet constructor transparently handled zerodecoding + if ((RecvBuffer[0] & Helpers.MSG_ZEROCODED) != 0) + { + // Allocate a temporary buffer for the zerocoded packet + byte[] zeroBuffer = new byte[4096]; + int zeroBytes = Helpers.ZeroDecode(RecvBuffer, numBytes, zeroBuffer); + numBytes = zeroBytes; + packet = new Packet(zeroBuffer, numBytes, Protocol); + } + else + { + // Create the packet object from our byte array + packet = new Packet(RecvBuffer, numBytes, Protocol); + } + + // Start listening again since we're done with RecvBuffer + Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null); + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + RecvBufferMutex.ReleaseMutex(); + } + #endregion RecvBufferMutex + + // Fail-safe checks + if (packet == null) + { + Client.Log("OnReceivedData() fail-safe reached, exiting", Helpers.LogLevel.Warning); + return; + } + else if (packet.Layout.Name == "") + { + // TODO: Add a packet dump function to Packet and dump the raw data here + Client.Log("Received an unrecognized packet", Helpers.LogLevel.Warning); + return; + } + + // Track the sequence number for this packet if it's marked as reliable + if ((packet.Data[0] & Helpers.MSG_RELIABLE) != 0) + { + // Send the ACK for this packet + // TODO: If we can make it stable, go back to the periodic ACK system + SendACK((uint)packet.Sequence); + + // Check if we already received this packet + #region InboxMutex + try + { + InboxMutex.WaitOne(); + + if (Inbox.Contains(packet.Sequence)) + { + Client.Log("Received a duplicate " + packet.Layout.Name + ", sequence=" + + packet.Sequence + ", resent=" + + (((packet.Data[0] & Helpers.MSG_RESENT) != 0) ? "Yes" : "No"), + Helpers.LogLevel.Info); + + // Avoid firing a callback twice for the same packet + return; + } + else + { + Inbox.Add(packet.Sequence, packet.Sequence); + } + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + InboxMutex.ReleaseMutex(); + } + #endregion InboxMutex + } + + if (packet.Layout.Name == "PacketAck") + { + // PacketAck is handled directly instead of using a callback to simplify access to + // the NeedAck hashtable and its mutex + ArrayList blocks = packet.Blocks(); + + #region NeedAckMutex + try + { + NeedAckMutex.WaitOne(); + foreach (Block block in blocks) + { + Field ID = (Field)block.Fields[0]; + NeedAck.Remove((ushort)(uint)ID.Data); + } + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + NeedAckMutex.ReleaseMutex(); + } + #endregion NeedAckMutex + } + + try + { + if (Callbacks.ContainsKey(packet.Layout.Name)) + { + ArrayList callbackArray = (ArrayList)Callbacks[packet.Layout.Name]; + + // Fire any registered callbacks + foreach (PacketCallback callback in callbackArray) + { + if (callback != null) + { + callback(packet, this); + } + } + } + else if (Callbacks.ContainsKey("Default")) + { + ArrayList callbackArray = (ArrayList)Callbacks["Default"]; + + // Fire any registered callbacks + foreach (PacketCallback callback in callbackArray) + { + if (callback != null) + { + callback(packet, this); + } + } + } + } + catch (Exception e) + { + Client.Log("Caught an exception in a packet callback: " + e.ToString(), Helpers.LogLevel.Warning); + } + + // Erase this packet from memory + packet = null; + } + } + + /// + /// NetworkManager is responsible for managing the network layer of + /// libsecondlife. It tracks all the server connections, serializes + /// outgoing traffic and deserializes incoming traffic, and provides + /// instances of delegates for network-related events. + /// + public class NetworkManager + { + /// + /// The permanent UUID for the logged in avatar + /// + public LLUUID AgentID; + + /// + /// A temporary UUID assigned to this session, used for secure + /// transactions + /// + public LLUUID SessionID; + + /// + /// A string holding a descriptive error on login failure, empty + /// otherwise + /// + public string LoginError; + + /// + /// The simulator that the logged in avatar is currently occupying + /// + public Simulator CurrentSim; + + /// + /// The complete hashtable of all the login values returned by the + /// RPC login server, converted to native data types wherever possible + /// + public Hashtable LoginValues; + + /// + /// Shows whether the network layer is logged in to the grid or not + /// + public bool Connected + { + get + { + return connected; + } + } + + /// + /// An event for the connection to a simulator other than the currently + /// occupied one disconnecting + /// + public SimDisconnected OnSimDisconnected; + + /// + /// An event for being logged out either through client request, server + /// forced, or network error + /// + public Disconnected OnDisconnected; + + private Hashtable Callbacks; + private SecondLife Client; + private ProtocolManager Protocol; + private ArrayList Simulators; + private Mutex SimulatorsMutex; + private System.Timers.Timer DisconnectTimer; + private bool connected; + + public NetworkManager(SecondLife client, ProtocolManager protocol) + { + Client = client; + Protocol = protocol; + Simulators = new ArrayList(); + SimulatorsMutex = new Mutex(true, "SimulatorsMutex"); + Callbacks = new Hashtable(); + CurrentSim = null; + LoginValues = null; + + // Register the internal callbacks + RegisterCallback("RegionHandshake", new PacketCallback(RegionHandshakeHandler)); + RegisterCallback("StartPingCheck", new PacketCallback(StartPingCheckHandler)); + RegisterCallback("ParcelOverlay", new PacketCallback(ParcelOverlayHandler)); + RegisterCallback("EnableSimulator", new PacketCallback(EnableSimulatorHandler)); + RegisterCallback("KickUser", new PacketCallback(KickUserHandler)); + + // Disconnect a sim if no network traffic has been received for 15 seconds + DisconnectTimer = new System.Timers.Timer(15000); + DisconnectTimer.Elapsed += new ElapsedEventHandler(DisconnectTimer_Elapsed); + } + + public void RegisterCallback(string packet, PacketCallback callback) + { + if (!Callbacks.ContainsKey(packet)) + { + Callbacks[packet] = new ArrayList(); + } + + ArrayList callbackArray = (ArrayList)Callbacks[packet]; + callbackArray.Add(callback); + } + + public void UnregisterCallback(string packet, PacketCallback callback) + { + if (!Callbacks.ContainsKey(packet)) + { + Client.Log("Trying to unregister a callback for packet " + packet + + " when no callbacks are setup for that packet", Helpers.LogLevel.Info); + return; + } + + ArrayList callbackArray = (ArrayList)Callbacks[packet]; + + if (callbackArray.Contains(callback)) + { + callbackArray.Remove(callback); + } + else + { + Client.Log("Trying to unregister a non-existant callback for packet " + packet, + Helpers.LogLevel.Info); + } + } + + public void SendPacket(Packet packet) + { + if (CurrentSim != null) + { + CurrentSim.SendPacket(packet, true); + } + else + { + throw new NotConnectedException(); + } + } + + public void SendPacket(Packet packet, Simulator simulator) + { + simulator.SendPacket(packet, true); + } + + public void SendPacket(byte[] payload) + { + if (CurrentSim != null) + { + CurrentSim.SendPacket(payload); + } + else + { + throw new NotConnectedException(); + } + } + + public static Hashtable DefaultLoginValues(string firstName, string lastName, string password, + string userAgent, string author) + { + return DefaultLoginValues(firstName, lastName, password, "00:00:00:00:00:00", "last", + 1, 50, 50, 50, "Win", "0", userAgent, author); + } + + public static Hashtable DefaultLoginValues(string firstName, string lastName, string password, string mac, + string startLocation, int major, int minor, int patch, int build, string platform, string viewerDigest, + string userAgent, string author) + { + Hashtable values = new Hashtable(); + + // Generate an MD5 hash of the password + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] hash = md5.ComputeHash(Encoding.ASCII.GetBytes(password)); + StringBuilder passwordDigest = new StringBuilder(); + // Convert the hash to a hex string + foreach(byte b in hash) + { + passwordDigest.AppendFormat("{0:x2}", b); + } + + values["first"] = firstName; + values["last"] = lastName; + values["passwd"] = "$1$" + passwordDigest; + values["start"] = startLocation; + values["major"] = major; + values["minor"] = minor; + values["patch"] = patch; + values["build"] = build; + values["platform"] = platform; + values["mac"] = mac; + values["agree_to_tos"] = "true"; + values["viewer_digest"] = viewerDigest; + values["user-agent"] = userAgent + " (" + Helpers.VERSION + ")"; + values["author"] = author; + + return values; + } + + public bool Login(Hashtable loginParams) + { + return Login(loginParams, "https://login.agni.lindenlab.com/cgi-bin/login.cgi"); + } + + public bool Login(Hashtable loginParams, string url) + { + XmlRpcResponse result; + XmlRpcRequest xmlrpc = new XmlRpcRequest(); + xmlrpc.MethodName = "login_to_simulator"; + xmlrpc.Params.Clear(); + xmlrpc.Params.Add(loginParams); + + try + { + result = (XmlRpcResponse)xmlrpc.Send(url); + } + catch (Exception e) + { + LoginError = e.Message; + LoginValues = null; + return false; + } + + if (result.IsFault) + { + Client.Log("Fault " + result.FaultCode + ": " + result.FaultString, Helpers.LogLevel.Error); + LoginError = "Fault " + result.FaultCode + ": " + result.FaultString; + LoginValues = null; + return false; + } + + LoginValues = (Hashtable)result.Value; + + if ((string)LoginValues["login"] == "false") + { + LoginError = LoginValues["reason"] + ": " + LoginValues["message"]; + return false; + } + + System.Text.RegularExpressions.Regex LLSDtoJSON = + new System.Text.RegularExpressions.Regex(@"('|r([0-9])|r(\-))"); + string json; + IDictionary jsonObject = null; + LLVector3d vector = null; + LLVector3d posVector = null; + LLVector3d lookatVector = null; + U64 regionHandle = null; + + if (LoginValues.Contains("look_at")) + { + // Replace LLSD variables with object representations + + // Convert LLSD string to JSON + json = "{vector:" + LLSDtoJSON.Replace((string)LoginValues["look_at"], "$2") + "}"; + + // Convert JSON string to a JSON object + jsonObject = JsonFacade.fromJSON(json); + JSONArray jsonVector = (JSONArray)jsonObject["vector"]; + + // Convert the JSON object to an LLVector3d + vector = new LLVector3d(Convert.ToDouble(jsonVector[0]), + Convert.ToDouble(jsonVector[1]), Convert.ToDouble(jsonVector[2])); + + LoginValues["look_at"] = vector; + } + + Hashtable home = null; + + if (LoginValues.Contains("home")) + { + // Convert LLSD string to JSON + json = LLSDtoJSON.Replace((string)LoginValues["home"], "$2"); + + // Convert JSON string to an object + jsonObject = JsonFacade.fromJSON(json); + + // Create the position vector + JSONArray array = (JSONArray)jsonObject["position"]; + posVector = new LLVector3d(Convert.ToDouble(array[0]), Convert.ToDouble(array[1]), + Convert.ToDouble(array[2])); + + // Create the look_at vector + array = (JSONArray)jsonObject["look_at"]; + lookatVector = new LLVector3d(Convert.ToDouble(array[0]), + Convert.ToDouble(array[1]), Convert.ToDouble(array[2])); + + // Create the regionhandle U64 + array = (JSONArray)jsonObject["region_handle"]; + regionHandle = new U64((int)array[0], (int)array[1]); + + // Create a hashtable to hold the home values + home = new Hashtable(); + home["position"] = posVector; + home["look_at"] = lookatVector; + home["region_handle"] = regionHandle; + + LoginValues["home"] = home; + } + + AgentID = new LLUUID((string)LoginValues["agent_id"]); + SessionID = new LLUUID((string)LoginValues["session_id"]); + Client.Avatar.ID = new LLUUID((string)LoginValues["agent_id"]); + Client.Avatar.FirstName = (string)LoginValues["first_name"]; + Client.Avatar.LastName = (string)LoginValues["last_name"]; + Client.Avatar.LookAt = vector; + Client.Avatar.HomePosition = posVector; + Client.Avatar.HomeLookAt = lookatVector; + uint circuitCode = (uint)(int)LoginValues["circuit_code"]; + + // Connect to the sim given in the login reply + Simulator simulator = new Simulator(Client, this.Callbacks, circuitCode, + IPAddress.Parse((string)LoginValues["sim_ip"]), (int)LoginValues["sim_port"]); + if (!simulator.Connected) + { + return false; + } + + // Set the current region + Client.CurrentRegion = simulator.Region; + + // Simulator is successfully connected, add it to the list and set it as default + Simulators.Add(simulator); + + CurrentSim = simulator; + + // Move our agent in to the sim to complete the connection + Packet packet = Packets.Sim.CompleteAgentMovement(Protocol, AgentID, SessionID, circuitCode); + SendPacket(packet, simulator); + + DisconnectTimer.Start(); + connected = true; + return true; + } + + public Simulator Connect(IPAddress ip, ushort port, uint circuitCode, bool setDefault) + { + Simulator simulator = new Simulator(Client, this.Callbacks, circuitCode, ip, (int)port); + + if (!simulator.Connected) + { + simulator = null; + return null; + } + + #region SimulatorsMutex + try + { + SimulatorsMutex.WaitOne(); + Simulators.Add(simulator); + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + SimulatorsMutex.ReleaseMutex(); + } + #endregion SimulatorsMutex + + if (setDefault) + { + CurrentSim = simulator; + } + + DisconnectTimer.Start(); + connected = true; + return simulator; + } + + public void Logout() + { + // This will catch a Logout when the client is not logged in + if (CurrentSim == null) + { + throw new NotConnectedException(); + } + + DisconnectTimer.Stop(); + connected = false; + + // Send a logout request to the current sim + Packet packet = Packets.Network.LogoutRequest(Protocol, AgentID, SessionID); + CurrentSim.SendPacket(packet, true); + + // TODO: We should probably check if the server actually received the logout request + + // Shutdown the network layer + Shutdown(); + + if (OnDisconnected != null) + { + OnDisconnected(DisconnectType.ClientInitiated, ""); + } + } + + public void DisconnectSim(Simulator sim) + { + sim.Disconnect(); + + // Fire the SimDisconnected event if a handler is registered + if (OnSimDisconnected != null) + { + OnSimDisconnected(sim, DisconnectType.NetworkTimeout); + } + + #region SimulatorsMutex + try + { + SimulatorsMutex.WaitOne(); + Simulators.Remove(sim); + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + SimulatorsMutex.ReleaseMutex(); + } + #endregion SimulatorsMutex + } + + /// + /// Shutdown will disconnect all the sims except for the current sim + /// first, and then kill the connection to CurrentSim. + /// + private void Shutdown() + { + #region SimulatorsMutex + try + { + SimulatorsMutex.WaitOne(); + + // Disconnect all simulators except the current one + foreach (Simulator simulator in Simulators) + { + // Don't disconnect the current sim, we'll use LogoutRequest for that + if (simulator != CurrentSim) + { + simulator.Disconnect(); + + // Fire the SimDisconnected event if a handler is registered + if (OnSimDisconnected != null) + { + OnSimDisconnected(simulator, DisconnectType.NetworkTimeout); + } + } + } + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + Simulators.Clear(); + SimulatorsMutex.ReleaseMutex(); + } + #endregion SimulatorsMutex + + CurrentSim.Disconnect(); + CurrentSim = null; + } + + private void DisconnectTimer_Elapsed(object sender, ElapsedEventArgs ev) + { + #region SimulatorsMutex + try + { + SimulatorsMutex.WaitOne(); + + Beginning: + + foreach (Simulator sim in Simulators) + { + if (sim.DisconnectCandidate == true) + { + if (sim == CurrentSim) + { + Client.Log("Network timeout for the current simulator (" + + sim.Region.Name + "), logging out", Helpers.LogLevel.Warning); + + DisconnectTimer.Stop(); + connected = false; + + // Shutdown the network layer + Shutdown(); + + if (OnDisconnected != null) + { + OnDisconnected(DisconnectType.NetworkTimeout, ""); + } + + // We're completely logged out and shut down, leave this function + return; + } + else + { + // This sim hasn't received any network traffic since the + // timer last elapsed, consider it disconnected + Client.Log("Network timeout for simulator " + sim.Region.Name + + ", disconnecting", Helpers.LogLevel.Warning); + + SimulatorsMutex.ReleaseMutex(); + DisconnectSim(sim); + SimulatorsMutex.WaitOne(); + + // Reset the iterator since we removed an element + goto Beginning; + } + } + else + { + sim.DisconnectCandidate = true; + } + } + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + finally + { + SimulatorsMutex.ReleaseMutex(); + } + #endregion SimulatorsMutex + } + + private void StartPingCheckHandler(Packet packet, Simulator simulator) + { + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "PingID") + { + // Respond to the ping request + Packet pingPacket = Packets.Network.CompletePingCheck(Protocol, (byte)field.Data); + SendPacket(pingPacket, simulator); + return; + } + } + } + } + + private void RegionHandshakeHandler(Packet packet, Simulator simulator) + { + try + { + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "TerrainHeightRange00") + { + simulator.Region.TerrainHeightRange00 = (float)field.Data; + } + else if (field.Layout.Name == "TerrainHeightRange01") + { + simulator.Region.TerrainHeightRange01 = (float)field.Data; + } + else if (field.Layout.Name == "TerrainHeightRange10") + { + simulator.Region.TerrainHeightRange10 = (float)field.Data; + } + else if (field.Layout.Name == "TerrainHeightRange11") + { + simulator.Region.TerrainHeightRange11 = (float)field.Data; + } + else if (field.Layout.Name == "TerrainStartHeight00") + { + simulator.Region.TerrainStartHeight00 = (float)field.Data; + } + else if (field.Layout.Name == "TerrainStartHeight01") + { + simulator.Region.TerrainStartHeight01 = (float)field.Data; + } + else if (field.Layout.Name == "TerrainStartHeight10") + { + simulator.Region.TerrainStartHeight10 = (float)field.Data; + } + else if (field.Layout.Name == "TerrainStartHeight11") + { + simulator.Region.TerrainStartHeight11 = (float)field.Data; + } + else if (field.Layout.Name == "WaterHeight") + { + simulator.Region.WaterHeight = (float)field.Data; + } + else if (field.Layout.Name == "SimOwner") + { + simulator.Region.SimOwner = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainBase0") + { + simulator.Region.TerrainBase0 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainBase1") + { + simulator.Region.TerrainBase1 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainBase2") + { + simulator.Region.TerrainBase2 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainBase3") + { + simulator.Region.TerrainBase3 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainDetail0") + { + simulator.Region.TerrainDetail0 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainDetail1") + { + simulator.Region.TerrainDetail1 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainDetail2") + { + simulator.Region.TerrainDetail2 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TerrainDetail3") + { + simulator.Region.TerrainDetail3 = (LLUUID)field.Data; + } + else if (field.Layout.Name == "IsEstateManager") + { + simulator.Region.IsEstateManager = (bool)field.Data; + } + else if (field.Layout.Name == "SimName") + { + byte[] byteArray = (byte[])field.Data; + simulator.Region.Name = System.Text.Encoding.UTF8.GetString(byteArray, 0, byteArray.Length).Replace("\0", ""); + } + else if (field.Layout.Name == "CacheID") + { + simulator.Region.ID = (LLUUID)field.Data; + } + } + } + + Client.Log("Received a region handshake for " + simulator.Region.Name, Helpers.LogLevel.Info); + + // Send a RegionHandshakeReply + Packet replyPacket = new Packet("RegionHandshakeReply", Protocol, 12); + SendPacket(replyPacket, simulator); + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Warning); + } + } + + private void ParcelOverlayHandler(Packet packet, Simulator simulator) + { + int sequenceID = -1; + byte[] byteArray = null; + + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "SequenceID") + { + sequenceID = (int)field.Data; + } + else if (field.Layout.Name == "Data") + { + byteArray = (byte[])field.Data; + if (byteArray.Length != 1024) + { + Client.Log("Received a parcel overlay packet with " + byteArray.Length + " bytes", + Helpers.LogLevel.Error); + } + } + } + } + + if (sequenceID >= 0 && sequenceID <= 3) + { + Array.Copy(byteArray, 0, simulator.Region.ParcelOverlay, sequenceID * 1024, 1024); + simulator.Region.ParcelOverlaysReceived++; + + if (simulator.Region.ParcelOverlaysReceived > 3) + { + //simulator.Region.ParcelOverlaysReceived = 0; + Client.Log("Finished building the " + simulator.Region.Name + " parcel overlay", + Helpers.LogLevel.Info); + } + } + else + { + Client.Log("Parcel overlay with sequence ID of " + sequenceID + " received from " + + simulator.Region.Name, Helpers.LogLevel.Warning); + } + } + + private void EnableSimulatorHandler(Packet packet, Simulator simulator) + { + // TODO: Actually connect to the simulator + + // TODO: Sending ConfirmEnableSimulator completely screws things up. :-? + + // Respond to the simulator connection request + //Packet replyPacket = Packets.Network.ConfirmEnableSimulator(Protocol, AgentID, SessionID); + //SendPacket(replyPacket, circuit); + } + + private void KickUserHandler(Packet packet, Simulator simulator) + { + string message = ""; + + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "Reason") + { + message = Helpers.FieldToString(field.Data); + } + } + } + + // Shutdown the network layer + Shutdown(); + + if (OnDisconnected != null) + { + OnDisconnected(DisconnectType.ServerInitiated, message); + } + } + } +} diff --git a/old/libsecondlife-cs/ObjectManager.cs b/old/libsecondlife-cs/ObjectManager.cs new file mode 100644 index 00000000..9f713245 --- /dev/null +++ b/old/libsecondlife-cs/ObjectManager.cs @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife +{ + public delegate void NewPrimCallback(Simulator simulator, PrimObject prim, U64 regionHandle, ushort timeDilation); + public delegate void NewAvatarCallback(Simulator simulator, Avatar avatar, U64 regionHandle, ushort timeDilation); + public delegate void PrimMovedCallback(Simulator simulator, PrimUpdate prim, U64 regionHandle, ushort timeDilation); + public delegate void AvatarMovedCallback(Simulator simulator, AvatarUpdate avatar, U64 regionHandle, ushort timeDilation); + + /// + /// Contains all of the variables sent in an object update packet for a + /// prim object. Used to track position and movement of prims. + /// + public struct PrimUpdate + { + public uint LocalID; + public byte State; + public LLVector3 Position; + public LLVector3 Velocity; + public LLVector3 Acceleration; + public LLQuaternion Rotation; + public LLVector3 RotationVelocity; + } + + /// + /// Contains all of the variables sent in an object update packet for an + /// avatar. Used to track position and movement of avatars. + /// + public struct AvatarUpdate + { + public uint LocalID; + public byte State; + public LLVector4 CollisionPlane; + public LLVector3 Position; + public LLVector3 Velocity; + public LLVector3 Acceleration; + public LLQuaternion Rotation; + public LLVector3 RotationVelocity; + } + + /// + /// Handles all network traffic related to prims and avatar positions and + /// movement. + /// + public class ObjectManager + { + /// + /// This event will be raised for every ObjectUpdate block that + /// contains a new prim. Depending on the circumstances a client could + /// receive two or more of these events for the same object, if you + /// or the object left the current sim and returned for example. Client + /// applications are responsible for tracking and storing objects. + /// + public event NewPrimCallback OnNewPrim; + + /// + /// This event will be raised for every ObjectUpdate block that + /// contains a new avatar. Depending on the circumstances a client + /// could receive two or more of these events for the same avatar, if + /// you or the other avatar left the current sim and returned for + /// example. Client applications are responsible for tracking and + /// storing objects. + /// + public event NewAvatarCallback OnNewAvatar; + + /// + /// This event will be raised when a prim movement packet is received, + /// containing the updated position, rotation, and movement-related + /// vectors. + /// + public event PrimMovedCallback OnPrimMoved; + + /// + /// This event will be raised when an avatar movement packet is + /// received, containing the updated position, rotation, and + /// movement-related vectors. + /// + public event AvatarMovedCallback OnAvatarMoved; + + protected SecondLife Client; + + public ObjectManager(SecondLife client) + { + Client = client; + + Client.Network.RegisterCallback("ObjectUpdate", new PacketCallback(UpdateHandler)); + Client.Network.RegisterCallback("ImprovedTerseObjectUpdate", new PacketCallback(TerseUpdateHandler)); + Client.Network.RegisterCallback("ObjectUpdateCompressed", new PacketCallback(CompressedUpdateHandler)); + Client.Network.RegisterCallback("ObjectUpdateCached", new PacketCallback(CachedUpdateHandler)); + } + + private void ParseAvName(string name, ref string firstName, ref string lastName, ref string groupName) + { + string[] lines = name.Split('\n'); + + foreach (string line in lines) + { + if (line.Substring(0, 19) == "Title STRING RW SV ") + { + groupName = line.Substring(19); + } + else if (line.Substring(0, 23) == "FirstName STRING RW SV ") + { + firstName = line.Substring(23); + } + else if (line.Substring(0, 22) == "LastName STRING RW SV ") + { + lastName = line.Substring(22); + } + else + { + Client.Log("Unhandled line in an avatar name: " + line, Helpers.LogLevel.Warning); + } + } + } + + private void UpdateHandler(Packet packet, Simulator simulator) + { + U64 regionHandle = null; + ushort timeDilation = 0; + + foreach (Block block in packet.Blocks()) + { + Avatar avatar = null; + PrimObject prim = new PrimObject(); + + foreach (Field field in block.Fields) + { + switch (field.Layout.Name) + { + case "ID": + prim.LocalID = (UInt32)field.Data; + break; + case "State": + prim.State = (byte)field.Data; + break; + case "FullID": + prim.ID = (LLUUID)field.Data; + break; + case "ParentID": + // Linked objects? + break; + case "OwnerID": + // Sound-related + break; + case "Material": + prim.Material = (byte)(field.Data); + break; + case "PathCurve": + prim.PathCurve = (byte)field.Data; + break; + case "ProfileCurve": + prim.ProfileCurve = (byte)field.Data; + break; + case "PathBegin": + prim.PathBegin = PrimObject.PathBeginFloat((byte)field.Data); + break; + case "PathEnd": + prim.PathEnd = PrimObject.PathEndFloat((byte)field.Data); + break; + case "PathScaleX": + prim.PathScaleX = PrimObject.PathScaleFloat((byte)field.Data); + break; + case "PathScaleY": + prim.PathScaleY = PrimObject.PathScaleFloat((byte)field.Data); + break; + case "PathShearX": + prim.PathShearX = PrimObject.PathShearFloat((byte)field.Data); + break; + case "PathShearY": + prim.PathShearY = PrimObject.PathShearFloat((byte)field.Data); + break; + case "PathTwist": + prim.PathTwist = PrimObject.PathTwistFloat((sbyte)field.Data); + break; + case "PathTwistBegin": + prim.PathTwistBegin = PrimObject.PathTwistFloat((sbyte)field.Data); + break; + case "PathRadiusOffset": + prim.PathRadiusOffset = PrimObject.PathRadiusOffsetFloat((sbyte)field.Data); + break; + case "PathTaperX": + prim.PathTaperX = PrimObject.PathTaperFloat((byte)(sbyte)field.Data); + break; + case "PathTaperY": + prim.PathTaperY = PrimObject.PathTaperFloat((byte)(sbyte)field.Data); + break; + case "PathRevolutions": + prim.PathRevolutions = PrimObject.PathRevolutionsFloat((byte)field.Data); + break; + case "PathSkew": + prim.PathSkew = PrimObject.PathSkewFloat((byte)(sbyte)field.Data); + break; + case "ProfileBegin": + prim.ProfileBegin = PrimObject.ProfileBeginFloat((byte)field.Data); + break; + case "ProfileEnd": + prim.ProfileEnd = PrimObject.ProfileEndFloat((byte)field.Data); + break; + case "ProfileHollow": + prim.ProfileHollow = (byte)field.Data; + break; + case "NameValue": + //Console.WriteLine("[debug] Name: " + Helpers.FieldToString(field.Data)); + prim.Name = Helpers.FieldToString(field.Data); + break; + case "Data": + // ? + break; + case "Text": + // Hovering text + break; + case "TextColor": + // LLColor4U of the hovering text + break; + case "MediaURL": + // Quicktime stream + //Client.Log("MediaURL: " + Helpers.FieldToString(field.Data), Helpers.LogLevel.Info); + break; + case "TextureEntry": + // TODO: Multi-texture support + byte[] bytes = (byte[])field.Data; + if (bytes.Length >= 16) + { + prim.Texture = new LLUUID(bytes, 0); + } + else + { + prim.Texture = new LLUUID(); + } + break; + case "TextureAnim": + // Not sure how this works + break; + case "JointType": + // ? + break; + case "JointPivot": + // ? + break; + case "JointAxisOrAnchor": + // ? + break; + case "PCode": + // ? + break; + case "PSBlock": + // Particle system related + break; + case "ExtraParams": + // ? + break; + case "Scale": + prim.Scale = (LLVector3)field.Data; + break; + case "Flags": + // ? + break; + case "UpdateFlags": + // ? + break; + case "CRC": + // We could optionally verify this on the client side + break; + case "ClickAction": + // + break; + case "Gain": + // Sound-related + break; + case "Sound": + // Sound-related + break; + case "Radius": + // Sound-related + break; + case "ObjectData": + byte[] data = (byte[])field.Data; + if (data.Length == 60) + { + prim.Position = new LLVector3(data, 0); + prim.Rotation = new LLQuaternion(data, 36); + // Calculate the quaternion W value from the given X/Y/Z + float xyzsum = 1.0F - + prim.Rotation.X * prim.Rotation.X - + prim.Rotation.Y * prim.Rotation.Y - + prim.Rotation.Z * prim.Rotation.Z; + prim.Rotation.S = (xyzsum > 0.0F) ? (float)Math.Sqrt(xyzsum) : 0.0F; + // TODO: Parse the rest of the fields + } + else if (data.Length == 76) + { + avatar = new Avatar(); + + //avatar.CollisionPlane = new LLQuaternion(data, 0); + avatar.Position = new LLVector3(data, 16); + avatar.Rotation = new LLQuaternion(data, 52); + float xyzsum = 1.0F - + avatar.Rotation.X * avatar.Rotation.X - + avatar.Rotation.Y * avatar.Rotation.Y - + avatar.Rotation.Z * avatar.Rotation.Z; + avatar.Rotation.S = (xyzsum > 0.0F) ? (float)Math.Sqrt(xyzsum) : 0.0F; + } + else + { + Client.Log("Unhandled ObjectData:\n" + field.ToString(), Helpers.LogLevel.Warning); + } + break; + case "TimeDilation": + timeDilation = (ushort)field.Data; + break; + case "RegionHandle": + regionHandle = (U64)field.Data; + break; + default: + Client.Log("ObjectUpdate field not handled: " + field.Layout.Name + " " + + field.Data.GetType().ToString(), Helpers.LogLevel.Info); + break; + } + } + + // Parse the NameValue to see if this is actually an avatar + if (prim.LocalID != 0) + { + if (avatar != null) + { + string FirstName = ""; + string LastName = ""; + string GroupName = ""; + + // Get the individual components of the avatar name + ParseAvName(prim.Name, ref FirstName, ref LastName, ref GroupName); + + avatar.ID = prim.ID; + avatar.LocalID = prim.LocalID; + avatar.Name = FirstName + " " + LastName; + avatar.GroupName = GroupName; + avatar.Online = true; + avatar.Position = prim.Position; + avatar.Rotation = prim.Rotation; + // TODO: Look up the region by regionHandle instead + avatar.CurrentRegion = simulator.Region; + + prim = null; + + // Is this our avatar? Update the position + if (FirstName == Client.Avatar.FirstName && LastName == Client.Avatar.LastName) + { + // Update our avatar + Client.Avatar.LocalID = avatar.LocalID; + Client.Avatar.Position = avatar.Position; + Client.Avatar.Rotation = avatar.Rotation; + } + else + { + Client.AddAvatar(avatar); + + // If an event handler is registered call it + if (OnNewAvatar != null) + { + OnNewAvatar(simulator, avatar, regionHandle, timeDilation); + } + } + } + else if (prim != null) + { + // If an event handler is registered call it + if (OnNewPrim != null) + { + OnNewPrim(simulator, prim, regionHandle, timeDilation); + } + } + } + } + } + + private void TerseUpdateHandler(Packet packet, Simulator simulator) + { + U64 regionHandle = null; + ushort timeDilation = 0; + bool avatar = false; + int i; + byte[] data; + uint localid = 0; + byte state = 0; + float x, y, z, s; + LLVector4 CollisionPlane = null; + LLVector3 Position = null, Velocity = null, Acceleration = null, RotationVelocity = null; + LLQuaternion Rotation = null; + + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + switch (field.Layout.Name) + { + case "Data": + i = 0; + data = (byte[])field.Data; + + // Region ID + localid = (uint)(data[i] + (data[i + 1] << 8) + (data[i + 2] << 16) + (data[i + 3] << 24)); + i += 4; + + // Object state + state = data[i++]; + + // Avatar boolean + avatar = Convert.ToBoolean(data[i]); + i++; + + if (avatar) + { + CollisionPlane = new LLVector4(data, i); + i += 16; + } + + // Position + Position = new LLVector3(data, i); + i += 12; + // Velocity + x = Dequantize(data, i, -128.0F, 128.0F); + i += 2; + y = Dequantize(data, i, -128.0F, 128.0F); + i += 2; + z = Dequantize(data, i, -128.0F, 128.0F); + i += 2; + Velocity = new LLVector3(x, y, z); + // Acceleration + x = Dequantize(data, i, -64.0F, 64.0F); + i += 2; + y = Dequantize(data, i, -64.0F, 64.0F); + i += 2; + z = Dequantize(data, i, -64.0F, 64.0F); + i += 2; + Acceleration = new LLVector3(x, y, z); + // Rotation + x = Dequantize(data, i, -1.0F, 1.0F); + i += 2; + y = Dequantize(data, i, -1.0F, 1.0F); + i += 2; + z = Dequantize(data, i, -1.0F, 1.0F); + i += 2; + s = Dequantize(data, i, -1.0F, 1.0F); + i += 2; + Rotation = new LLQuaternion(x, y, z, s); + // Rotation velocity + x = Dequantize(data, i, -64.0F, 64.0F); + i += 2; + y = Dequantize(data, i, -64.0F, 64.0F); + i += 2; + z = Dequantize(data, i, -64.0F, 64.0F); + i += 2; + RotationVelocity = new LLVector3(x, y, z); + + break; + case "RegionHandle": + regionHandle = (U64)field.Data; + break; + case "TimeDilation": + timeDilation = (ushort)field.Data; + break; + case "TextureEntry": + // + break; + } + } + } + + if (avatar) + { + if (localid == Client.Avatar.LocalID) + { + Client.Avatar.Position = Position; + Client.Avatar.Rotation = Rotation; + } + else + { + AvatarUpdate avupdate = new AvatarUpdate(); + avupdate.LocalID = localid; + avupdate.State = state; + avupdate.Position = Position; + avupdate.CollisionPlane = CollisionPlane; + avupdate.Velocity = Velocity; + avupdate.Acceleration = Acceleration; + avupdate.Rotation = Rotation; + avupdate.RotationVelocity = RotationVelocity; + + // If an event handler is registered call it + if (OnAvatarMoved != null) + { + OnAvatarMoved(simulator, avupdate, regionHandle, timeDilation); + } + } + } + else + { + PrimUpdate primupdate = new PrimUpdate(); + primupdate.LocalID = localid; + primupdate.State = state; + primupdate.Position = Position; + primupdate.Velocity = Velocity; + primupdate.Acceleration = Acceleration; + primupdate.Rotation = Rotation; + primupdate.RotationVelocity = RotationVelocity; + + // If an event handler is registered call it + if (OnPrimMoved != null) + { + OnPrimMoved(simulator, primupdate, regionHandle, timeDilation); + } + } + } + + private void CompressedUpdateHandler(Packet packet, Simulator simulator) + { + //Client.Log("Received an ObjectUpdateCompressed packet, length=" + packet.Data.Length, Helpers.LogLevel.Info); + } + + private void CachedUpdateHandler(Packet packet, Simulator simulator) + { + //Client.Log("Received an ObjectUpdateCached packet, length=" + packet.Data.Length, Helpers.LogLevel.Info); + } + + /// + /// Takes a quantized 16-bit value from a byte array and its range and returns + /// a float representation of the continuous value. For example, a value of + /// 32767 and a range of -128.0 to 128.0 would return 0.0. The endian conversion + /// from the 16-bit little endian to the native platform will also be handled. + /// + /// The byte array containing the short value + /// The beginning position of the short (quantized) value + /// The lower quantization range + /// The upper quantization range + /// A 32-bit floating point representation of the dequantized value + private float Dequantize(byte[] byteArray, int pos, float lower, float upper) + { + ushort value = (ushort)(byteArray[pos] + (byteArray[pos + 1] << 8)); + float QV = (float)value; + float range = upper - lower; + float QF = range / 65536.0F; + return (float)((QV * QF - (0.5F * range)) + QF); + } + } +} diff --git a/old/libsecondlife-cs/Packet.cs b/old/libsecondlife-cs/Packet.cs new file mode 100644 index 00000000..7126851c --- /dev/null +++ b/old/libsecondlife-cs/Packet.cs @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Collections; + +namespace libsecondlife +{ + public struct Field + { + public object Data; + public MapField Layout; + + public override string ToString() + { + string output = ""; + + if (Layout.Type == FieldType.Variable || Layout.Type == FieldType.Fixed) + { + bool printable = true; + byte[] byteArray = (byte[])Data; + + for (int i = 0; i < byteArray.Length; ++i) + { + // Check if there are any unprintable characters in the array + if ((byteArray[i] < 0x20 || byteArray[i] > 0x7E) && byteArray[i] != 0x09 + && byteArray[i] != 0x0D) + { + printable = false; + } + } + + if (printable) + { + output = Helpers.FieldToString(byteArray); + } + else + { + for (int i = 0; i < byteArray.Length; i += 16) + { + output += Layout.Name + ": "; + + for (int j = 0; j < 16; j++) + { + if ((i + j) < byteArray.Length) + { + output += String.Format("{0:X2} ", byteArray[i + j]); + } + else + { + output += " "; + } + } + + for (int j = 0; j < 16 && (i + j) < byteArray.Length; j++) + { + if (byteArray[i + j] >= 0x20 && byteArray[i + j] < 0x7E) + { + output += (char)byteArray[i + j]; + } + else + { + output += "."; + } + } + + output += "\n"; + } + } + } + else + { + output += Layout.Name + ": " + Data.ToString(); + } + + return output; + } + } + + public struct Block + { + public ArrayList Fields; + public MapBlock Layout; + } + + /// + /// The Packet class is a wrapper around a raw UDP payload of a Second Life + /// message. It is used for both constructing outgoing packets and + /// interpreting incoming packets. + /// + public class Packet + { + /// + /// This is the complete, raw UDP payload of an incoming or outgoing + /// packet. + /// + public byte[] Data; + + /// + /// The packet layout is built from the Second Life message template + /// and describes all the blocks and fields of this packet. It is + /// used to serialize and unserialize the packet data. + /// + public MapPacket Layout; + + /// + /// Every Second Life message sent has an incremental sequence number + /// that is used for tracking reliable packets and measuring packet + /// loss. For outgoing packets the sequence number will be + /// automatically set by the network layer as the packet is sent out. + /// + public ushort Sequence + { + get + { + // The sequence number is the third and fourth bytes of the packet, stored + // in network order + return (ushort)(Data[2] * 256 + Data[3]); + } + + set + { + Data[2] = (byte)(value / 256); + Data[3] = (byte)(value % 256); + } + } + + /// + /// The TickCount is used for internally tracking packet timeouts, + /// please do not use this member. + /// + public int TickCount; + + private ProtocolManager Protocol; + + /// + /// Constructor used for building a packet where the length of the data + /// is known in advance. This is being phased out in favor of + /// pre-assembling the data or using PacketBuilder.BuildPacket(). + /// + /// The name of the command in the message template + /// A reference to the ProtocolManager instance + /// The length of the packet data + public Packet(string command, ProtocolManager protocol, int length) + { + Protocol = protocol; + Data = new byte[length]; + Layout = protocol.Command(command); + + if (Layout == null) + { + Console.WriteLine("Attempting to build a packet with invalid command \"" + command + "\""); + + // Create an empty Layout + Layout = new MapPacket(); + Layout.Blocks = new ArrayList(); + return; + } + + switch (Layout.Frequency) + { + case PacketFrequency.Low: + // Set the low frequency identifier bits + byte[] lowHeader = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF}; + Array.Copy(lowHeader, 0, Data, 0, 6); + + // Store the packet ID in network order + Data[6] = (byte)(Layout.ID / 256); + Data[7] = (byte)(Layout.ID % 256); + + break; + case PacketFrequency.Medium: + // Set the medium frequency identifier bits + byte[] mediumHeader = {0x00, 0x00, 0x00, 0x00, 0xFF}; + Array.Copy(mediumHeader, 0, Data, 0, 5); + Data[5] = (byte)Layout.ID; + + break; + case PacketFrequency.High: + // Set the high frequency identifier bits + byte[] highHeader = {0x00, 0x00, 0x00, 0x00}; + Array.Copy(highHeader, 0, Data, 0, 4); + Data[4] = (byte)Layout.ID; + + break; + } + } + + /// + /// Constructor used to build a Packet object from incoming data. + /// + /// Byte array containing the full UDP payload + /// Length of the actual data in the byte array + /// A reference to the ProtocolManager instance + public Packet(byte[] data, int length, ProtocolManager protocol) + : this(data, length, protocol, protocol.Command(data), true) + { + } + + /// + /// This is a special constructor created specifically for optimizing + /// SLProxy, do not use it under any circumstances. + /// + /// + /// + /// + /// + /// + public Packet(byte[] data, int length, ProtocolManager protocol, MapPacket layout, bool copy) + { + Protocol = protocol; + Layout = layout; + + if (Layout == null) + { + // Create an empty MapPacket + Layout = new MapPacket(); + Layout.Blocks = new ArrayList(); + } + + if (copy) { + // Copy the network byte array to this packet's byte array + Data = new byte[length]; + Array.Copy(data, 0, Data, 0, length); + } + else + { + // Use the buffer we got for Data + Data = data; + } + } + + /// + /// Unserializes packet data in to higher level representations + /// and native C# data types. + /// + /// An ArrayList of all the Block objects in this packet, + /// each of which contain Field objects for each data field. + public ArrayList Blocks() + { + Field field; + Block block; + byte blockCount; + int fieldSize; + + // Get the starting position of the SL payload (different than the UDP payload) + int pos = HeaderLength(); + + // Initialize the block list we are returning + ArrayList blocks = new ArrayList(); + + // Get the packet body's length so we can do bounds checking + int length = Data.Length; + if ((Data[0] & Helpers.MSG_APPENDED_ACKS) != 0) + length -= Data[Data.Length - 1] * 4 + 1; + + foreach (MapBlock blockMap in Layout.Blocks) + { + if (blockMap.Count == -1) + { + // Variable count block + if (pos < length) + { + blockCount = Data[pos]; + pos++; + } + else + { + // FIXME: Figure out a sane way to log from this function + Console.WriteLine("WARNING: Blocks(): end of packet in 1-byte variable block count for " + + Layout.Name + "." + blockMap.Name + " (" + pos + "/" + length + ")"); + goto Done; + } + } + else + { + blockCount = (byte)blockMap.Count; + } + + for (int i = 0; i < blockCount; ++i) + { + // Create a new block to push back on the list + block = new Block(); + block.Layout = blockMap; + block.Fields = new ArrayList(); + + foreach (MapField fieldMap in blockMap.Fields) + { + if (fieldMap.Type == FieldType.Variable) + { + if (fieldMap.Count == 1) + { + // Field length described with one byte + if (pos < length) + { + fieldSize = (ushort)Data[pos]; + pos++; + } + else + { + Console.WriteLine("WARNING: Blocks(): end of packet in 1-byte variable field count for " + + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")"); + goto BlockDone; + } + } + else // (fieldMap.Count == 2) + { + // Field length described with two bytes + if (pos + 1 < length) + { + fieldSize = (ushort)(Data[pos] + Data[pos + 1] * 256); + pos += 2; + } + else + { + Console.WriteLine("WARNING: Blocks(): end of packet in 2-byte variable field count for " + + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")"); + goto BlockDone; + } + } + + if (fieldSize != 0) + { + if (pos + fieldSize <= length) + { + // Create a new field to add to the fields for this block + field = new Field(); + field.Data = GetField(pos, fieldMap.Type, fieldSize); + field.Layout = fieldMap; + + block.Fields.Add(field); + + pos += fieldSize; + } + else + { + Console.WriteLine("WARNING: Blocks(): end of packet in " + fieldSize + + "-byte variable field " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + + " (" + pos + "/" + length + ")"); + goto BlockDone; + } + } + else + { + // Create a zero-length byte-array for this field + field = new Field(); + field.Data = new byte[0]; + field.Layout = fieldMap; + + block.Fields.Add(field); + } + } + else if (fieldMap.Type == FieldType.Fixed) + { + fieldSize = fieldMap.Count; + + if (pos + fieldSize <= length) + { + // Create a new field to add to the fields for this block + field = new Field(); + field.Data = GetField(pos, fieldMap.Type, fieldSize); + field.Layout = fieldMap; + + block.Fields.Add(field); + + pos += fieldSize; + } + else + { + Console.WriteLine("WARNING: Blocks(): end of packet in " + fieldSize + "-byte fixed field " + + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")"); + goto BlockDone; + } + } + else + { + for (int j = 0; j < fieldMap.Count; ++j) + { + fieldSize = (int)Protocol.TypeSizes[fieldMap.Type]; + + if (pos + fieldSize <= length) + { + // Create a new field to add to the fields for this block + field = new Field(); + field.Data = GetField(pos, fieldMap.Type, fieldSize); + field.Layout = fieldMap; + + block.Fields.Add(field); + + pos += fieldSize; + } + else + { + Console.WriteLine("WARNING: Blocks(): end of packet in " + fieldSize + "-byte " + + fieldMap.Type + " field " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + + " (" + pos + "/" + length + ")"); + goto BlockDone; + } + } + } + } + + BlockDone: + blocks.Add(block); + } + } + + Done: + return blocks; + } + + public override string ToString() + { + string output = ""; + ArrayList blocks = Blocks(); + + output += "---- " + Layout.Name + " ----\n"; + + foreach (Block block in blocks) + { + output += "-- " + block.Layout.Name + " --\n"; + + foreach (Field field in block.Fields) + { + output += field.ToString() + "\n"; + } + } + + return output; + } + + private int HeaderLength() + { + switch (Layout.Frequency) + { + case PacketFrequency.High: + return 5; + case PacketFrequency.Medium: + return 6; + case PacketFrequency.Low: + return 8; + } + + return 0; + } + + private object GetField(int pos, FieldType type, int fieldSize) + { + switch (type) + { + case FieldType.U8: + return Data[pos]; + case FieldType.U16: + return (ushort)(Data[pos] + (Data[pos + 1] << 8)); + case FieldType.IPPORT: + return (ushort)((Data[pos] << 8) + Data[pos + 1]); + case FieldType.U32: + return (uint)(Data[pos] + (Data[pos + 1] << 8) + + (Data[pos + 2] << 16) + (Data[pos + 3] << 24)); + case FieldType.U64: + return new U64(Data, pos); + case FieldType.S8: + return (sbyte)Data[pos]; + case FieldType.S16: + return (short)(Data[pos] + (Data[pos + 1] << 8)); + case FieldType.S32: + return Data[pos] + (Data[pos + 1] << 8) + + (Data[pos + 2] << 16) + (Data[pos + 3] << 24); + case FieldType.S64: + return (long)(Data[pos] + (Data[pos + 1] << 8) + + (Data[pos + 2] << 16) + (Data[pos + 3] << 24) + + (Data[pos + 4] << 32) + (Data[pos + 5] << 40) + + (Data[pos + 6] << 48) + (Data[pos + 7] << 56)); + case FieldType.F32: + return BitConverter.ToSingle(Data, pos); + case FieldType.F64: + return BitConverter.ToDouble(Data, pos); + case FieldType.LLUUID: + return new LLUUID(Data, pos); + case FieldType.BOOL: + return (Data[pos] != 0) ? (bool)true : (bool)false; + case FieldType.LLVector3: + return new LLVector3(Data, pos); + case FieldType.LLVector3d: + return new LLVector3d(Data, pos); + case FieldType.LLVector4: + return new LLVector4(Data, pos); + case FieldType.LLQuaternion: + return new LLQuaternion(Data, pos); + case FieldType.IPADDR: + uint address = (uint)(Data[pos] + (Data[pos + 1] << 8) + + (Data[pos + 2] << 16) + (Data[pos + 3] << 24)); + return new IPAddress(address); + case FieldType.Variable: + case FieldType.Fixed: + byte[] bytes = new byte[fieldSize]; + Array.Copy(Data, pos, bytes, 0, fieldSize); + return bytes; + } + + return null; + } + } + + public class PacketBuilder + { + public static Packet BuildPacket(string name, ProtocolManager protocol, Hashtable blocks, byte flags) + { + Hashtable fields; + ArrayList payload = new ArrayList(); + byte[] byteArray = new byte[4096]; + int length = 0; + int blockCount = 0; + int fieldLength = 0; + IDictionaryEnumerator blocksEnum; + + MapPacket packetMap = protocol.Command(name); + + // Build the header + #region Header + switch (packetMap.Frequency) + { + case PacketFrequency.High: + byteArray[4] = (byte)packetMap.ID; + length = 5; + break; + case PacketFrequency.Medium: + byteArray[4] = 0xFF; + byteArray[5] = (byte)packetMap.ID; + length = 6; + break; + case PacketFrequency.Low: + byteArray[4] = 0xFF; + byteArray[5] = 0xFF; + byteArray[6] = (byte)(packetMap.ID / 256); + byteArray[7] = (byte)(packetMap.ID % 256); + length = 8; + break; + } + #endregion Header + + foreach (MapBlock blockMap in packetMap.Blocks) + { + // If this is a variable count block, count the number of appearances of this block in the + // passed in Hashtable and prepend a counter byte + #region VariableSize + if (blockMap.Count == -1) + { + blockCount = 0; + + // Count the number of this type of block in the blocks Hashtable + blocksEnum = blocks.GetEnumerator(); + + while (blocksEnum.MoveNext()) + { + if ((string)blocksEnum.Value == blockMap.Name) + { + blockCount++; + } + } + + if (blockCount > 255) + { + throw new Exception("Trying to put more than 255 blocks in a variable block"); + } + + // Prepend the blocks with a count + byteArray[length] = (byte)blockCount; + length++; + } + #endregion VariableSize + + // Reset blockCount + blockCount = 0; + + // Check for blocks of this type in the Hashtable + #region BuildBlock + blocksEnum = blocks.GetEnumerator(); + + while (blocksEnum.MoveNext()) + { + if ((string)blocksEnum.Value == blockMap.Name) + { + // Found a match of this block + if ((blockMap.Count == -1 && blockCount < 255) || blockCount < blockMap.Count) + { + blockCount++; + + #region TryBlockTypecast + try + { + fields = (Hashtable)blocksEnum.Key; + } + catch (Exception e) + { + throw new Exception("A block Hashtable did not contain a fields Hashtable", e); + } + #endregion TryBlockTypecast + + foreach (MapField fieldMap in blockMap.Fields) + { + if (fields.ContainsKey(fieldMap.Name)) + { + object field = fields[fieldMap.Name]; + + #region AddField + switch (fieldMap.Type) + { + case FieldType.U8: + byteArray[length++] = (byte)field; + break; + case FieldType.U16: + ushort fieldUShort = (ushort)field; + byteArray[length++] = (byte)(fieldUShort % 256); + fieldUShort >>= 8; + byteArray[length++] = (byte)(fieldUShort % 256); + break; + case FieldType.U32: + uint fieldUInt = (uint)field; + byteArray[length++] = (byte)(fieldUInt % 256); + fieldUInt >>= 8; + byteArray[length++] = (byte)(fieldUInt % 256); + fieldUInt >>= 8; + byteArray[length++] = (byte)(fieldUInt % 256); + fieldUInt >>= 8; + byteArray[length++] = (byte)(fieldUInt % 256); + break; + case FieldType.U64: + // FIXME: Apply endianness patch + Array.Copy(((U64)field).GetBytes(), 0, byteArray, length, 8); + length += 8; + break; + case FieldType.S8: + byteArray[length++] = (byte)((sbyte)field); + break; + case FieldType.S16: + // FIXME: Apply endianness patch + Array.Copy(BitConverter.GetBytes((short)field), 0, byteArray, length, 2); + length += 2; + break; + case FieldType.S32: + // FIXME: Apply endianness patch + Array.Copy(BitConverter.GetBytes((int)field), 0, byteArray, length, 4); + length += 4; + break; + case FieldType.S64: + // FIXME: Apply endianness patch + Array.Copy(BitConverter.GetBytes((long)field), 0, byteArray, length, 8); + length += 8; + break; + case FieldType.F32: + Array.Copy(BitConverter.GetBytes((float)field), 0, byteArray, length, 4); + length += 4; + break; + case FieldType.F64: + Array.Copy(BitConverter.GetBytes((double)field), 0, byteArray, length, 8); + length += 8; + break; + case FieldType.LLUUID: + Array.Copy(((LLUUID)field).Data, 0, byteArray, length, 16); + length += 16; + break; + case FieldType.BOOL: + byteArray[length] = (byte)((bool)field == true ? 1 : 0); + length++; + break; + case FieldType.LLVector3: + Array.Copy(((LLVector3)field).GetBytes(), 0, byteArray, length, 12); + length += 12; + break; + case FieldType.LLVector3d: + Array.Copy(((LLVector3d)field).GetBytes(), 0, byteArray, length, 24); + length += 24; + break; + case FieldType.LLVector4: + Array.Copy(((LLVector4)field).GetBytes(), 0, byteArray, length, 16); + length += 16; + break; + case FieldType.LLQuaternion: + Array.Copy(((LLQuaternion)field).GetBytes(), 0, byteArray, length, 16); + length += 16; + break; + case FieldType.IPADDR: + Array.Copy(((IPAddress)field).GetAddressBytes(), 0, byteArray, length, 4); + length += 4; + break; + case FieldType.IPPORT: + ushort fieldIPPort = (ushort)field; + byteArray[length + 1] = (byte)(fieldIPPort % 256); + fieldIPPort >>= 8; + byteArray[length] = (byte)(fieldIPPort % 256); + length += 2; + break; + case FieldType.Variable: + if (field.GetType().IsArray) + { + // Assume this is a byte array + fieldLength = ((byte[])field).Length; + } + else + { + // Assume this is a string, add 1 for the null terminator + fieldLength = ((string)field).Length + 1; + } + + if (fieldMap.Count == 1) + { + if (fieldLength > 255) + { + throw new Exception("Variable byte field longer than 255 characters"); + } + + byteArray[length] = (byte)(fieldLength); + length++; + } + else if (fieldMap.Count == 2) + { + if (fieldLength > 1024) + { + throw new Exception("Variable byte field longer than 1024 characters"); + } + + byteArray[length++] = (byte)(fieldLength % 256); + byteArray[length++] = (byte)(fieldLength / 256); + } + else + { + throw new Exception("Variable field with an unknown count, protocol map error"); + } + + if (field.GetType().IsArray) + { + // Assume this is a byte array + Array.Copy((byte[])field, 0, byteArray, length, fieldLength); + } + else + { + // Assume this is a string, add 1 for the null terminator + byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes((string)field); + Array.Copy(stringBytes, 0, byteArray, length, stringBytes.Length); + fieldLength = stringBytes.Length + 1; + } + + length += fieldLength; + + break; + case FieldType.Fixed: + Array.Copy((byte[])field, 0, byteArray, length, fieldMap.Count); + length += fieldMap.Count; + break; + default: + throw new Exception("Unhandled FieldType"); + } + #endregion AddField + } + else + { + // This field wasn't passed in, create an empty version + #region EmptyField + if (fieldMap.Type == FieldType.Variable) + { + // Just set the counter to zero and move on + if (fieldMap.Count == 2) + { + length += 2; + } + else + { + if (fieldMap.Count != 1) + { + throw new Exception("Variable length field has an invalid Count"); + } + + length++; + } + } + else if (fieldMap.Type == FieldType.Fixed) + { + length += fieldMap.Count; + } + else + { + length += (int)protocol.TypeSizes[fieldMap.Type]; + } + #endregion EmptyField + } + } + } + else + { + throw new Exception("Too many blocks"); + } + } + } + #endregion BuildBlock + + // If this is a fixed count block and it doesn't appear in the Hashtable passed in, create + // empty filler blocks + #region EmptyBlock + if (blockCount == 0 && blockMap.Count != -1) + { + for (int i = 0; i < blockMap.Count; ++i) + { + foreach (MapField field in blockMap.Fields) + { + if (field.Type == FieldType.Variable) + { + length++; + } + else + { + length += (int)protocol.TypeSizes[field.Type]; + } + } + } + } + #endregion EmptyBlock + } + + Packet packet = new Packet(byteArray, length, protocol); + packet.Data[0] = flags; + return packet; + } + } +} diff --git a/old/libsecondlife-cs/Packets/AssetPackets.cs b/old/libsecondlife-cs/Packets/AssetPackets.cs new file mode 100644 index 00000000..74783c78 --- /dev/null +++ b/old/libsecondlife-cs/Packets/AssetPackets.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections; + +using libsecondlife; +using libsecondlife.InventorySystem; +using libsecondlife.AssetSystem; + +namespace libsecondlife.Packets +{ + /// + /// + public class AssetPackets + { + /* + Low 00408 - AssetUploadRequest - Untrusted - Zerocoded + 1299 AssetBlock (01) + 0394 UUID (LLUUID / 1) + 0630 Type (S8 / 1) + 0766 Tempfile (BOOL / 1) + 1355 AssetData (Variable / 2) + + + ----- AssetUploadRequest ----- + AssetBlock + UUID: fba4594511897d91ab5145f430c0b37d + Type: 7 + Tempfile: False + AssetData: 4c 69 6e 64 65 6e 20 74 65 78 74 20 76 65 72 73 Linden text vers + AssetData: 69 6f 6e 20 31 0a 7b 0a 4c 4c 45 6d 62 65 64 64 ion 1.{.LLEmbedd + AssetData: 65 64 49 74 65 6d 73 20 76 65 72 73 69 6f 6e 20 edItems version + AssetData: 31 0a 7b 0a 63 6f 75 6e 74 20 30 0a 7d 0a 54 65 1.{.count 0.}.Te + AssetData: 78 74 20 6c 65 6e 67 74 68 20 32 31 0a 45 64 69 xt length 21.Edi + AssetData: 74 69 6e 67 20 74 68 69 73 20 6e 6f 74 65 63 61 ting this noteca + AssetData: 72 64 7d 0a 00 rd}.. + + + */ + public static Packet AssetUploadRequest(ProtocolManager protocol, Asset asset) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["UUID"] = asset.AssetID; + fields["Type"] = asset.Type; + fields["Tempfile"] = asset.Tempfile; + fields["AssetData"] = asset.AssetData; + fields["StoreLocal"] = false; + + blocks[fields] = "AssetBlock"; + + return PacketBuilder.BuildPacket("AssetUploadRequest", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + public static Packet AssetUploadRequestHeaderOnly(ProtocolManager protocol, Asset asset) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["UUID"] = asset.AssetID; + fields["Type"] = asset.Type; + fields["Tempfile"] = asset.Tempfile; + fields["StoreLocal"] = false; + blocks[fields] = "AssetBlock"; + + return PacketBuilder.BuildPacket("AssetUploadRequest", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + + /* + * First xferpacket includes a prefixed S32 for the length of the asset. + * + High 00020 - SendXferPacket - Untrusted - Zerocoded + 0234 DataPacket (01) + 0527 Data (Variable / 2) + 0804 XferID (01) + 0030 ID (U64 / 1) + 0785 Packet (U32 / 1) + High 00021 - ConfirmXferPacket - Untrusted - Zerocoded + 0804 XferID (01) + 0030 ID (U64 / 1) + 0785 Packet (U32 / 1) + + ----- SendXferPacket ----- + DataPacket + Data: cb 16 00 00 4c 69 6e 64 65 6e 20 74 65 78 74 20 ....Linden text + + Data: 20 63 6f 6e 74 61 63 74 20 79 6f 75 contact you + XferID + ID: 12874913228238730530 + Packet: 0 + */ + + public static Packet SendXferPacket(ProtocolManager protocol, U64 id, byte[] data, uint packetNum) + { + Hashtable blocks = new Hashtable(); + Hashtable fields; + + fields = new Hashtable(); + fields["Data"] = data; + blocks[fields] = "DataPacket"; + + fields = new Hashtable(); + fields["ID"] = id; + fields["Packet"] = (uint)packetNum; + blocks[fields] = "XferID"; + + return PacketBuilder.BuildPacket("SendXferPacket", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + /* + ----- TransferRequest ----- + TransferInfo + TransferID: cc75b93dd4d8c25f6cf56c22f1b3b26c + Params: 25 47 26 83 cb 32 45 16 90 4a 6c d0 ec ab f1 28 %G&..2E..Jl....( + Params: ea ba cb 97 42 49 49 db 9f a6 37 f5 ab 56 61 7a ....BII...7..Vaz + Params: 25 47 26 83 cb 32 45 16 90 4a 6c d0 ec ab f1 28 %G&..2E..Jl....( + Params: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + Params: 58 26 f4 2e 9b 57 3f b1 68 f6 1b c6 0f e1 11 18 X&...W?.h....... + Params: 6e c6 d5 9b 4b d2 53 47 24 26 73 13 5f d3 3b 94 n...K.SG$&s._.;. + Params: 07 00 00 00 .... + ChannelType: 2 + SourceType: 3 + Priority: 101.000000 + + Low 00193 - TransferRequest - Untrusted - Unencoded + 0770 TransferInfo (01) + 0072 TransferID (LLUUID / 1) + 0867 Params (Variable / 2) + 0912 ChannelType (S32 / 1) + 1264 SourceType (S32 / 1) + 1370 Priority (F32 / 1) + + Params: 1: OwnerID / *AgentID + Params: 2: SessionID + Params: 3: *OwnerID / AgentID + Params: 4: Unknown (Maybe Group ID) + Params: 5: ItemID + Params: 6: AssetID + Params: 7: Type + Params: 8: Last Three Bytes Unknown + */ + + public static Packet TransferRequest(ProtocolManager protocol, LLUUID SessionID, LLUUID AgentID, LLUUID TransferID, InventoryItem item) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + byte[] param = new byte[100]; + int pos = 0; + + Array.Copy(AgentID.Data, 0, param, pos, 16); + pos += 16; + + Array.Copy(SessionID.Data, 0, param, pos, 16); + pos += 16; + + Array.Copy(item.OwnerID.Data, 0, param, pos, 16); + pos += 16; + + Array.Copy(item.GroupID.Data, 0, param, pos, 16); + pos += 16; + + Array.Copy(item.ItemID.Data, 0, param, pos, 16); + pos += 16; + + Array.Copy(item.AssetID.Data, 0, param, pos, 16); + pos += 16; + + param[pos] = (byte)item.Type; + pos += 1; + + fields["TransferID"] = TransferID; + fields["Params"] = param; + fields["ChannelType"] = 2; + fields["SourceType"] = 3; + fields["Priority"] = (float)101.0; + + blocks[fields] = "TransferInfo"; + + return PacketBuilder.BuildPacket("TransferRequest", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + } +} diff --git a/old/libsecondlife-cs/Packets/CommunicationPackets.cs b/old/libsecondlife-cs/Packets/CommunicationPackets.cs new file mode 100644 index 00000000..7176eb95 --- /dev/null +++ b/old/libsecondlife-cs/Packets/CommunicationPackets.cs @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class Communication + { + public static Packet UUIDNameRequest(ProtocolManager protocol, LLUUID ID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["ID"] = ID; + blocks[fields] = "UUIDNameBlock"; + + Packet packet = PacketBuilder.BuildPacket("UUIDNameRequest", protocol, blocks, Helpers.MSG_RELIABLE); + return packet; + } + + public static Packet ImprovedInstantMessage(ProtocolManager protocol, LLUUID targetAgentID, + LLUUID myAgentID, uint parentEstateID, LLUUID regionID, LLVector3 position, byte offline, + byte dialog, LLUUID id, uint timestamp, string myAgentName, string message, + byte[] binaryBucket, LLUUID mySessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["FromAgentID"] = myAgentID; + fields["ToAgentID"] = targetAgentID; + fields["ParentEstateID"] = parentEstateID; + fields["RegionID"] = regionID; + fields["Position"] = position; + fields["Offline"] = offline; + fields["Dialog"] = dialog; + fields["ID"] = id; + fields["Timestamp"] = timestamp; + fields["FromAgentName"] = myAgentName; + fields["Message"] = message; + fields["BinaryBucket"] = binaryBucket; + blocks[fields] = "MessageBlock"; + + // Agent Data Block + Hashtable agentData = new Hashtable(); + agentData["AgentID"] = myAgentID; + agentData["SessionID"] = mySessionID; + blocks[agentData] = "AgentData"; + + + return PacketBuilder.BuildPacket("ImprovedInstantMessage", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ChatFromViewer(ProtocolManager protocol, LLUUID myAgentID, LLUUID mySessionID, string message, + byte type, int channel, byte command, LLUUID commandID, float radius, LLVector3 position) + { + Hashtable blocks = new Hashtable(); + Hashtable agentData = new Hashtable(); + Hashtable chatData = new Hashtable(); + Hashtable conversationData = new Hashtable(); + + // Agent Data Block + agentData["AgentID"] = myAgentID; + agentData["SessionID"] = mySessionID; + blocks[agentData] = "AgentData"; + + // Chat Data Block + chatData["Message"] = message; + chatData["Type"] = type; + chatData["Channel"] = channel; + blocks[chatData] = "ChatData"; + + // Conversation Data Block + conversationData["Command"] = command; + conversationData["CommandID"] = commandID; + conversationData["Radius"] = radius; + conversationData["Position"] = position; + blocks[conversationData] = "ConversationData"; + + return PacketBuilder.BuildPacket("ChatFromViewer", protocol, blocks, Helpers.MSG_RELIABLE); + } + } +} diff --git a/old/libsecondlife-cs/Packets/EstatePackets.cs b/old/libsecondlife-cs/Packets/EstatePackets.cs new file mode 100644 index 00000000..ac052701 --- /dev/null +++ b/old/libsecondlife-cs/Packets/EstatePackets.cs @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2006, Second Life Reverse Engineering Team +* All rights reserved. +* +* - Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* - Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* - Neither the name of the Second Life Reverse Engineering Team nor the names +* of its contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class Estate + { + public static Packet EstateOwnerMessage(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, string method, LLUUID invoice, Hashtable parameterlists) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["Method"] = method; + fields["Invoice"] = invoice; + blocks[fields] = "MethodData"; + + foreach(Hashtable field in parameterlists.Keys) + { + blocks[field] = parameterlists[field]; + } + + Packet packet = PacketBuilder.BuildPacket("EstateOwnerMessage", protocol, blocks, Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + return packet; + } + public static Packet EstateKick(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, LLUUID targetID) + { + Hashtable plist = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["Parameter"] = agentID.ToStringHyphenated(); + plist[fields] = "ParamList"; + fields = new Hashtable(); + fields["Parameter"] = targetID.ToStringHyphenated(); + plist[fields] = "ParamList"; + + return Estate.EstateOwnerMessage(protocol,agentID,sessionID,"kick",new LLUUID(true),plist); + } + + public static Packet EstateBan(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, LLUUID targetID) + { + Hashtable plist = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["Parameter"] = targetID.ToStringHyphenated(); + plist[fields] = "ParamList"; + + fields = new Hashtable(); + fields["Parameter"] = "65"; + plist[fields] = "ParamList"; + + fields = new Hashtable(); + fields["Parameter"] = agentID.ToStringHyphenated(); + plist[fields] = "ParamList"; + + return Estate.EstateOwnerMessage(protocol,agentID,sessionID,"estateaccessdelta",new LLUUID(true),plist); + } + + public static Packet EstateUnBan(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, LLUUID targetID) + { + Hashtable plist = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["Parameter"] = targetID.ToStringHyphenated(); + plist[fields] = "ParamList"; + + fields = new Hashtable(); + fields["Parameter"] = "129"; + plist[fields] = "ParamList"; + + fields = new Hashtable(); + fields["Parameter"] = agentID.ToStringHyphenated(); + plist[fields] = "ParamList"; + + return Estate.EstateOwnerMessage(protocol,agentID,sessionID,"estateaccessdelta",new LLUUID(true),plist); + } + + public static Packet EstateTeleportUser(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, LLUUID targetID) + { + Hashtable plist = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["Parameter"] = targetID.ToStringHyphenated(); + plist[fields] = "ParamList"; + fields = new Hashtable(); + fields["Parameter"] = agentID.ToStringHyphenated(); + plist[fields] = "ParamList"; + + return Estate.EstateOwnerMessage(protocol,agentID,sessionID,"teleporthomeuser",new LLUUID(true),plist); + } + } +} \ No newline at end of file diff --git a/old/libsecondlife-cs/Packets/ImagePackets.cs b/old/libsecondlife-cs/Packets/ImagePackets.cs new file mode 100644 index 00000000..9a648c8e --- /dev/null +++ b/old/libsecondlife-cs/Packets/ImagePackets.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections; + +using libsecondlife; + +namespace libsecondlife.Packets +{ + /// + /// Summary description for ImagePackets. + /// + public class ImagePackets + { + private ImagePackets() { } + + + public static Packet RequestImage(ProtocolManager protocol, LLUUID imageID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["DownloadPriority"] = (float)1215000.0; + fields["DiscardLevel"] = (int)0; + fields["Packet"] = (uint)0; + fields["Image"] = imageID; + + blocks[fields] = "RequestImage"; + + return PacketBuilder.BuildPacket("RequestImage", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + } +} diff --git a/old/libsecondlife-cs/Packets/InventoryPackets.cs b/old/libsecondlife-cs/Packets/InventoryPackets.cs new file mode 100644 index 00000000..c9c9a313 --- /dev/null +++ b/old/libsecondlife-cs/Packets/InventoryPackets.cs @@ -0,0 +1,742 @@ +using System; +using System.Collections; + +using libsecondlife; +using libsecondlife.InventorySystem; + +namespace libsecondlife.Packets +{ + /// + /// Summary description for Other. + /// + public class InventoryPackets + { + private InventoryPackets() + { + //Prevents this class from being instantiated. + } + + + + + + public static Packet FetchInventoryDescendents(ProtocolManager protocol, LLUUID ownerID, + LLUUID folderID, LLUUID agentID) + { + return FetchInventoryDescendents(protocol, ownerID, folderID, agentID, true, true); + } + + public static Packet FetchInventoryDescendents(ProtocolManager protocol, LLUUID ownerID, + LLUUID folderID, LLUUID agentID, bool fetchFolders, bool fetchItems) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["OwnerID"] = ownerID; + fields["FolderID"] = folderID; + fields["SortOrder"] = FETCH_INVENTORY_SORT_NAME; + fields["FetchFolders"] = fetchFolders; + fields["FetchItems"] = fetchItems; + blocks[fields] = "InventoryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("FetchInventoryDescendents", protocol, blocks, Helpers.MSG_RELIABLE); + } + + /* + Low 00334 - FetchInventory - Untrusted - Unencoded + 0065 InventoryData (Variable) + 0719 OwnerID (LLUUID / 1) + 0968 ItemID (LLUUID / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + */ + public static Packet FetchInventory(ProtocolManager protocol, LLUUID ownerID, LLUUID itemID, LLUUID agentID) + { + int packetLength = 8; // header + packetLength += 16; // OwnerID (UUID) + packetLength += 16; // ItemID (UUID) + packetLength += 16; // AgentID (UUID) + + // FIXME: Convert this function to use BuildPacket + Packet packet = new Packet("AgentWearablesRequest", protocol, packetLength); + + int pos = 8; // Leave room for header + + // OwnerID + Array.Copy(ownerID.Data, 0, packet.Data, pos, 16); + pos += 16; + + // ItemID + Array.Copy(itemID.Data, 0, packet.Data, pos, 16); + pos += 16; + + // AgentID + Array.Copy(agentID.Data, 0, packet.Data, pos, 16); + pos += 16; + + // Set the packet flags + // packet.Data[0] = Helpers.MSG_ZEROCODED + Helpers.MSG_RELIABLE; + // packet.Data[0] = Helpers.MSG_RELIABLE; + + return packet; + } + + public static Packet AgentWearablesRequest(ProtocolManager protocol, LLUUID agentID) + { + int packetLength = 8; // header + packetLength += 16; // AgentID (UUID) + + // FIXME: Convert this function to use BuildPacket + Packet packet = new Packet("AgentWearablesRequest", protocol, packetLength ); + + int pos = 8; // Leave room for header + + // AgentID + Array.Copy(agentID.Data, 0, packet.Data, pos, 16); + pos += 16; + + // Set the packet flags + packet.Data[0] = Helpers.MSG_ZEROCODED + Helpers.MSG_RELIABLE; + + return packet; + } + + /* + Low 00328 - CreateInventoryFolder - Untrusted - Zerocoded + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + 1298 FolderData (01) + 0506 Name (Variable / 1) + 0558 ParentID (LLUUID / 1) + 0630 Type (S8 / 1) + 1025 FolderID (LLUUID / 1) + + ----- CreateInventoryFolder ----- + AgentData + AgentID: 25472683cb324516904a6cd0ecabf128 + FolderData + Name: New Folder + ParentID: a4947fc066c247518d9854aaf90097f4 + Type: 255 + FolderID: fdc8b4cc8ff9d678a8e15aa6ea700271 + */ + public static Packet CreateInventoryFolder(ProtocolManager protocol + , LLUUID agentID + , string name + , LLUUID parentID + , sbyte type + , LLUUID folderID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["Name"] = name; + fields["ParentID"] = parentID; + fields["Type"] = type; + fields["FolderID"] = folderID; + blocks[fields] = "FolderData"; + + + return PacketBuilder.BuildPacket("CreateInventoryFolder", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + + + /* + ----- MoveInventoryFolder ----- + InventoryData + ParentID: 4d68743474c3084812d3a3fdda2ca2bd + FolderID: 8c8412df3064dc40ad676826b03b87d7 + AgentData + AgentID: 25472683cb324516904a6cd0ecabf128 + Stamp: True + + Low 00330 - MoveInventoryFolder - Untrusted - Unencoded + 0065 InventoryData (Variable) + 0558 ParentID (LLUUID / 1) + 1025 FolderID (LLUUID / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + 1252 Stamp (BOOL / 1) + */ + public static Packet MoveInventoryFolder(ProtocolManager protocol + , LLUUID agentID + , LLUUID parentID + , LLUUID folderID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["Stamp"] = true; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["ParentID"] = parentID; + fields["FolderID"] = folderID; + blocks[fields] = "InventoryData"; + + + return PacketBuilder.BuildPacket("MoveInventoryFolder", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + + /* + ----- RemoveInventoryFolder ----- + AgentData + AgentID: 25472683cb324516904a6cd0ecabf128 + FolderData + FolderID: 8c8412df3064dc40ad676826b03b87d7 + + Low 00331 - RemoveInventoryFolder - Untrusted - Zerocoded + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + 1298 FolderData (Variable) + 1025 FolderID (LLUUID / 1) + */ + public static Packet RemoveInventoryFolder(ProtocolManager protocol + , LLUUID agentID + , LLUUID folderID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["FolderID"] = folderID; + blocks[fields] = "FolderData"; + + + return PacketBuilder.BuildPacket("RemoveInventoryFolder", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + + /* + ----- UpdateInventoryFolder ----- + AgentData + AgentID: 25472683cb324516904a6cd0ecabf128 + FolderData + Name: Renamed + ParentID: a4947fc066c247518d9854aaf90097f4 + Type: 255 + FolderID: 10dce442915c01581a931170664d0616 + + Low 00329 - UpdateInventoryFolder - Untrusted - Zerocoded + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + 1298 FolderData (Variable) + 0506 Name (Variable / 1) + 0558 ParentID (LLUUID / 1) + 0630 Type (S8 / 1) + 1025 FolderID (LLUUID / 1) + */ + public static Packet UpdateInventoryFolder(ProtocolManager protocol + , LLUUID agentID + , string name + , LLUUID parentID + , sbyte type + , LLUUID folderID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["Name"] = name; + fields["ParentID"] = parentID; + fields["Type"] = type; + fields["FolderID"] = folderID; + blocks[fields] = "FolderData"; + + + return PacketBuilder.BuildPacket("UpdateInventoryFolder", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + /* + Low 00323 - MoveInventoryItem - Untrusted - Unencoded + 0065 InventoryData (Variable) + 0968 ItemID (LLUUID / 1) + 1025 FolderID (LLUUID / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + 1252 Stamp (BOOL / 1) + */ + public static Packet MoveInventoryItem(ProtocolManager protocol + , LLUUID agentID + , LLUUID itemID + , LLUUID folderID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields; + + fields = new Hashtable(); + fields["ItemID"] = itemID; + fields["FolderID"] = folderID; + blocks[fields] = "InventoryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["Stamp"] = true; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("MoveInventoryItem", protocol, blocks, Helpers.MSG_RELIABLE); + } + + /* + Low 00324 - CopyInventoryItem - Untrusted - Unencoded + 0065 InventoryData (Variable) + 0224 NewFolderID (LLUUID / 1) + 0991 OldItemID (LLUUID / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + */ + public static Packet CopyInventoryItem(ProtocolManager protocol + , LLUUID agentID + , LLUUID itemID + , LLUUID folderID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields; + + fields = new Hashtable(); + fields["ItemID"] = itemID; + fields["FolderID"] = folderID; + blocks[fields] = "InventoryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("CopyInventoryItem", protocol, blocks, Helpers.MSG_RELIABLE); + } + + /* + Low 00325 - RemoveInventoryItem - Untrusted - Zerocoded + 0065 InventoryData (Variable) + 0968 ItemID (LLUUID / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + */ + public static Packet RemoveInventoryItem(ProtocolManager protocol + , LLUUID agentID + , LLUUID itemID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["ItemID"] = itemID; + blocks[fields] = "InventoryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + + + return PacketBuilder.BuildPacket("RemoveInventoryItem", protocol, blocks, Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED); + } + + /* + ----- ImprovedInstantMessage ----- + MessageBlock + ID: 8006f744d08bbad1f941d59ffce4059e + ToAgentID: f6ec1e24fd294f4cb21e23b42841c8c7 + Offline: 0 + Timestamp: 0 + Message: Big Card 2:04 PM + RegionID: 00000000000000000000000000000000 + FromAgentID: 25472683cb324516904a6cd0ecabf128 + Dialog: 4 + BinaryBucket: 07 9a 31 a7 1a 05 ff 76 4d af 8f ef a0 b3 e7 08 ..1....vM....... + BinaryBucket: e6 . + ParentEstateID: 0 + FromAgentName: Bot Ringo + Position: 25.528299, 214.016006, 1.088448 + + Low 00304 - ImprovedInstantMessage - Untrusted - Unencoded + 1231 MessageBlock (01) + 0030 ID (LLUUID / 1) + 0172 ToAgentID (LLUUID / 1) + 0248 Offline (U8 / 1) + 0369 Timestamp (U32 / 1) + 0389 Message (Variable / 2) + 0488 RegionID (LLUUID / 1) + 0597 FromAgentID (LLUUID / 1) + 0889 Dialog (U8 / 1) + 1124 BinaryBucket (Variable / 2) + 1129 ParentEstateID (U32 / 1) + 1150 FromAgentName (Variable / 1) + 1389 Position (LLVector3 / 1) + + */ + public static Packet ImprovedInstantMessage(ProtocolManager protocol + , LLUUID ID + , LLUUID ToAgentID + , LLUUID FromAgentID + , String FromAgentName + , LLVector3 FromAgentLoc + , InventoryItem Item + , LLUUID AgentID + , LLUUID SessionID + ) + { + byte[] BinaryBucket = new byte[17]; + BinaryBucket[0] = (byte)Item.Type; + Array.Copy(Item.ItemID.Data, 0, BinaryBucket, 1, 16); + + + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["ID"] = ID; + fields["ToAgentID"] = ToAgentID; + fields["Offline"] = (byte)0; + fields["TimeStamp"] = (uint)0; + fields["Message"] = Item.Name; + fields["RegionID"] = new LLUUID(); + fields["FromAgentID"] = FromAgentID; + fields["Dialog"] = (byte)4; + fields["BinaryBucket"] = BinaryBucket; + fields["ParentEstateID"]= (uint)0; + fields["FromAgentName"] = FromAgentName; + fields["Position"] = FromAgentLoc; + blocks[fields] = "MessageBlock"; + + fields = new Hashtable(); + fields["AgentID"] = AgentID; + fields["SessionID"] = SessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ImprovedInstantMessage", protocol, blocks, Helpers.MSG_RELIABLE ); + } + + + + /* + Low 00337 - RequestInventoryAsset - Trusted - Zerocoded + 1266 QueryData (01) + 0219 AgentID (LLUUID / 1) + 0640 QueryID (LLUUID / 1) + 0719 OwnerID (LLUUID / 1) + 0968 ItemID (LLUUID / 1) + Low 00338 - InventoryAssetResponse - Trusted - Zerocoded + 1266 QueryData (01) + 0640 QueryID (LLUUID / 1) + 0680 AssetID (LLUUID / 1) + 1058 IsReadable (BOOL / 1) + */ + public static Packet RequestInventoryAsset(ProtocolManager protocol + , LLUUID agentID, LLUUID queryUD, LLUUID ownerID, LLUUID itemID ) + { + int packetLength = 8; // header + packetLength += 16; // AgentID (UUID) + packetLength += 16; // QueryID (UUID) + packetLength += 16; // OwnerID (UUID) + packetLength += 16; // ItemID (UUID) + + // FIXME: Convert this function to use BuildPacket + Packet packet = new Packet("RequestInventoryAsset", protocol, packetLength ); + + int pos = 8; // Leave room for header + + // AgentID + Array.Copy(agentID.Data, 0, packet.Data, pos, 16); + pos += 16; + + // QueryID + Array.Copy(queryUD.Data, 0, packet.Data, pos, 16); + pos += 16; + + // OwnerID + Array.Copy(ownerID.Data, 0, packet.Data, pos, 16); + pos += 16; + + // ItemID + Array.Copy(itemID.Data, 0, packet.Data, pos, 16); + pos += 16; + + // Set the packet flags + packet.Data[0] = Helpers.MSG_ZEROCODED + Helpers.MSG_RELIABLE; + + return packet; + } + + /* + Low 00322 - UpdateInventoryItemAsset - Untrusted - Unencoded + 0065 InventoryData (Variable) + 0680 AssetID (LLUUID / 1) + 0968 ItemID (LLUUID / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + Low 00326 - ChangeInventoryItemFlags - Untrusted - Zerocoded + 0065 InventoryData (Variable) + 0968 ItemID (LLUUID / 1) + 1189 Flags (U32 / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + */ + + public static Packet UpdateInventoryItem(ProtocolManager protocol, InventoryItem iitem, LLUUID agentID, LLUUID sessionID) + { + return UpdateInventoryItem( protocol + , iitem.GroupOwned + , InventoryUpdateCRC(iitem) + , iitem.CreationDate + , iitem.SaleType + , iitem.BaseMask + , iitem.Name + , iitem.InvType + , iitem.Type + , iitem.AssetID + , iitem.GroupID + , iitem.SalePrice + , iitem.OwnerID + , iitem.CreatorID + , iitem.ItemID + , iitem.FolderID + , iitem.EveryoneMask + , iitem.Description + , iitem.Flags + , iitem.NextOwnerMask + , iitem.GroupMask + , iitem.OwnerMask + , agentID + , sessionID + ); + } + + /* + Low 00321 - UpdateInventoryItem - Untrusted - Unencoded + 0065 InventoryData (Variable) + 0047 GroupOwned (BOOL / 1) + 0149 CRC (U32 / 1) + 0159 CreationDate (S32 / 1) + 0345 SaleType (U8 / 1) + 0395 BaseMask (U32 / 1) + 0506 Name (Variable / 1) + 0562 InvType (S8 / 1) + 0630 Type (S8 / 1) + 0680 AssetID (LLUUID / 1) + 0699 GroupID (LLUUID / 1) + 0716 SalePrice (S32 / 1) + 0719 OwnerID (LLUUID / 1) + 0736 CreatorID (LLUUID / 1) + 0968 ItemID (LLUUID / 1) + 1025 FolderID (LLUUID / 1) + 1084 EveryoneMask (U32 / 1) + 1101 Description (Variable / 1) + 1189 Flags (U32 / 1) + 1348 NextOwnerMask (U32 / 1) + 1452 GroupMask (U32 / 1) + 1505 OwnerMask (U32 / 1) + 1297 AgentData (01) + 0219 AgentID (LLUUID / 1) + + + ----- UpdateInventoryItem ----- + InventoryData + GroupOwned: False + CRC: 3330379543 + CreationDate: 1152566548 + SaleType: 0 + BaseMask: 2147483647 + Name: New Note + InvType: 7 + Type: 7 + AssetID: 00000000000000000000000000000000 + GroupID: 00000000000000000000000000000000 + SalePrice: 10 + OwnerID: 25472683cb324516904a6cd0ecabf128 + CreatorID: 25472683cb324516904a6cd0ecabf128 + ItemID: 6f11a788c6478fb50610b65b4a8f9c11 + FolderID: a4947fc066c247518d9854aaf90097f4 + EveryoneMask: 0 + Description: 2006-07-10 14:22:38 note card + Flags: 0 + NextOwnerMask: 2147483647 + GroupMask: 0 + OwnerMask: 2147483647 + AgentData + AgentID: 25472683cb324516904a6cd0ecabf128 + + */ + private static Packet UpdateInventoryItem(ProtocolManager protocol + , bool groupOwned + , uint crc + , int creationDate + , byte saleType + , uint baseMask + , string name + , sbyte invType, sbyte type + , LLUUID assetID + , LLUUID groupID + , int salePrice + , LLUUID ownerID + , LLUUID creatorID + , LLUUID itemID + , LLUUID folderID + , uint everyoneMask + , string description + , uint flags + , uint nextOwnerMask + , uint groupMask + , uint ownerMask + , LLUUID agentID + , LLUUID sessionID + ) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["GroupOwned"] = groupOwned; + fields["CRC"] = crc; + fields["CreationDate"] = creationDate; + fields["SaleType"] = saleType; + fields["BaseMask"] = baseMask; + fields["Name"] = name; + fields["InvType"] = invType; + fields["Type"] = type; + fields["AssetID"] = assetID; + fields["GroupID"] = groupID; + fields["SalePrice"] = salePrice; + fields["OwnerID"] = ownerID; + fields["CreatorID"] = creatorID; + fields["ItemID"] = itemID; + fields["FolderID"] = folderID; + fields["EveryoneMask"] = everyoneMask; + fields["Description"] = description; + fields["Flags"] = flags; + fields["NextOwnerMask"] = nextOwnerMask; + fields["GroupMask"] = groupMask; + fields["OwnerMask"] = ownerMask; + blocks[fields] = "InventoryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + + return PacketBuilder.BuildPacket("UpdateInventoryItem", protocol, blocks, Helpers.MSG_RELIABLE); + } + +/* + // Confirm InventoryUpdate CRC + uint test = libsecondlife.Packets.InventoryPackets.InventoryUpdateCRC + ( + (int)1159214416 + , (byte)0 + , (sbyte)7 + , (sbyte)7 + , (LLUUID)"00000000000000000000000000000000" + , (LLUUID)"00000000000000000000000000000000" + , (int)10 + , (LLUUID)"25472683cb324516904a6cd0ecabf128" + , (LLUUID)"25472683cb324516904a6cd0ecabf128" + , (LLUUID)"77364021f09f13dfb692f036be53b9e2" + , (LLUUID)"a4947fc066c247518d9854aaf90097f4" + , (uint)0 + , (uint)0 + , (uint)2147483647 + , (uint)0 + , (uint)2147483647 + ); + + if( test != (uint)895206313 ) + { + Console.WriteLine("CRC Generation is no longer correct."); + return; + } +*/ + + public static uint InventoryUpdateCRC(InventoryItem iitem) + { + return InventoryUpdateCRC( + iitem.CreationDate + , iitem.SaleType + , iitem.InvType + , iitem.Type + , iitem.AssetID + , iitem.GroupID + , iitem.SalePrice + , iitem.OwnerID + , iitem.CreatorID + , iitem.ItemID + , iitem.FolderID + , iitem.EveryoneMask + , iitem.Flags + , iitem.NextOwnerMask + , iitem.GroupMask + , iitem.OwnerMask + ); + } + + private static uint InventoryUpdateCRC ( + int creationDate + , byte saleType + , sbyte invType, sbyte type + , LLUUID assetID + , LLUUID groupID + , int salePrice + , LLUUID ownerID + , LLUUID creatorID + , LLUUID itemID + , LLUUID folderID + , uint everyoneMask + , uint flags + , uint nextOwnerMask + , uint groupMask + , uint ownerMask + ) + { + + uint CRC = 0; + + /* IDs */ + CRC += assetID.CRC(); // AssetID + CRC += folderID.CRC(); // FolderID + CRC += itemID.CRC(); // ItemID + + /* Permission stuff */ + CRC += creatorID.CRC(); // CreatorID + CRC += ownerID.CRC(); // OwnerID + CRC += groupID.CRC(); // GroupID + + /* CRC += another 4 words which always seem to be zero -- unclear if this is a LLUUID or what */ + CRC += ownerMask; //owner_mask; // Either owner_mask or next_owner_mask may need to be + CRC += nextOwnerMask; //next_owner_mask; // switched with base_mask -- 2 values go here and in my + CRC += everyoneMask; //everyone_mask; // study item, the three were identical. + CRC += groupMask; //group_mask; + + /* The rest of the CRC fields */ + CRC += flags; // Flags + CRC += (uint)invType; // InvType + CRC += (uint)type; // Type + CRC += (uint)creationDate; // CreationDate + CRC += (uint)salePrice; // SalePrice + CRC += (uint)((uint)saleType * 0x07073096); // SaleType + + return CRC; + } + } +} diff --git a/old/libsecondlife-cs/Packets/InventoryPacketsOld.cs b/old/libsecondlife-cs/Packets/InventoryPacketsOld.cs new file mode 100644 index 00000000..cccaf20b --- /dev/null +++ b/old/libsecondlife-cs/Packets/InventoryPacketsOld.cs @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class InventoryOld + { + public static Packet FetchInventoryDescendents(ProtocolManager protocol, LLUUID ownerID, + LLUUID folderID, LLUUID agentID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["OwnerID"] = ownerID; + fields["FolderID"] = folderID; + fields["SortOrder"] = (int)1; // TODO: Any ideas on valid values for this field? + fields["FetchFolders"] = true; + fields["FetchItems"] = true; + blocks[fields] = "InventoryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("FetchInventoryDescendents", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet RequestInventoryAsset(ProtocolManager protocol, LLUUID agentID, + LLUUID queryID, LLUUID ownerID, LLUUID itemID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["QueryID"] = queryID; + fields["OwnerID"] = ownerID; + fields["ItemID"] = itemID; + blocks[fields] = "QueryData"; + + return PacketBuilder.BuildPacket("RequestInventoryAsset", protocol, blocks, Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + } + + public static Packet UpdateInventoryItem(ProtocolManager protocol, string name, string description, + sbyte inventoryType, sbyte type, LLUUID assetID, LLUUID groupID, LLUUID creatorID, LLUUID ownerID, + LLUUID folderID, LLUUID itemID, int salePrice, byte saleType, uint baseMask, uint everyoneMask, + uint nextOwnerMask, uint groupMask, uint ownerMask, bool groupOwned, uint flags) + { + TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); + int now = (int)t.TotalSeconds; + + uint CRC = 0; + + // IDs + CRC += assetID.CRC(); + CRC += folderID.CRC(); + CRC += itemID.CRC(); + + // Permission stuff + CRC += creatorID.CRC(); + CRC += ownerID.CRC(); + CRC += groupID.CRC(); + + // CRC += another 4 words which always seem to be zero -- unclear if this is a LLUUID or what + CRC += ownerMask; // Either owner_mask or next_owner_mask may need to be + CRC += nextOwnerMask; // switched with base_mask -- 2 values go here and in my + CRC += everyoneMask; // study item, the three were identical. + CRC += groupMask; + + // The rest of the CRC fields + CRC += flags; + CRC += (uint)inventoryType; + CRC += (uint)type; + CRC += (uint)now; + CRC += (uint)salePrice; + CRC += (uint)((uint)saleType * 0x07073096); + + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["GroupOwned"] = groupOwned; + fields["CRC"] = CRC; + fields["CreationDate"] = now; + fields["SaleType"] = saleType; + fields["BaseMask"] = baseMask; + fields["Name"] = name; + fields["InvType"] = inventoryType; + fields["Type"] = type; + fields["AssetID"] = assetID; + fields["GroupID"] = groupID; + fields["SalePrice"] = salePrice; + fields["OwnerID"] = ownerID; + fields["CreatorID"] = creatorID; + fields["ItemID"] = itemID; + fields["FolderID"] = folderID; + fields["EveryoneMask"] = everyoneMask; + fields["Description"] = description; + fields["Flags"] = flags; + fields["NextOwnerMask"] = nextOwnerMask; + fields["GroupMask"] = groupMask; + fields["OwnerMask"] = ownerMask; + + return null; + } + } +} diff --git a/old/libsecondlife-cs/Packets/NetworkPackets.cs b/old/libsecondlife-cs/Packets/NetworkPackets.cs new file mode 100644 index 00000000..033e2b01 --- /dev/null +++ b/old/libsecondlife-cs/Packets/NetworkPackets.cs @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class Network + { + public static Packet PacketAck(ProtocolManager protocol, ArrayList acks) + { + Hashtable blocks = new Hashtable(); + Hashtable fields; + + foreach (uint ack in acks) + { + fields = new Hashtable(); + fields["ID"] = ack; + blocks[fields] = "Packets"; + } + + return PacketBuilder.BuildPacket("PacketAck", protocol, blocks, 0); + } + + public static Packet UseCircuitCode(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, + uint circuitCode) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + fields["ID"] = agentID; + fields["SessionID"] = sessionID; + fields["Code"] = circuitCode; + blocks[fields] = "CircuitCode"; + + return PacketBuilder.BuildPacket("UseCircuitCode", protocol, blocks, Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + } + + public static Packet CompletePingCheck(ProtocolManager protocol, byte pingID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + fields["PingID"] = pingID; + blocks[fields] = "PingID"; + + return PacketBuilder.BuildPacket("CompletePingCheck", protocol, blocks, Helpers.MSG_ZEROCODED); + } + + public static Packet ConfirmEnableSimulator(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ConfirmEnableSimulator", protocol, blocks, Helpers.MSG_ZEROCODED); + } + + public static Packet LogoutRequest(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("LogoutRequest", protocol, blocks, Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + } + } +} diff --git a/old/libsecondlife-cs/Packets/ObjectPackets.cs b/old/libsecondlife-cs/Packets/ObjectPackets.cs new file mode 100644 index 00000000..cbbf6ced --- /dev/null +++ b/old/libsecondlife-cs/Packets/ObjectPackets.cs @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class Object + { + public static Packet ObjectAdd(ProtocolManager protocol, LLUUID senderID, LLUUID targetID, + LLVector3 rayStart, LLVector3 rayEnd, PrimObject prim, + byte[] textureEntry) + { + Hashtable fields = new Hashtable(); + Hashtable blocks = new Hashtable(); + + fields["AddFlags"] = (uint)2; // TODO: ??? + fields["PathTwistBegin"] = (sbyte)prim.PathTwistBegin; + fields["PathEnd"] = (byte)prim.PathEnd; + fields["ProfileBegin"] = (byte)prim.ProfileBegin; + fields["PathRadiusOffset"] = (sbyte)prim.PathRadiusOffset; + fields["PathSkew"] = (sbyte)prim.PathSkew; + fields["SenderID"] = senderID; + fields["RayStart"] = rayStart; + fields["ProfileCurve"] = (prim.ProfileCurve > 5) ? (byte)5 : (byte)prim.ProfileCurve; + fields["PathScaleX"] = (byte)prim.PathScaleX; + fields["PathScaleY"] = (byte)prim.PathScaleY; + fields["GroupID"] = prim.GroupID; + fields["Material"] = (byte)prim.Material; + fields["NameValue"] = prim.Name; + fields["PathShearX"] = (byte)prim.PathShearX; + fields["PathShearY"] = (byte)prim.PathShearY; + fields["PathTaperX"] = (sbyte)prim.PathTaperX; + fields["PathTaperY"] = (sbyte)prim.PathTaperY; + fields["RayEndIsIntersection"] = (byte)0; + fields["RayEnd"] = rayEnd; + fields["ProfileEnd"] = (byte)prim.ProfileEnd; + fields["PathBegin"] = (byte)prim.PathBegin; + fields["BypassRaycast"] = (byte)1; + fields["PCode"] = (byte)9; // TODO: ??? + fields["PathCurve"] = (byte)prim.PathCurve; + fields["Scale"] = prim.Scale; + fields["State"] = (byte)prim.State; + fields["PathTwist"] = (sbyte)prim.PathTwist; + fields["TextureEntry"] = textureEntry; + fields["ProfileHollow"] = (byte)prim.ProfileHollow; + fields["PathRevolutions"] = (byte)prim.PathRevolutions; + fields["Rotation"] = prim.Rotation; + fields["RayTargetID"] = targetID; + blocks[fields] = "ObjectData"; + + return PacketBuilder.BuildPacket("ObjectAdd", protocol, blocks, Helpers.MSG_RELIABLE); + } + } +} diff --git a/old/libsecondlife-cs/Packets/ParcelPackets.cs b/old/libsecondlife-cs/Packets/ParcelPackets.cs new file mode 100644 index 00000000..4fd7926f --- /dev/null +++ b/old/libsecondlife-cs/Packets/ParcelPackets.cs @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class Parcel + { + // DataServer Based ------------------------------------------------- + public static Packet ParcelInfoRequest(ProtocolManager protocol, LLUUID parcelID, + LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["ParcelID"] = parcelID; + blocks[fields] = "Data"; + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ParcelInfoRequest", protocol, blocks, + Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + } + + // Sim Based --------------------------------------------------------- + public static Packet ParcelBuy(ProtocolManager protocol, int localID, bool groupOwned, + LLUUID groupID, bool final, LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["LocalID"] = localID; + fields["IsGroupOwned"] = groupOwned; + fields["GroupID"] = groupID; + fields["Final"] = final; + blocks[fields] = "Data"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ParcelBuy", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelDeedToGroup(ProtocolManager protocol, int localID, LLUUID groupID, + LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["LocalID"] = localID; + fields["GroupID"] = groupID; + blocks[fields] = "Data"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ParcelDeedToGroup", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelDwellRequest(ProtocolManager protocol, LLUUID agentID, int localID, LLUUID parcelID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["LocalID"] = localID; + fields["ParcelID"] = parcelID; + blocks[fields] = "Data"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ParcelDwellRequest", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelReclaim(ProtocolManager protocol, int localID, + LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["LocalID"] = localID; + blocks[fields] = "Data"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ParcelReclaim", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelRelease(ProtocolManager protocol, int localID, + LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["LocalID"] = localID; + blocks[fields] = "Data"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("ParcelRelease", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelJoin(ProtocolManager protocol, LLUUID agentID, + float west, float south, float east, float north) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["West"] = west; + fields["South"] = south; + fields["East"] = east; + fields["North"] = north; + + blocks[fields] = "ParcelData"; + return PacketBuilder.BuildPacket("ParcelJoin", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelDivide(ProtocolManager protocol, LLUUID agentID, + float west, float south, float east, float north) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["West"] = west; + fields["South"] = south; + fields["East"] = east; + fields["North"] = north; + + blocks[fields] = "ParcelData"; + return PacketBuilder.BuildPacket("ParcelDivide", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelPropertiesRequest(ProtocolManager protocol, LLUUID agentID, int sequenceID, + float west, float south, float east, float north, bool snapSelection) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SequenceID"] = sequenceID; + fields["West"] = west; + fields["South"] = south; + fields["East"] = east; + fields["North"] = north; + fields["SnapSelection"] = snapSelection; + + blocks[fields] = "ParcelData"; + return PacketBuilder.BuildPacket("ParcelPropertiesRequest", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelPropertiesRequestByID(ProtocolManager protocol, LLUUID agentID, int sequenceID, + int localID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SequenceID"] = sequenceID; + fields["LocalID"] = localID; + + blocks[fields] = "ParcelData"; + return PacketBuilder.BuildPacket("ParcelPropertiesRequestByID", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelPropertiesUpdate(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, libsecondlife.Parcel parcel) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["LocalID"] = parcel.LocalID; + fields["Flags"] = 0; //TODO: !!IMPORTANT!! Find out what we are. + fields["ParcelFlags"] = parcel.ParcelFlags; + fields["SalePrice"] = parcel.SalePrice; + fields["Name"] = parcel.Name; + fields["Desc"] = parcel.Desc; + fields["MusicURL"] = parcel.MusicURL; + fields["MediaURL"] = parcel.MediaURL; + fields["MediaID"] = parcel.MediaID; + fields["MediaAutoScale"] = parcel.MediaAutoScale; + fields["GroupID"] = parcel.GroupID; + fields["PassPrice"] = parcel.PassPrice; + fields["PassHours"] = parcel.PassHours; + fields["Category"] = parcel.Category; + fields["AuthBuyerID"] = parcel.AuthBuyerID; + fields["SnapshotID"] = parcel.SnapshotID; + fields["UserLocation"] = parcel.UserLocation; + fields["UserLookAt"] = parcel.UserLookAt; + fields["LandingType"] = parcel.LandingType; + blocks[fields] = "ParcelData"; + + return PacketBuilder.BuildPacket("ParcelPropertiesUpdate", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelReturnObjects(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, int localID, int returnType, + int otherCleanTime) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["LocalID"] = localID; + fields["ReturnType"] = returnType; + fields["OtherCleanTime"] = otherCleanTime; + blocks[fields] = "ParcelData"; + + return PacketBuilder.BuildPacket("ParcelPropertiesRequestByID", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet ParcelReturnObjects(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, int localID, int returnType, + int otherCleanTime, LLUUID ownerID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["LocalID"] = localID; + fields["ReturnType"] = returnType; + fields["OtherCleanTime"] = otherCleanTime; + blocks[fields] = "ParcelData"; + + fields = new Hashtable(); + fields["OwnerID"] = ownerID; + + blocks[fields] = "OwnerIDs"; + + return PacketBuilder.BuildPacket("ParcelPropertiesRequestByID", protocol, blocks, Helpers.MSG_RELIABLE); + } + } +} diff --git a/old/libsecondlife-cs/Packets/SimPackets.cs b/old/libsecondlife-cs/Packets/SimPackets.cs new file mode 100644 index 00000000..17dd7d57 --- /dev/null +++ b/old/libsecondlife-cs/Packets/SimPackets.cs @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class Sim + { + public static Packet MapNameRequest(ProtocolManager protocol, LLUUID agentID, uint flags, uint estateID, bool godlike, string name) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["Flags"] = flags; + fields["EstateID"] = estateID; + fields["Godlike"] = godlike; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["Name"] = name; + blocks[fields] = "NameData"; + + return PacketBuilder.BuildPacket("MapNameRequest", protocol, blocks, Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + } + + public static Packet MapBlockRequest(ProtocolManager protocol, LLUUID agentID, uint flags, uint estateID, bool godlike, + ushort minX, ushort maxX, ushort minY, ushort maxY) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["AgentID"] = agentID; + fields["Flags"] = flags; + fields["EstateID"] = estateID; + fields["Godlike"] = godlike; + blocks[fields] = "AgentData"; + + fields = new Hashtable(); + fields["MinX"] = minX; + fields["MaxX"] = maxX; + fields["MinY"] = minY; + fields["MaxY"] = maxY; + blocks[fields] = "PositionData"; + + return PacketBuilder.BuildPacket("MapBlockRequest", protocol, blocks, Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + } + + public static Packet CompleteAgentMovement(ProtocolManager protocol, LLUUID agentID, LLUUID sessionID, + uint circuitCode) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + fields["CircuitCode"] = circuitCode; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("CompleteAgentMovement", protocol, blocks, Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + } + + public static Packet AgentUpdate(ProtocolManager protocol, LLUUID agentID, float drawDistance, + LLVector3 cameraCenter, byte flags, byte state) + { + LLVector3 cameraAtAxis = new LLVector3(0.0F, 1.0F, 0.0F); // Looking straight ahead, north + LLVector3 cameraLeftAxis = new LLVector3(0.0F, 0.0F, 0.0F); //FIXME + LLVector3 cameraUpAxis = new LLVector3(0.0F, 0.0F, 0.0F); //FIXME + LLQuaternion headRotation = new LLQuaternion(0.0F, 0.0F, 0.0F, 0.0F); + + return AgentUpdate(protocol, agentID, drawDistance, cameraCenter, + cameraAtAxis, cameraLeftAxis, cameraUpAxis, headRotation, flags, state); + } + + public static Packet AgentUpdate(ProtocolManager protocol, LLUUID agentID, float drawDistance, + LLVector3 cameraCenter, LLVector3 cameraAtAxis, LLVector3 cameraLeftAxis, LLVector3 cameraUpAxis, + LLQuaternion headRotation, byte flags, byte state) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["ID"] = agentID; + fields["ControlFlags"] = (uint)0; + fields["CameraAtAxis"] = cameraAtAxis; + fields["Far"] = drawDistance; + fields["CameraCenter"] = cameraCenter; + fields["CameraLeftAxis"] = cameraLeftAxis; + fields["HeadRotation"] = headRotation; + fields["CameraUpAxis"] = cameraUpAxis; + fields["BodyRotation"] = new LLQuaternion(0.0F, 0.0F, 0.0F, 0.0F); + fields["Flags"] = flags; + fields["State"] = state; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("AgentUpdate", protocol, blocks, (byte)0); + } + + + public static Packet DirFindQuery(ProtocolManager protocol, string query, int queryStart, LLUUID queryID, + LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["QueryID"] = queryID; + fields["QueryFlags"] = (uint)1; + fields["QueryStart"] = queryStart; + fields["QueryText"] = query; + blocks[fields] = "QueryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("DirFindQuery", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet DirLandQuery(ProtocolManager protocol, bool reservedNewbie, bool forSale, LLUUID queryID, + bool auction, uint queryFlags, LLUUID agentID, LLUUID sessionID) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["ReservedNewbie"] = reservedNewbie; + fields["ForSale"] = forSale; + fields["QueryID"] = queryID; + fields["Auction"] = auction; + fields["QueryFlags"] = queryFlags; + blocks[fields] = "QueryData"; + + fields = new Hashtable(); + fields["AgentID"] = agentID; + fields["SessionID"] = sessionID; + blocks[fields] = "AgentData"; + + return PacketBuilder.BuildPacket("DirLandQuery", protocol, blocks, Helpers.MSG_RELIABLE); + } + } +} diff --git a/old/libsecondlife-cs/Packets/TransferPackets.cs b/old/libsecondlife-cs/Packets/TransferPackets.cs new file mode 100644 index 00000000..3c1c21fd --- /dev/null +++ b/old/libsecondlife-cs/Packets/TransferPackets.cs @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; + +namespace libsecondlife.Packets +{ + public class Transfer + { + public static Packet AssetUploadRequest(ProtocolManager protocol, LLUUID uuid, sbyte type, bool tempfile) + { + return AssetUploadRequest(protocol, uuid, type, tempfile, null); + } + + public static Packet AssetUploadRequest(ProtocolManager protocol, LLUUID uuid, sbyte type, + bool tempfile, byte[] assetData) + { + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + + fields["UUID"] = uuid; + fields["Type"] = type; + fields["Tempfile"] = tempfile; + + if (assetData != null) + { + fields["AssetData"] = assetData; + } + + blocks[fields] = "AssetBlock"; + + return PacketBuilder.BuildPacket("AssetUploadRequest", protocol, blocks, Helpers.MSG_RELIABLE); + } + + public static Packet RequestXfer() + { + return null; + } + + public static Packet SendXferPacket() + { + return null; + } + + public static Packet AssetUploadComplete() + { + return null; + } + } +} diff --git a/old/libsecondlife-cs/Parcel.cs b/old/libsecondlife-cs/Parcel.cs new file mode 100644 index 00000000..0f5971b2 --- /dev/null +++ b/old/libsecondlife-cs/Parcel.cs @@ -0,0 +1,809 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Timers; +using System.Collections; + +namespace libsecondlife +{ + // Class for parcels used by the dataserver + // Such as the "For-Sale" listings + public class DirectoryParcel + { + public LLUUID ID; + public LLUUID OwnerID; + public LLUUID SnapshotID; + public U64 RegionHandle; + public string Name; + public string SimName; + public string Desc; + public int SalePrice; + public int ActualArea; + public LLVector3 GlobalPosition; + public LLVector3 SimPosition; + public float Dwell; + + public DirectoryParcel() + { + GlobalPosition = new LLVector3(); + SimPosition = new LLVector3(); + } + } + + // Class for parcels within a sim + public class Parcel + { + public int RequestResult; + public int SequenceID; + public bool SnapSelection; + public int SelfCount; + public int OtherCount; + public int PublicCount; + public int LocalID; + public LLUUID OwnerID; + public bool IsGroupOwned; + public uint AuctionID; + public bool ReservedNewbie; + public int ClaimDate; + public int ClaimPrice; + public int RentPrice; + public LLVector3 AABBMin; + public LLVector3 AABBMax; + public byte[] Bitmap; + public int Area; + public byte Status; + public int SimWideMaxObjects; + public int SimWideTotalObjects; + public int MaxObjects; + public int TotalObjects; + public int OwnerObjects; + public int GroupObjects; + public int OtherObjects; + public float ParcelObjectBonus; + public int OtherCleanTime; + public uint ParcelFlags; + public int SalePrice; + public string Name; + public string Desc; + public string MusicURL; + public string MediaURL; + public LLUUID MediaID; + public byte MediaAutoScale; + public LLUUID GroupID; + public int PassPrice; + public float PassHours; + public byte Category; + public LLUUID AuthBuyerID; + public LLUUID SnapshotID; + public LLVector3 UserLocation; + public LLVector3 UserLookAt; + public byte LandingType; + public float Dwell; + + private Simulator Sim; // Using Sim instead of Region since it references both + + private void init() + { + Dwell = 0.0f; + RequestResult = 0; + SequenceID = 0; + SnapSelection = false; + SelfCount = 0; + OtherCount = 0; + PublicCount = 0; + LocalID = 0; + OwnerID = new LLUUID(); + IsGroupOwned = false; + AuctionID = 0; + ReservedNewbie = false; + ClaimDate = 0; + ClaimPrice = 0; + RentPrice = 0; + AABBMin = new LLVector3(); + AABBMax = new LLVector3(); + Bitmap = new byte[512]; + Area = 0; + Status = 0; + SimWideMaxObjects = 0; + SimWideTotalObjects = 0; + MaxObjects = 0; + TotalObjects = 0; + OwnerObjects = 0; + GroupObjects = 0; + OtherObjects = 0; + ParcelObjectBonus = 0.0f; + OtherCleanTime = 0; + ParcelFlags = 0; + SalePrice = 0; + Name = ""; + Desc = ""; + MusicURL = ""; + MediaURL = ""; + MediaID = new LLUUID(); + MediaAutoScale = 0; + GroupID = new LLUUID(); + PassPrice = 0; + PassHours = 0.0f; + Category = 0; + AuthBuyerID = new LLUUID(); + SnapshotID = new LLUUID(); + UserLocation = new LLVector3(); + UserLookAt = new LLVector3(); + LandingType = 0; + } + + public Parcel() + { + init(); + } + + public Parcel(Simulator simulator) + { + Sim = simulator; + init(); + } + + public void GetDwell(SecondLife client) + { + Packet DwellPacket = Packets.Parcel.ParcelDwellRequest(client.Protocol,client.Avatar.ID,LocalID,new LLUUID()); + Sim.SendPacket(DwellPacket,true); + } + + public bool Buy(SecondLife client, bool forGroup, LLUUID groupID) + { + Packet buyPacket = Packets.Parcel.ParcelBuy(client.Protocol,LocalID,forGroup,groupID,true,client.Avatar.ID,client.Network.SessionID); + Sim.SendPacket(buyPacket,true); + + return false; + } + + public bool Reclaim(SecondLife client) + { + Packet reclaimPacket = Packets.Parcel.ParcelReclaim(client.Protocol,LocalID,client.Avatar.ID,client.Network.SessionID); + Sim.SendPacket(reclaimPacket,true); + + return false; + } + + public bool Deed(SecondLife client, LLUUID groupID) + { + Packet deedPacket = Packets.Parcel.ParcelDeedToGroup(client.Protocol,LocalID,groupID,client.Avatar.ID,client.Network.SessionID); + Sim.SendPacket(deedPacket,true); + + return false; + } + + public void Update(SecondLife client) + { + Packet updatePacket = Packets.Parcel.ParcelPropertiesUpdate(client.Protocol,client.Avatar.ID,client.Network.SessionID,this); + Sim.SendPacket(updatePacket,true); + } + + public void ReturnObjects(SecondLife client, int returnType, int otherCleanTime) + { + Packet returnPacket = Packets.Parcel.ParcelReturnObjects(client.Protocol,client.Avatar.ID,client.Network.SessionID,LocalID, + returnType,otherCleanTime); + Sim.SendPacket(returnPacket,true); + } + + public void ReturnObjects(SecondLife client, int returnType, int otherCleanTime, LLUUID ownerID) + { + Packet returnPacket = Packets.Parcel.ParcelReturnObjects(client.Protocol,client.Avatar.ID,client.Network.SessionID,LocalID, + returnType,otherCleanTime,ownerID); + Sim.SendPacket(returnPacket,true); + } + } + + public class ParcelManager + { + public ArrayList ParcelsForSale; + + private SecondLife Client; + private bool ReservedNewbie; + private bool ForSale; + private bool Auction; + private bool Finished; + private Timer DirLandTimer; + private bool DirLandTimeout; + private bool ParcelInfoTimeout; + private DirectoryParcel ParcelInfoParcel; + + public ParcelManager(SecondLife client) + { + Client = client; + ParcelsForSale = new ArrayList(); + + // Setup the callbacks + PacketCallback callback = new PacketCallback(DirLandReplyHandler); + Client.Network.RegisterCallback("DirLandReply", callback); + callback = new PacketCallback(ParcelInfoReplyHandler); + Client.Network.RegisterCallback("ParcelInfoReply", callback); + callback = new PacketCallback(ParcelPropertiesHandler); + Client.Network.RegisterCallback("ParcelProperties",callback); + callback = new PacketCallback(ParcelDwellReplyHandler); + Client.Network.RegisterCallback("ParcelDwellReply",callback); + } + + public void ParcelDwellReplyHandler(Packet packet, Simulator simulator) + { + int LocalID = 0; + LLUUID ParcelID = new LLUUID(); + float Dwell = 0.0f; + + foreach( Block block in packet.Blocks()) + { + foreach(Field field in block.Fields) + { + if(field.Layout.Name == "LocalID") + LocalID = (int)field.Data; + else if(field.Layout.Name == "ParcelID") + ParcelID = (LLUUID)field.Data; + else if(field.Layout.Name == "Dwell") + Dwell = (float)field.Data; + } + } + if(Dwell != 0.0f && simulator.Region.Parcels.ContainsKey(LocalID)) + ((Parcel)simulator.Region.Parcels[LocalID]).Dwell = Dwell; + } + + public bool RequestParcelInfo(DirectoryParcel parcel) + { + int attempts = 0; + + Beginning: + if (attempts++ > 3) + { + return false; + } + + Finished = false; + ParcelInfoTimeout = false; + ParcelInfoParcel = parcel; + + // Setup the timer + Timer ParcelInfoTimer = new Timer(5000); + ParcelInfoTimer.Elapsed += new ElapsedEventHandler(ParcelInfoTimerEvent); + ParcelInfoTimeout = false; + + // Build the ParcelInfoRequest packet + Packet parcelInfoPacket = Packets.Parcel.ParcelInfoRequest(Client.Protocol, parcel.ID, + Client.Network.AgentID, Client.Network.SessionID); + + // Start the timer + ParcelInfoTimer.Start(); + + Client.Network.SendPacket(parcelInfoPacket); + + while (!Finished) + { + if (ParcelInfoTimeout) + { + goto Beginning; + } + + Client.Tick(); + } + + return true; + } + + public void ParcelPropertiesHandler(Packet packet, Simulator simulator) + { + // Marked == Added to Parcel Class specifically for this Packet + // -> XYZ == Equivilent to property XYZ in Packet. + int RequestResult = 0; + int SequenceID = 0; + bool SnapSelection = false; + int SelfCount = 0; + int OtherCount = 0; + int PublicCount = 0; + int LocalID = 0; // Marked + LLUUID OwnerID = new LLUUID(); // -> OwnerID + bool IsGroupOwned = false; // Marked + uint AuctionID = 0; + bool ReservedNewbie = false; // Marked -> FirstLand + int ClaimDate = 0; // Marked + int ClaimPrice = 0; + int RentPrice = 0; + LLVector3 AABBMin = new LLVector3(); + LLVector3 AABBMax = new LLVector3(); + byte[] Bitmap = new byte[512]; // Marked + int Area = 0; // -> ActualArea + byte Status = 0; + int SimWideMaxObjects = 0; + int SimWideTotalObjects = 0; + int MaxObjects = 0; + int TotalObjects = 0; + int OwnerObjects = 0; + int GroupObjects = 0; + int OtherObjects = 0; + float ParcelObjectBonus = 0.0f; + int OtherCleanTime = 0; + uint ParcelFlags = 0; + int SalePrice = 0; // -> SalePrice + string Name = ""; + string Desc = ""; + string MusicURL = ""; + string MediaURL = ""; + LLUUID MediaID = new LLUUID(); + byte MediaAutoScale = 0; + LLUUID GroupID = new LLUUID(); + int PassPrice = 0; + float PassHours = 0.0f; + byte Category = 0; + LLUUID AuthBuyerID = new LLUUID(); // Marked + LLUUID SnapshotID = new LLUUID(); // -> SnapshotID + LLVector3 UserLocation = new LLVector3(); + LLVector3 UserLookAt = new LLVector3(); + byte LandingType = 0; + + foreach( Block block in packet.Blocks()) + { + foreach(Field field in block.Fields) + { + if(field.Layout.Name == "RequestResult") + RequestResult = (int)field.Data; + else if(field.Layout.Name == "SequenceID") + SequenceID = (int)field.Data; + else if(field.Layout.Name == "SnapSelection") + SnapSelection = (bool)field.Data; + else if(field.Layout.Name == "SelfCount") + SelfCount = (int)field.Data; + else if(field.Layout.Name == "OtherCount") + OtherCount = (int)field.Data; + else if(field.Layout.Name == "PublicCount") + PublicCount = (int)field.Data; + else if(field.Layout.Name == "LocalID") + LocalID = (int)field.Data; + else if(field.Layout.Name == "OwnerID") + OwnerID = (LLUUID)field.Data; + else if(field.Layout.Name == "IsGroupOwned") + IsGroupOwned = (bool)field.Data; + else if(field.Layout.Name == "AuctionID") + AuctionID = (uint)field.Data; + else if(field.Layout.Name == "ReservedNewbie") + ReservedNewbie = (bool)field.Data; + else if(field.Layout.Name == "ClaimDate") + ClaimDate = (int)field.Data; + else if(field.Layout.Name == "ClaimPrice") + ClaimPrice = (int)field.Data; + else if(field.Layout.Name == "RentPrice") + RentPrice = (int)field.Data; + else if(field.Layout.Name == "AABBMin") + AABBMin = (LLVector3)field.Data; + else if(field.Layout.Name == "AABBMax") + AABBMax = (LLVector3)field.Data; + else if(field.Layout.Name == "Bitmap") + Bitmap = (byte[])field.Data; + else if(field.Layout.Name == "Area") + Area = (int)field.Data; + else if(field.Layout.Name == "Status") + Status = (byte)field.Data; + else if(field.Layout.Name == "SimWideMaxObjects") + SimWideMaxObjects = (int)field.Data; + else if(field.Layout.Name == "SimWideTotalObjects") + SimWideTotalObjects = (int)field.Data; + else if(field.Layout.Name == "MaxObjects") + MaxObjects = (int)field.Data; + else if(field.Layout.Name == "TotalObjects") + TotalObjects = (int)field.Data; + else if(field.Layout.Name == "OwnerObjects") + OwnerObjects = (int)field.Data; + else if(field.Layout.Name == "GroupObjects") + GroupObjects = (int)field.Data; + else if(field.Layout.Name == "OtherObjects") + OtherObjects = (int)field.Data; + else if(field.Layout.Name == "ParcelObjectBonus") + ParcelObjectBonus = (float)field.Data; + else if(field.Layout.Name == "OtherCleanTime") + OtherCleanTime = (int)field.Data; + else if(field.Layout.Name == "ParcelFlags") + ParcelFlags = (uint)field.Data; + else if(field.Layout.Name == "SalePrice") + SalePrice = (int)field.Data; + else if(field.Layout.Name == "Name") + Name = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + else if(field.Layout.Name == "Desc") + Desc = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + else if(field.Layout.Name == "MusicURL") + MusicURL = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + else if(field.Layout.Name == "MediaURL") + MediaURL = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + else if(field.Layout.Name == "MediaID") + MediaID = (LLUUID)field.Data; + else if(field.Layout.Name == "MediaAutoScale") + MediaAutoScale = (byte)field.Data; + else if(field.Layout.Name == "GroupID") + GroupID = (LLUUID)field.Data; + else if(field.Layout.Name == "PassPrice") + PassPrice = (int)field.Data; + else if(field.Layout.Name == "PassHours") + PassHours = (float)field.Data; + else if(field.Layout.Name == "Category") + Category = (byte)field.Data; + else if(field.Layout.Name == "AuthBuyerID") + AuthBuyerID = (LLUUID)field.Data; + else if(field.Layout.Name == "SnapshotID") + SnapshotID = (LLUUID)field.Data; + else if(field.Layout.Name == "UserLocation") + UserLocation = (LLVector3)field.Data; + else if(field.Layout.Name == "UserLookAt") + UserLookAt = (LLVector3)field.Data; + else if(field.Layout.Name == "LandingType") + LandingType = (byte)field.Data; + // else + // Client.Log("Unknown field type '" + field.Layout.Name + "' in ParcelProperties",Helpers.LogLevel.Warning); + + } + } + + /* Mark this area as downloaded */ + int x, y, index, subindex; + byte val; + + for(x = 0; x < 64; x++) + { + for(y = 0; y < 64; y++) + { + if(simulator.Region.ParcelMarked[y,x] == 0) + { + index = ((x * 64) + y); + subindex = index % 8; + index /= 8; + + val = Bitmap[index]; + + simulator.Region.ParcelMarked[y,x] = ((val >> subindex) & 1) == 1 ? LocalID : 0; + } + } + } + + /* Fire off the next request, if we are downloading the whole sim */ + bool hasTriggered = false; + if(simulator.Region.ParcelDownloading == true) + { + for(x = 0; x < 64; x++) + { + for(y = 0; y < 64; y++) + { + if(simulator.Region.ParcelMarked[x,y] == 0) + { + Client.Network.SendPacket(libsecondlife.Packets.Parcel.ParcelPropertiesRequest(Client.Protocol,Client.Avatar.ID, -10000 - (x*64) - y, + (x*4.0f),(y*4.0f),(x*4.0f) + 4.0f,(y*4.0f) + 4.0f, false)); + hasTriggered = true; + + goto exit; + } + } + } + exit:; + } + + /* This map is complete, fire callback */ + if(hasTriggered == false) + { + simulator.Region.FilledParcels(); + } + + /* Save this parcels data */ + // TODO: Lots of values are not being stored, Parcel needs to be expanded to take all the data. + simulator.Region.ParcelsMutex.WaitOne(); + + if(!simulator.Region.Parcels.ContainsKey(LocalID)) + { + simulator.Region.Parcels[LocalID] = new Parcel(simulator); + } + + // God help me should I have to type this out again... argh. + ((Parcel)simulator.Region.Parcels[LocalID]).RequestResult = RequestResult; + ((Parcel)simulator.Region.Parcels[LocalID]).SequenceID = SequenceID; + ((Parcel)simulator.Region.Parcels[LocalID]).SnapSelection = SnapSelection; + ((Parcel)simulator.Region.Parcels[LocalID]).SelfCount = SelfCount; + ((Parcel)simulator.Region.Parcels[LocalID]).OtherCount = OtherCount; + ((Parcel)simulator.Region.Parcels[LocalID]).PublicCount = PublicCount; + ((Parcel)simulator.Region.Parcels[LocalID]).LocalID = LocalID; + ((Parcel)simulator.Region.Parcels[LocalID]).OwnerID = OwnerID; + ((Parcel)simulator.Region.Parcels[LocalID]).IsGroupOwned = IsGroupOwned; + ((Parcel)simulator.Region.Parcels[LocalID]).AuctionID = AuctionID; + ((Parcel)simulator.Region.Parcels[LocalID]).ReservedNewbie = ReservedNewbie; + ((Parcel)simulator.Region.Parcels[LocalID]).ClaimDate = ClaimDate; + ((Parcel)simulator.Region.Parcels[LocalID]).ClaimPrice = ClaimPrice; + ((Parcel)simulator.Region.Parcels[LocalID]).RentPrice = RentPrice; + ((Parcel)simulator.Region.Parcels[LocalID]).AABBMin = AABBMin; + ((Parcel)simulator.Region.Parcels[LocalID]).AABBMax = AABBMax; + ((Parcel)simulator.Region.Parcels[LocalID]).Bitmap = Bitmap; + ((Parcel)simulator.Region.Parcels[LocalID]).Area = Area; + ((Parcel)simulator.Region.Parcels[LocalID]).Status = Status; + ((Parcel)simulator.Region.Parcels[LocalID]).SimWideMaxObjects = SimWideMaxObjects; + ((Parcel)simulator.Region.Parcels[LocalID]).SimWideTotalObjects = SimWideTotalObjects; + ((Parcel)simulator.Region.Parcels[LocalID]).MaxObjects = MaxObjects; + ((Parcel)simulator.Region.Parcels[LocalID]).TotalObjects = TotalObjects; + ((Parcel)simulator.Region.Parcels[LocalID]).OwnerObjects = OwnerObjects; + ((Parcel)simulator.Region.Parcels[LocalID]).GroupObjects = GroupObjects; + ((Parcel)simulator.Region.Parcels[LocalID]).OtherObjects = OtherObjects; + ((Parcel)simulator.Region.Parcels[LocalID]).ParcelObjectBonus = ParcelObjectBonus; + ((Parcel)simulator.Region.Parcels[LocalID]).OtherCleanTime = OtherCleanTime; + ((Parcel)simulator.Region.Parcels[LocalID]).ParcelFlags = ParcelFlags; + ((Parcel)simulator.Region.Parcels[LocalID]).SalePrice = SalePrice; + ((Parcel)simulator.Region.Parcels[LocalID]).Name = Name; + ((Parcel)simulator.Region.Parcels[LocalID]).Desc = Desc; + ((Parcel)simulator.Region.Parcels[LocalID]).MusicURL = MusicURL; + ((Parcel)simulator.Region.Parcels[LocalID]).MediaURL = MediaURL; + ((Parcel)simulator.Region.Parcels[LocalID]).MediaID = MediaID; + ((Parcel)simulator.Region.Parcels[LocalID]).MediaAutoScale = MediaAutoScale; + ((Parcel)simulator.Region.Parcels[LocalID]).GroupID = GroupID; + ((Parcel)simulator.Region.Parcels[LocalID]).PassPrice = PassPrice; + ((Parcel)simulator.Region.Parcels[LocalID]).PassHours = PassHours; + ((Parcel)simulator.Region.Parcels[LocalID]).Category = Category; + ((Parcel)simulator.Region.Parcels[LocalID]).AuthBuyerID = AuthBuyerID; + ((Parcel)simulator.Region.Parcels[LocalID]).SnapshotID = SnapshotID; + ((Parcel)simulator.Region.Parcels[LocalID]).UserLocation = UserLocation; + ((Parcel)simulator.Region.Parcels[LocalID]).UserLookAt = UserLookAt; + ((Parcel)simulator.Region.Parcels[LocalID]).LandingType = LandingType; + + simulator.Region.ParcelsMutex.ReleaseMutex(); + } + + + + private void ParcelInfoReplyHandler(Packet packet, Simulator simulator) + { + string simName = ""; + int actualArea = 0; + float globalX = 0.0F; + float globalY = 0.0F; + float globalZ = 0.0F; + LLUUID parcelID = null; + string name = ""; + string desc = ""; + int salePrice = 0; + LLUUID ownerID = null; + LLUUID snapshotID = null; + float dwell = 0.0F; + + try + { + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "ParcelID") + { + parcelID = (LLUUID)field.Data; + + if (!parcelID.Equals(ParcelInfoParcel.ID)) + { + Client.Log("Received a ParcelInfoReply for " + parcelID.ToString() + + ", looking for " + ParcelInfoParcel.ID.ToString(), Helpers.LogLevel.Warning); + + // Build and resend the ParcelInfoRequest packet + Packet parcelInfoPacket = Packets.Parcel.ParcelInfoRequest(Client.Protocol, ParcelInfoParcel.ID, + Client.Network.AgentID, Client.Network.SessionID); + + Client.Network.SendPacket(parcelInfoPacket); + + return; + } + } + else if (field.Layout.Name == "ActualArea") + { + actualArea = (int)field.Data; + } + else if (field.Layout.Name == "SalePrice") + { + salePrice = (int)field.Data; + } + else if (field.Layout.Name == "Name") + { + name = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "SimName") + { + simName = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "GlobalX") + { + globalX = (float)field.Data; + } + else if (field.Layout.Name == "GlobalY") + { + globalY = (float)field.Data; + } + else if (field.Layout.Name == "GlobalZ") + { + globalZ = (float)field.Data; + } + else if (field.Layout.Name == "Desc") + { + desc = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "OwnerID") + { + ownerID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "SnapshotID") + { + snapshotID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "Dwell") + { + dwell = (float)field.Data; + } + } + } + + ParcelInfoParcel.SimName = simName; + ParcelInfoParcel.ActualArea = actualArea; + ParcelInfoParcel.GlobalPosition.X = globalX; + ParcelInfoParcel.GlobalPosition.Y = globalY; + ParcelInfoParcel.GlobalPosition.Z = globalZ; + ParcelInfoParcel.Name = name; + ParcelInfoParcel.Desc = desc; + ParcelInfoParcel.SalePrice = salePrice; + ParcelInfoParcel.OwnerID = ownerID; + ParcelInfoParcel.SnapshotID = snapshotID; + ParcelInfoParcel.Dwell = dwell; + + // Get RegionHandle from GlobalX/GlobalY + uint handleX = (uint)Math.Floor(ParcelInfoParcel.GlobalPosition.X / 256.0F); + handleX *= 256; + uint handleY = (uint)Math.Floor(ParcelInfoParcel.GlobalPosition.Y / 256.0F); + handleY *= 256; + ParcelInfoParcel.RegionHandle = new U64(handleX, handleY); + + // Get SimPosition from GlobalX/GlobalY and RegionHandle + ParcelInfoParcel.SimPosition.X = ParcelInfoParcel.GlobalPosition.X - (float)handleX; + ParcelInfoParcel.SimPosition.Y = ParcelInfoParcel.GlobalPosition.Y - (float)handleY; + ParcelInfoParcel.SimPosition.Z = ParcelInfoParcel.GlobalPosition.Z; + } + catch (Exception e) + { + Client.Log(e.ToString(), Helpers.LogLevel.Error); + } + + Finished = true; + } + + private void ParcelInfoTimerEvent(object source, System.Timers.ElapsedEventArgs ea) + { + ParcelInfoTimeout = true; + } + + public int DirLandRequest(bool reservedNewbie, bool forSale, bool auction) + { + // Set the class-wide variables so the callback has them + ReservedNewbie = reservedNewbie; + ForSale = forSale; + Auction = auction; + + // Clear the list + ParcelsForSale.Clear(); + + // Setup the timer + DirLandTimer = new Timer(15000); + DirLandTimer.Elapsed += new ElapsedEventHandler(DirLandTimerEvent); + DirLandTimeout = false; + DirLandTimer.Start(); + + LLUUID queryID = new LLUUID(); + Packet landQuery = Packets.Sim.DirLandQuery(Client.Protocol, ReservedNewbie, ForSale, queryID, + Auction, 0, Client.Network.AgentID, Client.Network.SessionID); + Client.Network.SendPacket(landQuery); + + while (!DirLandTimeout) + { + Client.Tick(); + } + + // Double check the timer is actually stopped + DirLandTimer.Stop(); + + return ParcelsForSale.Count; + } + + private void DirLandReplyHandler(Packet packet, Simulator simulator) + { + if (!DirLandTimeout) + { + // Reset the timer + DirLandTimer.Stop(); + DirLandTimer.Start(); + + foreach (Block block in packet.Blocks()) + { + DirectoryParcel parcel = new DirectoryParcel(); + + if (block.Layout.Name == "QueryReplies") + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "ReservedNewbie") + { + if ((bool)field.Data != ReservedNewbie) + { + goto Skip; + } + } + else if (field.Layout.Name == "Auction") + { + if ((bool)field.Data != Auction) + { + goto Skip; + } + } + else if (field.Layout.Name == "ForSale") + { + if ((bool)field.Data != ForSale) + { + goto Skip; + } + } + else if (field.Layout.Name == "ParcelID") + { + parcel.ID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "Name") + { + parcel.Name = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "ActualArea") + { + parcel.ActualArea = (int)field.Data; + } + else if (field.Layout.Name == "SalePrice") + { + parcel.SalePrice = (int)field.Data; + } + } + + if (parcel.ID != null) + { + ParcelsForSale.Add(parcel); + } + else + { + Client.Log("Parcel with no ID found in DirLandReply, skipping", Helpers.LogLevel.Warning); + } + } + + Skip: + ; + } + } + else + { + Console.WriteLine("Received a DirLandReply after the timeout!"); + } + } + + private void DirLandTimerEvent(object source, System.Timers.ElapsedEventArgs ea) + { + DirLandTimer.Stop(); + DirLandTimeout = true; + } + } +} diff --git a/old/libsecondlife-cs/Prims.cs b/old/libsecondlife-cs/Prims.cs new file mode 100644 index 00000000..e2948e89 --- /dev/null +++ b/old/libsecondlife-cs/Prims.cs @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace libsecondlife +{ + /// + /// + /// + public class PrimObject + { + public float PathTwistBegin = 0; + public float PathEnd = 0; + public float ProfileBegin = 0; + public float PathRadiusOffset = 0; + public float PathSkew = 0; + public LLVector3 Position = new LLVector3(); + public uint ProfileCurve = 0; + public float PathScaleX = 0; + public float PathScaleY = 0; + public LLUUID ID = new LLUUID(); + public uint LocalID = 0; + public LLUUID GroupID = new LLUUID(); + public uint Material = 0; + public string Name = ""; + public string Description; + public float PathShearX = 0; + public float PathShearY = 0; + public float PathTaperX = 0; + public float PathTaperY = 0; + public float ProfileEnd = 0; + public float PathBegin = 0; + public uint PathCurve = 0; + public LLVector3 Scale = new LLVector3(); + public float PathTwist = 0; + public LLUUID Texture = new LLUUID(); // TODO: Add multi-texture support + public uint ProfileHollow = 0; + public float PathRevolutions = 0; + public LLQuaternion Rotation = new LLQuaternion(); + public uint State; + + public PrimObject(LLUUID texture) + { + Texture = texture; + } + + public PrimObject() + { + Texture = new LLUUID(); + } + + public static byte PathScaleByte(float pathScale) + { + // Y = 100 + 100X + return (byte)(100 + Convert.ToInt16(100.0F * pathScale)); + } + + public static float PathScaleFloat(byte pathScale) + { + // Y = -1 + 0.01X + return (float)pathScale * 0.01F - 1.0F; + } + + public static byte PathTwistByte(float pathTwist) + { + // Y = 256 + ceil (X / 1.8) + ushort temp = Convert.ToUInt16(256 + Math.Ceiling(pathTwist / 1.8F)); + return (byte)(temp % 256); + } + + public static float PathTwistFloat(sbyte pathTwist) + { + // Y = 0.5556X + return (float)pathTwist * 0.5556F; + } + + public static byte PathShearByte(float pathShear) + { + // Y = 256 + 100X + ushort temp = Convert.ToUInt16(100.0F * pathShear); + temp += 256; + return (byte)(temp % 256); + } + + public static float PathShearFloat(byte pathShear) + { + // Y = (X - 256) / 100 + if (pathShear > 150) + { + return ((float)pathShear - 256.0F) / 100.0F; + } + else + { + return (float)pathShear / 100.0F; + } } + + public static byte ProfileBeginByte(float profileBegin) + { + // Y = ceil (200X) + return (byte)Convert.ToInt16(200.0F * profileBegin); + } + + public static float ProfileBeginFloat(byte profileBegin) + { + // Y = 0.005X + return (float)profileBegin * 0.005F; + } + + public static byte ProfileEndByte(float profileEnd) + { + // Y = 200 - ceil (200X) + return (byte)(200 - (200.0F * profileEnd)); + } + + public static float ProfileEndFloat(byte profileEnd) + { + // Y = 1 - 0.005X + return 1.0F - (float)profileEnd * 0.005F; + } + + public static byte PathBeginByte(float pathBegin) + { + // Y = 100X + return (byte)Convert.ToInt16(100.0F * pathBegin); + } + + public static float PathBeginFloat(byte pathBegin) + { + // Y = X / 100 + return (float)pathBegin / 100.0F; + } + + public static byte PathEndByte(float pathEnd) + { + // Y = 100 - 100X + return (byte)(100 - Convert.ToInt16(100.0F * pathEnd)); + } + + public static float PathEndFloat(byte pathEnd) + { + // Y = 1 - X / 100 + return 1.0F - (float)pathEnd / 100; + } + + public static byte PathRadiusOffsetByte(float pathRadiusOffset) + { + // Y = 256 + 100X + return PathShearByte(pathRadiusOffset); + } + + public static float PathRadiusOffsetFloat(sbyte pathRadiusOffset) + { + // Y = X / 100 + return (float)pathRadiusOffset / 100.0F; + } + + public static byte PathRevolutionsByte(float pathRevolutions) + { + // Y = ceil (66X) - 66 + return (byte)(Convert.ToInt16(Math.Ceiling(66.0F * pathRevolutions)) - 66); + } + + public static float PathRevolutionsFloat(byte pathRevolutions) + { + // Y = 1 + 0.015X + return 1.0F + (float)pathRevolutions * 0.015F; + } + + public static byte PathSkewByte(float pathSkew) + { + return PathTaperByte(pathSkew); + } + + public static float PathSkewFloat(byte pathSkew) + { + return PathTaperFloat(pathSkew); + } + + public static byte PathTaperByte(float pathTaper) + { + // Y = 256 + 100X + return PathShearByte(pathTaper); + } + + public static float PathTaperFloat(byte pathTaper) + { + if (pathTaper > 100) + { + return (float)(256 - pathTaper) * 0.01F; + } + else + { + return (float)pathTaper * 0.01F; + } + } + } +} diff --git a/old/libsecondlife-cs/ProtocolManager.cs b/old/libsecondlife-cs/ProtocolManager.cs new file mode 100644 index 00000000..a9de3f0f --- /dev/null +++ b/old/libsecondlife-cs/ProtocolManager.cs @@ -0,0 +1,598 @@ +using System; +using System.Collections; +using System.IO; + +namespace libsecondlife +{ + public enum PacketFrequency + { + Low, + Medium, + High + } + + public enum FieldType + { + U8, + U16, + U32, + U64, + S8, + S16, + S32, + S64, + F32, + F64, + LLUUID, + BOOL, + LLVector3, + LLVector3d, + LLVector4, + LLQuaternion, + IPADDR, + IPPORT, + Variable, + Fixed, + Single, + Multiple + } + + public class MapField : IComparable + { + public int KeywordPosition; + public string Name; + public FieldType Type; + public int Count; + + public int CompareTo(object obj) + { + MapField temp = (MapField)obj; + + if (this.KeywordPosition > temp.KeywordPosition) + { + return 1; + } + else + { + if(temp.KeywordPosition == this.KeywordPosition) + { + return 0; + } + else + { + return -1; + } + } + } + } + + public class MapBlock : IComparable + { + public int KeywordPosition; + public string Name; + public int Count; + public ArrayList Fields; + + public int CompareTo(object obj) + { + MapBlock temp = (MapBlock)obj; + + if (this.KeywordPosition > temp.KeywordPosition) + { + return 1; + } + else + { + if(temp.KeywordPosition == this.KeywordPosition) + { + return 0; + } + else + { + return -1; + } + } + } + } + + public class MapPacket + { + public ushort ID; + public string Name; + public PacketFrequency Frequency; + public bool Trusted; + public bool Encoded; + public ArrayList Blocks; + } + + public class ProtocolManager + { + public Hashtable TypeSizes; + public Hashtable KeywordPositions; + public MapPacket[] LowMaps; + public MapPacket[] MediumMaps; + public MapPacket[] HighMaps; + + private SecondLife Client; + private int i = 0; + + public ProtocolManager(string keywordFile, string mapFile, SecondLife client) + { + Client = client; + + // Initialize the map arrays + LowMaps = new MapPacket[65536]; + MediumMaps = new MapPacket[256]; + HighMaps = new MapPacket[256]; + + // Build the type size hash table + TypeSizes = new Hashtable(); + TypeSizes.Add(FieldType.U8, 1); + TypeSizes.Add(FieldType.U16, 2); + TypeSizes.Add(FieldType.U32, 4); + TypeSizes.Add(FieldType.U64, 8); + TypeSizes.Add(FieldType.S8, 1); + TypeSizes.Add(FieldType.S16, 2); + TypeSizes.Add(FieldType.S32, 4); + TypeSizes.Add(FieldType.S64, 8); + TypeSizes.Add(FieldType.F32, 4); + TypeSizes.Add(FieldType.F64, 8); + TypeSizes.Add(FieldType.LLUUID, 16); + TypeSizes.Add(FieldType.BOOL, 1); + TypeSizes.Add(FieldType.LLVector3, 12); + TypeSizes.Add(FieldType.LLVector3d, 24); + TypeSizes.Add(FieldType.LLVector4, 16); + TypeSizes.Add(FieldType.LLQuaternion, 16); + TypeSizes.Add(FieldType.IPADDR, 4); + TypeSizes.Add(FieldType.IPPORT, 2); + TypeSizes.Add(FieldType.Variable, -1); + TypeSizes.Add(FieldType.Fixed, -2); + + LoadKeywordFile(keywordFile); + LoadMapFile(mapFile); + } + + public MapPacket Command(string command) + { + //TODO: Get a hashtable in here quick! + + foreach (MapPacket map in HighMaps) + { + if (map != null) + { + if (command == map.Name) + { + return map; + } + } + } + + foreach (MapPacket map in MediumMaps) + { + if (map != null) + { + if (command == map.Name) + { + return map; + } + } + } + + // This will speed things up for now + if (command == LowMaps[65531].Name) + { + return LowMaps[65531]; + } + + foreach (MapPacket map in LowMaps) + { + if (map != null) + { + if (command == map.Name) + { + return map; + } + } + } + + throw new Exception("Cannot find map for command \"" + command + "\""); + } + + public MapPacket Command(byte[] data) + { + ushort command; + + if (data.Length < 5) + { + return null; + } + + if (data[4] == 0xFF) + { + if ((byte)data[5] == 0xFF) + { + // Low frequency + command = (ushort)(data[6] * 256 + data[7]); + return Command(command, PacketFrequency.Low); + } + else + { + // Medium frequency + command = (ushort)data[5]; + return Command(command, PacketFrequency.Medium); + } + } + else + { + // High frequency + command = (ushort)data[4]; + return Command(command, PacketFrequency.High); + } + } + + public MapPacket Command(ushort command, PacketFrequency frequency) + { + switch (frequency) + { + case PacketFrequency.High: + return HighMaps[command]; + case PacketFrequency.Medium: + return MediumMaps[command]; + case PacketFrequency.Low: + return LowMaps[command]; + } + + throw new Exception("Cannot find map for command \"" + command + "\" with frequency \"" + frequency + "\""); + } + + public void PrintMap() + { + PrintOneMap(LowMaps, "Low "); + PrintOneMap(MediumMaps, "Medium"); + PrintOneMap(HighMaps, "High "); + } + + private void PrintOneMap(MapPacket[] map, string frequency) { + int i; + + for (i = 0; i < map.Length; ++i) + { + if (map[i] != null) + { + Console.WriteLine("{0} {1,5} - {2} - {3} - {4}", frequency, i, map[i].Name, + map[i].Trusted ? "Trusted" : "Untrusted", + map[i].Encoded ? "Unencoded" : "Zerocoded"); + + foreach (MapBlock block in map[i].Blocks) + { + if (block.Count == -1) + { + Console.WriteLine("\t{0,4} {1} (Variable)", block.KeywordPosition, block.Name); + } + else + { + Console.WriteLine("\t{0,4} {1} ({2})", block.KeywordPosition, block.Name, block.Count); + } + + foreach (MapField field in block.Fields) + { + Console.WriteLine("\t\t{0,4} {1} ({2} / {3})", field.KeywordPosition, field.Name, + field.Type, field.Count); + } + } + } + } + } + + private void LoadKeywordFile(string keywordFile) + { + string line; + StreamReader file; + + KeywordPositions = new Hashtable(); + + // Load the keyword file + try + { + file = File.OpenText(keywordFile); + } + catch(Exception e) + { + Client.Log("Error opening \"" + keywordFile + "\": " + e.Message, Helpers.LogLevel.Error); + throw new Exception("Keyword file error", e); + } + + while((line = file.ReadLine()) != null) + { + KeywordPositions.Add(line.Trim(), i++); + } + + file.Close(); + } + + public static void DecodeMapFile(string mapFile, string outputFile) + { + byte magicKey = 0; + byte[] buffer = new byte[2048]; + int nread; + BinaryReader map; + BinaryWriter output; + + try + { + map = new BinaryReader(new FileStream(mapFile, FileMode.Open)); + } + catch(Exception e) + { + throw new Exception("Map file error", e); + } + + try + { + output = new BinaryWriter(new FileStream(outputFile, FileMode.CreateNew)); + } + catch(Exception e) + { + throw new Exception("Map file error", e); + } + + while ((nread = map.Read(buffer, 0, 2048)) != 0) + { + for (int i = 0; i < nread; ++i) + { + buffer[i] ^= magicKey; + magicKey += 43; + } + + output.Write(buffer, 0, nread); + } + + map.Close(); + output.Close(); + } + + private void LoadMapFile(string mapFile) + { + FileStream map; + ushort low = 1; + ushort medium = 1; + ushort high = 1; + + // Load the protocol map file + try + { + map = new FileStream(mapFile, FileMode.Open, FileAccess.Read); + } + catch(Exception e) + { + throw new Exception("Map file error", e); + } + + try + { + StreamReader r = new StreamReader(map); + r.BaseStream.Seek(0, SeekOrigin.Begin); + string newline; + string trimmedline; + bool inPacket = false; + bool inBlock = false; + MapPacket currentPacket = null; + MapBlock currentBlock = null; + char[] trimArray = new char[] {' ', '\t'}; + + // While not at the end of the file + while (r.Peek() > -1) + { + #region ParseMap + + newline = r.ReadLine(); + trimmedline = System.Text.RegularExpressions.Regex.Replace(newline, @"\s+", " "); + trimmedline = trimmedline.Trim(trimArray); + + if (!inPacket) + { + // Outside of all packet blocks + + if (trimmedline == "{") + { + inPacket = true; + } + } + else + { + // Inside of a packet block + + if (!inBlock) + { + // Inside a packet block, outside of the blocks + + if (trimmedline == "{") + { + inBlock = true; + } + else if (trimmedline == "}") + { + // Reached the end of the packet + currentPacket.Blocks.Sort(); + inPacket = false; + } + else + { + // The packet header + #region ParsePacketHeader + + // Splice the string in to tokens + string[] tokens = trimmedline.Split(new char[] {' ', '\t'}); + + if (tokens.Length > 3) + { + if (tokens[1] == "Fixed") + { + // Remove the leading "0x" + if (tokens[2].Substring(0, 2) == "0x") + { + tokens[2] = tokens[2].Substring(2, tokens[2].Length - 2); + } + + uint fixedID = UInt32.Parse(tokens[2], System.Globalization.NumberStyles.HexNumber); + // Truncate the id to a short + fixedID ^= 0xFFFF0000; + LowMaps[fixedID] = new MapPacket(); + LowMaps[fixedID].ID = (ushort)fixedID; + LowMaps[fixedID].Frequency = PacketFrequency.Low; + LowMaps[fixedID].Name = tokens[0]; + LowMaps[fixedID].Trusted = (tokens[3] == "Trusted"); + LowMaps[fixedID].Encoded = (tokens[4] == "Zerocoded"); + LowMaps[fixedID].Blocks = new ArrayList(); + + currentPacket = LowMaps[fixedID]; + } + else if (tokens[1] == "Low") + { + LowMaps[low] = new MapPacket(); + LowMaps[low].ID = low; + LowMaps[low].Frequency = PacketFrequency.Low; + LowMaps[low].Name = tokens[0]; + LowMaps[low].Trusted = (tokens[2] == "Trusted"); + LowMaps[low].Encoded = (tokens[3] == "Zerocoded"); + LowMaps[low].Blocks = new ArrayList(); + + currentPacket = LowMaps[low]; + + low++; + } + else if (tokens[1] == "Medium") + { + MediumMaps[medium] = new MapPacket(); + MediumMaps[medium].ID = medium; + MediumMaps[medium].Frequency = PacketFrequency.Medium; + MediumMaps[medium].Name = tokens[0]; + MediumMaps[medium].Trusted = (tokens[2] == "Trusted"); + MediumMaps[medium].Encoded = (tokens[3] == "Zerocoded"); + MediumMaps[medium].Blocks = new ArrayList(); + + currentPacket = MediumMaps[medium]; + + medium++; + } + else if (tokens[1] == "High") + { + HighMaps[high] = new MapPacket(); + HighMaps[high].ID = high; + HighMaps[high].Frequency = PacketFrequency.High; + HighMaps[high].Name = tokens[0]; + HighMaps[high].Trusted = (tokens[2] == "Trusted"); + HighMaps[high].Encoded = (tokens[3] == "Zerocoded"); + HighMaps[high].Blocks = new ArrayList(); + + currentPacket = HighMaps[high]; + + high++; + } + else + { + Client.Log("Unknown packet frequency", Helpers.LogLevel.Error); + } + } + + #endregion + } + } + else + { + if (trimmedline.Length > 0 && trimmedline.Substring(0, 1) == "{") + { + // A field + #region ParseField + + MapField field = new MapField(); + + // Splice the string in to tokens + string[] tokens = trimmedline.Split(new char[] {' ', '\t'}); + + field.Name = tokens[1]; + field.KeywordPosition = KeywordPosition(field.Name); + field.Type = (FieldType)Enum.Parse(typeof(FieldType), tokens[2], true); + + if (tokens[3] != "}") + { + field.Count = Int32.Parse(tokens[3]); + } + else + { + field.Count = 1; + } + + // Save this field to the current block + currentBlock.Fields.Add(field); + + #endregion + } + else if (trimmedline == "}") + { + currentBlock.Fields.Sort(); + inBlock = false; + } + else if (trimmedline.Length != 0 && trimmedline.Substring(0, 2) != "//") + { + // The block header + #region ParseBlockHeader + + currentBlock = new MapBlock(); + + // Splice the string in to tokens + string[] tokens = trimmedline.Split(new char[] {' ', '\t'}); + + currentBlock.Name = tokens[0]; + currentBlock.KeywordPosition = KeywordPosition(currentBlock.Name); + currentBlock.Fields = new ArrayList(); + currentPacket.Blocks.Add(currentBlock); + + if (tokens[1] == "Single") + { + currentBlock.Count = 1; + } + else if (tokens[1] == "Multiple") + { + currentBlock.Count = Int32.Parse(tokens[2]); + } + else if (tokens[1] == "Variable") + { + currentBlock.Count = -1; + } + else + { + Client.Log("Unknown block frequency", Helpers.LogLevel.Error); + } + + #endregion + } + } + } + + #endregion + } + + r.Close(); + map.Close(); + } + catch (Exception e) + { + throw e; + } + } + + private int KeywordPosition(string keyword) + { + if (KeywordPositions.ContainsKey(keyword)) + { + return (int)KeywordPositions[keyword]; + } + else + { + Client.Log("Couldn't find keyword: " + keyword, Helpers.LogLevel.Warning); + return -1; + } + } + } +} diff --git a/old/libsecondlife-cs/README.Mono b/old/libsecondlife-cs/README.Mono new file mode 100644 index 00000000..79104394 --- /dev/null +++ b/old/libsecondlife-cs/README.Mono @@ -0,0 +1,39 @@ +How to build libSL-cs using Mono: + +1. Download and install Mono for your platform -- for OS X, I used +ftp://www.go-mono.com/archive/1.1.15/macos-10-ppc/2/MonoFramework-1.1.15_2.macos10.novell.ppc.dmg + +2. If you haven't already, install the Subversion client from +http://subversion.tigris.org/project_packages.html + +3. Grab the latest version of libsecondlife-cs: + +$ svn co svn://svn.gna.org/svn/libsecondlife/trunk libsecondlife +$ cd libsecondlife/libsecondlife-cs + +4. Build the project: + +$ perl build + +If you don't have perl, see 'Building without Perl' below. + +5. The examples will be built and installed into bin/Debug: + +$ cd bin/Debug +$ mono name2key.exe eddy stryker +Info: Connecting to 72.5.13.170:12035 +UUID: f6ec1e24fd294f4cb21e23b42841c8c7 + + +Building without Perl: + +If step 4 fails because you don't have perl installed, you can build +with prj2make instead. First, type: + +$ prj2make libsecondlife.sln + +Open Makefile, and change the line 'MCS=mcs' to 'MCS=gmcs'. + +You can now build the project by typing: + +$ make diff --git a/old/libsecondlife-cs/Region.cs b/old/libsecondlife-cs/Region.cs new file mode 100644 index 00000000..31d76b30 --- /dev/null +++ b/old/libsecondlife-cs/Region.cs @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace libsecondlife +{ + public delegate void ParcelCompleteCallback(Region region); + + /// + /// Represents a region (also known as a sim) in Second Life. + /// + public class Region + { + public LLUUID ID; + public U64 Handle; + public string Name; + public byte[] ParcelOverlay; + public int ParcelOverlaysReceived; + + public int[,] ParcelMarked; // 64x64 Array of parcels which have been successfully downloaded. (and their LocalID's, 0 = Null) + public bool ParcelDownloading; // Flag to indicate whether we are downloading a sim's parcels. + public bool ParcelDwell; // Flag to indicate whether to get Dwell values automatically (NOT USED YET). + // Call .GetDwell() instead. + + public System.Collections.Hashtable Parcels; + public System.Threading.Mutex ParcelsMutex; + + public float TerrainHeightRange00; + public float TerrainHeightRange01; + public float TerrainHeightRange10; + public float TerrainHeightRange11; + public float TerrainStartHeight00; + public float TerrainStartHeight01; + public float TerrainStartHeight10; + public float TerrainStartHeight11; + public float WaterHeight; + + public LLUUID SimOwner; + + public LLUUID TerrainBase0; + public LLUUID TerrainBase1; + public LLUUID TerrainBase2; + public LLUUID TerrainBase3; + public LLUUID TerrainDetail0; + public LLUUID TerrainDetail1; + public LLUUID TerrainDetail2; + public LLUUID TerrainDetail3; + + public bool IsEstateManager; + public EstateTools Estate; + + private SecondLife Client; + + public event ParcelCompleteCallback OnParcelCompletion; + + public Region(SecondLife client) + { + Estate = new EstateTools(client); + Client = client; + ID = new LLUUID(); + Handle = new U64(); + Name = ""; + ParcelOverlay = new byte[4096]; + ParcelOverlaysReceived = 0; + + ParcelMarked = new int[64, 64]; + ParcelDownloading = false; + ParcelDwell = false; + + Parcels = new System.Collections.Hashtable(); + ParcelsMutex = new System.Threading.Mutex(false, "ParcelsMutex"); + + SimOwner = new LLUUID(); + + TerrainBase0 = new LLUUID(); + TerrainBase1 = new LLUUID(); + TerrainBase2 = new LLUUID(); + TerrainBase3 = new LLUUID(); + TerrainDetail0 = new LLUUID(); + TerrainDetail1 = new LLUUID(); + TerrainDetail2 = new LLUUID(); + TerrainDetail3 = new LLUUID(); + + IsEstateManager = false; + } + + public Region(SecondLife client, LLUUID id, U64 handle, string name, float[] heightList, + LLUUID simOwner, LLUUID[] terrainImages, bool isEstateManager) + { + Client = client; + Estate = new EstateTools(client); + ID = id; + Handle = handle; + Name = name; + ParcelOverlay = new byte[4096]; + ParcelMarked = new int[64, 64]; + ParcelDownloading = false; + ParcelDwell = false; + + TerrainHeightRange00 = heightList[0]; + TerrainHeightRange01 = heightList[1]; + TerrainHeightRange10 = heightList[2]; + TerrainHeightRange11 = heightList[3]; + TerrainStartHeight00 = heightList[4]; + TerrainStartHeight01 = heightList[5]; + TerrainStartHeight10 = heightList[6]; + TerrainStartHeight11 = heightList[7]; + WaterHeight = heightList[8]; + + SimOwner = simOwner; + + TerrainBase0 = terrainImages[0]; + TerrainBase1 = terrainImages[1]; + TerrainBase2 = terrainImages[2]; + TerrainBase3 = terrainImages[3]; + TerrainDetail0 = terrainImages[4]; + TerrainDetail1 = terrainImages[5]; + TerrainDetail2 = terrainImages[6]; + TerrainDetail3 = terrainImages[7]; + + IsEstateManager = isEstateManager; + } + + public void ParcelSubdivide(float west, float south, float east, float north) + { + Client.Network.SendPacket( + Packets.Parcel.ParcelDivide(Client.Protocol, Client.Avatar.ID, + west, south, east, north)); + } + + public void ParcelJoin(float west, float south, float east, float north) + { + Client.Network.SendPacket( + Packets.Parcel.ParcelJoin(Client.Protocol, Client.Avatar.ID, + west, south, east, north)); + } + + public void RezObject(PrimObject prim, LLVector3 position, LLVector3 avatarPosition) + { + byte[] textureEntry = new byte[40]; + Array.Copy(prim.Texture.Data, textureEntry, 16); + textureEntry[35] = 0xe0; // No clue + + Packet objectAdd = libsecondlife.Packets.Object.ObjectAdd(Client.Protocol, Client.Network.AgentID, + LLUUID.GenerateUUID(), avatarPosition, + position, prim, textureEntry); + Client.Network.SendPacket(objectAdd); + } + + public void FillParcels() + { + // Begins filling parcels + ParcelDownloading = true; + + // TODO: Replace Client.Network with Region.Simulator, or similar? + Client.Network.SendPacket(libsecondlife.Packets.Parcel.ParcelPropertiesRequest(Client.Protocol, Client.Avatar.ID, -10000, + 0.0f, 0.0f, 4.0f, 4.0f, false)); + } + + public void ResetParcelDownload() + { + Parcels = new System.Collections.Hashtable(); + ParcelMarked = new int[64, 64]; + } + + public void FilledParcels() + { + if (OnParcelCompletion != null) + { + OnParcelCompletion(this); + } + } + + public override int GetHashCode() + { + return ID.GetHashCode(); + } + + public override bool Equals(object o) + { + if (!(o is Region)) + { + return false; + } + + Region region = (Region)o; + + return (region.ID == ID); + } + + public static bool operator ==(Region lhs, Region rhs) + { + try + { + return (lhs.ID == rhs.ID); + } + catch (NullReferenceException) + { + byte test; + bool lhsnull = false; + bool rhsnull = false; + + try + { + test = lhs.ID.Data[0]; + } + catch (NullReferenceException) + { + lhsnull = true; + } + + try + { + test = rhs.ID.Data[0]; + } + catch (NullReferenceException) + { + rhsnull = true; + } + + return (lhsnull == rhsnull); + } + } + + public static bool operator !=(Region lhs, Region rhs) + { + return !(lhs == rhs); + } + } +} diff --git a/old/libsecondlife-cs/SecondLife.cs b/old/libsecondlife-cs/SecondLife.cs new file mode 100644 index 00000000..059535f4 --- /dev/null +++ b/old/libsecondlife-cs/SecondLife.cs @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Threading; + +namespace libsecondlife +{ + /// + /// Main class to expose Second Life functionality to clients. All of the + /// classes are accessible through this class. + /// + public class SecondLife + { + public ProtocolManager Protocol; + public NetworkManager Network; + public ParcelManager Parcels; + public MainAvatar Avatar; + public Hashtable Avatars; + public Mutex AvatarsMutex; + public Inventory Inventory; + public Region CurrentRegion; + public GridManager Grid; + public ObjectManager Objects; + public bool Debug; + + public SecondLife(string keywordFile, string mapFile) + { + Protocol = new ProtocolManager(keywordFile, mapFile, this); + Network = new NetworkManager(this, Protocol); + Parcels = new ParcelManager(this); + Avatar = new MainAvatar(this); + Avatars = new Hashtable(); + AvatarsMutex = new Mutex(false, "AvatarsMutex"); + Inventory = new Inventory(this); + Grid = new GridManager(this); + Objects = new ObjectManager(this); + CurrentRegion = null; + Debug = true; + + Network.RegisterCallback("UUIDNameReply", new PacketCallback(GetAgentNameHandler)); + } + + public override string ToString() + { + return Avatar.FirstName + " " + Avatar.LastName; + } + + /// + /// A simple sleep function that will allow pending threads to run + /// + public void Tick() + { + System.Threading.Thread.Sleep(0); + } + + /// + /// Send a log message to the debugging output system + /// + /// The log message + /// From the LogLevel enum, either Info, Warning, or Error + public void Log(string message, Helpers.LogLevel level) + { + if (Debug) + { + Console.WriteLine(level.ToString() + ": " + message); + } + } + + /// + /// + /// + /// + public void AddAvatar(LLUUID AgentID) + { + // Quick sanity check + if (Avatars.ContainsKey(AgentID)) + { + return; + } + + GetAgentDetails(AgentID); + + AvatarsMutex.WaitOne(); + Avatars[AgentID] = new Avatar(); + AvatarsMutex.ReleaseMutex(); + } + + /// + /// + /// + /// + public void AddAvatar(Avatar avatar) + { + AvatarsMutex.WaitOne(); + Avatars[avatar.ID] = avatar; + AvatarsMutex.ReleaseMutex(); + } + + /// + /// + /// + /// + private void GetAgentDetails(LLUUID AgentID) + { + Packet packet = Packets.Communication.UUIDNameRequest(Protocol, AgentID); + Network.SendPacket(packet); + + // TODO: Shouldn't this function block? + } + + /// + /// + /// + /// + /// + private void GetAgentNameHandler(Packet packet, Simulator simulator) + { + if (packet.Layout.Name == "UUIDNameReply") + { + LLUUID ID = new LLUUID(); + string Firstname = ""; + string Lastname = ""; + + ArrayList blocks; + + blocks = packet.Blocks(); + + foreach (Block block in blocks) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "ID") + { + ID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "FirstName") + { + Firstname = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "LastName") + { + Lastname = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + } + } + AvatarsMutex.WaitOne(); + ((Avatar)Avatars[ID]).Name = Firstname + " " + Lastname; + AvatarsMutex.ReleaseMutex(); + } + } + } + + /// + /// Static helper functions and global variables + /// + public class Helpers + { + public readonly static string VERSION = "libsecondlife 0.0.9"; + + public const byte MSG_APPENDED_ACKS = 0x10; + public const byte MSG_RESENT = 0x20; + public const byte MSG_RELIABLE = 0x40; + public const byte MSG_ZEROCODED = 0x80; + public const ushort MSG_FREQ_HIGH = 0x0000; + public const ushort MSG_FREQ_MED = 0xFF00; + public const ushort MSG_FREQ_LOW = 0xFFFF; + + public enum LogLevel + { + Info, + Warning, + Error + }; + + /// + /// Converting a variable length field (byte array) to a string + /// + /// The Data member of the Field class you are converting + public static string FieldToString(object data) + { + byte[] byteArray; + + try + { + byteArray = (byte[])data; + } + catch (Exception) + { + return "[object]"; + } + + return System.Text.Encoding.ASCII.GetString(byteArray).Replace("\0", ""); + } + + /// + /// Decode a zerocoded byte array. Used to decompress packets marked + /// with the zerocoded flag. Any time a zero is encountered, the + /// next byte is a count of how many zeroes to expand. One zero is + /// encoded with 0x00 0x01, two zeroes is 0x00 0x02, three zeroes is + /// 0x00 0x03, etc. The first four bytes are copied directly to the + /// output buffer. + /// + /// The byte array to decode + /// The length of the byte array to decode + /// The output byte array to decode to + /// The length of the output buffer + public static int ZeroDecode(byte[] src, int srclen, byte[] dest) + { + uint zerolen = 0; + + Array.Copy(src, 0, dest, 0, 4); + zerolen += 4; + + int bodylen; + if ((src[0] & MSG_APPENDED_ACKS) == 0) + { + bodylen = srclen; + } + else + { + bodylen = srclen - src[srclen - 1] * 4 - 1; + } + + uint i; + for (i = zerolen; i < bodylen; i++) + { + if (src[i] == 0x00) + { + for (byte j = 0; j < src[i + 1]; j++) + { + dest[zerolen++] = 0x00; + } + + i++; + } + else + { + dest[zerolen++] = src[i]; + } + } + + // HACK: Fix truncated zerocoded messages + for (uint j = zerolen; j < zerolen + 16; j++) + { + dest[j] = 0; + } + zerolen += 16; + + // copy appended ACKs + for (; i < srclen; i++) + { + dest[zerolen++] = src[i]; + } + + return (int)zerolen; + } + + /// + /// Decode enough of a byte array to get the packet ID. Data before and + /// after the packet ID is undefined. + /// + /// The byte array to decode + /// The output byte array to encode to + public static void ZeroDecodeCommand(byte[] src, byte[] dest) + { + for (int srcPos = 4, destPos = 4; destPos < 8; ++srcPos) + { + if (src[srcPos] == 0x00) + { + for (byte j = 0; j < src[srcPos + 1]; ++j) + { + dest[destPos++] = 0x00; + } + + ++srcPos; + } + else + { + dest[destPos++] = src[srcPos]; + } + } + } + + /// + /// Encode a byte array with zerocoding. Used to compress packets marked + /// with the zerocoded flag. Any zeroes in the array are compressed down + /// to a single zero byte followed by a count of how many zeroes to expand + /// out. A single zero becomes 0x00 0x01, two zeroes becomes 0x00 0x02, + /// three zeroes becomes 0x00 0x03, etc. The first four bytes are copied + /// directly to the output buffer. + /// + /// The byte array to encode + /// The length of the byte array to encode + /// The output byte array to encode to + /// The length of the output buffer + public static int ZeroEncode(byte[] src, int srclen, byte[] dest) + { + uint zerolen = 0; + byte zerocount = 0; + + Array.Copy(src, 0, dest, 0, 4); + zerolen += 4; + + int bodylen; + if ((src[0] & MSG_APPENDED_ACKS) == 0) + { + bodylen = srclen; + } + else + { + bodylen = srclen - src[srclen - 1] * 4 - 1; + } + + uint i; + for (i = zerolen; i < bodylen; i++) + { + if (src[i] == 0x00) + { + zerocount++; + + if (zerocount == 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = 0xff; + zerocount++; + } + } + else + { + if (zerocount != 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = (byte)zerocount; + zerocount = 0; + } + + dest[zerolen++] = src[i]; + } + } + + if (zerocount != 0) + { + dest[zerolen++] = 0x00; + dest[zerolen++] = (byte)zerocount; + } + + // copy appended ACKs + for (; i < srclen; i++) + { + dest[zerolen++] = src[i]; + } + + return (int)zerolen; + } + } +} diff --git a/old/libsecondlife-cs/Types.cs b/old/libsecondlife-cs/Types.cs new file mode 100644 index 00000000..6ed186a9 --- /dev/null +++ b/old/libsecondlife-cs/Types.cs @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; + +namespace libsecondlife +{ + public class U64 + { + public uint[] Data; + + public U64() + { + Data = new uint[2]; + Data[0] = 0; + Data[1] = 1; + } + + public U64(uint left, uint right) + { + Data = new uint[2]; + // "backwards", due to little-endian ordering + Data[0] = right; + Data[1] = left; + } + + public U64(int left, int right) + { + Data = new uint[2]; + // "backwards", due to little-endian ordering + Data[0] = (uint)right; + Data[1] = (uint)left; + } + + public U64(byte[] bA, int pos) + { + Data = new uint[2]; + Data[0] = (uint)(bA[pos] + (bA[pos+1]<<8) + (bA[pos+2]<<16) + (bA[pos+3]<<24)); + Data[1] = (uint)(bA[pos+4] + (bA[pos+5]<<8) + (bA[pos+6]<<16) + (bA[pos+7]<<24)); + } + + public byte[] GetBytes() + { + byte[] bA = new byte[8]; + + bA[0]=(byte)((Data[0]) %256); bA[1]=(byte)((Data[0]>>8) %256); + bA[2]=(byte)((Data[0]>>16)%256); bA[3]=(byte)((Data[0]>>24)%256); + bA[4]=(byte)((Data[1]) %256); bA[5]=(byte)((Data[1]>>8) %256); + bA[6]=(byte)((Data[1]>>16)%256); bA[7]=(byte)((Data[1]>>24)%256); + + return bA; + } + + public override int GetHashCode() + { + return (int)(Data[0] ^ Data[1]); + } + + public override bool Equals(object o) + { + if (!(o is U64)) return false; + + U64 u64 = (U64)o; + + return (u64.Data[0] == Data[0] && u64.Data[1] == Data[1]); + } + + public static bool operator==(U64 lhs, U64 rhs) + { + if(object.ReferenceEquals(lhs, rhs)) return true; + if(object.ReferenceEquals(lhs, null)) return false; + if(object.ReferenceEquals(rhs, null)) return false; + + return (lhs.Data[0] == rhs.Data[0] && lhs.Data[1] == rhs.Data[1]); + } + + public static bool operator!=(U64 lhs, U64 rhs) + { + return !(lhs == rhs); + } + + public static bool operator==(U64 lhs, int rhs) + { + if(object.ReferenceEquals(lhs, null)) return (rhs == 0); + /* this used to ignore the upper half of the U64, and I don't think + that's correct. */ + return (lhs.Data[0] == 0 && lhs.Data[1] == rhs); + } + + public static bool operator!=(U64 lhs, int rhs) + { + return !(lhs == rhs); + } + + public override string ToString() + { + ulong u64 = (Data[1] << 32) + Data[0]; + return u64.ToString(); + } + } + + public class LLUUID + { + private byte[] data = null; + public byte[] Data + { + get { return data; } + } + + public LLUUID() + { + data = new byte[16]; + } + + public LLUUID(string val) + { + data = new byte[16]; + + if (val.Length == 36) val = val.Replace("-", ""); + + if (val.Length != 32) return; + + for(int i = 0; i < 16; ++i) + { + data[i] = Convert.ToByte(val.Substring(i * 2, 2), 16); + } + } + + public LLUUID(byte[] byteArray, int pos) + { + data = new byte[16]; + + Array.Copy(byteArray, pos, data, 0, 16); + } + + public LLUUID(bool randomize) + { + if (randomize) data = Guid.NewGuid().ToByteArray(); + else data = new byte[16]; + } + + /// + /// Calculate an LLCRC for the given LLUUID + /// + /// The LLUUID to calculate the CRC value for + /// The CRC checksum for this LLUUID + public uint CRC() + { + uint retval = 0; + + retval += (uint)((Data[3] << 24) + (Data[2] << 16) + (Data[1] << 8) + Data[0]); + retval += (uint)((Data[7] << 24) + (Data[6] << 16) + (Data[5] << 8) + Data[4]); + retval += (uint)((Data[11] << 24) + (Data[10] << 16) + (Data[9] << 8) + Data[8]); + retval += (uint)((Data[15] << 24) + (Data[14] << 16) + (Data[13] << 8) + Data[12]); + + return retval; + } + + public static LLUUID GenerateUUID() + { + return new LLUUID(Guid.NewGuid().ToByteArray(), 0); + } + + public override int GetHashCode() + { + return ToString().GetHashCode(); + } + + public override bool Equals(object o) + { + if (!(o is LLUUID)) return false; + + LLUUID uuid = (LLUUID)o; + + for (int i = 0; i < 16; ++i) + { + if (Data[i] != uuid.Data[i]) return false; + } + + return true; + } + + public static bool operator==(LLUUID lhs, LLUUID rhs) + { + if(object.ReferenceEquals(lhs, rhs)) return true; + if(object.ReferenceEquals(lhs, null)) return false; + if(object.ReferenceEquals(rhs, null)) return false; + + for (int i = 0; i < 16; ++i) + { + if (lhs.Data[i] != rhs.Data[i]) return false; + } + + return true; + } + + public static bool operator!=(LLUUID lhs, LLUUID rhs) + { + return !(lhs == rhs); + } + + public static implicit operator LLUUID(string val) + { + return new LLUUID(val); + } + + public override string ToString() + { + string uuid = ""; + + for (int i = 0; i < 16; ++i) + { + uuid += Data[i].ToString("x2"); + } + + return uuid; + } + + public string ToStringHyphenated() + { + string uuid = ""; + + for (int i = 0; i < 16; ++i) + { + uuid += Data[i].ToString("x2"); + + } + uuid = uuid.Insert(20,"-"); + uuid = uuid.Insert(16,"-"); + uuid = uuid.Insert(12,"-"); + uuid = uuid.Insert(8,"-"); + + + return uuid; + } + } + + public class LLVector3 + { + public float X; + public float Y; + public float Z; + + public LLVector3() + { + X = Y = Z = 0.0F; + } + + public LLVector3(LLVector3d vector) + { + X = (float)vector.X; + Y = (float)vector.Y; + Z = (float)vector.Z; + } + + public LLVector3(byte[] byteArray, int pos) + { + if(!BitConverter.IsLittleEndian) + { + Array.Reverse(byteArray, pos, 4); + Array.Reverse(byteArray, pos + 4, 4); + Array.Reverse(byteArray, pos + 8, 4); + } + + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + } + + public LLVector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public byte[] GetBytes() + { + byte[] byteArray = new byte[12]; + + Array.Copy(BitConverter.GetBytes(X), 0, byteArray, 0, 4); + Array.Copy(BitConverter.GetBytes(Y), 0, byteArray, 4, 4); + Array.Copy(BitConverter.GetBytes(Z), 0, byteArray, 8, 4); + + if(!BitConverter.IsLittleEndian) { + Array.Reverse(byteArray, 0, 4); + Array.Reverse(byteArray, 4, 4); + Array.Reverse(byteArray, 8, 4); + } + + return byteArray; + } + + public override string ToString() + { + return X.ToString() + " " + Y.ToString() + " " + Z.ToString(); + } + + public override int GetHashCode() + { + int x = (int)X; + int y = (int)Y; + int z = (int)Z; + + return (x ^ y ^ z); + } + + public override bool Equals(object o) + { + if (!(o is LLVector3)) return false; + + LLVector3 vector = (LLVector3)o; + + return (X == vector.X && Y == vector.Y && Z == vector.Z); + } + + public static bool operator==(LLVector3 lhs, LLVector3 rhs) + { + if(object.ReferenceEquals(lhs, rhs)) return true; + if(object.ReferenceEquals(lhs, null)) return false; + if(object.ReferenceEquals(rhs, null)) return false; + + return (lhs.X == rhs.X && lhs.Y == rhs.Y && lhs.Z == rhs.Z); + } + + public static bool operator!=(LLVector3 lhs, LLVector3 rhs) + { + return !(lhs == rhs); + } + } + + public class LLVector3d + { + public double X; + public double Y; + public double Z; + + public LLVector3d() + { + X = Y = Z = 0.0D; + } + + public LLVector3d(double x, double y, double z) + { + X = x; + Y = y; + Z = z; + } + + public LLVector3d(byte[] byteArray, int pos) + { + if(!BitConverter.IsLittleEndian) { + Array.Reverse(byteArray, pos, 8); + Array.Reverse(byteArray, pos + 8, 8); + Array.Reverse(byteArray, pos + 16, 8); + } + + X = BitConverter.ToDouble(byteArray, pos); + Y = BitConverter.ToDouble(byteArray, pos + 8); + Z = BitConverter.ToDouble(byteArray, pos + 16); + } + + public byte[] GetBytes() + { + byte[] byteArray = new byte[24]; + + Array.Copy(BitConverter.GetBytes(X), 0, byteArray, 0, 8); + Array.Copy(BitConverter.GetBytes(Y), 0, byteArray, 8, 8); + Array.Copy(BitConverter.GetBytes(Z), 0, byteArray, 16, 8); + + if(!BitConverter.IsLittleEndian) { + Array.Reverse(byteArray, 0, 8); + Array.Reverse(byteArray, 8, 8); + Array.Reverse(byteArray, 16, 8); + } + + return byteArray; + } + + public override string ToString() + { + return X.ToString() + " " + Y.ToString() + " " + Z.ToString(); + } + } + + public class LLVector4 + { + public float X; + public float Y; + public float Z; + public float S; + + public LLVector4() + { + X = Y = Z = S = 0.0F; + } + + public LLVector4(byte[] byteArray, int pos) + { + if(!BitConverter.IsLittleEndian) { + Array.Reverse(byteArray, pos, 4); + Array.Reverse(byteArray, pos + 4, 4); + Array.Reverse(byteArray, pos + 8, 4); + Array.Reverse(byteArray, pos + 12, 4); + } + + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + S = BitConverter.ToSingle(byteArray, pos + 12); + } + + public byte[] GetBytes() + { + byte[] byteArray = new byte[16]; + + Array.Copy(BitConverter.GetBytes(X), 0, byteArray, 0, 4); + Array.Copy(BitConverter.GetBytes(Y), 0, byteArray, 4, 4); + Array.Copy(BitConverter.GetBytes(Z), 0, byteArray, 8, 4); + Array.Copy(BitConverter.GetBytes(S), 0, byteArray, 12, 4); + + if(!BitConverter.IsLittleEndian) { + Array.Reverse(byteArray, 0, 4); + Array.Reverse(byteArray, 4, 4); + Array.Reverse(byteArray, 8, 4); + Array.Reverse(byteArray, 12, 4); + } + + return byteArray; + } + + public override string ToString() + { + return X.ToString() + " " + Y.ToString() + " " + Z.ToString() + " " + S.ToString(); + } + } + + public class LLQuaternion + { + public float X; + public float Y; + public float Z; + public float S; + + public LLQuaternion() + { + X = Y = Z = S = 0.0F; + } + + public LLQuaternion(byte[] byteArray, int pos) + { + if(!BitConverter.IsLittleEndian) { + Array.Reverse(byteArray, pos,4); + Array.Reverse(byteArray, pos + 4, 4); + Array.Reverse(byteArray, pos + 8, 4); + Array.Reverse(byteArray, pos + 12, 4); + } + + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + S = BitConverter.ToSingle(byteArray, pos + 12); + } + + public LLQuaternion(float x, float y, float z, float s) + { + X = x; + Y = y; + Z = z; + S = s; + } + + public byte[] GetBytes() + { + byte[] byteArray = new byte[16]; + + Array.Copy(BitConverter.GetBytes(X), 0, byteArray, 0, 4); + Array.Copy(BitConverter.GetBytes(Y), 0, byteArray, 4, 4); + Array.Copy(BitConverter.GetBytes(Z), 0, byteArray, 8, 4); + Array.Copy(BitConverter.GetBytes(S), 0, byteArray, 12, 4); + + if(!BitConverter.IsLittleEndian) { + Array.Reverse(byteArray, 0, 4); + Array.Reverse(byteArray, 4, 4); + Array.Reverse(byteArray, 8, 4); + Array.Reverse(byteArray, 12, 4); + } + + return byteArray; + } + + public override string ToString() + { + return X.ToString() + " " + Y.ToString() + " " + Z.ToString() + " " + S.ToString(); + } + } + + public class DataConvert + { + private static byte[] ba; + + public static float toFloat(object Data, int offset) + { + ba = (byte[])Data; + if(!BitConverter.IsLittleEndian) + Array.Reverse(ba, offset, 4); + return BitConverter.ToSingle(ba, offset); + } + + public static float toFloat(object Data) + { + return toFloat(Data, 0); + } + + public static double toDouble(object Data, int offset) + { + ba = (byte[])Data; + if(!BitConverter.IsLittleEndian) + Array.Reverse(ba, offset, 8); + return BitConverter.ToDouble(ba, offset); + } + + public static double toDouble(object Data) + { + return toDouble(Data, 0); + } + + public static byte toU8(object Data, int offset) + { + ba = (byte[])Data; + return ba[offset]; + } + + public static byte toU8(object Data) + { + return toU8(Data,0); + } + + public static ushort toU16(object Data, int offset) + { + return (ushort)(toU8(Data,0) | (ushort)toU8(Data,1) << 8); + } + + public static ushort toU16(object Data) + { + return toU16(Data, 0); + } + + public static uint toU32(object Data, int offset) + { + return ((uint)(toU16(Data,0)) | ((uint)(toU16(Data,2) << 16))); + } + + public static uint toU32(object Data) + { + return toU32(Data, 0); + } + + public static String toChoppedString(object Data) + { + return System.Text.Encoding.UTF8.GetString((byte[])Data).Replace("\0", ""); + } + + public static byte[] from(byte data) { + return new byte[1]{data}; + } + + public static byte[] from(ushort data) { + return new byte[2]{(byte)(data%256),(byte)(data>>8)}; + } + + public static byte[] from(uint data) { + return new byte[4] {(byte) (data%256),(byte)((data>> 8)%256), + (byte)((data>>16)%256),(byte)((data>>24)%256)}; + } + + public static byte[] from(float data) + { + ba = BitConverter.GetBytes(data); + if(!BitConverter.IsLittleEndian) + Array.Reverse(ba, 0, 4); + return ba; + } + + public static byte[] from(double data) + { + ba = BitConverter.GetBytes(data); + if(!BitConverter.IsLittleEndian) + Array.Reverse(ba, 0, 8); + return ba; + } + + } +} diff --git a/old/libsecondlife-cs/Utils/ImageTools.cs b/old/libsecondlife-cs/Utils/ImageTools.cs new file mode 100644 index 00000000..5982ce90 --- /dev/null +++ b/old/libsecondlife-cs/Utils/ImageTools.cs @@ -0,0 +1,117 @@ +using System; +using System.IO; +using System.Diagnostics; + +namespace libsecondlife.Utils +{ + /// + /// Summary description for ImageTools. + /// + public class ImageTools + { + private ImageTools() + { + } + + public static bool Check4Tools() + { + bool status = true; + if( File.Exists("kdu_expand.exe") == false ) + { + status = false; + Console.WriteLine("You need kdu_expand.exe to save SL images."); + } + + if( File.Exists("kdu_compress.exe") == false ) + { + status = false; + Console.WriteLine("You need kdu_compress.exe to load images into SL."); + } + + return status; + } + + public static void WriteJ2CToFile( string j2c_filename, byte[] J2CData ) + { + FileStream fs = System.IO.File.OpenWrite( j2c_filename ); + fs.Write(J2CData, 0, J2CData.Length); + fs.Close(); + } + + + public static void Convert2Tiff( string j2c_filename, string tif_filename ) + { + if( File.Exists("kdu_expand.exe") == false ) + { + throw new Exception("You must have kdu_expand.exe"); + } + + if( tif_filename.ToLower().EndsWith(".tif") == false ) + { + tif_filename += ".tif"; + } + + Process p = new Process(); + p.StartInfo.UseShellExecute = false; + p.StartInfo.FileName = "kdu_expand.exe"; + p.StartInfo.Arguments = "-i " + j2c_filename + " -o " + tif_filename; + p.Start(); + p.WaitForExit(); + } + + public static void WriteJ2CAsTiff( string tif_filename, byte[] J2CData ) + { + String tempname = tif_filename + ".j2c"; + WriteJ2CToFile( tempname, J2CData ); + Convert2Tiff( tempname, tif_filename ); + File.Delete( tempname ); + } + + + /* + * kdu_compress -no_info -no_weights -no_palette -i TestTexture.tif -o TestTexture.J2C + */ + public static void Convert2J2C( string tif_filename, string j2c_filename ) + { + if( File.Exists("kdu_compress.exe") == false ) + { + throw new Exception("You must have kdu_compress.exe"); + } + + if( j2c_filename.ToLower().EndsWith(".j2c") == false ) + { + j2c_filename += ".j2c"; + } + + Process p = new Process(); + p.StartInfo.UseShellExecute = false; + p.StartInfo.FileName = "kdu_compress.exe"; + p.StartInfo.Arguments = "-no_info -no_weights -no_palette -i " + tif_filename + " -o " + j2c_filename; + p.Start(); + p.WaitForExit(); + } + + public static byte[] ReadJ2CData( string filename ) + { + if( (filename.ToLower().EndsWith(".j2c") == false) && (filename.ToLower().EndsWith(".tif") == true) ) + { + string tempname = filename + ".j2c"; + Convert2J2C( filename, tempname ); + filename = tempname; + } + + FileStream fs = File.OpenRead( filename ); + + byte[] data = new byte[fs.Length]; + + if( fs.Length > int.MaxValue ) + { + throw new Exception("AssetImage.cs: Bad stuff going to happen because length bigger then Max Integer"); + } + + fs.Read(data, 0, (int)fs.Length); + + return data; + } + } +} diff --git a/old/libsecondlife-cs/Utils/InventoryApp.cs b/old/libsecondlife-cs/Utils/InventoryApp.cs new file mode 100644 index 00000000..5e7a25e0 --- /dev/null +++ b/old/libsecondlife-cs/Utils/InventoryApp.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; + +using libsecondlife; +using libsecondlife.InventorySystem; + +namespace libsecondlife.Utils +{ + /// + /// Summary description for InventoryApp. + /// + abstract public class InventoryApp + { + protected SecondLife client; + protected InventoryManager AgentInventory; + + protected bool DownloadInventoryOnConnect = true; + + protected InventoryApp() + { + try + { + client = new SecondLife("keywords.txt", "message_template.msg"); + } + catch (Exception e) + { + if( e.Message.Equals("Keyword file error") ) + { + Console.WriteLine("Keyword file not found, or there was an error reading it. Please make sure you have a copy of the keyword file in the same directory as this appplication."); + } + else if ( e.Message.Equals("Map file error") ) + { + Console.WriteLine("Map file not found, or there was an error reading it. Please make sure you have a copy of the map file in the same directory as this appplication."); + } + else + { + // Error initializing the client, probably missing file(s) + Console.WriteLine(); + Console.WriteLine(e.ToString()); + } + return; + } + } + + protected void Connect(string[] args) + { + if (args.Length < 3) + { + Console.WriteLine("Usage: InventoryDump [loginfirstname] [loginlastname] [password]"); + return; + } + + // Setup Login to Second Life + Hashtable loginParams = NetworkManager.DefaultLoginValues(args[0], args[1], args[2], "00:00:00:00:00:00", + "last", 1, 12, 12, 12, "Win", "0", "createnotecard", "static.sprocket@gmail.com"); + Hashtable loginReply = new Hashtable(); + + // Request information on the Root Inventory Folder, and Inventory Skeleton + ArrayList alAdditionalInfo = new ArrayList(); + alAdditionalInfo.Add("inventory-root"); + alAdditionalInfo.Add("inventory-skeleton"); + loginParams.Add("options",alAdditionalInfo); + + // Login + if (!client.Network.Login(loginParams)) + { + // Login failed + Console.WriteLine("Error logging in: " + client.Network.LoginError); + return; + } + + // Login was successful + + + // Get Root Inventory Folder UUID + ArrayList alInventoryRoot = (ArrayList)client.Network.LoginValues["inventory-root"]; + Hashtable htInventoryRoot = (Hashtable)alInventoryRoot[0]; + LLUUID agentRootFolderID = new LLUUID( (string)htInventoryRoot["folder_id"] ); + + // Initialize Inventory Manager object + AgentInventory = new InventoryManager(client, agentRootFolderID); + + if( DownloadInventoryOnConnect ) + { + // and request an inventory download + AgentInventory.DownloadInventory(); + } + + } + + protected void Disconnect() + { + // Logout of Second Life + + Console.WriteLine("Request logout"); + client.Network.Logout(); + } + + abstract protected void doStuff(); + } +} diff --git a/old/libsecondlife-cs/Utils/Utils.cs b/old/libsecondlife-cs/Utils/Utils.cs new file mode 100644 index 00000000..2a8c857d --- /dev/null +++ b/old/libsecondlife-cs/Utils/Utils.cs @@ -0,0 +1,88 @@ +using System; + +namespace libsecondlife.Utils +{ + /// + /// Summary description for Utils. + /// + public class MiscUtils + { + private MiscUtils() + { + // This class isn't intended to be instantiated + } + + public static int getUnixtime() + { + TimeSpan ts = (DateTime.UtcNow - new DateTime(1970,1,1,0,0,0)); + return (int)ts.TotalSeconds; + } + + + public static string ByteArrayToString( byte[] byteArray ) + { + if ( byteArray == null ) + { + return ""; + } + + string output = ""; + + bool printable = true; + + for (int i = 0; i < byteArray.Length; ++i) + { + // Check if there are any unprintable characters in the array + if ((byteArray[i] < 0x20 || byteArray[i] > 0x7E) && byteArray[i] != 0x09 + && byteArray[i] != 0x0D) + { + printable = false; + } + } + + if (printable) + { + output = Helpers.FieldToString(byteArray); + } + else + { + for (int i = 0; i < byteArray.Length; i += 16) + { + for (int j = 0; j < 16; j++) + { + if ((i + j) < byteArray.Length) + { + string s = String.Format("{0:X} ", byteArray[i + j]); + if( s.Length == 2 ) + { + s = "0" + s; + } + + output += s; + } + else + { + output += " "; + } + } + + for (int j = 0; j < 16 && (i + j) < byteArray.Length; j++) + { + if (byteArray[i + j] >= 0x20 && byteArray[i + j] < 0x7E) + { + output += (char)byteArray[i + j]; + } + else + { + output += "."; + } + } + + output += "\n"; + } + } + + return output; + } + } +} diff --git a/old/libsecondlife-cs/Utils/fubar.txt b/old/libsecondlife-cs/Utils/fubar.txt new file mode 100644 index 00000000..e69de29b diff --git a/old/libsecondlife-cs/XmlRpcCS/Logger.cs b/old/libsecondlife-cs/XmlRpcCS/Logger.cs new file mode 100644 index 00000000..2c4379d3 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/Logger.cs @@ -0,0 +1,46 @@ +namespace Nwc.XmlRpc +{ + using System; + + /// Define levels of logging. This duplicates + /// similar enumerations in System.Diagnostics.EventLogEntryType. The + /// duplication was merited because .NET Compact Framework lacked the EventLogEntryType enum. + public enum LogLevel + { + /// Information level, log entry for informational reasons only. + Information, + /// Warning level, indicates a possible problem. + Warning, + /// Error level, implies a significant problem. + Error + } + + /// + ///Logging singleton with swappable output delegate. + /// + /// + ///This singleton provides a centralized log. The actual WriteEntry calls are passed + ///off to a delegate however. Having a delegate do the actual logginh allows you to + ///implement different logging mechanism and have them take effect throughout the system. + /// + public class Logger + { + ///Delegate definition for logging. + ///The message String to log. + ///The LogLevel of your message. + public delegate void LoggerDelegate(String message, LogLevel level); + ///The LoggerDelegate that will recieve WriteEntry requests. + static public LoggerDelegate Delegate = null; + + /// + ///Method logging events are sent to. + /// + ///The message String to log. + ///The LogLevel of your message. + static public void WriteEntry(String message, LogLevel level) + { + if (Delegate != null) + Delegate(message, level); + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcDeserializer.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcDeserializer.cs new file mode 100644 index 00000000..7af124f3 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcDeserializer.cs @@ -0,0 +1,180 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.IO; + using System.Xml; + using System.Globalization; + + /// Parser context, we maintain contexts in a stack to avoiding recursion. + struct Context + { + public String Name; + public Object Container; + } + + /// Basic XML-RPC data deserializer. + /// Uses XmlTextReader to parse the XML data. This level of the class + /// only handles the tokens common to both Requests and Responses. This class is not useful in and of itself + /// but is designed to be subclassed. + public class XmlRpcDeserializer : XmlRpcXmlTokens + { + private static DateTimeFormatInfo _dateFormat = new DateTimeFormatInfo(); + + private Object _container; + private Stack _containerStack; + + /// Protected reference to last text. + protected String _text; + /// Protected reference to last deserialized value. + protected Object _value; + /// Protected reference to last name field. + protected String _name; + + /// Basic constructor. + public XmlRpcDeserializer() + { + Reset(); + _dateFormat.FullDateTimePattern = ISO_DATETIME; + } + + /// Static method that parses XML data into a response using the Singleton. + /// StreamReader containing an XML-RPC response. + /// Object object resulting from the deserialization. + virtual public Object Deserialize(TextReader xmlData) + { + return null; + } + + /// Protected method to parse a node in an XML-RPC XML stream. + /// Method deals with elements common to all XML-RPC data, subclasses of + /// this object deal with request/response spefic elements. + /// XmlTextReader of the in progress parsing data stream. + protected void DeserializeNode(XmlTextReader reader) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + if (Logger.Delegate != null) + Logger.WriteEntry("START " + reader.Name, LogLevel.Information); + switch (reader.Name) + { + case VALUE: + _value = null; + _text = null; + break; + case STRUCT: + PushContext(); + _container = new Hashtable(); + break; + case ARRAY: + PushContext(); + _container = new ArrayList(); + break; + } + break; + case XmlNodeType.EndElement: + if (Logger.Delegate != null) + Logger.WriteEntry("END " + reader.Name, LogLevel.Information); + switch (reader.Name) + { + case BASE64: + _value = Convert.FromBase64String(_text); + break; + case BOOLEAN: + int val = Int16.Parse(_text); + if (val == 0) + _value = false; + else if (val == 1) + _value = true; + break; + case STRING: + _value = _text; + break; + case DOUBLE: + _value = Double.Parse(_text); + break; + case INT: + case ALT_INT: + _value = Int32.Parse(_text); + break; + case DATETIME: +#if __MONO__ + _value = DateParse(_text); +#else + _value = DateTime.ParseExact(_text, "F", _dateFormat); +#endif + break; + case NAME: + _name = _text; + break; + case VALUE: + if (_value == null) + _value = _text; // some kits don't use tag, they just do + + if ((_container != null) && (_container is IList)) // in an array? If so add value to it. + ((IList)_container).Add(_value); + break; + case MEMBER: + if ((_container != null) && (_container is IDictionary)) // in an struct? If so add value to it. + ((IDictionary)_container).Add(_name, _value); + break; + case ARRAY: + case STRUCT: + _value = _container; + PopContext(); + break; + } + break; + case XmlNodeType.Text: + if (Logger.Delegate != null) + Logger.WriteEntry("Text " + reader.Value, LogLevel.Information); + _text = reader.Value; + break; + default: + break; + } + } + + /// Static method that parses XML in a String into a + /// request using the Singleton. + /// String containing an XML-RPC request. + /// XmlRpcRequest object resulting from the parse. + public Object Deserialize(String xmlData) + { + StringReader sr = new StringReader(xmlData); + return Deserialize(sr); + } + + /// Pop a Context of the stack, an Array or Struct has closed. + private void PopContext() + { + Context c = (Context)_containerStack.Pop(); + _container = c.Container; + _name = c.Name; + } + + /// Push a Context on the stack, an Array or Struct has opened. + private void PushContext() + { + Context context; + + context.Container = _container; + context.Name = _name; + + _containerStack.Push(context); + } + + /// Reset the internal state of the deserializer. + protected void Reset() + { + _text = null; + _value = null; + _name = null; + _container = null; + _containerStack = new Stack(); + } + } +} + + diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcErrorCodes.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcErrorCodes.cs new file mode 100644 index 00000000..01a0ad97 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcErrorCodes.cs @@ -0,0 +1,19 @@ +namespace Nwc.XmlRpc +{ + using System; + + /// Standard XML-RPC error codes. + public class XmlRpcErrorCodes + { + /** + -32400 ---> system error + **/ + + /// + public const int TRANSPORT_ERROR = -32300; + /// + public const String TRANSPORT_ERROR_MSG = "Transport Layer Error"; + } +} + + diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcException.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcException.cs new file mode 100644 index 00000000..96bff8d1 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcException.cs @@ -0,0 +1,38 @@ +namespace Nwc.XmlRpc +{ + using System; + + /// An XML-RPC Exception. + /// Maps a C# exception to an XML-RPC fault. Normal exceptions + /// include a message so this adds the code needed by XML-RPC. + public class XmlRpcException : Exception + { + private int _code; + + /// Instantiate an XmlRpcException with a code and message. + /// Int faultCode associated with this exception. + /// String faultMessage associated with this exception. + public XmlRpcException(int code, String message) : base(message) + { + _code = code; + } + + /// The value of the faults message, i.e. the faultString. + public String FaultString + { + get { return Message; } + } + + /// The value of the faults code, i.e. the faultCode. + public int FaultCode + { + get { return _code; } + } + + /// Format the message to include the code. + override public String ToString() + { + return "Code: " + FaultCode + " Message: " + base.ToString(); + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequest.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequest.cs new file mode 100644 index 00000000..9d306bd4 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequest.cs @@ -0,0 +1,96 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.IO; + using System.Xml; + using System.Net; + using System.Text; + using System.Reflection; + + internal class AcceptAllCertificatePolicy : ICertificatePolicy + { + public AcceptAllCertificatePolicy() + { + } + + public bool CheckValidationResult(ServicePoint sPoint, + System.Security.Cryptography.X509Certificates.X509Certificate cert, + WebRequest wRequest,int certProb) + { + // Always accept + return true; + } + } + + /// Class supporting the request side of an XML-RPC transaction. + public class XmlRpcRequest + { + private String _methodName = null; + private Encoding _encoding = new ASCIIEncoding(); + private XmlRpcRequestSerializer _serializer = new XmlRpcRequestSerializer(); + private XmlRpcResponseDeserializer _deserializer = new XmlRpcResponseDeserializer(); + + /// ArrayList containing the parameters. + protected IList _params = null; + + /// Instantiate an XmlRpcRequest + public XmlRpcRequest() + { + _params = new ArrayList(); + } + + /// ArrayList conntaining the parameters for the request. + public virtual IList Params + { + get { return _params; } + } + + /// String conntaining the method name, both object and method, that the request will be sent to. + public virtual String MethodName + { + get { return _methodName; } + set { _methodName = value; } + } + + /// Send the request to the server. + /// String The url of the XML-RPC server. + /// XmlRpcResponse The response generated. + public XmlRpcResponse Send(String url) + { + // Override SSL authentication mechanisms + ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy(); + + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + if (request == null) + throw new XmlRpcException(XmlRpcErrorCodes.TRANSPORT_ERROR, + XmlRpcErrorCodes.TRANSPORT_ERROR_MSG +": Could not create request with " + url); + request.Method = "POST"; + request.ContentType = "text/xml"; + request.AllowWriteStreamBuffering = true; + request.KeepAlive = false; + request.Timeout = 15000; // miliseconds adjust as you see fit + + Stream stream = request.GetRequestStream(); + XmlTextWriter xml = new XmlTextWriter(stream, _encoding); + _serializer.Serialize(xml, this); + xml.Flush(); + xml.Close(); + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + StreamReader input = new StreamReader(response.GetResponseStream()); + + XmlRpcResponse resp = (XmlRpcResponse)_deserializer.Deserialize(input); + input.Close(); + response.Close(); + return resp; + } + + /// Produce String representation of the object. + /// String representation of the object. + override public String ToString() + { + return _serializer.Serialize(this); + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestDeserializer.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestDeserializer.cs new file mode 100644 index 00000000..5975a152 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestDeserializer.cs @@ -0,0 +1,64 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.IO; + using System.Xml; + + /// Class to deserialize XML data representing a request. + public class XmlRpcRequestDeserializer : XmlRpcDeserializer + { + static private XmlRpcRequestDeserializer _singleton; + /// A static singleton instance of this deserializer. + [Obsolete("This object is now thread safe, just use an instance.",false)] + static public XmlRpcRequestDeserializer Singleton + { + get + { + if (_singleton == null) + _singleton = new XmlRpcRequestDeserializer(); + + return _singleton; + } + } + + /// Static method that parses XML data into a request using the Singleton. + /// StreamReader containing an XML-RPC request. + /// XmlRpcRequest object resulting from the parse. + override public Object Deserialize(TextReader xmlData) + { + XmlTextReader reader = new XmlTextReader(xmlData); + XmlRpcRequest request = new XmlRpcRequest(); + bool done = false; + + lock(this) + { + Reset(); + while (!done && reader.Read()) + { + DeserializeNode(reader); // Parent parse... + switch (reader.NodeType) + { + case XmlNodeType.EndElement: + switch (reader.Name) + { + case METHOD_NAME: + request.MethodName = _text; + break; + case METHOD_CALL: + done = true; + break; + case PARAM: + request.Params.Add(_value); + _text = null; + break; + } + break; + } + } + } + return request; + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestSerializer.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestSerializer.cs new file mode 100644 index 00000000..c232caf1 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcRequestSerializer.cs @@ -0,0 +1,38 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.Xml; + using System.IO; + + /// Class responsible for serializing an XML-RPC request. + /// This class handles the request envelope, depending on XmlRpcSerializer + /// to serialize the payload. + /// + public class XmlRpcRequestSerializer : XmlRpcSerializer + { + /// Serialize the XmlRpcRequest to the output stream. + /// An XmlTextWriter stream to write data to. + /// An XmlRpcRequest to serialize. + /// + override public void Serialize(XmlTextWriter output, Object obj) + { + XmlRpcRequest request = (XmlRpcRequest)obj; + output.WriteStartDocument(); + output.WriteStartElement(METHOD_CALL); + output.WriteElementString(METHOD_NAME,request.MethodName); + output.WriteStartElement(PARAMS); + foreach (Object param in request.Params) + { + output.WriteStartElement(PARAM); + output.WriteStartElement(VALUE); + SerializeObject(output, param); + output.WriteEndElement(); + output.WriteEndElement(); + } + + output.WriteEndElement(); + output.WriteEndElement(); + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponse.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponse.cs new file mode 100644 index 00000000..6484268d --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponse.cs @@ -0,0 +1,73 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.IO; + using System.Xml; + + /// Class designed to represent an XML-RPC response. + public class XmlRpcResponse + { + private Object _value; + /// bool indicating if this response represents a fault. + public bool IsFault; + + /// Basic constructor + public XmlRpcResponse() + { + Value = null; + IsFault = false; + } + + /// The data value of the response, may be fault data. + public Object Value + { + get { return _value; } + set { + IsFault = false; + _value = value; + } + } + + /// The faultCode if this is a fault. + public int FaultCode + { + get { + if (!IsFault) + return 0; + else + return (int)((Hashtable)_value)[XmlRpcXmlTokens.FAULT_CODE]; + } + } + + /// The faultString if this is a fault. + public String FaultString + { + get { + if (!IsFault) + return ""; + else + return (String)((Hashtable)_value)[XmlRpcXmlTokens.FAULT_STRING]; + } + } + + /// Set this response to be a fault. + /// int the numeric faultCode value. + /// String the faultString value. + public void SetFault(int code, String message) + { + Hashtable fault = new Hashtable(); + fault.Add("faultCode", code); + fault.Add("faultString", message); + Value = fault; + IsFault = true; + } + + /// Form a useful string representation of the object, in this case the XML response. + /// String The XML serialized XML-RPC response. + override public String ToString() + { + return XmlRpcResponseSerializer.Singleton.Serialize(this); + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseDeserializer.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseDeserializer.cs new file mode 100644 index 00000000..a94388a4 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseDeserializer.cs @@ -0,0 +1,51 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.IO; + using System.Xml; + + /// Class to deserialize XML data representing a response. + public class XmlRpcResponseDeserializer : XmlRpcDeserializer + { + /// Static method that parses XML data into a response using the Singleton. + /// StreamReader containing an XML-RPC response. + /// XmlRpcResponse object resulting from the parse. + override public Object Deserialize(TextReader xmlData) + { + XmlTextReader reader = new XmlTextReader(xmlData); + XmlRpcResponse response = new XmlRpcResponse(); + bool done = false; + + lock(this) + { + Reset(); + + while (!done && reader.Read()) + { + DeserializeNode(reader); // Parent parse... + switch (reader.NodeType) + { + case XmlNodeType.EndElement: + switch (reader.Name) + { + case FAULT: + response.Value = _value; + response.IsFault = true; + break; + case PARAM: + response.Value = _value; + _value = null; + _text = null; + break; + } + break; + default: + break; + } + } + } + return response; + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseSerializer.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseSerializer.cs new file mode 100644 index 00000000..b2df7cc0 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcResponseSerializer.cs @@ -0,0 +1,57 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.Xml; + + /// Class responsible for serializing an XML-RPC response. + /// This class handles the response envelope, depending on XmlRpcSerializer + /// to serialize the payload. + /// + public class XmlRpcResponseSerializer : XmlRpcSerializer + { + static private XmlRpcResponseSerializer _singleton; + /// A static singleton instance of this deserializer. + static public XmlRpcResponseSerializer Singleton + { + get + { + if (_singleton == null) + _singleton = new XmlRpcResponseSerializer(); + + return _singleton; + } + } + + /// Serialize the XmlRpcResponse to the output stream. + /// An XmlTextWriter stream to write data to. + /// An Object to serialize. + /// + override public void Serialize(XmlTextWriter output, Object obj) + { + XmlRpcResponse response = (XmlRpcResponse) obj; + + output.WriteStartDocument(); + output.WriteStartElement(METHOD_RESPONSE); + + if (response.IsFault) + output.WriteStartElement(FAULT); + else + { + output.WriteStartElement(PARAMS); + output.WriteStartElement(PARAM); + } + + output.WriteStartElement(VALUE); + + SerializeObject(output,response.Value); + + output.WriteEndElement(); + + output.WriteEndElement(); + if (!response.IsFault) + output.WriteEndElement(); + output.WriteEndElement(); + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcSerializer.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcSerializer.cs new file mode 100644 index 00000000..459bce15 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcSerializer.cs @@ -0,0 +1,109 @@ +namespace Nwc.XmlRpc +{ + using System; + using System.Collections; + using System.IO; + using System.Xml; + + /// Base class of classes serializing data to XML-RPC's XML format. + /// This class handles the basic type conversions like Integer to <i4>. + /// + public class XmlRpcSerializer : XmlRpcXmlTokens + { + + /// Serialize the XmlRpcRequest to the output stream. + /// An XmlTextWriter stream to write data to. + /// An Object to serialize. + /// + virtual public void Serialize(XmlTextWriter output, Object obj) + { + } + + /// Serialize the XmlRpcRequest to a String. + /// Note this may represent a real memory hog for a large request. + /// An Object to serialize. + /// String containing XML-RPC representation of the request. + /// + public String Serialize(Object obj) + { + StringWriter strBuf = new StringWriter(); + XmlTextWriter xml = new XmlTextWriter(strBuf); + xml.Formatting = Formatting.Indented; + xml.Indentation = 4; + Serialize(xml, obj); + xml.Flush(); + String returns = strBuf.ToString(); + xml.Close(); + return returns; + } + + /// Serialize the object to the output stream. + /// An XmlTextWriter stream to write data to. + /// An Object to serialize. + public void SerializeObject(XmlTextWriter output, Object obj) + { + if (obj == null) + return; + + if (obj is byte[]) + { + byte[] ba = (byte[])obj; + output.WriteStartElement(BASE64); + output.WriteBase64(ba,0,ba.Length); + output.WriteEndElement(); + } + else if (obj is String) + { + output.WriteElementString(STRING,obj.ToString()); + } + else if (obj is Int32) + { + output.WriteElementString(INT,obj.ToString()); + } + else if (obj is DateTime) + { + output.WriteElementString(DATETIME,((DateTime)obj).ToString(ISO_DATETIME)); + } + else if (obj is Double) + { + output.WriteElementString(DOUBLE,obj.ToString()); + } + else if (obj is Boolean) + { + output.WriteElementString(BOOLEAN, ((((Boolean)obj) == true)?"1":"0")); + } + else if (obj is IList) + { + output.WriteStartElement(ARRAY); + output.WriteStartElement(DATA); + if (((ArrayList)obj).Count > 0) + { + foreach (Object member in ((IList)obj)) + { + output.WriteStartElement(VALUE); + SerializeObject(output,member); + output.WriteEndElement(); + } + } + output.WriteEndElement(); + output.WriteEndElement(); + } + else if (obj is IDictionary) + { + IDictionary h = (IDictionary)obj; + output.WriteStartElement(STRUCT); + foreach (String key in h.Keys) + { + output.WriteStartElement(MEMBER); + output.WriteElementString(NAME,key); + output.WriteStartElement(VALUE); + SerializeObject(output,h[key]); + output.WriteEndElement(); + output.WriteEndElement(); + } + output.WriteEndElement(); + } + + } + } +} diff --git a/old/libsecondlife-cs/XmlRpcCS/XmlRpcXmlTokens.cs b/old/libsecondlife-cs/XmlRpcCS/XmlRpcXmlTokens.cs new file mode 100644 index 00000000..5203bca2 --- /dev/null +++ b/old/libsecondlife-cs/XmlRpcCS/XmlRpcXmlTokens.cs @@ -0,0 +1,76 @@ +namespace Nwc.XmlRpc +{ + using System; + + /// Class collecting String tokens that are part of XML-RPC files. + public class XmlRpcXmlTokens + { + /// C# formatting string to describe an ISO 8601 date. + public const String ISO_DATETIME = "yyyyMMdd\\THH\\:mm\\:ss"; + /// Base64 field indicator. + /// Corresponds to the <base64> tag. + public const String BASE64 = "base64"; + /// String field indicator. + /// Corresponds to the <string> tag. + public const String STRING = "string"; + /// Integer field integer. + /// Corresponds to the <i4> tag. + public const String INT = "i4"; + /// Alternate integer field indicator. + /// Corresponds to the <int> tag. + public const String ALT_INT = "int"; + /// Date field indicator. + /// Corresponds to the <dateTime.iso8601> tag. + public const String DATETIME = "dateTime.iso8601"; + /// Boolean field indicator. + /// Corresponds to the <boolean> tag. + public const String BOOLEAN = "boolean"; + /// Value token. + /// Corresponds to the <value> tag. + public const String VALUE = "value"; + /// Name token. + /// Corresponds to the <name> tag. + public const String NAME = "name"; + /// Array field indicator.. + /// Corresponds to the <array> tag. + public const String ARRAY = "array"; + /// Data token. + /// Corresponds to the <data> tag. + public const String DATA = "data"; + /// Member token. + /// Corresponds to the <member> tag. + public const String MEMBER = "member"; + /// Stuct field indicator. + /// Corresponds to the <struct> tag. + public const String STRUCT = "struct"; + /// Double field indicator. + /// Corresponds to the <double> tag. + public const String DOUBLE = "double"; + /// Param token. + /// Corresponds to the <param> tag. + public const String PARAM = "param"; + /// Params token. + /// Corresponds to the <params> tag. + public const String PARAMS = "params"; + /// MethodCall token. + /// Corresponds to the <methodCall> tag. + public const String METHOD_CALL = "methodCall"; + /// MethodName token. + /// Corresponds to the <methodName> tag. + public const String METHOD_NAME = "methodName"; + /// MethodResponse token + /// Corresponds to the <methodResponse> tag. + public const String METHOD_RESPONSE = "methodResponse"; + /// Fault response token. + /// Corresponds to the <fault> tag. + public const String FAULT = "fault"; + /// FaultCode token. + /// Corresponds to the <faultCode> tag. + public const String FAULT_CODE = "faultCode"; + /// FaultString token. + /// Corresponds to the <faultString> tag. + public const String FAULT_STRING = "faultString"; + } +} + + diff --git a/old/libsecondlife-cs/build b/old/libsecondlife-cs/build new file mode 100644 index 00000000..5e85cb9a --- /dev/null +++ b/old/libsecondlife-cs/build @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +system('prj2make libsecondlife.sln') + and die "*** prj2make failed\n"; + +open(MAKEFILE, 'Makefile') + or die "*** failed to open Makefile for reading: $!\n"; + +while () { + s/^MCS=mcs$/MCS=gmcs/; + push @patched, $_; +} + +close(MAKEFILE); + +open(MAKEFILE, '>Makefile') + or die "*** failed to open Makefile for writing: $!\n"; + +print MAKEFILE $_ foreach @patched; + +close(MAKEFILE); + +system('make', @ARGV) + and die "*** make failed\n"; diff --git a/old/libsecondlife-cs/examples/CreateNotecard/App.ico b/old/libsecondlife-cs/examples/CreateNotecard/App.ico new file mode 100644 index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6 GIT binary patch literal 1078 zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1 z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<{9 literal 0 HcmV?d00001 diff --git a/old/libsecondlife-cs/examples/CreateNotecard/AssemblyInfo.cs b/old/libsecondlife-cs/examples/CreateNotecard/AssemblyInfo.cs new file mode 100644 index 00000000..177a4f0e --- /dev/null +++ b/old/libsecondlife-cs/examples/CreateNotecard/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.cs b/old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.cs new file mode 100644 index 00000000..038548c6 --- /dev/null +++ b/old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections; +using System.IO; + +using libsecondlife; +using libsecondlife.InventorySystem; +using libsecondlife.Packets; + +namespace InventoryTools +{ + /// + /// Summary description for Class1. + /// + class CreateNotecard : libsecondlife.Utils.InventoryApp + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + CreateNotecard cn = new CreateNotecard(); + cn.Connect(args); + cn.doStuff(); + cn.Disconnect(); + + System.Threading.Thread.Sleep(500); + } + + + override protected void doStuff() + { + if( AgentInventory == null ) + { + return; + } + + Console.WriteLine("This example contains numerous code snippets for inventory management and notecard creation, please see the source code. The default SVN operation simply creates a single notecard in your Notecards folder."); + + // Find folder to put notecard in + InventoryFolder ifNotecards = AgentInventory.getFolder("Notecards"); + + // Create Notecard + Console.WriteLine("Create Notecard"); + InventoryItem iiNotecard = ifNotecards.NewNotecard("Test Card " + System.DateTime.Now.ToShortTimeString(),"Test Description", "Test Body"); + +// iiNotecard.GiveTo("e225438416bc4f1788ac5beb5b41f141"); +// iiNotecard.GiveTo("4403a8f0-245c-a56b-23a7-cc1c72c8f2e9"); +// iiNotecard.GiveTo("25472683-cb32-4516-904a-6cd0ecabf128"); + + + +/* + StreamReader sr = System.IO.File.OpenText("bignote.txt"); + String body = sr.ReadToEnd(); + body = "Testing Inventory Delivery"; + + // Create Notecard + Console.WriteLine("Create Notecard"); + InventoryNotecard iNotecard = ifNotecards.NewNotecard("Big Card " + System.DateTime.Now.ToShortTimeString(),"Test Description", body); +*/ + + // Delete Notecard +// Console.WriteLine("Delete Notecard"); +// iNotecard.Delete(); + + +/* + // Create Folder + InventoryFolder ifTestFolderA = ifNotecards.CreateFolder("SubA"); + InventoryFolder ifTestFolderB = ifNotecards.CreateFolder("SubB"); + + // Move a folder + ifTestFolderB.MoveTo( ifTestFolderA ); + + // Rename a folder + ifTestFolderA.Name = "Sub1"; + + // Delete Folder + ifTestFolderB.Delete(); + + // Create Notecard + Console.WriteLine("Create Notecard"); + InventoryItem iiNotecard = ifNotecards.NewNotecard("Test Card " + System.DateTime.Now.ToShortTimeString(),"Test Description", "Test Body"); + + // Move Notecard + Console.WriteLine("Move Notecard"); + iiNotecard.MoveTo( ifTestFolderA ); + + // Delete Notecard + Console.WriteLine("Delete Notecard"); + iiNotecard.Delete(); + + // Delete Folder + ifTestFolderA.Delete(); + + // Download inventory and output to visually verify Folder has been deleted + + AgentInventory.DownloadInventory(); + ifNotecards = AgentInventory.getFolder("Notecards"); + Console.WriteLine(ifNotecards.toXML(false)); +*/ + } + } +} \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.csproj b/old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.csproj new file mode 100644 index 00000000..d2e9eb4d --- /dev/null +++ b/old/libsecondlife-cs/examples/CreateNotecard/CreateNotecard.csproj @@ -0,0 +1,107 @@ + + + Local + 8.0.50727 + 2.0 + {D5ACEEA1-89CD-4FD2-8A1F-1BD828988FDC} + Debug + AnyCPU + App.ico + + + CreateNotecard + + + JScript + Grid + IE50 + false + Exe + CreateNotecard + OnBuildSuccess + + + + + + + + + bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + + + + Code + + + Code + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/ImageTool/App.ico b/old/libsecondlife-cs/examples/ImageTool/App.ico new file mode 100644 index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6 GIT binary patch literal 1078 zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1 z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<{9 literal 0 HcmV?d00001 diff --git a/old/libsecondlife-cs/examples/ImageTool/AssemblyInfo.cs b/old/libsecondlife-cs/examples/ImageTool/AssemblyInfo.cs new file mode 100644 index 00000000..177a4f0e --- /dev/null +++ b/old/libsecondlife-cs/examples/ImageTool/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/old/libsecondlife-cs/examples/ImageTool/ImageTool.cs b/old/libsecondlife-cs/examples/ImageTool/ImageTool.cs new file mode 100644 index 00000000..4c58cd8b --- /dev/null +++ b/old/libsecondlife-cs/examples/ImageTool/ImageTool.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using System.IO; + +using libsecondlife; +using libsecondlife.InventorySystem; +using libsecondlife.AssetSystem; +using libsecondlife.Utils; + +namespace ImageTool +{ + /// + /// Summary description for Class1. + /// + class ImageTool : libsecondlife.Utils.InventoryApp + { + private LLUUID _ImageID; + private string _FileName; + private bool _Put; + + /// + /// Sample texture for downloading: 0444bf21-f77e-7f63-89e9-b839ec66bc15 + /// + [STAThread] + static void Main(string[] args) + { + if( ImageTools.Check4Tools() == false ) + { + return; + } + + if (args.Length < 5) + { + Console.WriteLine("Usage: ImageTool [first] [last] [password] [get] [uuid] [(filename)]"); + Console.WriteLine("Usage: ImageTool [first] [last] [password] [put] [filename]"); + + Console.WriteLine(); + Console.WriteLine("Example: ImageTool John Doe Password get 0444bf21-f77e-7f63-89e9-b839ec66bc15 cloud.tif"); + Console.WriteLine("Example: ImageTool John Doe Password put Sample.tif"); + return; + } + + + LLUUID id = null; + string filename = ""; + bool put = false; + if( args[3].ToLower().Equals("put") ) + { + put = true; + filename = args[4]; + } + else + { + id = new LLUUID(args[4]); + if( args.Length == 6 ) + { + filename = args[5]; + } + else if (!args[4].ToLower().EndsWith(".j2c")) + { + filename = args[4] + ".j2c"; + } + } + + ImageTool it = new ImageTool( id, filename, put ); + it.Connect(args); + it.doStuff(); + it.Disconnect(); + + System.Threading.Thread.Sleep(500); + } + + protected ImageTool( LLUUID imageID, string filename, bool put ) + { + _ImageID = imageID; + _FileName = filename; + _Put = put; + } + + protected override void doStuff() + { + if( _Put ) + { + Console.WriteLine("Reading: " + _FileName); + + byte[] j2cdata = ImageTools.ReadJ2CData( _FileName ); + + Console.WriteLine("Connecting to your Texture folder..."); + InventoryFolder iFolder = AgentInventory.getFolder("Textures"); + + Console.WriteLine("Uploading Texture..."); + iFolder.NewImage( _FileName, "ImageTool Upload", j2cdata ); + } + else + { + Console.WriteLine("Downloading: " + _ImageID); + + ImageManager im = new ImageManager( base.client ); + byte[] j2cdata = im.RequestImage( _ImageID ); + + Console.WriteLine("Writing to: " + _FileName); + //ImageTools.WriteJ2CAsTiff( _FileName, j2cdata ); + ImageTools.WriteJ2CToFile(_FileName, j2cdata); + } + + Console.WriteLine("Done..."); + + } + + } +} \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/ImageTool/ImageTool.csproj b/old/libsecondlife-cs/examples/ImageTool/ImageTool.csproj new file mode 100644 index 00000000..5373201d --- /dev/null +++ b/old/libsecondlife-cs/examples/ImageTool/ImageTool.csproj @@ -0,0 +1,106 @@ + + + Local + 8.0.50727 + 2.0 + {6ACF3FF4-CFA5-478B-993E-F788A1030CEB} + Debug + AnyCPU + App.ico + + + ImageTool + + + JScript + Grid + IE50 + false + Exe + ImageTool + OnBuildSuccess + ImageTool.ImageTool + + + + + + + ..\..\bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + + + + Code + + + Code + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/ImageTool/Readme.txt b/old/libsecondlife-cs/examples/ImageTool/Readme.txt new file mode 100644 index 00000000..9a69ee88 --- /dev/null +++ b/old/libsecondlife-cs/examples/ImageTool/Readme.txt @@ -0,0 +1,5 @@ +SecondLife uses Kakadu Software's JPEG2000 framework to compress and expand images to/from JPEG2000. + +Libsecondlife currently makes use of a freely available set of command line tools from Kakadu to support Image upload and download from SecondLife. + +These tools are available from Kakadu's website at http://www.kakadusoftware.com/ \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/InventoryDump/App.ico b/old/libsecondlife-cs/examples/InventoryDump/App.ico new file mode 100644 index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6 GIT binary patch literal 1078 zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1 z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<{9 literal 0 HcmV?d00001 diff --git a/old/libsecondlife-cs/examples/InventoryDump/AssemblyInfo.cs b/old/libsecondlife-cs/examples/InventoryDump/AssemblyInfo.cs new file mode 100644 index 00000000..177a4f0e --- /dev/null +++ b/old/libsecondlife-cs/examples/InventoryDump/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/old/libsecondlife-cs/examples/InventoryDump/InventoryDump.cs b/old/libsecondlife-cs/examples/InventoryDump/InventoryDump.cs new file mode 100644 index 00000000..3549243b --- /dev/null +++ b/old/libsecondlife-cs/examples/InventoryDump/InventoryDump.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using System.IO; + +using libsecondlife; +using libsecondlife.InventorySystem; + +namespace InventoryDump +{ + class InventoryDump : libsecondlife.Utils.InventoryApp + { + private string sOutputFile; + private bool bOutputAssets; + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + if (args.Length < 3) + { + Console.WriteLine("Usage: InventoryDump [loginfirstname] [loginlastname] [password] [output.xml]"); + return; + } + + + + InventoryDump id = new InventoryDump(); + + if( args.Length == 4 ) + { + id.sOutputFile = args[3]; + } else { + id.sOutputFile = "output.xml"; + } + + id.bOutputAssets = false; + + id.Connect(args); + id.doStuff(); + id.Disconnect(); + + System.Threading.Thread.Sleep(500); + } + + override protected void doStuff() + { + if( AgentInventory == null ) + { + return; + } + + // Request Inventory Download + try + { + AgentInventory.DownloadInventory(); + + Console.WriteLine("Writing Inventory to " + sOutputFile); + // Save inventory to file. + StreamWriter sw = File.CreateText(sOutputFile); + sw.Write(AgentInventory.getRootFolder().toXML( bOutputAssets ) ); + sw.Close(); + Console.WriteLine("Done."); + } + catch ( Exception e ) + { + Console.WriteLine( e.Message ); + Console.WriteLine("An error occured while downloading inventory, please report this along with any output to Static Sprocket."); + } + } + } +} + diff --git a/old/libsecondlife-cs/examples/InventoryDump/InventoryDump.csproj b/old/libsecondlife-cs/examples/InventoryDump/InventoryDump.csproj new file mode 100644 index 00000000..e1ec81e4 --- /dev/null +++ b/old/libsecondlife-cs/examples/InventoryDump/InventoryDump.csproj @@ -0,0 +1,107 @@ + + + Local + 8.0.50727 + 2.0 + {6478BE37-9272-4D91-B641-5E2FD0680B27} + Debug + AnyCPU + App.ico + + + InventoryDump + + + JScript + Grid + IE50 + false + Exe + InventoryDump + OnBuildSuccess + + + + + + + + + bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + + + + Code + + + Code + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.cs b/old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.cs new file mode 100644 index 00000000..d42f95ce --- /dev/null +++ b/old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.cs @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using libsecondlife; + +namespace ParcelDownloader +{ + /// + /// Summary description for ParcelDownload. + /// + class ParcelDownload + { + static SecondLife client; + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + + if (args.Length < 3) + { + Console.WriteLine("Usage: ParcelDownloader [loginfirstname] [loginlastname] [password]"); + return; + } + + try + { + client = new SecondLife("keywords.txt", "message_template.msg"); + } + catch (Exception e) + { + // Error initializing the client, probably missing file(s) + Console.WriteLine(e.ToString()); + return; + } + + Hashtable loginParams = NetworkManager.DefaultLoginValues(args[0], args[1], args[2], "00:00:00:00:00:00", + "last", 1, 50, 50, 50, "Win", "0", "ParcelDownload", "Adam \"Zaius\" Frisby "); + + if (!client.Network.Login(loginParams)) + { + // Login failed + Console.WriteLine("ERROR: " + client.Network.LoginError); + return; + } + + // The magic happens in these three lines + client.CurrentRegion.FillParcels(); // Tell libsl to download parcels + System.Threading.Thread.Sleep(10000); // Give it some time to do it + client.Tick(); // Let things happen + + // Dump some info about our parcels + foreach(int pkey in client.CurrentRegion.Parcels.Keys) + { + Parcel parcel = (Parcel)client.CurrentRegion.Parcels[pkey]; + // Probably should comment this out :-) + //parcel.Buy(client,false,new LLUUID()); + Console.WriteLine(""); + Console.WriteLine("\tName: " + parcel.Name); + Console.WriteLine("\tSize: " + parcel.Area); + Console.WriteLine("\tDesc: " + parcel.Desc); + } + + client.Network.Logout(); + return; + } + } +} diff --git a/old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.csproj b/old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.csproj new file mode 100644 index 00000000..8182b2c5 --- /dev/null +++ b/old/libsecondlife-cs/examples/ParcelDownload/ParcelDownload.csproj @@ -0,0 +1,104 @@ + + + Local + 8.0.50727 + 2.0 + {623B86F7-7753-44B7-A8C8-CBC89FB8AF8E} + Debug + AnyCPU + + + + + ParcelDownload + + + JScript + Grid + IE50 + false + Exe + ParcelDownload + OnBuildSuccess + + + + + + + + + ..\..\bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + + + Code + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/examples.build b/old/libsecondlife-cs/examples/examples.build new file mode 100644 index 00000000..7bf55ed3 --- /dev/null +++ b/old/libsecondlife-cs/examples/examples.build @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/old/libsecondlife-cs/examples/name2key/name2key.cs b/old/libsecondlife-cs/examples/name2key/name2key.cs new file mode 100644 index 00000000..291cb88e --- /dev/null +++ b/old/libsecondlife-cs/examples/name2key/name2key.cs @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using libsecondlife; + +namespace name2key +{ + class name2key + { + static bool waiting = true; + + // + public static void QueryHandler(Packet packet, Simulator simulator) + { + if (packet.Layout.Name.IndexOf("Dir") > -1) + { + ArrayList blocks = packet.Blocks(); + + if (blocks.Count > 3) + { + Console.WriteLine("ERROR: Ambiguous name. Returning first match"); + } + + foreach (Block block in blocks) + { + if (block.Layout.Name == "QueryReplies") + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "AgentID") + { + Console.WriteLine("UUID: " + field.Data.ToString()); + goto Done; + } + } + } + } + + Done: + waiting = false; + } + } + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + SecondLife client; + + if (args.Length < 5) + { + Console.WriteLine("Usage: name2key [loginfirstname] [loginlastname] [password] [firstname] [lastname]"); + return; + } + + try + { + client = new SecondLife("keywords.txt", "message_template.msg"); + } + catch (Exception e) + { + // Error initializing the client, probably missing file(s) + Console.WriteLine(e.ToString()); + return; + } + + // Setup the callback + client.Network.RegisterCallback("DirPeopleReply", new PacketCallback(QueryHandler)); + + // Setup the login values + Hashtable loginParams = NetworkManager.DefaultLoginValues(args[0], args[1], args[2], "00:00:00:00:00:00", + "last", 1, 50, 50, 50, "Win", "0", "name2key", "contact@libsecondlife.org"); + + if (!client.Network.Login(loginParams)) + { + // Login failed + Console.WriteLine("ERROR: " + client.Network.LoginError); + return; + } + + // Send the Query + string name = args[3] + " " + args[4]; + LLUUID queryID = LLUUID.GenerateUUID(); + Packet packet = libsecondlife.Packets.Sim.DirFindQuery(client.Protocol, name, 0, queryID, + client.Network.AgentID, client.Network.SessionID); + client.Network.SendPacket(packet); + + while (waiting) + { + client.Tick(); + } + + client.Network.Logout(); + } + } +} diff --git a/old/libsecondlife-cs/examples/name2key/name2key.csproj b/old/libsecondlife-cs/examples/name2key/name2key.csproj new file mode 100644 index 00000000..18b7c665 --- /dev/null +++ b/old/libsecondlife-cs/examples/name2key/name2key.csproj @@ -0,0 +1,105 @@ + + + Local + 8.0.50727 + 2.0 + {66FFD34E-652C-4EF5-81FE-06AD011169D2} + Debug + AnyCPU + + + + + name2key + + + JScript + Grid + IE50 + false + Exe + name2key + OnBuildSuccess + + + + + + + + + ..\..\bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + False + + + + + Code + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/primexport/frmPrimExport.cs b/old/libsecondlife-cs/examples/primexport/frmPrimExport.cs new file mode 100644 index 00000000..0c86a067 --- /dev/null +++ b/old/libsecondlife-cs/examples/primexport/frmPrimExport.cs @@ -0,0 +1,364 @@ +using System; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using System.Collections; +using libsecondlife; + +namespace primexport +{ + public class frmPrimExport : Form + { + private GroupBox grpLogin; + private Label label3; + private Label label2; + private Label label1; + private TextBox txtPassword; + private TextBox txtLastName; + private Button cmdConnect; + private TextBox txtFirstName; + private Button cmdCapture; + private TextBox txtLog; + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + private SecondLife client; + private NewPrimCallback primCallback; + private string currentText; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.grpLogin = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.txtLastName = new System.Windows.Forms.TextBox(); + this.cmdConnect = new System.Windows.Forms.Button(); + this.txtFirstName = new System.Windows.Forms.TextBox(); + this.cmdCapture = new System.Windows.Forms.Button(); + this.txtLog = new System.Windows.Forms.TextBox(); + this.grpLogin.SuspendLayout(); + this.SuspendLayout(); + // + // grpLogin + // + this.grpLogin.Controls.Add(this.label3); + this.grpLogin.Controls.Add(this.label2); + this.grpLogin.Controls.Add(this.label1); + this.grpLogin.Controls.Add(this.txtPassword); + this.grpLogin.Controls.Add(this.txtLastName); + this.grpLogin.Controls.Add(this.cmdConnect); + this.grpLogin.Controls.Add(this.txtFirstName); + this.grpLogin.Enabled = false; + this.grpLogin.Location = new System.Drawing.Point(12, 204); + this.grpLogin.Name = "grpLogin"; + this.grpLogin.Size = new System.Drawing.Size(560, 80); + this.grpLogin.TabIndex = 51; + this.grpLogin.TabStop = false; + // + // label3 + // + this.label3.Location = new System.Drawing.Point(280, 24); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(120, 16); + this.label3.TabIndex = 50; + this.label3.Text = "Password"; + // + // label2 + // + this.label2.Location = new System.Drawing.Point(152, 24); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(120, 16); + this.label2.TabIndex = 50; + this.label2.Text = "Last Name"; + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 24); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(120, 16); + this.label1.TabIndex = 50; + this.label1.Text = "First Name"; + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(280, 40); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.PasswordChar = '*'; + this.txtPassword.Size = new System.Drawing.Size(120, 20); + this.txtPassword.TabIndex = 2; + // + // txtLastName + // + this.txtLastName.Location = new System.Drawing.Point(152, 40); + this.txtLastName.Name = "txtLastName"; + this.txtLastName.Size = new System.Drawing.Size(112, 20); + this.txtLastName.TabIndex = 1; + // + // cmdConnect + // + this.cmdConnect.Location = new System.Drawing.Point(424, 40); + this.cmdConnect.Name = "cmdConnect"; + this.cmdConnect.Size = new System.Drawing.Size(120, 24); + this.cmdConnect.TabIndex = 3; + this.cmdConnect.Text = "Connect"; + this.cmdConnect.Click += new System.EventHandler(this.cmdConnect_Click); + // + // txtFirstName + // + this.txtFirstName.Location = new System.Drawing.Point(16, 40); + this.txtFirstName.Name = "txtFirstName"; + this.txtFirstName.Size = new System.Drawing.Size(120, 20); + this.txtFirstName.TabIndex = 0; + // + // cmdCapture + // + this.cmdCapture.Enabled = false; + this.cmdCapture.Location = new System.Drawing.Point(12, 12); + this.cmdCapture.Name = "cmdCapture"; + this.cmdCapture.Size = new System.Drawing.Size(560, 49); + this.cmdCapture.TabIndex = 52; + this.cmdCapture.Text = "Start Capture"; + this.cmdCapture.Click += new System.EventHandler(this.cmdCapture_Click); + // + // txtLog + // + this.txtLog.Location = new System.Drawing.Point(12, 67); + this.txtLog.Multiline = true; + this.txtLog.Name = "txtLog"; + this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtLog.Size = new System.Drawing.Size(560, 131); + this.txtLog.TabIndex = 53; + // + // frmPrimExport + // + this.ClientSize = new System.Drawing.Size(587, 299); + this.Controls.Add(this.txtLog); + this.Controls.Add(this.cmdCapture); + this.Controls.Add(this.grpLogin); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(595, 326); + this.MinimumSize = new System.Drawing.Size(595, 326); + this.Name = "frmPrimExport"; + this.Text = "Prim Exporter"; + this.TopMost = true; + this.grpLogin.ResumeLayout(false); + this.grpLogin.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + public frmPrimExport() + { + InitializeComponent(); + + primCallback = new NewPrimCallback(PrimSeen); + + try + { + client = new SecondLife("keywords.txt", "message_template.msg"); + grpLogin.Enabled = true; + } + catch (Exception error) + { + MessageBox.Show(this, error.ToString()); + } + } + + private void Log(string text) + { + currentText = text; + + if (this.InvokeRequired) + { + this.Invoke(new MethodInvoker(UpdateLog)); + } + else + { + UpdateLog(); + } + } + + private void UpdateLog() + { + txtLog.Text += currentText + Environment.NewLine; + } + + private void PrimSeen(Simulator simulator, PrimObject prim, U64 regionHandle, ushort timeDilation) + { + uint type = 0; + string output = ""; + + output += "" + Environment.NewLine; + output += "" + Environment.NewLine + + "false" + Environment.NewLine + + "false" + Environment.NewLine + + "false" + Environment.NewLine + + "" + Environment.NewLine; + output += "" + Environment.NewLine + + "" + Environment.NewLine; + + if (prim.ProfileCurve == 1 && prim.PathCurve == 16) + { + type = 0; + } + else if (prim.ProfileCurve == 0 && prim.PathCurve == 16) + { + type = 1; + } + else if (prim.ProfileCurve == 3 && prim.PathCurve == 16) + { + type = 2; + } + else if (prim.ProfileCurve == 5 && prim.PathCurve == 32) + { + type = 3; + } + else if (prim.ProfileCurve == 0 && prim.PathCurve == 32) + { + type = 4; + } + else if (prim.ProfileCurve == 1 && prim.PathCurve == 32) + { + type = 5; + } + else if (prim.ProfileCurve == 3 && prim.PathCurve == 32) + { + type = 6; + } + else + { + Console.WriteLine("Unhandled prim type, ProfileCurve=" + + prim.ProfileCurve + ", PathCurve=" + prim.PathCurve); + type = 0; + } + + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + + if (type == 1) + { + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + } + else + { + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + } + + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + // prim.blender stores taper values a bit different than the SL network layer + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + output += "" + Environment.NewLine; + // TODO: Hollowshape. 16-21 = circle, 32-37 = square, 48-53 = triangle + output += "" + Environment.NewLine; + + output += "" + Environment.NewLine + + "" + Environment.NewLine + + "" + Environment.NewLine + + "" + Environment.NewLine + + "" + Environment.NewLine + + "" + Environment.NewLine; + + Log(output); + } + + private void cmdConnect_Click(object sender, EventArgs e) + { + cmdCapture.Text = "Start Capture"; + cmdCapture.Enabled = false; + + if (cmdConnect.Text == "Connect") + { + cmdConnect.Text = "Disconnect"; + txtFirstName.Enabled = txtLastName.Enabled = txtPassword.Enabled = false; + + Hashtable loginParams = NetworkManager.DefaultLoginValues(txtFirstName.Text, + txtLastName.Text, txtPassword.Text, "00:00:00:00:00:00", "last", 1, 50, 50, 50, + "Win", "0", "primexport", "jhurliman@wsu.edu"); + + // HAX + cmdCapture.Text = "Stop Capture"; + client.Objects.OnNewPrim += primCallback; + + if (client.Network.Login(loginParams)) + { + cmdCapture.Enabled = true; + } + else + { + MessageBox.Show(this, "Error logging in: " + client.Network.LoginError); + cmdConnect.Text = "Connect"; + txtFirstName.Enabled = txtLastName.Enabled = txtPassword.Enabled = true; + } + } + else + { + client.Network.Logout(); + cmdConnect.Text = "Connect"; + txtFirstName.Enabled = txtLastName.Enabled = txtPassword.Enabled = true; + } + } + + private void cmdCapture_Click(object sender, EventArgs e) + { + if (cmdCapture.Text == "Start Capture") + { + cmdCapture.Text = "Stop Capture"; + client.Objects.OnNewPrim += primCallback; + } + else + { + cmdCapture.Text = "Start Capture"; + client.Objects.OnNewPrim -= primCallback; + } + } + } +} diff --git a/old/libsecondlife-cs/examples/primexport/frmPrimExport.resx b/old/libsecondlife-cs/examples/primexport/frmPrimExport.resx new file mode 100644 index 00000000..ff31a6db --- /dev/null +++ b/old/libsecondlife-cs/examples/primexport/frmPrimExport.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/primexport/primexport.cs b/old/libsecondlife-cs/examples/primexport/primexport.cs new file mode 100644 index 00000000..29aa462c --- /dev/null +++ b/old/libsecondlife-cs/examples/primexport/primexport.cs @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using libsecondlife; + +namespace primexport +{ + class primexport + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + frmPrimExport exportForm = new frmPrimExport(); + exportForm.ShowDialog(); + } + } +} diff --git a/old/libsecondlife-cs/examples/primexport/primexport.csproj b/old/libsecondlife-cs/examples/primexport/primexport.csproj new file mode 100644 index 00000000..c83973de --- /dev/null +++ b/old/libsecondlife-cs/examples/primexport/primexport.csproj @@ -0,0 +1,116 @@ + + + Local + 8.0.50727 + 2.0 + {77E5330D-8A8C-41B4-A2D1-6F06FE45ED6D} + Debug + AnyCPU + + + + + primexport + + + JScript + Grid + IE50 + false + WinExe + primexport + OnBuildSuccess + + + + + + + + + ..\..\..\bin\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + False + + + + + Form + + + Code + + + + + Designer + frmPrimExport.cs + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/slaccountant/App.ico b/old/libsecondlife-cs/examples/slaccountant/App.ico new file mode 100644 index 0000000000000000000000000000000000000000..3a5525fd794f7a7c5c8e6187f470ea3af38cd2b6 GIT binary patch literal 1078 zcmeHHJr05}7=1t!Hp3A*8IHkVf+j?-!eHY14Gtcw1Eb*_9>Bq^zETJ@GKj{_2j4$w zo9}xCh!8{T3=X##Skq>ikMjsvB|y%crWBM2iW(4pI}c%z6%lW!=~4v77#3{z!dmB1 z__&l)-{KUYR+|8|;wB^R|9ET$J@(@=#rd^=)qs85?vAy(PSF5CyNkus435LVkZ$rj zNw|JG-P7^hF<(;#o*Vk}5R#e|^13tBbQkeF?djULtvqyxd3<{9 literal 0 HcmV?d00001 diff --git a/old/libsecondlife-cs/examples/slaccountant/AssemblyInfo.cs b/old/libsecondlife-cs/examples/slaccountant/AssemblyInfo.cs new file mode 100644 index 00000000..177a4f0e --- /dev/null +++ b/old/libsecondlife-cs/examples/slaccountant/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs b/old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs new file mode 100644 index 00000000..79373d21 --- /dev/null +++ b/old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.cs @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Drawing; +using System.Collections; +using System.ComponentModel; +using System.Windows.Forms; +using System.Data; +using System.Threading; +using libsecondlife; + +namespace SLAccountant +{ + /// + /// Summary description for Form1. + /// + public class frmSLAccountant : System.Windows.Forms.Form + { + private System.Windows.Forms.GroupBox grpLogin; + private System.Windows.Forms.TextBox txtPassword; + private System.Windows.Forms.TextBox txtLastName; + private System.Windows.Forms.Button cmdConnect; + private System.Windows.Forms.TextBox txtFirstName; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + /// + /// Required designer variable. + /// + private System.ComponentModel.Container components = null; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label lblName; + private System.Windows.Forms.Label lblBalance; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox txtFind; + private System.Windows.Forms.Button cmdFind; + private System.Windows.Forms.TextBox txtTransfer; + private System.Windows.Forms.Button cmdTransfer; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.ListView lstFind; + private System.Windows.Forms.ColumnHeader colName; + private System.Windows.Forms.ColumnHeader colOnline; + private System.Windows.Forms.ColumnHeader colUuid; + + // libsecondlife instance + private SecondLife client; + // Mutex for locking the listview + Mutex lstFindMutex; + + public frmSLAccountant() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + client.Network.Logout(); + + if( disposing ) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.grpLogin = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.txtLastName = new System.Windows.Forms.TextBox(); + this.cmdConnect = new System.Windows.Forms.Button(); + this.txtFirstName = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.lblName = new System.Windows.Forms.Label(); + this.lblBalance = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.txtFind = new System.Windows.Forms.TextBox(); + this.cmdFind = new System.Windows.Forms.Button(); + this.txtTransfer = new System.Windows.Forms.TextBox(); + this.cmdTransfer = new System.Windows.Forms.Button(); + this.label7 = new System.Windows.Forms.Label(); + this.lstFind = new System.Windows.Forms.ListView(); + this.colName = new System.Windows.Forms.ColumnHeader(); + this.colOnline = new System.Windows.Forms.ColumnHeader(); + this.colUuid = new System.Windows.Forms.ColumnHeader(); + this.grpLogin.SuspendLayout(); + this.SuspendLayout(); + // + // grpLogin + // + this.grpLogin.Controls.Add(this.label3); + this.grpLogin.Controls.Add(this.label2); + this.grpLogin.Controls.Add(this.label1); + this.grpLogin.Controls.Add(this.txtPassword); + this.grpLogin.Controls.Add(this.txtLastName); + this.grpLogin.Controls.Add(this.cmdConnect); + this.grpLogin.Controls.Add(this.txtFirstName); + this.grpLogin.Enabled = false; + this.grpLogin.Location = new System.Drawing.Point(16, 344); + this.grpLogin.Name = "grpLogin"; + this.grpLogin.Size = new System.Drawing.Size(560, 80); + this.grpLogin.TabIndex = 50; + this.grpLogin.TabStop = false; + // + // label3 + // + this.label3.Location = new System.Drawing.Point(280, 24); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(120, 16); + this.label3.TabIndex = 50; + this.label3.Text = "Password"; + // + // label2 + // + this.label2.Location = new System.Drawing.Point(152, 24); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(120, 16); + this.label2.TabIndex = 50; + this.label2.Text = "Last Name"; + // + // label1 + // + this.label1.Location = new System.Drawing.Point(16, 24); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(120, 16); + this.label1.TabIndex = 50; + this.label1.Text = "First Name"; + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(280, 40); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.PasswordChar = '*'; + this.txtPassword.Size = new System.Drawing.Size(120, 20); + this.txtPassword.TabIndex = 2; + this.txtPassword.Text = ""; + // + // txtLastName + // + this.txtLastName.Location = new System.Drawing.Point(152, 40); + this.txtLastName.Name = "txtLastName"; + this.txtLastName.Size = new System.Drawing.Size(112, 20); + this.txtLastName.TabIndex = 1; + this.txtLastName.Text = ""; + // + // cmdConnect + // + this.cmdConnect.Location = new System.Drawing.Point(424, 40); + this.cmdConnect.Name = "cmdConnect"; + this.cmdConnect.Size = new System.Drawing.Size(120, 24); + this.cmdConnect.TabIndex = 3; + this.cmdConnect.Text = "Connect"; + this.cmdConnect.Click += new System.EventHandler(this.cmdConnect_Click); + // + // txtFirstName + // + this.txtFirstName.Location = new System.Drawing.Point(16, 40); + this.txtFirstName.Name = "txtFirstName"; + this.txtFirstName.Size = new System.Drawing.Size(120, 20); + this.txtFirstName.TabIndex = 0; + this.txtFirstName.Text = ""; + // + // label4 + // + this.label4.Location = new System.Drawing.Point(16, 8); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(48, 16); + this.label4.TabIndex = 50; + this.label4.Text = "Name:"; + // + // lblName + // + this.lblName.Location = new System.Drawing.Point(64, 8); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(184, 16); + this.lblName.TabIndex = 50; + // + // lblBalance + // + this.lblBalance.Location = new System.Drawing.Point(512, 8); + this.lblBalance.Name = "lblBalance"; + this.lblBalance.Size = new System.Drawing.Size(64, 16); + this.lblBalance.TabIndex = 50; + this.lblBalance.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // label6 + // + this.label6.Location = new System.Drawing.Point(456, 8); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(56, 16); + this.label6.TabIndex = 50; + this.label6.Text = "Balance:"; + // + // label5 + // + this.label5.Location = new System.Drawing.Point(16, 40); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(88, 16); + this.label5.TabIndex = 50; + this.label5.Text = "People Search"; + // + // txtFind + // + this.txtFind.Enabled = false; + this.txtFind.Location = new System.Drawing.Point(16, 56); + this.txtFind.Name = "txtFind"; + this.txtFind.Size = new System.Drawing.Size(184, 20); + this.txtFind.TabIndex = 4; + this.txtFind.Text = ""; + // + // cmdFind + // + this.cmdFind.Enabled = false; + this.cmdFind.Location = new System.Drawing.Point(208, 56); + this.cmdFind.Name = "cmdFind"; + this.cmdFind.Size = new System.Drawing.Size(48, 24); + this.cmdFind.TabIndex = 5; + this.cmdFind.Text = "Find"; + this.cmdFind.Click += new System.EventHandler(this.cmdFind_Click); + // + // txtTransfer + // + this.txtTransfer.Enabled = false; + this.txtTransfer.Location = new System.Drawing.Point(360, 192); + this.txtTransfer.MaxLength = 7; + this.txtTransfer.Name = "txtTransfer"; + this.txtTransfer.Size = new System.Drawing.Size(104, 20); + this.txtTransfer.TabIndex = 7; + this.txtTransfer.Text = ""; + // + // cmdTransfer + // + this.cmdTransfer.Enabled = false; + this.cmdTransfer.Location = new System.Drawing.Point(472, 192); + this.cmdTransfer.Name = "cmdTransfer"; + this.cmdTransfer.Size = new System.Drawing.Size(104, 24); + this.cmdTransfer.TabIndex = 8; + this.cmdTransfer.Text = "Transfer Lindens"; + this.cmdTransfer.Click += new System.EventHandler(this.cmdTransfer_Click); + // + // label7 + // + this.label7.Location = new System.Drawing.Point(360, 176); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(88, 16); + this.label7.TabIndex = 17; + this.label7.Text = "Amount:"; + // + // lstFind + // + this.lstFind.Activation = System.Windows.Forms.ItemActivation.OneClick; + this.lstFind.AllowColumnReorder = true; + this.lstFind.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.colName, + this.colOnline, + this.colUuid}); + this.lstFind.FullRowSelect = true; + this.lstFind.HideSelection = false; + this.lstFind.Location = new System.Drawing.Point(16, 88); + this.lstFind.Name = "lstFind"; + this.lstFind.Size = new System.Drawing.Size(336, 248); + this.lstFind.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.lstFind.TabIndex = 6; + this.lstFind.View = System.Windows.Forms.View.Details; + // + // colName + // + this.colName.Text = "Name"; + this.colName.Width = 120; + // + // colOnline + // + this.colOnline.Text = "Online"; + this.colOnline.Width = 50; + // + // colUuid + // + this.colUuid.Text = "UUID"; + this.colUuid.Width = 150; + // + // frmSLAccountant + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(592, 437); + this.Controls.Add(this.lstFind); + this.Controls.Add(this.label7); + this.Controls.Add(this.cmdTransfer); + this.Controls.Add(this.txtTransfer); + this.Controls.Add(this.txtFind); + this.Controls.Add(this.cmdFind); + this.Controls.Add(this.label5); + this.Controls.Add(this.lblBalance); + this.Controls.Add(this.label6); + this.Controls.Add(this.lblName); + this.Controls.Add(this.label4); + this.Controls.Add(this.grpLogin); + this.Name = "frmSLAccountant"; + this.Text = "SL Accountant"; + this.Load += new System.EventHandler(this.frmSLAccountant_Load); + this.grpLogin.ResumeLayout(false); + this.ResumeLayout(false); + + } + #endregion + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.Run(new frmSLAccountant()); + } + + private void BalanceHandler(Packet packet, Simulator simulator) + { + if (packet.Layout.Name == "MoneyBalanceReply") + { + int balance = 0; + int squareMetersCredit = 0; + string description = ""; + LLUUID transactionID = null; + bool transactionSuccess = false; + + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "MoneyBalance") + { + balance = (int)field.Data; + } + else if (field.Layout.Name == "SquareMetersCredit") + { + squareMetersCredit = (int)field.Data; + } + else if (field.Layout.Name == "Description") + { + byte[] byteArray = (byte[])field.Data; + description = System.Text.Encoding.ASCII.GetString(byteArray).Replace("\0", ""); + } + else if (field.Layout.Name == "TransactionID") + { + transactionID = (LLUUID)field.Data; + } + else if (field.Layout.Name == "TransactionSuccess") + { + transactionSuccess = (bool)field.Data; + } + } + } + + lblBalance.Text = balance.ToString(); + } + } + + private void DirPeopleHandler(Packet packet, Simulator simulator) + { + lstFindMutex.WaitOne(); + + foreach (Block block in packet.Blocks()) + { + if (block.Layout.Name == "QueryReplies") + { + LLUUID id = null; + string firstName = ""; + string lastName = ""; + bool online = false; + + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "AgentID") + { + id = (LLUUID)field.Data; + } + else if (field.Layout.Name == "LastName") + { + lastName = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "FirstName") + { + firstName = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", ""); + } + else if (field.Layout.Name == "Online") + { + online = (bool)field.Data; + } + } + + if (id != null) + { + ListViewItem listItem = new ListViewItem(new string[] + { firstName + " " + lastName, (online ? "Yes" : "No"), id.ToString() }); + lstFind.Items.Add(listItem); + } + } + } + + lstFindMutex.ReleaseMutex(); + } + + private void AvatarAppearanceHandler(Packet packet, Simulator simulator) + { + LLUUID id = null; + bool trial = false; + + foreach (Block block in packet.Blocks()) + { + foreach (Field field in block.Fields) + { + if (field.Layout.Name == "ID") + { + id = (LLUUID)field.Data; + } + else if (field.Layout.Name == "IsTrial") + { + trial = (bool)field.Data; + } + } + } + + //txtLog.AppendText("AvatarAppearance: " + id.ToString() + " (Trial: " + ((trial) ? "Yes" : "No") + ")\n"); + } + + private void frmSLAccountant_Load(object sender, System.EventArgs e) + { + lstFindMutex = new Mutex(false, "lstFindMutex"); + + try + { + client = new SecondLife("keywords.txt", "message_template.msg"); + + // Install our packet handlers + client.Network.RegisterCallback("AvatarAppearance", new PacketCallback(AvatarAppearanceHandler)); + client.Network.RegisterCallback("MoneyBalanceReply", new PacketCallback(BalanceHandler)); + client.Network.RegisterCallback("DirPeopleReply", new PacketCallback(DirPeopleHandler)); + + grpLogin.Enabled = true; + } + catch (Exception error) + { + MessageBox.Show(this, error.ToString()); + } + } + + private void cmdConnect_Click(object sender, System.EventArgs e) + { + if (cmdConnect.Text == "Connect") + { + cmdConnect.Text = "Disconnect"; + txtFirstName.Enabled = txtLastName.Enabled = txtPassword.Enabled = false; + + Hashtable loginParams = NetworkManager.DefaultLoginValues(txtFirstName.Text, + txtLastName.Text, txtPassword.Text, "00:00:00:00:00:00", "last", 1, 50, 50, 50, + "Win", "0", "accountant", "jhurliman@wsu.edu"); + + if (client.Network.Login(loginParams)) + { + Random rand = new Random(); + + lblName.Text = client.Network.LoginValues["first_name"] + " " + + client.Network.LoginValues["last_name"]; + + // AgentHeightWidth + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + fields["ID"] = client.Network.AgentID; + fields["GenCounter"] = (uint)0; + fields["CircuitCode"] = client.Network.CurrentSim.CircuitCode; + blocks[fields] = "Sender"; + fields = new Hashtable(); + fields["Height"] = (ushort)rand.Next(0, 65535); + fields["Width"] = (ushort)rand.Next(0, 65535); + blocks[fields] = "HeightWidthBlock"; + Packet packet = PacketBuilder.BuildPacket("AgentHeightWidth", client.Protocol, blocks, + Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + + client.Network.SendPacket(packet); + + // ConnectAgentToUserserver + blocks = new Hashtable(); + fields = new Hashtable(); + fields["AgentID"] = client.Network.AgentID; + fields["SessionID"] = client.Network.SessionID; + blocks[fields] = "AgentData"; + packet = PacketBuilder.BuildPacket("ConnectAgentToUserserver", client.Protocol, blocks, + Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED); + + client.Network.SendPacket(packet); + + // MoneyBalanceRequest + blocks = new Hashtable(); + fields = new Hashtable(); + fields["AgentID"] = client.Network.AgentID; + fields["TransactionID"] = LLUUID.GenerateUUID(); + blocks[fields] = "MoneyData"; + packet = PacketBuilder.BuildPacket("MoneyBalanceRequest", client.Protocol, blocks, + Helpers.MSG_RELIABLE); + + client.Network.SendPacket(packet); + + // AgentSetAppearance + blocks = new Hashtable(); + // Setup some random appearance values + for (int i = 0; i < 218; ++i) + { + fields = new Hashtable(); + fields["ParamValue"] = (byte)rand.Next(255); + blocks[fields] = "VisualParam"; + } + fields = new Hashtable(); + byte[] byteArray = new byte[400]; + fields["TextureEntry"] = byteArray; + blocks[fields] = "ObjectData"; + fields = new Hashtable(); + fields["SerialNum"] = (uint)1; + fields["ID"] = client.Network.AgentID; + // Setup a random avatar size + LLVector3 sizeVector = new LLVector3(0.45F, 0.6F, 1.831094F); + fields["Size"] = sizeVector; + blocks[fields] = "Sender"; + packet = PacketBuilder.BuildPacket("AgentSetAppearance", client.Protocol, blocks, + Helpers.MSG_RELIABLE); + + client.Network.SendPacket(packet); + + txtFind.Enabled = cmdFind.Enabled = true; + txtTransfer.Enabled = cmdTransfer.Enabled = true; + } + else + { + MessageBox.Show(this, "Error logging in: " + client.Network.LoginError); + cmdConnect.Text = "Connect"; + txtFirstName.Enabled = txtLastName.Enabled = txtPassword.Enabled = true; + txtFind.Enabled = cmdFind.Enabled = false; + lblName.Text = lblBalance.Text = ""; + txtTransfer.Enabled = cmdTransfer.Enabled = false; + } + } + else + { + client.Network.Logout(); + cmdConnect.Text = "Connect"; + txtFirstName.Enabled = txtLastName.Enabled = txtPassword.Enabled = true; + txtFind.Enabled = cmdFind.Enabled = false; + lblName.Text = lblBalance.Text = ""; + txtTransfer.Enabled = cmdTransfer.Enabled = false; + } + } + + private void cmdFind_Click(object sender, System.EventArgs e) + { + lstFind.Items.Clear(); + + Hashtable blocks = new Hashtable(); + Hashtable fields = new Hashtable(); + fields["QueryID"] = LLUUID.GenerateUUID(); + fields["QueryFlags"] = (uint)1; + fields["QueryStart"] = (int)0; + fields["QueryText"] = txtFind.Text; + blocks[fields] = "QueryData"; + + fields = new Hashtable(); + fields["AgentID"] = client.Network.AgentID; + fields["SessionID"] = client.Network.SessionID; + blocks[fields] = "AgentData"; + + Packet packet = PacketBuilder.BuildPacket("DirFindQuery", client.Protocol, blocks, + Helpers.MSG_RELIABLE); + + client.Network.SendPacket(packet); + } + + private void cmdTransfer_Click(object sender, System.EventArgs e) + { + int amount = 0; + + try + { + amount = System.Convert.ToInt32(txtTransfer.Text); + } + catch (Exception) + { + MessageBox.Show(txtTransfer.Text + " is not a valid amount"); + return; + } + + if (lstFind.SelectedItems.Count != 1) + { + MessageBox.Show("Find an avatar using the directory search and select " + + "their name to transfer money"); + return; + } + + client.Avatar.GiveMoney(new LLUUID(lstFind.SelectedItems[0].SubItems[2].Text), + amount, "SLAccountant payment"); + } + } +} diff --git a/old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.resx b/old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.resx new file mode 100644 index 00000000..0b39743a --- /dev/null +++ b/old/libsecondlife-cs/examples/slaccountant/frmSLAccountant.resx @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Private + + + 8, 8 + + + True + + + False + + + True + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + False + + + Private + + + Private + + + Private + + + False + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + Private + + + False + + + Private + + + False + + + Private + + + Private + + + Private + + + False + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + False + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + False + + + (Default) + + + False + + + False + + + 8, 8 + + + True + + + 80 + + + True + + + frmSLAccountant + + + Private + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/slaccountant/slaccountant.csproj b/old/libsecondlife-cs/examples/slaccountant/slaccountant.csproj new file mode 100644 index 00000000..0f9f66fd --- /dev/null +++ b/old/libsecondlife-cs/examples/slaccountant/slaccountant.csproj @@ -0,0 +1,117 @@ + + + Local + 8.0.50727 + 2.0 + {FC19D5F6-076E-4923-8456-9B0E00E22896} + Debug + AnyCPU + App.ico + + + slaccountant + + + JScript + Grid + IE50 + false + WinExe + slaccountant + OnBuildSuccess + + + + + + + + + ..\..\..\bin\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.Drawing + + + System.Windows.Forms + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + False + + + + + + Code + + + Form + + + frmSLAccountant.cs + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/examples/sldump/sldump.cs b/old/libsecondlife-cs/examples/sldump/sldump.cs new file mode 100644 index 00000000..a891e0e4 --- /dev/null +++ b/old/libsecondlife-cs/examples/sldump/sldump.cs @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using libsecondlife; + +namespace sldump +{ + class sldump + { + static int i = 0; + + // Default packet handler, registered for all packet types + public static void DefaultHandler(Packet packet, Simulator simulator) + { + if (i < 10) + { + Console.Write(packet.ToString()); + } + i++; + } + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + SecondLife client; + + if (args.Length == 0 || (args.Length < 3 && args[0] != "--printmap")) + { + Console.WriteLine("Usage: sldump [--printmap] [--decrypt] [inputfile] [outputfile] [--protocol] [firstname] " + + "[lastname] [password]"); + return; + } + + if (args[0] == "--decrypt") + { + try + { + ProtocolManager.DecodeMapFile(args[1], args[2]); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + + return; + } + + try + { + client = new SecondLife("keywords.txt", "message_template.msg"); + } + catch (Exception e) + { + // Error initializing the client, probably missing file(s) + Console.WriteLine(e.ToString()); + return; + } + + if (args[0] == "--printmap") + { + client.Protocol.PrintMap(); + return; + } + + // Setup the callback + client.Network.RegisterCallback("Default", new PacketCallback(DefaultHandler)); + + Hashtable loginParams = NetworkManager.DefaultLoginValues(args[0], args[1], args[2], "00:00:00:00:00:00", + "last", 1, 50, 50, 50, "Win", "0", "sldump", "jhurliman@wsu.edu"); + + // An example of how to pass additional options to the login server + ArrayList optionsArray = new ArrayList(); + optionsArray.Add("inventory-root"); + optionsArray.Add("inventory-skeleton"); + loginParams["options"] = optionsArray; + + if (!client.Network.Login(loginParams)) + { + // Login failed + Console.WriteLine("Error logging in: " + client.Network.LoginError); + return; + } + + // Login was successful + Console.WriteLine("Message of the day: " + client.Network.LoginValues["message"]); + + while (true) + { + client.Tick(); + } + } + } +} diff --git a/old/libsecondlife-cs/examples/sldump/sldump.csproj b/old/libsecondlife-cs/examples/sldump/sldump.csproj new file mode 100644 index 00000000..acfda7da --- /dev/null +++ b/old/libsecondlife-cs/examples/sldump/sldump.csproj @@ -0,0 +1,105 @@ + + + Local + 8.0.50727 + 2.0 + {F6258A68-C624-46A0-BA73-B55D21BB0A3B} + Debug + AnyCPU + + + + + sldump + + + JScript + Grid + IE50 + false + Exe + sldump + OnBuildSuccess + + + + + + + + + ..\..\..\bin\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.XML + + + libsecondlife + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + False + + + + + Code + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/libsecondlife.build b/old/libsecondlife-cs/libsecondlife.build new file mode 100644 index 00000000..16b1aa38 --- /dev/null +++ b/old/libsecondlife-cs/libsecondlife.build @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/old/libsecondlife-cs/libsecondlife.csproj b/old/libsecondlife-cs/libsecondlife.csproj new file mode 100644 index 00000000..a71a07c1 --- /dev/null +++ b/old/libsecondlife-cs/libsecondlife.csproj @@ -0,0 +1,265 @@ + + + Local + 8.0.50727 + 2.0 + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + Debug + AnyCPU + + + + + libsecondlife + + + JScript + Grid + IE50 + false + Library + libsecondlife + OnBuildSuccess + + + + + + + + + ..\bin\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + false + + + true + false + false + false + 4 + none + prompt + + + ..\bin\ + + + + System + + + System.Data + + + System.XML + + + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/libsecondlife.sln b/old/libsecondlife-cs/libsecondlife.sln new file mode 100644 index 00000000..17938eb3 --- /dev/null +++ b/old/libsecondlife-cs/libsecondlife.sln @@ -0,0 +1,79 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "libsecondlife", "libsecondlife.csproj", "{D9CDEDFB-8169-4B03-B57F-0DF638F044EC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sldump", "examples\sldump\sldump.csproj", "{F6258A68-C624-46A0-BA73-B55D21BB0A3B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "slaccountant", "examples\slaccountant\slaccountant.csproj", "{FC19D5F6-076E-4923-8456-9B0E00E22896}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "name2key", "examples\name2key\name2key.csproj", "{66FFD34E-652C-4EF5-81FE-06AD011169D2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParcelDownload", "examples\ParcelDownload\ParcelDownload.csproj", "{623B86F7-7753-44B7-A8C8-CBC89FB8AF8E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateNotecard", "examples\CreateNotecard\CreateNotecard.csproj", "{D5ACEEA1-89CD-4FD2-8A1F-1BD828988FDC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageTool", "examples\ImageTool\ImageTool.csproj", "{6ACF3FF4-CFA5-478B-993E-F788A1030CEB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InventoryDump", "examples\InventoryDump\InventoryDump.csproj", "{6478BE37-9272-4D91-B641-5E2FD0680B27}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "primexport", "examples\primexport\primexport.csproj", "{77E5330D-8A8C-41B4-A2D1-6F06FE45ED6D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "libsecondlife.Tests", "tests\libsecondlife.Tests.csproj", "{E0BCBBAE-A620-431A-9EB7-30173EAF195B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mapgenerator", "mapgenerator\mapgenerator.csproj", "{C59B1312-57EF-4146-B6B2-1C7B6DC4638B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC}.Debug|Any CPU.ActiveCfg = Debug|.NET 1.1 + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC}.Debug|Any CPU.Build.0 = Debug|.NET 1.1 + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC}.Release|Any CPU.Build.0 = Release|Any CPU + {F6258A68-C624-46A0-BA73-B55D21BB0A3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6258A68-C624-46A0-BA73-B55D21BB0A3B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6258A68-C624-46A0-BA73-B55D21BB0A3B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6258A68-C624-46A0-BA73-B55D21BB0A3B}.Release|Any CPU.Build.0 = Release|Any CPU + {FC19D5F6-076E-4923-8456-9B0E00E22896}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC19D5F6-076E-4923-8456-9B0E00E22896}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC19D5F6-076E-4923-8456-9B0E00E22896}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC19D5F6-076E-4923-8456-9B0E00E22896}.Release|Any CPU.Build.0 = Release|Any CPU + {66FFD34E-652C-4EF5-81FE-06AD011169D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {66FFD34E-652C-4EF5-81FE-06AD011169D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {66FFD34E-652C-4EF5-81FE-06AD011169D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {66FFD34E-652C-4EF5-81FE-06AD011169D2}.Release|Any CPU.Build.0 = Release|Any CPU + {623B86F7-7753-44B7-A8C8-CBC89FB8AF8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {623B86F7-7753-44B7-A8C8-CBC89FB8AF8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {623B86F7-7753-44B7-A8C8-CBC89FB8AF8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {623B86F7-7753-44B7-A8C8-CBC89FB8AF8E}.Release|Any CPU.Build.0 = Release|Any CPU + {D5ACEEA1-89CD-4FD2-8A1F-1BD828988FDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5ACEEA1-89CD-4FD2-8A1F-1BD828988FDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5ACEEA1-89CD-4FD2-8A1F-1BD828988FDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5ACEEA1-89CD-4FD2-8A1F-1BD828988FDC}.Release|Any CPU.Build.0 = Release|Any CPU + {6ACF3FF4-CFA5-478B-993E-F788A1030CEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6ACF3FF4-CFA5-478B-993E-F788A1030CEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6ACF3FF4-CFA5-478B-993E-F788A1030CEB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6ACF3FF4-CFA5-478B-993E-F788A1030CEB}.Release|Any CPU.Build.0 = Release|Any CPU + {6478BE37-9272-4D91-B641-5E2FD0680B27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6478BE37-9272-4D91-B641-5E2FD0680B27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6478BE37-9272-4D91-B641-5E2FD0680B27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6478BE37-9272-4D91-B641-5E2FD0680B27}.Release|Any CPU.Build.0 = Release|Any CPU + {77E5330D-8A8C-41B4-A2D1-6F06FE45ED6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77E5330D-8A8C-41B4-A2D1-6F06FE45ED6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77E5330D-8A8C-41B4-A2D1-6F06FE45ED6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77E5330D-8A8C-41B4-A2D1-6F06FE45ED6D}.Release|Any CPU.Build.0 = Release|Any CPU + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Debug|Any CPU.ActiveCfg = Debug|.NET 1.1 + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Debug|Any CPU.Build.0 = Debug|.NET 1.1 + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Release|Any CPU.Build.0 = Release|Any CPU + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/old/libsecondlife-cs/mapgenerator/Properties/AssemblyInfo.cs b/old/libsecondlife-cs/mapgenerator/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..88fa1df9 --- /dev/null +++ b/old/libsecondlife-cs/mapgenerator/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("mapgenerator")] +[assembly: AssemblyDescription("C# class generator from the Second Life message template")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("libsecondlife")] +[assembly: AssemblyProduct("mapgenerator")] +[assembly: AssemblyCopyright("Copyright © libsecondlife 2006")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("87314973-b32d-4dab-b0da-ab3c5280d268")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.0.0.1")] +[assembly: AssemblyFileVersion("0.0.0.1")] diff --git a/old/libsecondlife-cs/mapgenerator/mapgenerator.cs b/old/libsecondlife-cs/mapgenerator/mapgenerator.cs new file mode 100644 index 00000000..152d23e0 --- /dev/null +++ b/old/libsecondlife-cs/mapgenerator/mapgenerator.cs @@ -0,0 +1,392 @@ +using System; +using System.Text; +using System.IO; +using libsecondlife; + +namespace mapgenerator +{ + class mapgenerator + { + static void WriteFieldMember(MapField field) + { + string type = ""; + + switch (field.Type) + { + case FieldType.BOOL: + type = "bool"; + break; + case FieldType.F32: + type = "float"; + break; + case FieldType.F64: + type = "double"; + break; + case FieldType.IPPORT: + case FieldType.U16: + type = "ushort"; + break; + case FieldType.IPADDR: + case FieldType.U32: + type = "uint"; + break; + case FieldType.LLQuaternion: + type = "LLQuaternion"; + break; + case FieldType.LLUUID: + type = "LLUUID"; + break; + case FieldType.LLVector3: + type = "LLVector3"; + break; + case FieldType.LLVector3d: + type = "LLVector3d"; + break; + case FieldType.LLVector4: + type = "LLVector4"; + break; + case FieldType.S16: + type = "short"; + break; + case FieldType.S32: + type = "int"; + break; + case FieldType.S64: + type = "long"; + break; + case FieldType.S8: + type = "sbyte"; + break; + case FieldType.U64: + type = "ulong"; + break; + case FieldType.U8: + type = "byte"; + break; + case FieldType.Fixed: + type = "byte[]"; + break; + } + if (field.Type != FieldType.Variable) + { + Console.WriteLine(" public " + type + " " + field.Name + ";"); + } + else + { + Console.WriteLine(" private byte[] _" + field.Name.ToLower() + ";"); + Console.WriteLine(" public byte[] " + field.Name + "\n {"); + Console.WriteLine(" get { return _" + field.Name.ToLower() + "; }"); + Console.WriteLine(" set\n {"); + Console.WriteLine(" if (value == null) { _" + + field.Name.ToLower() + " = null; return; }"); + Console.WriteLine(" if (value.Length > " + + ((field.Count == 1) ? "255" : "1024") + ") { throw new OverflowException(" + + "\"Value exceeds " + ((field.Count == 1) ? "255" : "1024") + " characters\"); }"); + Console.WriteLine(" else { _" + field.Name.ToLower() + + " = new byte[value.Length]; Array.Copy(value, _" + + field.Name.ToLower() + ", value.Length); }"); + Console.WriteLine(" }\n }"); + } + } + + static void WriteFieldFromBytes(MapField field) + { + switch (field.Type) + { + case FieldType.BOOL: + Console.WriteLine(" " + + field.Name + " = (bytes[i++] != 0) ? (bool)true : (bool)false;"); + break; + case FieldType.F32: + Console.WriteLine(" " + + "if (!BitConverter.IsLittleEndian) Array.Reverse(bytes, i, 4);"); + Console.WriteLine(" " + + field.Name + " = BitConverter.ToSingle(bytes, i); i += 4;"); + break; + case FieldType.F64: + Console.WriteLine(" " + + "if (!BitConverter.IsLittleEndian) Array.Reverse(bytes, i, 8);"); + Console.WriteLine(" " + + field.Name + " = BitConverter.ToDouble(bytes, i); i += 8;"); + break; + case FieldType.Fixed: + Console.WriteLine(" " + field.Name + " = new byte[" + field.Count + "];"); + Console.WriteLine(" Array.Copy(bytes, i, " + field.Name + + ", 0, " + field.Count + "); i += " + field.Count + ";"); + break; + case FieldType.IPADDR: + case FieldType.U32: + Console.WriteLine(" " + field.Name + + " = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24));"); + break; + case FieldType.IPPORT: + case FieldType.U16: + Console.WriteLine(" " + field.Name + + " = (ushort)(bytes[i++] + (bytes[i++] << 8));"); + break; + case FieldType.LLQuaternion: + Console.WriteLine(" " + field.Name + + " = new LLQuaternion(bytes, i); i += 16;"); + break; + case FieldType.LLUUID: + Console.WriteLine(" " + field.Name + + " = new LLUUID(bytes, i); i += 16;"); + break; + case FieldType.LLVector3: + Console.WriteLine(" " + field.Name + + " = new LLVector3(bytes, i); i += 12;"); + break; + case FieldType.LLVector3d: + Console.WriteLine(" " + field.Name + + " = new LLVector3d(bytes, i); i += 24;"); + break; + case FieldType.LLVector4: + Console.WriteLine(" " + field.Name + + " = new LLVector4(bytes, i); i += 16;"); + break; + case FieldType.S16: + Console.WriteLine(" " + field.Name + + " = (short)(bytes[i++] + (bytes[i++] << 8));"); + break; + case FieldType.S32: + Console.WriteLine(" " + field.Name + + " = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24));"); + break; + case FieldType.S64: + Console.WriteLine(" " + field.Name + + " = (long)(bytes[i++] + (bytes[i++] << 8) + " + + "(bytes[i++] << 16) + (bytes[i++] << 24) + " + + "(bytes[i++] << 32) + (bytes[i++] << 40) + " + + "(bytes[i++] << 48) + (bytes[i++] << 56));"); + break; + case FieldType.S8: + Console.WriteLine(" " + field.Name + + " = (sbyte)bytes[i++];"); + break; + case FieldType.U64: + Console.WriteLine(" " + field.Name + + " = (ulong)(bytes[i++] + (bytes[i++] << 8) + " + + "(bytes[i++] << 16) + (bytes[i++] << 24) + " + + "(bytes[i++] << 32) + (bytes[i++] << 40) + " + + "(bytes[i++] << 48) + (bytes[i++] << 56));"); + break; + case FieldType.U8: + Console.WriteLine(" " + field.Name + + " = (byte)bytes[i++];"); + break; + case FieldType.Variable: + if (field.Count == 1) + { + Console.WriteLine(" length = (ushort)bytes[i++];"); + } + else + { + Console.WriteLine(" length = (ushort)(bytes[i++] + (bytes[i++] << 8));"); + } + Console.WriteLine(" _" + field.Name.ToLower() + " = new byte[length];"); + Console.WriteLine(" Array.Copy(bytes, i, _" + field.Name.ToLower() + + ", 0, length); i += length;"); + break; + } + } + + static void WriteBlockClass(MapBlock block) + { + bool variableFields = false; + + Console.WriteLine(" public class " + block.Name + "Block\n {"); + + foreach (MapField field in block.Fields) + { + WriteFieldMember(field); + + if (field.Type == FieldType.Variable) { variableFields = true; } + } + + Console.WriteLine(""); + + // Default constructor + Console.WriteLine(" public " + block.Name + "Block() { }"); + + // + Console.WriteLine(" public " + block.Name + "Block(byte[] bytes, ref int i)" + + "\n {"); + + // Declare a length variable if we need it for variable fields in this constructor + if (variableFields) + { + Console.WriteLine(" int length;"); + } + Console.WriteLine(" try\n {"); + + foreach (MapField field in block.Fields) + { + WriteFieldFromBytes(field); + } + + Console.WriteLine(" }\n catch (Exception)\n" + + " {\n throw new MalformedDataException();\n" + + " }\n }\n"); + + // FIXME: Write the ToBytes() function + Console.WriteLine(" public byte[] ToBytes() { return null; }"); + + Console.WriteLine(" }\n"); + } + + static void WritePacketClass(MapPacket packet) + { + Console.WriteLine(" class " + packet.Name + "Packet\n {"); + + // Write out each block class + foreach (MapBlock block in packet.Blocks) + { + WriteBlockClass(block); + } + + // Header member + Console.WriteLine(" public " + packet.Frequency.ToString() + "Header Header;"); + + // PacketType member + Console.WriteLine(" public PacketType Type { get { return Type; } set { Type = value; } }"); + + // Block members + foreach (MapBlock block in packet.Blocks) + { + Console.WriteLine(" public " + block.Name + "Block" + + ((block.Count != 1) ? "[]" : "") + " " + block.Name + ";"); + } + + Console.WriteLine(""); + + // Default constructor + Console.WriteLine(" " + packet.Name + "Packet()\n {"); + Console.WriteLine(" Type = PacketType." + packet.Name + ";"); + Console.WriteLine(" Header = new " + packet.Frequency.ToString() + "Header();"); + foreach (MapBlock block in packet.Blocks) + { + if (block.Count == 1) + { + // Single count block + Console.WriteLine(" " + block.Name + " = new " + block.Name + "Block();"); + } + else if (block.Count == -1) + { + // Variable count block + Console.WriteLine(" " + block.Name + " = new " + block.Name + "Block[0];"); + } + else + { + // Multiple count block + Console.WriteLine(" " + block.Name + " = new " + block.Name + + "Block[" + block.Count + "];"); + } + } + Console.WriteLine(" }\n"); + + // Constructor that takes a byte array and beginning position only (no prebuilt header) + bool seenVariable = false; + Console.WriteLine(" " + packet.Name + "Packet(byte[] bytes, ref int i)\n {"); + Console.WriteLine(" Type = PacketType." + packet.Name + ";"); + Console.WriteLine(" int packetEnd = bytes.Length - 1;"); + Console.WriteLine(" Header = new " + packet.Frequency.ToString() + + "Header(bytes, ref i, ref packetEnd);"); + foreach (MapBlock block in packet.Blocks) + { + if (block.Count == 1) + { + // Single count block + Console.WriteLine(" " + block.Name + " = new " + block.Name + "Block(bytes, ref i);"); + } + else if (block.Count == -1) + { + // Variable count block + if (!seenVariable) + { + Console.WriteLine(" int count = (int)bytes[i++];"); + seenVariable = true; + } + else + { + Console.WriteLine(" count = (int)bytes[i++];"); + } + Console.WriteLine(" for (int j = 0; j < count; j++)"); + Console.WriteLine(" { " + block.Name + "[j] = new " + + block.Name + "Block(bytes, ref i); }"); + } + else + { + // Multiple count block + Console.WriteLine(" for (int j = 0; j < " + block.Count + "; j++)"); + Console.WriteLine(" { " + block.Name + "[j] = new " + + block.Name + "Block(bytes, ref i); }"); + } + } + Console.WriteLine(" }\n"); + + // Constructor that takes a byte array and a prebuilt header + Console.WriteLine(" " + packet.Name + "Packet(" + packet.Frequency.ToString() + + "Header header, byte[] bytes, ref int i)\n {"); + Console.WriteLine(" Type = PacketType." + packet.Name + ";"); + Console.WriteLine(" Header = header;"); + Console.WriteLine(" //FIXME"); + Console.WriteLine(" }\n"); + + // ToBytes() function + Console.WriteLine(" public byte[] ToBytes() { return null; }"); + + // Closing bracket + Console.WriteLine(" }\n"); + } + + static void Main(string[] args) + { + SecondLife libsl = new SecondLife("keywords.txt", "message_template.msg"); + + TextReader reader = new StreamReader("template.cs"); + Console.WriteLine(reader.ReadToEnd()); + reader.Close(); + + Console.WriteLine(" public enum PacketType\n {"); + foreach (MapPacket packet in libsl.Protocol.LowMaps) + { + if (packet != null) + { + Console.WriteLine(" " + packet.Name + ","); + } + } + foreach (MapPacket packet in libsl.Protocol.MediumMaps) + { + if (packet != null) + { + Console.WriteLine(" " + packet.Name + ","); + } + } + foreach (MapPacket packet in libsl.Protocol.HighMaps) + { + if (packet != null) + { + Console.WriteLine(" " + packet.Name + ","); + } + } + Console.WriteLine(" }\n"); + + foreach (MapPacket packet in libsl.Protocol.LowMaps) + { + if (packet != null) { WritePacketClass(packet); } + } + + foreach (MapPacket packet in libsl.Protocol.MediumMaps) + { + if (packet != null) { WritePacketClass(packet); } + } + + foreach (MapPacket packet in libsl.Protocol.HighMaps) + { + if (packet != null) { WritePacketClass(packet); } + } + + Console.WriteLine("}"); + } + } +} diff --git a/old/libsecondlife-cs/mapgenerator/mapgenerator.csproj b/old/libsecondlife-cs/mapgenerator/mapgenerator.csproj new file mode 100644 index 00000000..925ca7e0 --- /dev/null +++ b/old/libsecondlife-cs/mapgenerator/mapgenerator.csproj @@ -0,0 +1,53 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B} + Exe + Properties + mapgenerator + mapgenerator + + + true + full + false + ..\..\bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + libsecondlife + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/mapgenerator/mapgenerator.sln b/old/libsecondlife-cs/mapgenerator/mapgenerator.sln new file mode 100644 index 00000000..0390683d --- /dev/null +++ b/old/libsecondlife-cs/mapgenerator/mapgenerator.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mapgenerator", "mapgenerator.csproj", "{C59B1312-57EF-4146-B6B2-1C7B6DC4638B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C59B1312-57EF-4146-B6B2-1C7B6DC4638B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/old/libsecondlife-cs/tests/DebugServer.cs b/old/libsecondlife-cs/tests/DebugServer.cs new file mode 100644 index 00000000..be13194c --- /dev/null +++ b/old/libsecondlife-cs/tests/DebugServer.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text.RegularExpressions; +using System.Threading; +using System.Xml; +using Nwc.XmlRpc; +using libsecondlife; + +namespace libsecondlife.Tests +{ + public class DebugServer + { + public bool Initialized = false; + + private SecondLife libsl; + private bool done = false; + private Socket Listener; + private IPEndPoint Endpoint; + EndPoint RemoteEndpoint = new IPEndPoint(IPAddress.Loopback, 0); + private ushort Sequence = 0; + + public DebugServer(string keywordFile, string mapFile, int port) + { + try + { + libsl = new SecondLife(keywordFile, mapFile); + } + catch (Exception) + { + return; + } + + BindSocket(port); + } + + private void BindSocket(int port) + { + Endpoint = new IPEndPoint(IPAddress.Loopback, port); + Listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + + Console.WriteLine("[SERVER] Binding a UDP socket to " + Endpoint.ToString()); + + try + { + Listener.Bind(Endpoint); + } + catch (SocketException) + { + Console.WriteLine("[SERVER] Failed to bind to " + Endpoint.ToString()); + return; + } + + // Start listening for incoming data + Thread thread = new Thread(new ThreadStart(Listen)); + thread.Start(); + + Initialized = true; + } + + private void Listen() + { + Packet packet; + int length; + byte[] bytes = new byte[4096]; + + Console.WriteLine("[SERVER] Listening for incoming data on " + Endpoint.ToString()); + + while (!done) + { + packet = null; + + // Grab the next packet + length = Listener.ReceiveFrom(bytes, ref RemoteEndpoint); + + Console.WriteLine("[SERVER] Received a packet from {0}", RemoteEndpoint.ToString()); + + if (System.Text.ASCIIEncoding.UTF8.GetString(bytes).Substring(0, 10) == "stopserver") + { + Console.WriteLine("[SERVER] Received a shutdown request, stopping the server"); + done = true; + break; + } + + if ((bytes[0] & Helpers.MSG_APPENDED_ACKS) != 0) + { + byte numAcks = bytes[length - 1]; + + Console.WriteLine("[SERVER] Found " + numAcks + " appended acks"); + + length = (length - numAcks * 4) - 1; + } + + if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) + { + // Allocate a temporary buffer for the zerocoded packet + byte[] zeroBuffer = new byte[4096]; + int zeroBytes = Helpers.ZeroDecode(bytes, length, zeroBuffer); + length = zeroBytes; + packet = new Packet(zeroBuffer, length, libsl.Protocol); + } + else + { + // Create the packet object from our byte array + packet = new Packet(bytes, length, libsl.Protocol); + } + + if ((packet.Data[0] & Helpers.MSG_RELIABLE) != 0) + { + SendACK((uint)packet.Sequence); + } + + Console.WriteLine(packet.ToString()); + } + + Console.WriteLine("[SERVER] Shutting down the socket on " + Endpoint.ToString()); + Listener.Close(); + } + + private void SendACK(uint id) + { + try + { + Packet packet = new Packet("PacketAck", libsl.Protocol, 13); + packet.Data[8] = 1; + Array.Copy(BitConverter.GetBytes(id), 0, packet.Data, 9, 4); + + // Set the sequence number + packet.Sequence = ++Sequence; + + Listener.SendTo(packet.Data, RemoteEndpoint); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + } + } +} diff --git a/old/libsecondlife-cs/tests/Tests.cs b/old/libsecondlife-cs/tests/Tests.cs new file mode 100644 index 00000000..965a50d9 --- /dev/null +++ b/old/libsecondlife-cs/tests/Tests.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections; +using System.Net; +using libsecondlife; +using NUnit.Framework; + +namespace libsecondlife.Tests +{ + [TestFixture] + public class EndianTests : Assert + { + SecondLife Client = null; + DebugServer Server = null; + Packet CurrentPacket = null; + bool NetworkFinished = false; + + [SetUp] + public void Init() + { + try + { + Client = new SecondLife("keywords.txt", "message_template.msg"); + Client.Network.AgentID = LLUUID.GenerateUUID(); + Client.Network.SessionID = LLUUID.GenerateUUID(); + } + catch (Exception) + { + Assert.IsTrue(false, "Failed to initialize the client, " + + "keywords.txt or message_template.msg missing?"); + } + + Server = new DebugServer("keywords.txt", "message_template.msg", 8338); + Assert.IsTrue(Server.Initialized, "Failed to initialize the server, couldn't bind to port 8338?"); + + Simulator debugSim = Client.Network.Connect(IPAddress.Loopback, 8338, 1, true); + Assert.IsNotNull(debugSim, "Failed to connect to the debugging simulator"); + + Client.Network.RegisterCallback("SimulatorAssign", new PacketCallback(SimulatorAssignHandler)); + } + + [Test] + public void U8Receive() + { + CurrentPacket = null; + NetworkFinished = false; + + // 2. Instruct the server to send a SimulatorAssign to the client with some fixed values + + int start = Environment.TickCount; + + while (!NetworkFinished && Environment.TickCount - start < 5000) + { + System.Threading.Thread.Sleep(0); + } + + // 5. Parse the Packet and run our assertion(s) + Assert.IsNotNull(CurrentPacket, "Never received the packet"); + Assert.IsTrue(true); + } + + [Test] + public void S8Receive() + { + ; + } + + [Test] + public void U16Receive() + { + ; + } + + [Test] + public void S16Receive() + { + ; + } + + private void SimulatorAssignHandler(Packet packet, Simulator sim) + { + CurrentPacket = packet; + NetworkFinished = true; + } + + [TearDown] + public void Shutdown() + { + try + { + Client.Network.SendPacket(System.Text.Encoding.UTF8.GetBytes("stopserver")); + Client.Network.Logout(); + } + catch (NotConnectedException) + { + Assert.IsTrue(false, "Logout failed, not connected"); + } + + Client = null; + Server = null; + } + } +} diff --git a/old/libsecondlife-cs/tests/libsecondlife.Tests.csproj b/old/libsecondlife-cs/tests/libsecondlife.Tests.csproj new file mode 100644 index 00000000..93217279 --- /dev/null +++ b/old/libsecondlife-cs/tests/libsecondlife.Tests.csproj @@ -0,0 +1,61 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {E0BCBBAE-A620-431A-9EB7-30173EAF195B} + Library + Properties + libsecondlife.Tests + libsecondlife.Tests + + + true + full + false + ..\..\bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + ..\..\bin\ + + + + + + + + + + + + + + {D9CDEDFB-8169-4B03-B57F-0DF638F044EC} + libsecondlife + + + + + + + + + \ No newline at end of file diff --git a/old/libsecondlife-cs/tests/libsecondlife.Tests.sln b/old/libsecondlife-cs/tests/libsecondlife.Tests.sln new file mode 100644 index 00000000..69454e03 --- /dev/null +++ b/old/libsecondlife-cs/tests/libsecondlife.Tests.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "libsecondlife.Tests", "libsecondlife.Tests.csproj", "{E0BCBBAE-A620-431A-9EB7-30173EAF195B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0BCBBAE-A620-431A-9EB7-30173EAF195B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal