diff --git a/OpenMetaverse/Helpers.cs b/OpenMetaverse/Helpers.cs index 07d0e3b7..f0b1bbf0 100644 --- a/OpenMetaverse/Helpers.cs +++ b/OpenMetaverse/Helpers.cs @@ -527,69 +527,5 @@ namespace OpenMetaverse uint fixedState = (((byte)state & ATTACHMENT_MASK) >> 4) | (((byte)state & ~ATTACHMENT_MASK) << 4); return (AttachmentPoint)fixedState; } - - /// - /// Parse a packet into human readable formatted key/value pairs - /// - /// the Packet to parse - /// A string containing the packet block name, and key/value pairs of the data fields - public static string PacketToString(Packet packet) - { - StringBuilder result = new StringBuilder(); - - foreach(FieldInfo packetField in packet.GetType().GetFields()) - { - object packetDataObject = packetField.GetValue(packet); - - result.AppendFormat("-- {0} --" + System.Environment.NewLine, packetField.Name); - result.AppendFormat("-- {0} --" + System.Environment.NewLine, packet.Type); - foreach(FieldInfo packetValueField in packetField.GetValue(packet).GetType().GetFields()) - { - result.AppendFormat("{0}: {1}" + System.Environment.NewLine, - packetValueField.Name, packetValueField.GetValue(packetDataObject)); - } - - // handle blocks that are arrays - if (packetDataObject.GetType().IsArray) - { - foreach (object nestedArrayRecord in packetDataObject as Array) - { - foreach (FieldInfo packetArrayField in nestedArrayRecord.GetType().GetFields()) - { - result.AppendFormat("{0} {1}" + System.Environment.NewLine, - packetArrayField.Name, packetArrayField.GetValue(nestedArrayRecord)); - } - } - } - else - { - // handle non array data blocks - foreach (PropertyInfo packetPropertyField in packetField.GetValue(packet).GetType().GetProperties()) - { - // Handle fields named "Data" specifically, this is generally binary data, we'll display it as hex values - if (packetPropertyField.PropertyType.Equals(typeof(System.Byte[])) - && packetPropertyField.Name.Equals("Data")) - { - result.AppendFormat("{0}: {1}" + System.Environment.NewLine, - packetPropertyField.Name, - Utils.BytesToHexString((byte[])packetPropertyField.GetValue(packetDataObject, null), packetPropertyField.Name)); - } - // decode bytes into strings - else if (packetPropertyField.PropertyType.Equals(typeof(System.Byte[]))) - { - result.AppendFormat("{0}: {1}" + System.Environment.NewLine, - packetPropertyField.Name, - Utils.BytesToString((byte[])packetPropertyField.GetValue(packetDataObject, null))); - } - else - { - result.AppendFormat("{0}: {1}" + System.Environment.NewLine, - packetPropertyField.Name, packetPropertyField.GetValue(packetDataObject, null)); - } - } - } - } - return result.ToString(); - } } } diff --git a/OpenMetaverse/ObjectManager.cs b/OpenMetaverse/ObjectManager.cs index 149ad38f..9f3afac6 100644 --- a/OpenMetaverse/ObjectManager.cs +++ b/OpenMetaverse/ObjectManager.cs @@ -57,6 +57,7 @@ namespace OpenMetaverse [Flags] public enum CompressedFlags : uint { + None = 0x00, /// Unknown ScratchPad = 0x01, /// Whether the object has a TreeSpecies @@ -1351,7 +1352,7 @@ namespace OpenMetaverse { ObjectUpdatePacket update = (ObjectUpdatePacket)packet; UpdateDilation(simulator, update.RegionData.TimeDilation); - + for (int b = 0; b < update.ObjectData.Length; b++) { ObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[b]; diff --git a/OpenMetaverse/PacketDecoder.cs b/OpenMetaverse/PacketDecoder.cs new file mode 100644 index 00000000..4b65b770 --- /dev/null +++ b/OpenMetaverse/PacketDecoder.cs @@ -0,0 +1,1346 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace OpenMetaverse.Packets +{ + + public class PacketDecoder + { + /// + /// A custom decoder callback + /// + /// The key of the object + /// the data to decode + /// A string represending the fieldData + public delegate string CustomPacketDecoder(string fieldName, object fieldData); + + private static Dictionary> Callbacks = new Dictionary>(); + + public PacketDecoder() + { + AddCallback("Color", DecodeColorField); + AddCallback("TextColor", DecodeColorField); + AddCallback("Timestamp", DecodeTimeStamp); + AddCallback("EstateCovenantReply.Data.CovenantTimestamp", DecodeTimeStamp); + AddCallback("CreationDate", DecodeTimeStamp); + AddCallback("BinaryBucket", DecodeBinaryBucket); + AddCallback("ParcelData.Data", DecodeParcelData); + AddCallback("LayerData.Data", DecodeParcelData); + AddCallback("ImageData.Data", DecodeImageData); + AddCallback("ObjectData.TextureEntry", DecodeTextureEntry); + AddCallback("ImprovedInstantMessage.MessageBlock.Dialog", DecodeDialog); + + // Inventory/Permissions + AddCallback("BaseMask", DecodePermissionMask); + AddCallback("OwnerMask", DecodePermissionMask); + AddCallback("EveryoneMask", DecodePermissionMask); + AddCallback("NextOwnerMask", DecodePermissionMask); + AddCallback("GroupMask", DecodePermissionMask); + + AddCallback("WearableType", DecodeWearableType); + AddCallback("InventoryData.Type", DecodeInventoryType); + AddCallback("InventoryData.InvType", DecodeInventoryInvType); + AddCallback("InventoryData.Flags", DecodeInventoryFlags); + AddCallback("SaleType", DecodeObjectSaleType); + + AddCallback("Name", DecodeGenericByteArrayToFormattedString); + AddCallback("Description", DecodeGenericByteArrayToFormattedString); + + AddCallback("ScriptControlChange.Data.Controls", DecodeScriptControls); + + AddCallback("RegionFlags", DecodeRegionFlags); + AddCallback("SimAccess", DecodeSimAccess); + AddCallback("ControlFlags", DecodeControlFlags); + + // ViewerEffect TypeData + AddCallback("ViewerEffect.Effect.TypeData", DecodeViewerEffectTypeData); + AddCallback("ViewerEffect.Effect.Type", DecodeViewerEffectType); + + // Prim/ObjectUpdate decoders + AddCallback("ObjectUpdate.ObjectData.PCode", DecodeObjectPCode); + AddCallback("ObjectUpdate.ObjectData.Material", DecodeObjectMaterial); + AddCallback("ObjectUpdate.ObjectData.ClickAction", DecodeObjectClickAction); + AddCallback("ObjectData.UpdateFlags", DecodeObjectUpdateFlags); + + AddCallback("ObjectUpdate.ObjectData.ObjectData", DecodeObjectData); + AddCallback("TextureAnim", DecodeObjectTextureAnim); + AddCallback("ObjectUpdate.ObjectData.NameValue", DecodeNameValue); + AddCallback("ObjectUpdate.ObjectData.Data", DecodeObjectData); + + AddCallback("ObjectUpdate.ObjectData.Text", DecodeGenericByteArrayToFormattedString); + AddCallback("ObjectUpdate.ObjectData.MediaURL", DecodeGenericByteArrayToFormattedString); + AddCallback("ObjectUpdate.ObjectData.PSBlock", DecodeObjectParticleSystem); + AddCallback("ParticleSys", DecodeObjectParticleSystem); + AddCallback("ObjectUpdate.ObjectData.ExtraParams", DecodeObjectExtraParams); + + AddCallback("ImprovedTerseObjectUpdate.ObjectData.Data", DecodeTerseUpdate); + AddCallback("ImprovedTerseObjectUpdate.ObjectData.TextureEntry", DecodeTerseTextureEntry); + + AddCallback("ObjectUpdateCompressed.ObjectData.Data", DecodeObjectCompressedData); + + // ChatFromSimulator + AddCallback("ChatData.SourceType", DecodeChatSourceType); + AddCallback("ChatData.ChatType", DecodeChatChatType); + AddCallback("ChatData.Audible", DecodeChatAudible); + AddCallback("AttachedSound.DataBlock.Flags", DecodeAttachedSoundFlags); + + AddCallback("RequestImage.Type", DecodeImageType); + } + + /// + /// Add a custom decoder callback + /// + /// The key of the field to decode + /// The custom decode handler + public void AddCallback(string key, CustomPacketDecoder customPacketHandler) + { + if (Callbacks.ContainsKey(key)) + { + lock (Callbacks) + Callbacks[key].Add(customPacketHandler); + } + else + { + lock (Callbacks) + Callbacks.Add(key, new List() { customPacketHandler }); + } + } + + /// + /// Remove a custom decoder callback + /// + /// The key of the field to decode + /// The custom decode handler + public void RemoveCustomHandler(string key, CustomPacketDecoder customPacketHandler) + { + if (Callbacks.ContainsKey(key)) + lock (Callbacks) + { + if (Callbacks[key].Contains(customPacketHandler)) + Callbacks[key].Remove(customPacketHandler); + } + } + + #region Custom Decoders + + private static string DecodeTerseUpdate(string fieldName, object fieldData) + { + byte[] block = (byte[]) fieldData; + int i = 4; + + StringBuilder result = new StringBuilder(); + + // LocalID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "LocalID", + Utils.BytesToUInt(block, 0), + "Uint32"); + + + + // State + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "State", + block[i++], + "Byte"); + + // Avatar boolean + bool isAvatar = (block[i++] != 0); + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "IsAvatar", + isAvatar, + "Boolean"); + + // Collision normal for avatar + if (isAvatar) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "CollisionPlane", + new Vector4(block, i), + "Vector4"); + + i += 16; + } + + // Position + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Position", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Velocity + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Velocity", + new Vector3( + Utils.UInt16ToFloat(block, i, -128.0f, 128.0f), + Utils.UInt16ToFloat(block, i + 2, -128.0f, 128.0f), + Utils.UInt16ToFloat(block, i + 4, -128.0f, 128.0f)), + "Vector3"); + i += 6; + + // Acceleration + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Acceleration", + new Vector3( + Utils.UInt16ToFloat(block, i, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)), + "Vector3"); + + i += 6; + // Rotation (theta) + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Rotation", + new Quaternion( + Utils.UInt16ToFloat(block, i, -1.0f, 1.0f), + Utils.UInt16ToFloat(block, i + 2, -1.0f, 1.0f), + Utils.UInt16ToFloat(block, i + 4, -1.0f, 1.0f), + Utils.UInt16ToFloat(block, i + 6, -1.0f, 1.0f)), + "Quaternion"); + i += 8; + // Angular velocity (omega) + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "AngularVelocity", + new Vector3( + Utils.UInt16ToFloat(block, i, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f), + Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)), + "Vector3"); + //pos += 6; + // TODO: What is in these 6 bytes? + return result.ToString(); + } + + private static string DecodeObjectCompressedData(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + byte[] block = (byte[])fieldData; + int i = 0; + + // UUID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ID", + new UUID(block, 0), + "UUID"); + i += 16; + + // Local ID + uint LocalID = (uint)(block[i++] + (block[i++] << 8) + + (block[i++] << 16) + (block[i++] << 24)); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "LocalID", + LocalID, + "Uint32"); + // PCode + PCode pcode = (PCode)block[i++]; + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "PCode", + (int)pcode, + "(" + pcode + ")", + "PCode"); + + // State + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "State", + block[i++], + "Byte"); + + // TODO: CRC + + i += 4; + // Material + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "Material", + block[i], + "(" + (Material)block[i++] + ")", + "Material"); + + // Click action + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "ClickAction", + block[i], + "(" + (ClickAction)block[i++] + ")", + "ClickAction"); + + // Scale + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Scale", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Position + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Position", + new Vector3(block, i), + "Vector3"); + i += 12; + + // Rotation + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Rotation", + new Vector3(block, i), + "Vector3"); + + i += 12; + // Compressed flags + CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block, i); + result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, + "CompressedFlags", + Utils.BytesToUInt(block, i), + "(" + (CompressedFlags)Utils.BytesToUInt(block, i) + ")", + "UInt"); + i += 4; + + // Owners ID + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "OwnerID", + new UUID(block, i), + "UUID"); + i += 16; + + // Angular velocity + if ((flags & CompressedFlags.HasAngularVelocity) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "AngularVelocity", + new Vector3(block, i), + "Vector3"); + i += 12; + } + + // Parent ID + if ((flags & CompressedFlags.HasParent) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ParentID", + (uint)(block[i++] + (block[i++] << 8) + + (block[i++] << 16) + (block[i++] << 24)), + "UInt"); + } + + // Tree data + if ((flags & CompressedFlags.Tree) != 0) + { + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "TreeSpecies", + block[i++], + "(" + (Tree)block[i] + ")", + "Tree"); + } + + // Scratch pad + else if ((flags & CompressedFlags.ScratchPad) != 0) + { + int size = block[i++]; + byte[] scratch = new byte[size]; + Buffer.BlockCopy(block, i, scratch, 0, size); + result.AppendFormat("{0,30}: {1,-40} [ScratchPad[]]" + Environment.NewLine, + "ScratchPad", + Utils.BytesToHexString(scratch, String.Format("{0,30}", "Data"))); + i += size; + } + + // Floating text + if ((flags & CompressedFlags.HasText) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + // Floating text + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "Text", + text, + "string"); + + // Text color + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "TextColor", + new Color4(block, i, false), + "Color4"); + i += 4; + } + + // Media URL + if ((flags & CompressedFlags.MediaURL) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "MediaURL", + text, + "string"); + } + + // Particle system + if ((flags & CompressedFlags.HasParticles) != 0) + { + Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i); + result.AppendLine(DecodeObjectParticleSystem("ParticleSystem", p)); + i += 86; + } + + // Extra parameters TODO: + Primitive prim = new Primitive(); + i += prim.SetExtraParamsFromBytes(block, i); + + //Sound data + if ((flags & CompressedFlags.HasSound) != 0) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundID", + new UUID(block, i), + "UUID"); + i += 16; + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundGain", + Utils.BytesToFloat(block, i), + "Float"); + i += 4; + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "SoundFlags", + block[i++], + "(" + (SoundFlags)block[i] + ")", + "SoundFlags"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "SoundRadius", + Utils.BytesToFloat(block, i), + "Float"); + i += 4; + } + + // Name values + if ((flags & CompressedFlags.HasNameValues) != 0) + { + string text = String.Empty; + while (block[i] != 0) + { + text += (char)block[i]; + i++; + } + i++; + + // Parse the name values + if (text.Length > 0) + { + string[] lines = text.Split('\n'); + NameValue[] nameValues = new NameValue[lines.Length]; + + for (int j = 0; j < lines.Length; j++) + { + if (!String.IsNullOrEmpty(lines[j])) + { + NameValue nv = new NameValue(lines[j]); + nameValues[j] = nv; + } + } + DecodeNameValue("NameValues", nameValues); + } + } + + result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, + "PathCurve", + block[i], + "(" + (PathCurve)block[i++] + ")", + "PathCurve"); + + ushort pathBegin = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathBegin", + Primitive.UnpackBeginCut(pathBegin), + "float"); + + ushort pathEnd = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathEnd", + Primitive.UnpackEndCut(pathEnd), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathScaleX", + Primitive.UnpackPathScale(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathScaleY", + Primitive.UnpackPathScale(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathShearX", + Primitive.UnpackPathShear((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathShearY", + Primitive.UnpackPathShear((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTwist", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTwistBegin", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathRadiusOffset", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTaperX", + Primitive.UnpackPathTaper((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathTaperY", + Primitive.UnpackPathTaper((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathRevolutions", + Primitive.UnpackPathRevolutions(block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "PathSkew", + Primitive.UnpackPathTwist((sbyte)block[i++]), + "float"); + + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileCurve", + block[i++], + "float"); + + ushort profileBegin = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileBegin", + Primitive.UnpackBeginCut(profileBegin), + "float"); + + ushort profileEnd = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileEnd", + Primitive.UnpackEndCut(profileEnd), + "float"); + + ushort profileHollow = Utils.BytesToUInt16(block, i); + i += 2; + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + "ProfileHollow", + Primitive.UnpackProfileHollow(profileHollow), + "float"); + + int textureEntryLength = (int)Utils.BytesToUInt(block, i); + i += 4; + //prim.Textures = new Primitive.TextureEntry(block, i, textureEntryLength); + String s = DecodeTextureEntry("TextureEntry", new Primitive.TextureEntry(block, i, textureEntryLength)); + result.AppendLine(s); + i += textureEntryLength; + + // Texture animation + if ((flags & CompressedFlags.TextureAnimation) != 0) + { + i += 4; + string a = DecodeObjectTextureAnim("TextureAnimation", new Primitive.TextureAnimation(block, i)); + result.AppendLine(a); + } + + return result.ToString(); + } + + private static string DecodeObjectData(string fieldName, object fieldData) + { + byte[] data = (byte[])fieldData; + if (data.Length == 1) + { + return String.Format("{0,30}: {1,2} {2,-38} [{3}]", + fieldName + " (Tree Species)", + fieldData, + "(" + (Tree)(byte)fieldData + ")", + fieldData.GetType().Name); + } + else if (data.Length == 60) + { + /* TODO: these are likely useful packed fields, + * need to unpack them */ + return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); + } + else + { + return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); + } + } + + private static string DecodeObjectTextureAnim(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + Primitive.TextureAnimation TextureAnim; + if (fieldData is Primitive.TextureAnimation) + TextureAnim = (Primitive.TextureAnimation)fieldData; + else + TextureAnim = new Primitive.TextureAnimation((byte[])fieldData, 0); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericTypeDecoder(TextureAnim, ref result); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + + } + private static string DecodeGenericByteArrayToFormattedString(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, Utils.BytesToString((byte[])fieldData)); + } + + private static string DecodeNameValue(string fieldName, object fieldData) + { + string nameValue = Utils.BytesToString((byte[])fieldData); + NameValue[] nameValues = null; + if (nameValue.Length > 0) + { + string[] lines = nameValue.Split('\n'); + nameValues = new NameValue[lines.Length]; + + for (int i = 0; i < lines.Length; i++) + { + if (!String.IsNullOrEmpty(lines[i])) + { + NameValue nv = new NameValue(lines[i]); + nameValues[i] = nv; + } + } + } + + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (nameValues != null) + { + for (int i = 0; i < nameValues.Length; i++) + { + result.AppendFormat( + "{0,30}: Name={1} Value={2} Class={3} Type={4} Sendto={5}" + Environment.NewLine, "NameValue", + nameValues[i].Name, nameValues[i].Value, nameValues[i].Class, nameValues[i].Type, nameValues[i].Sendto); + } + } + result.AppendFormat("{0,30}", ""); + return result.ToString(); + } + + private static string DecodeObjectExtraParams(string fieldName, object fieldData) + { + + byte[] data = (byte[])fieldData; + + int i = 0; + //int totalLength = 1; + + Primitive.FlexibleData Flexible = null; + Primitive.LightData Light = null; + Primitive.SculptData Sculpt = null; + + byte extraParamCount = data[i++]; + + for (int k = 0; k < extraParamCount; k++) + { + ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i); + i += 2; + + uint paramLength = Utils.BytesToUInt(data, i); + i += 4; + + if (type == ExtraParamType.Flexible) + Flexible = new Primitive.FlexibleData(data, i); + else if (type == ExtraParamType.Light) + Light = new Primitive.LightData(data, i); + else if (type == ExtraParamType.Sculpt) + Sculpt = new Primitive.SculptData(data, i); + + i += (int)paramLength; + //totalLength += (int)paramLength + 6; + } + + StringBuilder result = new StringBuilder(); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + if (Flexible != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Flexible, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (Sculpt != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Sculpt, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + if (Light != null) + { + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(Light, ref result); + result.AppendFormat("{0,30}", "" + Environment.NewLine); + } + + result.AppendFormat("{0,30}", ""); + return result.ToString(); + } + + private static string DecodeObjectParticleSystem(string fieldName, object fieldData) + { + StringBuilder result = new StringBuilder(); + Primitive.ParticleSystem ParticleSys; + if (fieldData is Primitive.ParticleSystem) + ParticleSys = (Primitive.ParticleSystem)fieldData; + else + ParticleSys = new Primitive.ParticleSystem((byte[])fieldData, 0); + + result.AppendFormat("{0,30}", "" + Environment.NewLine); + GenericTypeDecoder(ParticleSys, ref result); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static void GenericTypeDecoder(object obj, ref StringBuilder result) + { + FieldInfo[] fields = obj.GetType().GetFields(); + + foreach (FieldInfo field in fields) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + field.Name, + field.GetValue(obj), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + System.Environment.NewLine, field.Name, + field.GetValue(obj), field.FieldType.Name); + } + } + } + + private static string DecodeObjectPCode(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,2} {2,-38} [{3}]", + fieldName, + fieldData, + "(" + (PCode)(byte)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeImageType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [{3}]", + fieldName, + fieldData, + "(" + (ImageType)(byte)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeImageCodec(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [{3}]", + fieldName, + fieldData, + "(" + (ImageCodec)(byte)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeObjectMaterial(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [{3}]", + fieldName, + fieldData, + "(" + (Material)(byte)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeObjectClickAction(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [{3}]", + fieldName, + fieldData, + "(" + (ClickAction)(byte)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeObjectUpdateFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + (PrimFlags)(uint)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeScriptControls(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [AgentManager.ControlFlags]", + fieldName, + (uint)fieldData, + "(" + (AgentManager.ControlFlags)(uint)fieldData + ")"); + } + + private static string DecodeColorField(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-40} [Color4]", + fieldName, + fieldData.GetType().Name.Equals("Color4") ? (Color4)fieldData : new Color4((byte[])fieldData, 0, false)); + } + + private static string DecodeTimeStamp(string fieldName, object fieldData) + { + if (fieldData is Int32 && (int)fieldData > 0) + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + Utils.UnixTimeToDateTime((int)fieldData) + ")", + fieldData.GetType().Name); + else if (fieldData is uint && (uint)fieldData > 0) + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + Utils.UnixTimeToDateTime((uint)fieldData) + ")", + fieldData.GetType().Name); + else + return String.Format("{0,30}: {1,-40} [{2}]", + fieldName, + fieldData, + fieldData.GetType().Name); + } + + private static string DecodeBinaryBucket(string fieldName, object fieldData) + { + byte[] bytes = (byte[])fieldData; + string bucket = String.Empty; + if (bytes.Length == 1) + { + bucket = String.Format("{0}", bytes[0]); + } + else if (bytes.Length == 17) + { + bucket = String.Format("{0} {1,-40} ({2}) [Byte[]]", + new UUID(bytes, 1), + bytes[0], + (AssetType)bytes[0]); + } + else + { + bucket = Utils.BytesToString(bytes); + } + return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, bucket); + } + + private static string DecodeParcelData(string fieldName, object fieldData) + { + return String.Format("{0,30}", + Utils.BytesToHexString((byte[])fieldData, + String.Format("{0,30}", fieldName))); + } + + private static string DecodeWearableType(string fieldName, object fieldData) + { + return String.Format("{0,30} {1,-2} {2,-38} [WearableType]", + fieldName, + (byte)fieldData, + "(" + (WearableType)fieldData + ")"); + } + + private static string DecodeInventoryType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [AssetType]", + fieldName, + (sbyte)fieldData, + "(" + (AssetType)(sbyte)fieldData + ")"); + } + + private static string DecodeInventoryInvType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [InventoryType]", + fieldName, + (sbyte)fieldData, + "(" + (InventoryType)fieldData + ")"); + } + + private static string DecodeInventoryFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [FixMe]", + fieldName, + fieldData, + "(" + fieldData + ")"); + } + + private static string DecodeObjectSaleType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [SaleType]", + fieldName, + (byte)fieldData, + "(" + (SaleType)fieldData + ")"); + } + + private static string DecodeRegionFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [RegionFlags]", + fieldName, + fieldData, + "(" + (RegionFlags)(uint)fieldData + ")", + fieldData.GetType().Name); + + } + + private static string DecodeSimAccess(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [SimAccess]", + fieldName, + (byte)fieldData, + "(" + (SimAccess)fieldData + ")"); + } + + private static string DecodeAttachedSoundFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [SoundFlags]", + fieldName, + (byte)fieldData, + "(" + (SoundFlags)fieldData + ")"); + } + + + private static string DecodeChatSourceType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [SourceType]", + fieldName, + fieldData, + "(" + (SourceType)(byte)fieldData + ")"); + } + + private static string DecodeChatChatType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [ChatType]", + fieldName, + (byte)fieldData, + "(" + (ChatType)fieldData + ")"); + } + + private static string DecodeChatAudible(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-38} [ChatAudibleLevel]", + fieldName, + (byte)fieldData, + "(" + (ChatAudibleLevel)(byte)fieldData + ")"); + } + + private static string DecodeImageData(string fieldName, object fieldData) + { + return String.Format("{0,10}", + Utils.BytesToHexString((byte[])fieldData, + String.Format("{0,30}", fieldName))); + } + + private string DecodeTerseTextureEntry(string fieldName, object fieldData) + { + byte[] block = (byte[]) fieldData; + + Primitive.TextureEntry te = new Primitive.TextureEntry(block, 4, block.Length - 4); + + StringBuilder result = new StringBuilder(); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (te.DefaultTexture != null) + { + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericFieldsDecoder(te.DefaultTexture, ref result); + GenericPropertiesDecoder(te.DefaultTexture, ref result); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + for (int i = 0; i < te.FaceTextures.Length; i++) + { + if (te.FaceTextures[i] != null) + { + result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); + GenericFieldsDecoder(te.FaceTextures[i], ref result); + GenericPropertiesDecoder(te.FaceTextures[i], ref result); + } + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static string DecodeTextureEntry(string fieldName, object fieldData) + { + Primitive.TextureEntry te; + if (fieldData is Primitive.TextureEntry) + te = (Primitive.TextureEntry)fieldData; + else + { + byte[] tebytes = (byte[])fieldData; + te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length); + } + + StringBuilder result = new StringBuilder(); + + result.AppendFormat("{0,30}", " " + Environment.NewLine); + if (te.DefaultTexture != null) + { + result.AppendFormat("{0,30}", " " + Environment.NewLine); + GenericFieldsDecoder(te.DefaultTexture, ref result); + GenericPropertiesDecoder(te.DefaultTexture, ref result); + result.AppendFormat("{0,30}", " " + Environment.NewLine); + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + for (int i = 0; i < te.FaceTextures.Length; i++) + { + if (te.FaceTextures[i] != null) + { + result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); + GenericFieldsDecoder(te.FaceTextures[i], ref result); + GenericPropertiesDecoder(te.FaceTextures[i], ref result); + } + } + result.AppendFormat("{0,30}", " " + Environment.NewLine); + result.AppendFormat("{0,30}", ""); + + return result.ToString(); + } + + private static void GenericFieldsDecoder(object obj, ref StringBuilder result) + { + Type parcelType = obj.GetType(); + FieldInfo[] fields = parcelType.GetFields(); + foreach (FieldInfo field in fields) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + field.Name, + field.GetValue(obj), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + field.Name, + field.GetValue(obj), + field.FieldType.Name); + } + } + } + + private static void GenericPropertiesDecoder(object obj, ref StringBuilder result) + { + Type parcelType = obj.GetType(); + PropertyInfo[] propertyInfos = parcelType.GetProperties(); + foreach (PropertyInfo property in propertyInfos) + { + String special; + if (SpecialDecoder("a" + "." + "b" + "." + property.Name, + property.GetValue(obj, null), out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + property.Name, + property.GetValue(obj, null), + property.PropertyType.Name); + } + } + } + + private static string DecodeDialog(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", + fieldName, + (byte)fieldData, + "(" + (InstantMessageDialog)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodeControlFlags(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + fieldData, + "(" + (AgentManager.ControlFlags)(uint)fieldData + ")", + fieldData.GetType().Name); + } + + private static string DecodePermissionMask(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", + fieldName, + (uint)fieldData, + "(" + (PermissionMask)fieldData + ")", + fieldData.GetType().Name); + } + + public static string DecodeViewerEffectTypeData(string fieldName, object fieldData) + { + byte[] data = (byte[])fieldData; + StringBuilder sb = new StringBuilder(); + if (data.Length == 56 || data.Length == 57) + { + UUID sourceAvatar = new UUID(data, 0); + UUID targetObject = new UUID(data, 16); + Vector3d targetPos = new Vector3d(data, 32); + sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Source AvatarID=" + sourceAvatar); + sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Target ObjectID=" + targetObject); + + + float lx, ly; + Helpers.GlobalPosToRegionHandle((float)targetPos.X, (float)targetPos.Y, out lx, out ly); + + sb.AppendFormat("{0,30}: {1,-40} [Vector3d]", fieldName, targetPos); + + if (data.Length == 57) + { + sb.AppendLine(); + sb.AppendFormat("{0,30}: {1,-17} {2,-22} [Byte]", fieldName, "Point At Type=" + data[56], + "(" + (PointAtType)data[56] + ")"); + } + + return sb.ToString(); + } + else + { + return String.Format("{0,30}: (No Decoder) Length={1}" + System.Environment.NewLine, fieldName, data.Length) + Utils.BytesToHexString(data, String.Format("{0,30}", "")); + } + } + + public static string DecodeViewerEffectType(string fieldName, object fieldData) + { + return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", + fieldName, + fieldData, + "(" + (EffectType)(byte)fieldData + ")", + fieldData.GetType().Name); + } + #endregion + + /// + /// Creates a formatted string containing the values of a Packet + /// + /// The Packet + /// A formatted string of values of the nested items in the Packet object + /// should be made generic enough to decode IMessage objects too. + public string PacketToString(Packet packet) + { + StringBuilder result = new StringBuilder(); + + result.AppendFormat("Packet Type: {0}" + System.Environment.NewLine, packet.Type); + result.AppendLine("[Packet Header]"); + // payload + result.AppendFormat("Sequence: {0}" + System.Environment.NewLine, packet.Header.Sequence); + result.AppendFormat(" Options: {0}" + System.Environment.NewLine, InterpretOptions(packet.Header)); + result.AppendLine(); + + result.AppendLine("[Packet Payload]"); + + FieldInfo[] fields = packet.GetType().GetFields(); + + for (int i = 0; i < fields.Length; i++) + { + if (fields[i].Name == "Type" || fields[i].Name == "Header") + continue; + + if (fields[i].FieldType.IsArray) + { + result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --"); + RecursePacketArray(fields[i], packet, ref result); + } + else + { + result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --"); + RecursePacketField(fields[i], packet, ref result); + } + } + return result.ToString(); + } + + private static string InterpretOptions(Header header) + { + return "[" + + (header.AppendedAcks ? "Ack" : " ") + + " " + + (header.Resent ? "Res" : " ") + + " " + + (header.Reliable ? "Rel" : " ") + + " " + + (header.Zerocoded ? "Zer" : " ") + + "]" + ; + } + + private static void RecursePacketArray(FieldInfo fieldInfo, object packet, ref StringBuilder result) + { + var packetDataObject = fieldInfo.GetValue(packet); + + foreach (object nestedArrayRecord in packetDataObject as Array) + { + FieldInfo[] fields = nestedArrayRecord.GetType().GetFields(); + + for (int i = 0; i < fields.Length; i++) + { + String special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + fields[i].Name, + fields[i].GetValue(nestedArrayRecord), out special)) + { + result.AppendLine(special); + } + else if (fields[i].FieldType.IsArray) // default for an array (probably a byte[]) + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + System.Environment.NewLine, + fields[i].Name, + fields[i].GetValue(nestedArrayRecord), + fields[i].GetValue(nestedArrayRecord).GetType().Name); + } + else // default for a field + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + System.Environment.NewLine, + fields[i].Name, + fields[i].GetValue(nestedArrayRecord), + fields[i].GetValue(nestedArrayRecord).GetType().Name); + } + } + + // Handle Properties + foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties()) + { + if (propertyInfo.Name.Equals("Length")) + continue; + + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, + propertyInfo.GetValue(nestedArrayRecord, null), + out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]c" + Environment.NewLine, + propertyInfo.Name, + /*Utils.BytesToString((byte[])*/propertyInfo.GetValue(nestedArrayRecord, null)/*)*/, + propertyInfo.PropertyType.Name); + } + } + result.AppendFormat("{0,32}" + Environment.NewLine, "***"); + } + } + + private static void RecursePacketField(FieldInfo fieldInfo, object packet, ref StringBuilder result) + { + object packetDataObject = fieldInfo.GetValue(packet); + + // handle Fields + foreach (FieldInfo packetValueField in fieldInfo.GetValue(packet).GetType().GetFields()) + { + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + packetValueField.Name, + packetValueField.GetValue(packetDataObject), + out special)) + { + result.AppendLine(special); + } + else + { + result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, + packetValueField.Name, packetValueField.GetValue(packetDataObject), packetValueField.FieldType.Name); + } + } + + // Handle Properties + foreach (PropertyInfo propertyInfo in packetDataObject.GetType().GetProperties()) + { + if (propertyInfo.Name.Equals("Length")) + continue; + + string special; + if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, + propertyInfo.GetValue(packetDataObject, null), + out special)) + { + result.AppendLine(special); + } + else if (propertyInfo.GetValue(packetDataObject, null).GetType() == typeof(byte[])) + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + propertyInfo.Name, + Utils.BytesToString((byte[])propertyInfo.GetValue(packetDataObject, null)), + propertyInfo.PropertyType.Name); + } + else + { + result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, + propertyInfo.Name, + propertyInfo.GetValue(packetDataObject, null), + propertyInfo.PropertyType.Name); + } + } + } + + private static bool SpecialDecoder(string decoderKey, object fieldData, out string result) + { + result = string.Empty; + string[] keys = decoderKey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + string[] keyList = { decoderKey, decoderKey.Replace("Packet", ""), keys[1] + "." + keys[2], keys[2] }; + foreach (string key in keyList) + { + + bool ok = true; + if (fieldData is byte[]) + { + byte[] fd = (byte[])fieldData; + ok = fd.Length > 0; + if (!ok) + { + // bypass the decoder since we were passed an empty byte array + result = String.Format("{0,30}:", keys[2]); + return true; + } + } + + if (ok && Callbacks.ContainsKey(key)) // fieldname e.g: Plane + { + foreach (CustomPacketDecoder decoder in Callbacks[key]) + result = decoder(keys[2], fieldData); + return true; + } + } + return false; + } + } +} diff --git a/OpenMetaverse/Primitives/Primitive.cs b/OpenMetaverse/Primitives/Primitive.cs index bd804341..baffd795 100644 --- a/OpenMetaverse/Primitives/Primitive.cs +++ b/OpenMetaverse/Primitives/Primitive.cs @@ -267,7 +267,11 @@ namespace OpenMetaverse /// Plane = 3, /// - Cylinder = 4 + Cylinder = 4, + /// + Invert = 64, + /// + Mirror = 128 } /// @@ -888,7 +892,7 @@ namespace OpenMetaverse /// public bool Invert { - get { return ((type & 64) != 0); } + get { return ((type & (byte)SculptType.Invert) != 0); } } /// @@ -896,7 +900,7 @@ namespace OpenMetaverse /// public bool Mirror { - get { return ((type & 128) != 0); } + get { return ((type & (byte)SculptType.Mirror) != 0); } } /// diff --git a/OpenMetaverse/SoundManager.cs b/OpenMetaverse/SoundManager.cs index 33d51a34..449ed0a7 100644 --- a/OpenMetaverse/SoundManager.cs +++ b/OpenMetaverse/SoundManager.cs @@ -30,11 +30,12 @@ using OpenMetaverse.Packets; namespace OpenMetaverse { + public class SoundManager { public readonly GridClient Client; - public delegate void AttachSoundCallback(UUID soundID, UUID ownerID, UUID objectID, float gain, byte flags); + public delegate void AttachSoundCallback(UUID soundID, UUID ownerID, UUID objectID, float gain, SoundFlags flags); public delegate void AttachedSoundGainChangeCallback(UUID objectID, float gain); public delegate void SoundTriggerCallback(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, float gain, ulong regionHandle, Vector3 position); public delegate void PreloadSoundCallback(UUID soundID, UUID ownerID, UUID objectID); @@ -125,7 +126,7 @@ namespace OpenMetaverse AttachedSoundPacket sound = (AttachedSoundPacket)packet; if (OnAttachSound != null) { - try { OnAttachSound(sound.DataBlock.SoundID, sound.DataBlock.OwnerID, sound.DataBlock.ObjectID, sound.DataBlock.Gain, sound.DataBlock.Flags); } + try { OnAttachSound(sound.DataBlock.SoundID, sound.DataBlock.OwnerID, sound.DataBlock.ObjectID, sound.DataBlock.Gain, (SoundFlags)sound.DataBlock.Flags); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } } diff --git a/Programs/GridProxy/GridProxy.cs b/Programs/GridProxy/GridProxy.cs index 21f2d017..6229d0cc 100644 --- a/Programs/GridProxy/GridProxy.cs +++ b/Programs/GridProxy/GridProxy.cs @@ -31,7 +31,7 @@ */ // #define DEBUG_SEQUENCE -//#define DEBUG_CAPS +// #define DEBUG_CAPS // #define DEBUG_THREADS using System; @@ -48,6 +48,8 @@ using OpenMetaverse; using OpenMetaverse.Http; using OpenMetaverse.StructuredData; using OpenMetaverse.Packets; +using log4net; +using Logger=Nwc.XmlRpc.Logger; namespace GridProxy { @@ -216,7 +218,7 @@ namespace GridProxy displayAddress = endPoint.Address; loginURI = "http://" + displayAddress + ":" + endPoint.Port + "/"; - Log("proxy ready at " + loginURI, false); + OpenMetaverse.Logger.Log("Proxy ready at " + loginURI, Helpers.LogLevel.Info); } } @@ -232,9 +234,9 @@ namespace GridProxy // KeepAlive: blocks until the proxy is free to shut down public void KeepAlive() { -#if DEBUG_THREADS - Console.WriteLine(">T> KeepAlive"); -#endif + + OpenMetaverse.Logger.Log(">T> KeepAlive", Helpers.LogLevel.Debug); + lock (keepAliveLock) { }; if (loginServer.Connected) @@ -245,13 +247,7 @@ namespace GridProxy loginServer.Close(); - - - -#if DEBUG_THREADS - Console.WriteLine("T> RunLoginProxy"); -#endif + OpenMetaverse.Logger.Log(">T> RunLoginProxy", Helpers.LogLevel.Debug); + try { for (; ; ) @@ -395,21 +383,18 @@ namespace GridProxy { Thread connThread = new Thread((ThreadStart)delegate { -#if DEBUG_THREADS - Console.WriteLine(">T> ProxyHTTP"); -#endif + OpenMetaverse.Logger.Log(">T> ProxyHTTP", Helpers.LogLevel.Debug); ProxyHTTP(client); -#if DEBUG_THREADS - Console.WriteLine(" " + packet.Type + " #" + packet.Header.Sequence); -#endif + OpenMetaverse.Logger.Log("-> " + packet.Type + " #" + packet.Header.Sequence, Helpers.LogLevel.Debug); // check for ACKs we're waiting for packet = CheckAcks(packet, Direction.Outgoing, ref length, ref needsCopy); @@ -1705,8 +1662,7 @@ namespace GridProxy } catch (Exception e) { - proxy.Log("exception in outgoing delegate: " + e.Message, true); - proxy.Log(e.StackTrace, true); + OpenMetaverse.Logger.Log("exception in outgoing delegate", Helpers.LogLevel.Error, e); } if (packet != null) @@ -1727,7 +1683,7 @@ namespace GridProxy } catch (Exception e) { - Console.WriteLine(e.ToString()); + OpenMetaverse.Logger.Log("Proxy error sending packet", Helpers.LogLevel.Error, e); } finally { @@ -1737,9 +1693,9 @@ namespace GridProxy socket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref clientEndPoint, new AsyncCallback(ReceiveFromClient), null); } - catch (Exception e) + catch (SocketException e) { - Console.WriteLine(e.Message); + OpenMetaverse.Logger.Log("Socket Shutdown: " + e.SocketErrorCode, Helpers.LogLevel.Warning); } } } @@ -2059,8 +2015,7 @@ namespace GridProxy // LogPacket: log a packet dump private Packet LogPacket(Packet packet, string type) { - Log(type + " packet:", true); - Log(packet, true); + OpenMetaverse.Logger.Log(type + " packet:\n" + packet, Helpers.LogLevel.Info); return packet; } diff --git a/Programs/GridProxy/GridProxyLoader.cs b/Programs/GridProxy/GridProxyLoader.cs index d3416484..1e7da2fd 100644 --- a/Programs/GridProxy/GridProxyLoader.cs +++ b/Programs/GridProxy/GridProxyLoader.cs @@ -10,6 +10,7 @@ using Nwc.XmlRpc; using OpenMetaverse; using OpenMetaverse.Packets; using GridProxy; +using Logger=OpenMetaverse.Logger; namespace GridProxy @@ -90,7 +91,9 @@ namespace GridProxy { string sw = arg.Substring(0, ipos); string val = arg.Substring(ipos + 1); - Console.WriteLine("arg '" + sw + "' val '" + val + "'"); + + Logger.Log("arg '" + sw + "' val '" + val + "'", Helpers.LogLevel.Debug); + if (sw == "--load") { //externalPlugin = true; @@ -114,7 +117,7 @@ namespace GridProxy } catch (Exception e) { - Console.WriteLine(e.ToString()); + Logger.Log("LoadPlugin exception", Helpers.LogLevel.Error, e); } } } @@ -136,7 +139,7 @@ namespace GridProxy } catch (Exception e) { - Console.WriteLine(e.ToString()); + Logger.Log("LoadPlugin exception", Helpers.LogLevel.Error, e); } } @@ -196,7 +199,10 @@ namespace GridProxy return packet; } - // SayToUser: send a message to the user as in-world chat + /// + /// Send a message to the viewer + /// + /// A string containing the message to send public void SayToUser(string message) { ChatFromSimulatorPacket packet = new ChatFromSimulatorPacket(); @@ -210,10 +216,8 @@ namespace GridProxy packet.ChatData.Message = Utils.StringToBytes(message); proxy.InjectPacket(packet, Direction.Incoming); } - } - public abstract class ProxyPlugin : MarshalByRefObject { // public abstract ProxyPlugin(ProxyFrame main); diff --git a/Programs/GridProxy/Plugins/Analyst.cs b/Programs/GridProxy/Plugins/Analyst.cs index 7997a8bd..393d9767 100644 --- a/Programs/GridProxy/Plugins/Analyst.cs +++ b/Programs/GridProxy/Plugins/Analyst.cs @@ -52,6 +52,8 @@ public class Analyst : ProxyPlugin private Dictionary> modifiedPackets = new Dictionary>(); private Assembly openmvAssembly; private StreamWriter output; + + private PacketDecoder DecodePacket = new PacketDecoder(); public Analyst(ProxyFrame frame) { @@ -827,7 +829,7 @@ public class Analyst : ProxyPlugin // LogPacket: dump a packet to the console private void LogPacket(Packet packet, IPEndPoint endPoint, Direction direction) { - string packetText = Helpers.PacketToString(packet); + string packetText = DecodePacket.PacketToString(packet); if (logGrep == null || (logGrep != null && Regex.IsMatch(packetText, logGrep))) { diff --git a/Programs/WinGridProxy/FireEventAppender.cs b/Programs/WinGridProxy/FireEventAppender.cs new file mode 100644 index 00000000..79a522ab --- /dev/null +++ b/Programs/WinGridProxy/FireEventAppender.cs @@ -0,0 +1,82 @@ +#region Copyright & License +// +// Copyright 2001-2004 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +using System; +using log4net.Core; + +namespace WinGridProxy +{ + public delegate void MessageLoggedEventHandler(object sender, MessageLoggedEventArgs e); + + public class MessageLoggedEventArgs : EventArgs + { + private LoggingEvent m_loggingEvent; + + public MessageLoggedEventArgs(LoggingEvent loggingEvent) + { + m_loggingEvent = loggingEvent; + } + public LoggingEvent LoggingEvent + { + get { return m_loggingEvent; } + } + } + + public class FireEventAppender : log4net.Appender.AppenderSkeleton + { + private static FireEventAppender m_instance; + + private FixFlags m_fixFlags = FixFlags.All; + + // Event handler + public event MessageLoggedEventHandler MessageLoggedEvent; + + // Easy singleton, gets the last instance created + public static FireEventAppender Instance + { + get { return m_instance; } + } + + public FireEventAppender() + { + // Store the instance created + m_instance = this; + } + + virtual public FixFlags Fix + { + get { return m_fixFlags; } + set { m_fixFlags = value; } + } + + override protected void Append(LoggingEvent loggingEvent) + { + // Because we the LoggingEvent may be used beyond the lifetime + // of the Append() method we must fix any volatile data in the event + loggingEvent.Fix = this.Fix; + + // Raise the event + MessageLoggedEventHandler handler = MessageLoggedEvent; + if (handler != null) + { + handler(this, new MessageLoggedEventArgs(loggingEvent)); + } + } + + } +} diff --git a/Programs/WinGridProxy/FormWinGridProxy.Designer.cs b/Programs/WinGridProxy/FormWinGridProxy.Designer.cs index 874e4e93..3dbb5293 100644 --- a/Programs/WinGridProxy/FormWinGridProxy.Designer.cs +++ b/Programs/WinGridProxy/FormWinGridProxy.Designer.cs @@ -40,6 +40,13 @@ this.label1 = new System.Windows.Forms.Label(); this.panelMainWindow = new System.Windows.Forms.Panel(); this.splitContainerSessionsTabs = new System.Windows.Forms.SplitContainer(); + this.listViewSessions = new WinGridProxy.ListViewNoFlicker(); + this.columnHeaderCounter = new System.Windows.Forms.ColumnHeader(); + this.columnHeaderProtocol = new System.Windows.Forms.ColumnHeader(); + this.columnHeaderType = new System.Windows.Forms.ColumnHeader(); + this.columnHeaderSize = new System.Windows.Forms.ColumnHeader(); + this.columnHeaderUrl = new System.Windows.Forms.ColumnHeader(); + this.columnHeaderContentType = new System.Windows.Forms.ColumnHeader(); this.contextMenuStripSessions = new System.Windows.Forms.ContextMenuStrip(this.components); this.toolStripMenuItemAutoScroll = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator(); @@ -73,6 +80,7 @@ this.imageList1 = new System.Windows.Forms.ImageList(this.components); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPageSummary = new System.Windows.Forms.TabPage(); + this.richTextBoxDebugLog = new System.Windows.Forms.RichTextBox(); this.panelStats = new System.Windows.Forms.Panel(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.labelPacketsTotal = new System.Windows.Forms.Label(); @@ -92,8 +100,14 @@ this.splitContainerFilters = new System.Windows.Forms.SplitContainer(); this.checkBoxCheckAllPackets = new System.Windows.Forms.CheckBox(); this.grpUDPFilters = new System.Windows.Forms.GroupBox(); + this.listViewPacketFilters = new WinGridProxy.ListViewNoFlicker(); + this.columnHeaderPacketName = new System.Windows.Forms.ColumnHeader(); + this.columnHeaderPacketType = new System.Windows.Forms.ColumnHeader(); this.checkBoxCheckAllMessages = new System.Windows.Forms.CheckBox(); this.grpCapsFilters = new System.Windows.Forms.GroupBox(); + this.listViewMessageFilters = new WinGridProxy.ListViewNoFlicker(); + this.columnHeaderName = new System.Windows.Forms.ColumnHeader(); + this.columnHeaderMessageType = new System.Windows.Forms.ColumnHeader(); this.tabPageInspect = new System.Windows.Forms.TabPage(); this.splitContainerInspectorTab = new System.Windows.Forms.SplitContainer(); this.tabControlInspectorRequest = new System.Windows.Forms.TabControl(); @@ -212,19 +226,6 @@ this.toolStripSeparator11 = new System.Windows.Forms.ToolStripSeparator(); this.autoColorizeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.colorDialog1 = new System.Windows.Forms.ColorDialog(); - this.listViewSessions = new WinGridProxy.ListViewNoFlicker(); - this.columnHeaderCounter = new System.Windows.Forms.ColumnHeader(); - this.columnHeaderProtocol = new System.Windows.Forms.ColumnHeader(); - this.columnHeaderType = new System.Windows.Forms.ColumnHeader(); - this.columnHeaderSize = new System.Windows.Forms.ColumnHeader(); - this.columnHeaderUrl = new System.Windows.Forms.ColumnHeader(); - this.columnHeaderContentType = new System.Windows.Forms.ColumnHeader(); - this.listViewPacketFilters = new WinGridProxy.ListViewNoFlicker(); - this.columnHeaderPacketName = new System.Windows.Forms.ColumnHeader(); - this.columnHeaderPacketType = new System.Windows.Forms.ColumnHeader(); - this.listViewMessageFilters = new WinGridProxy.ListViewNoFlicker(); - this.columnHeaderName = new System.Windows.Forms.ColumnHeader(); - this.columnHeaderMessageType = new System.Windows.Forms.ColumnHeader(); this.panelProxyConfig.SuspendLayout(); this.panelMainWindow.SuspendLayout(); this.splitContainerSessionsTabs.Panel1.SuspendLayout(); @@ -382,6 +383,59 @@ this.splitContainerSessionsTabs.SplitterWidth = 5; this.splitContainerSessionsTabs.TabIndex = 0; // + // listViewSessions + // + this.listViewSessions.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeaderCounter, + this.columnHeaderProtocol, + this.columnHeaderType, + this.columnHeaderSize, + this.columnHeaderUrl, + this.columnHeaderContentType}); + this.listViewSessions.ContextMenuStrip = this.contextMenuStripSessions; + this.listViewSessions.Dock = System.Windows.Forms.DockStyle.Fill; + this.listViewSessions.FullRowSelect = true; + this.listViewSessions.GridLines = true; + this.listViewSessions.HideSelection = false; + this.listViewSessions.Location = new System.Drawing.Point(0, 0); + this.listViewSessions.Name = "listViewSessions"; + this.listViewSessions.Size = new System.Drawing.Size(469, 428); + this.listViewSessions.SmallImageList = this.imageList1; + this.listViewSessions.TabIndex = 0; + this.listViewSessions.UseCompatibleStateImageBehavior = false; + this.listViewSessions.View = System.Windows.Forms.View.Details; + this.listViewSessions.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.listViewSessions_ItemSelectionChanged); + // + // columnHeaderCounter + // + this.columnHeaderCounter.Text = "#"; + this.columnHeaderCounter.Width = 54; + // + // columnHeaderProtocol + // + this.columnHeaderProtocol.Text = "Protocol"; + this.columnHeaderProtocol.Width = 59; + // + // columnHeaderType + // + this.columnHeaderType.Text = "Packet Type"; + this.columnHeaderType.Width = 151; + // + // columnHeaderSize + // + this.columnHeaderSize.Text = "Bytes"; + this.columnHeaderSize.Width = 64; + // + // columnHeaderUrl + // + this.columnHeaderUrl.Text = "Host/Address"; + this.columnHeaderUrl.Width = 312; + // + // columnHeaderContentType + // + this.columnHeaderContentType.Text = "Content Type"; + this.columnHeaderContentType.Width = 250; + // // contextMenuStripSessions // this.contextMenuStripSessions.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -596,7 +650,7 @@ // this.markToolStripMenuItem1.DropDown = this.contextMenuStripMark; this.markToolStripMenuItem1.Name = "markToolStripMenuItem1"; - this.markToolStripMenuItem1.Size = new System.Drawing.Size(152, 22); + this.markToolStripMenuItem1.Size = new System.Drawing.Size(143, 22); this.markToolStripMenuItem1.Text = "Mark"; // // toolStripSeparator16 @@ -635,6 +689,7 @@ // // tabPageSummary // + this.tabPageSummary.Controls.Add(this.richTextBoxDebugLog); this.tabPageSummary.Controls.Add(this.panelStats); this.tabPageSummary.Location = new System.Drawing.Point(4, 28); this.tabPageSummary.Name = "tabPageSummary"; @@ -644,6 +699,22 @@ this.tabPageSummary.Text = "Summary"; this.tabPageSummary.UseVisualStyleBackColor = true; // + // richTextBoxDebugLog + // + this.richTextBoxDebugLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.richTextBoxDebugLog.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.richTextBoxDebugLog.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.richTextBoxDebugLog.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.richTextBoxDebugLog.Location = new System.Drawing.Point(6, 101); + this.richTextBoxDebugLog.Name = "richTextBoxDebugLog"; + this.richTextBoxDebugLog.ReadOnly = true; + this.richTextBoxDebugLog.ShowSelectionMargin = true; + this.richTextBoxDebugLog.Size = new System.Drawing.Size(592, 289); + this.richTextBoxDebugLog.TabIndex = 3; + this.richTextBoxDebugLog.Text = ""; + // // panelStats // this.panelStats.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -854,6 +925,35 @@ this.grpUDPFilters.TabStop = false; this.grpUDPFilters.Text = "UDP Packets"; // + // listViewPacketFilters + // + this.listViewPacketFilters.CheckBoxes = true; + this.listViewPacketFilters.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeaderPacketName, + this.columnHeaderPacketType}); + this.listViewPacketFilters.Dock = System.Windows.Forms.DockStyle.Fill; + this.listViewPacketFilters.FullRowSelect = true; + this.listViewPacketFilters.GridLines = true; + this.listViewPacketFilters.Location = new System.Drawing.Point(3, 16); + this.listViewPacketFilters.MultiSelect = false; + this.listViewPacketFilters.Name = "listViewPacketFilters"; + this.listViewPacketFilters.Size = new System.Drawing.Size(286, 338); + this.listViewPacketFilters.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listViewPacketFilters.TabIndex = 0; + this.listViewPacketFilters.UseCompatibleStateImageBehavior = false; + this.listViewPacketFilters.View = System.Windows.Forms.View.Details; + this.listViewPacketFilters.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listViewPacketFilters_ItemChecked); + this.listViewPacketFilters.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listViewFilterSorter_ColumnClick); + // + // columnHeaderPacketName + // + this.columnHeaderPacketName.Text = "Packet Name"; + this.columnHeaderPacketName.Width = 215; + // + // columnHeaderPacketType + // + this.columnHeaderPacketType.Text = "Type"; + // // checkBoxCheckAllMessages // this.checkBoxCheckAllMessages.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -882,6 +982,36 @@ this.grpCapsFilters.TabStop = false; this.grpCapsFilters.Text = "Capabilities Messages"; // + // listViewMessageFilters + // + this.listViewMessageFilters.CheckBoxes = true; + this.listViewMessageFilters.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeaderName, + this.columnHeaderMessageType}); + this.listViewMessageFilters.Dock = System.Windows.Forms.DockStyle.Fill; + this.listViewMessageFilters.FullRowSelect = true; + this.listViewMessageFilters.GridLines = true; + this.listViewMessageFilters.Location = new System.Drawing.Point(3, 16); + this.listViewMessageFilters.MultiSelect = false; + this.listViewMessageFilters.Name = "listViewMessageFilters"; + this.listViewMessageFilters.Size = new System.Drawing.Size(284, 338); + this.listViewMessageFilters.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listViewMessageFilters.TabIndex = 1; + this.listViewMessageFilters.UseCompatibleStateImageBehavior = false; + this.listViewMessageFilters.View = System.Windows.Forms.View.Details; + this.listViewMessageFilters.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listViewMessageFilters_ItemChecked); + this.listViewMessageFilters.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listViewFilterSorter_ColumnClick); + // + // columnHeaderName + // + this.columnHeaderName.Text = "Message Name"; + this.columnHeaderName.Width = 181; + // + // columnHeaderMessageType + // + this.columnHeaderMessageType.Text = "Type"; + this.columnHeaderMessageType.Width = 92; + // // tabPageInspect // this.tabPageInspect.Controls.Add(this.splitContainerInspectorTab); @@ -952,6 +1082,7 @@ this.richTextBoxDecodedRequest.Size = new System.Drawing.Size(591, 143); this.richTextBoxDecodedRequest.TabIndex = 0; this.richTextBoxDecodedRequest.Text = ""; + this.richTextBoxDecodedRequest.TextChanged += new System.EventHandler(this.richTextBoxDecodedRequest_TextChanged); // // tabPageRawRequest // @@ -1104,6 +1235,7 @@ this.richTextBoxDecodedResponse.Size = new System.Drawing.Size(591, 176); this.richTextBoxDecodedResponse.TabIndex = 0; this.richTextBoxDecodedResponse.Text = ""; + this.richTextBoxDecodedResponse.TextChanged += new System.EventHandler(this.richTextBoxDecodedRequest_TextChanged); // // tabPageInspectorRAWResponse // @@ -1295,14 +1427,14 @@ // this.removeToolStripMenuItem2.DropDown = this.contextMenuStripRemove; this.removeToolStripMenuItem2.Name = "removeToolStripMenuItem2"; - this.removeToolStripMenuItem2.Size = new System.Drawing.Size(152, 22); + this.removeToolStripMenuItem2.Size = new System.Drawing.Size(143, 22); this.removeToolStripMenuItem2.Text = "Remove"; // // selectToolStripMenuItem1 // this.selectToolStripMenuItem1.DropDown = this.contextMenuStripSelect; this.selectToolStripMenuItem1.Name = "selectToolStripMenuItem1"; - this.selectToolStripMenuItem1.Size = new System.Drawing.Size(152, 22); + this.selectToolStripMenuItem1.Size = new System.Drawing.Size(143, 22); this.selectToolStripMenuItem1.Text = "Select"; // // toolStripLabelHexEditorRequest @@ -1477,7 +1609,7 @@ // this.copyToolStripMenuItem1.DropDown = this.contextMenuStripCopy; this.copyToolStripMenuItem1.Name = "copyToolStripMenuItem1"; - this.copyToolStripMenuItem1.Size = new System.Drawing.Size(152, 22); + this.copyToolStripMenuItem1.Size = new System.Drawing.Size(143, 22); this.copyToolStripMenuItem1.Text = "Copy"; this.copyToolStripMenuItem1.Visible = false; // @@ -1519,18 +1651,18 @@ // toolStripSeparator10 // this.toolStripSeparator10.Name = "toolStripSeparator10"; - this.toolStripSeparator10.Size = new System.Drawing.Size(149, 6); + this.toolStripSeparator10.Size = new System.Drawing.Size(140, 6); // // toolStripSeparator12 // this.toolStripSeparator12.Name = "toolStripSeparator12"; - this.toolStripSeparator12.Size = new System.Drawing.Size(149, 6); + this.toolStripSeparator12.Size = new System.Drawing.Size(140, 6); // // findToolStripMenuItem // this.findToolStripMenuItem.Name = "findToolStripMenuItem"; this.findToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); - this.findToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.findToolStripMenuItem.Size = new System.Drawing.Size(143, 22); this.findToolStripMenuItem.Text = "Find"; this.findToolStripMenuItem.Click += new System.EventHandler(this.findSessions_Click); // @@ -1938,118 +2070,6 @@ this.autoColorizeToolStripMenuItem.Text = "Auto Colorize"; this.autoColorizeToolStripMenuItem.Click += new System.EventHandler(this.autoColorizeToolStripMenuItem_Click); // - // listViewSessions - // - this.listViewSessions.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeaderCounter, - this.columnHeaderProtocol, - this.columnHeaderType, - this.columnHeaderSize, - this.columnHeaderUrl, - this.columnHeaderContentType}); - this.listViewSessions.ContextMenuStrip = this.contextMenuStripSessions; - this.listViewSessions.Dock = System.Windows.Forms.DockStyle.Fill; - this.listViewSessions.FullRowSelect = true; - this.listViewSessions.GridLines = true; - this.listViewSessions.HideSelection = false; - this.listViewSessions.Location = new System.Drawing.Point(0, 0); - this.listViewSessions.Name = "listViewSessions"; - this.listViewSessions.Size = new System.Drawing.Size(469, 428); - this.listViewSessions.SmallImageList = this.imageList1; - this.listViewSessions.TabIndex = 0; - this.listViewSessions.UseCompatibleStateImageBehavior = false; - this.listViewSessions.View = System.Windows.Forms.View.Details; - this.listViewSessions.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.listViewSessions_ItemSelectionChanged); - // - // columnHeaderCounter - // - this.columnHeaderCounter.Text = "#"; - this.columnHeaderCounter.Width = 54; - // - // columnHeaderProtocol - // - this.columnHeaderProtocol.Text = "Protocol"; - this.columnHeaderProtocol.Width = 59; - // - // columnHeaderType - // - this.columnHeaderType.Text = "Packet Type"; - this.columnHeaderType.Width = 151; - // - // columnHeaderSize - // - this.columnHeaderSize.Text = "Bytes"; - this.columnHeaderSize.Width = 64; - // - // columnHeaderUrl - // - this.columnHeaderUrl.Text = "Host/Address"; - this.columnHeaderUrl.Width = 312; - // - // columnHeaderContentType - // - this.columnHeaderContentType.Text = "Content Type"; - this.columnHeaderContentType.Width = 250; - // - // listViewPacketFilters - // - this.listViewPacketFilters.CheckBoxes = true; - this.listViewPacketFilters.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeaderPacketName, - this.columnHeaderPacketType}); - this.listViewPacketFilters.Dock = System.Windows.Forms.DockStyle.Fill; - this.listViewPacketFilters.FullRowSelect = true; - this.listViewPacketFilters.GridLines = true; - this.listViewPacketFilters.Location = new System.Drawing.Point(3, 16); - this.listViewPacketFilters.MultiSelect = false; - this.listViewPacketFilters.Name = "listViewPacketFilters"; - this.listViewPacketFilters.Size = new System.Drawing.Size(286, 338); - this.listViewPacketFilters.Sorting = System.Windows.Forms.SortOrder.Ascending; - this.listViewPacketFilters.TabIndex = 0; - this.listViewPacketFilters.UseCompatibleStateImageBehavior = false; - this.listViewPacketFilters.View = System.Windows.Forms.View.Details; - this.listViewPacketFilters.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listViewPacketFilters_ItemChecked); - this.listViewPacketFilters.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listViewFilterSorter_ColumnClick); - // - // columnHeaderPacketName - // - this.columnHeaderPacketName.Text = "Packet Name"; - this.columnHeaderPacketName.Width = 215; - // - // columnHeaderPacketType - // - this.columnHeaderPacketType.Text = "Type"; - // - // listViewMessageFilters - // - this.listViewMessageFilters.CheckBoxes = true; - this.listViewMessageFilters.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeaderName, - this.columnHeaderMessageType}); - this.listViewMessageFilters.Dock = System.Windows.Forms.DockStyle.Fill; - this.listViewMessageFilters.FullRowSelect = true; - this.listViewMessageFilters.GridLines = true; - this.listViewMessageFilters.Location = new System.Drawing.Point(3, 16); - this.listViewMessageFilters.MultiSelect = false; - this.listViewMessageFilters.Name = "listViewMessageFilters"; - this.listViewMessageFilters.Size = new System.Drawing.Size(284, 338); - this.listViewMessageFilters.Sorting = System.Windows.Forms.SortOrder.Ascending; - this.listViewMessageFilters.TabIndex = 1; - this.listViewMessageFilters.UseCompatibleStateImageBehavior = false; - this.listViewMessageFilters.View = System.Windows.Forms.View.Details; - this.listViewMessageFilters.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listViewMessageFilters_ItemChecked); - this.listViewMessageFilters.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listViewFilterSorter_ColumnClick); - // - // columnHeaderName - // - this.columnHeaderName.Text = "Message Name"; - this.columnHeaderName.Width = 181; - // - // columnHeaderMessageType - // - this.columnHeaderMessageType.Text = "Type"; - this.columnHeaderMessageType.Width = 92; - // // FormWinGridProxy // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -2319,6 +2339,7 @@ private System.Windows.Forms.ComboBox comboBoxListenAddress; private System.Windows.Forms.ToolStripMenuItem toolStripMenuItemPlugins; private System.Windows.Forms.ToolStripSeparator toolStripSeparator14; + private System.Windows.Forms.RichTextBox richTextBoxDebugLog; } } diff --git a/Programs/WinGridProxy/FormWinGridProxy.cs b/Programs/WinGridProxy/FormWinGridProxy.cs index e4401862..a470bfa7 100644 --- a/Programs/WinGridProxy/FormWinGridProxy.cs +++ b/Programs/WinGridProxy/FormWinGridProxy.cs @@ -30,7 +30,7 @@ using System.Net; using System.Collections; using System.Collections.Generic; using System.ComponentModel; - +using System.Text.RegularExpressions; using System.Drawing; using System.Text; using System.Windows.Forms; @@ -43,6 +43,7 @@ using OpenMetaverse.StructuredData; using OpenMetaverse.Interfaces; using System.Xml; using Nwc.XmlRpc; +using Logger=OpenMetaverse.Logger; namespace WinGridProxy { @@ -56,6 +57,7 @@ namespace WinGridProxy ProxyManager proxy; + private PacketDecoder DecodePacket = new PacketDecoder(); private int PacketCounter; @@ -73,12 +75,18 @@ namespace WinGridProxy { InitializeComponent(); + Logger.Log("WinGridProxy ready", Helpers.LogLevel.Info); + + if (FireEventAppender.Instance != null) + { + FireEventAppender.Instance.MessageLoggedEvent += new MessageLoggedEventHandler(Instance_MessageLoggedEvent); + } + // populate the listen box with IPs IPHostEntry iphostentry = Dns.GetHostByName(Dns.GetHostName()); foreach (IPAddress address in iphostentry.AddressList) comboBoxListenAddress.Items.Add(address.ToString()); - ProxyManager.OnPacketLog += ProxyManager_OnPacketLog; ProxyManager.OnMessageLog += ProxyManager_OnMessageLog; ProxyManager.OnLoginResponse += ProxyManager_OnLoginResponse; @@ -956,7 +964,7 @@ namespace WinGridProxy } else { - result.AppendFormat("{0, 30}: {1} ({2})" + System.Environment.NewLine, + result.AppendFormat("{0, 30}: {1} ({2})" + Environment.NewLine, nestedField.Name, nestedField.GetValue(nestedArrayObject), nestedField.GetValue(nestedArrayObject).GetType().Name); @@ -968,7 +976,7 @@ namespace WinGridProxy { if (messageField.FieldType.IsEnum) { - result.AppendFormat("{0, 30}: {1} {2} ({3})" + System.Environment.NewLine, + result.AppendFormat("{0, 30}: {1} {2} ({3})" + Environment.NewLine, messageField.Name, Enum.Format(messageField.GetValue(message).GetType(), messageField.GetValue(message), "D"), @@ -989,159 +997,6 @@ namespace WinGridProxy return result.ToString(); } - private static string InterpretOptions(Header header) - { - return "[" - + (header.AppendedAcks ? "Ack" : " ") - + " " - + (header.Resent ? "Res" : " ") - + " " - + (header.Reliable ? "Rel" : " ") - + " " - + (header.Zerocoded ? "Zer" : " ") - + "]" - ; - } - - /// - /// Creates a formatted string containing the values of a Packet - /// - /// The Packet - /// A formatted string of values of the nested items in the Packet object - /// TODO: This is overly complex. Static helpers should be created to clean this up and it - /// should be made generic enough to decode IMessage objects too. - public static string PacketToString(Packet packet) - { - StringBuilder result = new StringBuilder(); - - result.AppendFormat("Packet Type: {0}" + System.Environment.NewLine, packet.Type); - result.AppendLine("[Packet Header]"); - // payload - result.AppendFormat("Sequence: {0}" + System.Environment.NewLine, packet.Header.Sequence); - result.AppendFormat(" Options: {0}" + System.Environment.NewLine, InterpretOptions(packet.Header)); - result.AppendLine(); - - result.AppendLine("[Packet Payload]"); - foreach (FieldInfo packetField in packet.GetType().GetFields()) - { - object packetDataObject = packetField.GetValue(packet); - - result.AppendFormat("-- {0,20} --" + System.Environment.NewLine, packetField.Name); - foreach (FieldInfo packetValueField in packetField.GetValue(packet).GetType().GetFields()) - { - result.AppendFormat("{0,30}: {1}" + System.Environment.NewLine, - packetValueField.Name, packetValueField.GetValue(packetDataObject)); - } - - // handle blocks that are arrays - if (packetDataObject.GetType().IsArray) - { - foreach (object nestedArrayRecord in packetDataObject as Array) - { - // handle properties - foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties()) - { - if (propertyInfo.GetValue(nestedArrayRecord, null).GetType() == typeof(byte[])) - { - result.AppendFormat("{0, 30}: {1}" + Environment.NewLine, - propertyInfo.Name, - Utils.BytesToString((byte[])propertyInfo.GetValue(nestedArrayRecord, null))); - } - } - - // handle fields - foreach (FieldInfo packetArrayField in nestedArrayRecord.GetType().GetFields()) - { - if (packetArrayField.GetValue(nestedArrayRecord).GetType() == typeof(Byte[])) - { - result.AppendFormat("{0,30}: {1}" + Environment.NewLine, - packetArrayField.Name, - new Color4((byte[])packetArrayField.GetValue(nestedArrayRecord), 0, false)); - } - else - { - result.AppendFormat("{0,30}: {1}" + Environment.NewLine, - packetArrayField.Name, packetArrayField.GetValue(nestedArrayRecord)); - } - } - } - } - - else - { - // handle non array data blocks - foreach (PropertyInfo packetPropertyField in packetField.GetValue(packet).GetType().GetProperties()) - { - // Handle fields named "Data" specifically, this is generally binary data, we'll display it as hex values - if (packetPropertyField.PropertyType.Equals(typeof(Byte[])) - && packetPropertyField.Name.Equals("Data")) - { - result.AppendFormat("{0}" + System.Environment.NewLine, - Utils.BytesToHexString((byte[])packetPropertyField.GetValue(packetDataObject, null), - packetPropertyField.Name)); - } - // decode bytes into strings - else if (packetPropertyField.PropertyType.Equals(typeof(Byte[]))) - { - // Handle TextureEntry fields specifically - if (packetPropertyField.Name.Equals("TextureEntry")) - { - byte[] tebytes = (byte[])packetPropertyField.GetValue(packetDataObject, null); - - Primitive.TextureEntry te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length); - result.AppendFormat("{0,30}:\n{1}", packetPropertyField.Name, te.ToString()); - } - else - { - // Decode the BinaryBucket - if (packetPropertyField.Name.Equals("BinaryBucket")) - { - byte[] bytes = (byte[])packetPropertyField.GetValue(packetDataObject, null); - string bbDecoded = String.Empty; - if (bytes.Length == 1) - { - bbDecoded = String.Format("{0}", bytes[0]); - } - else if (bytes.Length == 17) - { - bbDecoded = String.Format("{0} {1} ({2})", - new UUID(bytes, 1), - bytes[0], - (AssetType)bytes[0]); - } - else - { - bbDecoded = Utils.BytesToString(bytes); - } - - result.AppendFormat("{0,30}: {1}" + System.Environment.NewLine, - packetPropertyField.Name, - bbDecoded); - } - else - { - result.AppendFormat("{0,30}: {1}" + System.Environment.NewLine, - packetPropertyField.Name, - Utils.BytesToString((byte[])packetPropertyField.GetValue(packetDataObject, null))); - } - } - } - else - { - // this seems to be limited to the length property, since all others have been previously handled - if (packetPropertyField.Name != "Length") - { - result.AppendFormat("{0,30}: {1} [{2}]" + System.Environment.NewLine, - packetPropertyField.Name, packetPropertyField.GetValue(packetDataObject, null), - packetPropertyField.GetType()); - } - } - } - } - } - return result.ToString(); - } - private void SaveAllSettings(string fileName) { Store.MessageSessions.Clear(); @@ -1336,8 +1191,7 @@ namespace WinGridProxy else if (tag is Packet) { Packet packet = (Packet)tag; - - return PacketToString(packet); + return DecodePacket.PacketToString(packet); } else if (tag is CapsRequest) { @@ -1561,7 +1415,6 @@ namespace WinGridProxy private void autoColorizeToolStripMenuItem_Click(object sender, EventArgs e) { - if (colorDialog1.ShowDialog() == DialogResult.OK) { //listview.BackColor = colorDialog1.Color; @@ -1573,5 +1426,59 @@ namespace WinGridProxy FormPluginManager pluginManager = new FormPluginManager(proxy.Proxy); pluginManager.ShowDialog(); } + + void Instance_MessageLoggedEvent(object sender, MessageLoggedEventArgs e) + { + if(this.IsDisposed || this.Disposing) + return; + + if (InvokeRequired) + { + BeginInvoke(new MethodInvoker(delegate() + { + Instance_MessageLoggedEvent(sender, e); + })); + } + else + { + string s = String.Format("{0} [{1}] {2} {3}", e.LoggingEvent.TimeStamp, e.LoggingEvent.Level, + e.LoggingEvent.RenderedMessage, e.LoggingEvent.ExceptionObject); + richTextBoxDebugLog.AppendText(s + "\n"); + } + } + + private void richTextBoxDecodedRequest_TextChanged(object sender, EventArgs e) + { + RichTextBox m_rtb = (RichTextBox) sender; + Regex typesRegex = new Regex(@"\[(?\w+|\w+\[\])\]|\((?.*)\)|\s-- (?
\w+|\w+ \[\]) --\s|(?\s\*\*\*\s)|(?\s<\w+>\s|\s<\/\w+>\s)|(?\s\w+\[\d+\]\s)", RegexOptions.ExplicitCapture); + + MatchCollection matches = typesRegex.Matches(m_rtb.Text); + foreach(Match match in matches) + { + m_rtb.SelectionStart = match.Index +1; + m_rtb.SelectionLength = match.Length -2; + m_rtb.SelectionFont = new Font(m_rtb.Font.FontFamily, m_rtb.Font.Size, FontStyle.Bold); + + if (!String.IsNullOrEmpty(match.Groups["Type"].Value)) + m_rtb.SelectionColor = Color.Blue; + else if (!String.IsNullOrEmpty(match.Groups["Enum"].Value)) + m_rtb.SelectionColor = Color.FromArgb(43, 145, 175); + else if (!String.IsNullOrEmpty(match.Groups["Header"].Value)) + { + m_rtb.SelectionColor = Color.Green; + m_rtb.SelectionBackColor = Color.LightSteelBlue; + } + else if (!String.IsNullOrEmpty(match.Groups["BlockSep"].Value)) + m_rtb.SelectionColor = Color.Gold; + else if (!String.IsNullOrEmpty(match.Groups["Tag"].Value)) + { + m_rtb.SelectionColor = Color.White; + m_rtb.SelectionBackColor = Color.Black; + } + else if (!String.IsNullOrEmpty(match.Groups["BlockCounter"].Value)) + m_rtb.SelectionColor = Color.Green; + + } + } } } diff --git a/Programs/WinGridProxy/FormWinGridProxy.resx b/Programs/WinGridProxy/FormWinGridProxy.resx index bc044b9f..986ae6e8 100644 --- a/Programs/WinGridProxy/FormWinGridProxy.resx +++ b/Programs/WinGridProxy/FormWinGridProxy.resx @@ -120,15 +120,6 @@ 524, 17 - - 185, 54 - - - 17, 54 - - - 705, 17 - 309, 17 @@ -187,6 +178,21 @@ 116, 17 + + 185, 54 + + + 17, 54 + + + 705, 17 + + + 414, 17 + + + 116, 17 + 17, 17 @@ -206,9 +212,6 @@ s1c0gHPmbrPTpHNJKOCo2G1mZs20zcwUJ5yp1AB5+8/zEwgF5GMVDxh4AAAAAElFTkSuQmCC - - 919, 17 - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 @@ -226,6 +229,9 @@ AAAAAElFTkSuQmCC + + 919, 17 + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 diff --git a/Programs/examples/TestClient/Commands/WhoCommand.cs b/Programs/examples/TestClient/Commands/WhoCommand.cs index a4ea2a34..dc5615e6 100644 --- a/Programs/examples/TestClient/Commands/WhoCommand.cs +++ b/Programs/examples/TestClient/Commands/WhoCommand.cs @@ -27,8 +27,8 @@ namespace OpenMetaverse.TestClient delegate(Avatar av) { result.AppendLine(); - result.AppendFormat("{0} (Group: {1}, Location: {2}, UUID: {3})", - av.Name, av.GroupName, av.Position, av.ID.ToString()); + result.AppendFormat("{0} (Group: {1}, Location: {2}, UUID: {3} LocalID: {4})", + av.Name, av.GroupName, av.Position, av.ID, av.LocalID); } ); } diff --git a/bin/WinGridProxy.exe.config b/bin/WinGridProxy.exe.config new file mode 100644 index 00000000..dca8fcae --- /dev/null +++ b/bin/WinGridProxy.exe.config @@ -0,0 +1,77 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prebuild.xml b/prebuild.xml index 8c60e6e9..c4ced7ed 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1 +1 @@ - TRACE;DEBUG false false true 4 false 1591,1574,0419,0618 bin true true false TRACE true false true 4 false 1591,1574,0419,0618 bin false true false ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ OpenMetaverseTypes.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.StructuredData.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.Http.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.Utilities.XML ../bin/ ../bin/ ../bin/ ../bin/ ../../bin/ ../../bin/ ../../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ OpenMetaverse.GUI.XML ../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ \ No newline at end of file + TRACE;DEBUG false false true 4 false 1591,1574,0419,0618 bin true true false TRACE true false true 4 false 1591,1574,0419,0618 bin false true false ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ OpenMetaverseTypes.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.StructuredData.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.Http.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.XML ../bin/ ../bin/ ../bin/ OpenMetaverse.Utilities.XML ../bin/ ../bin/ ../bin/ ../bin/ ../../bin/ ../../bin/ ../../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ ../bin/ OpenMetaverse.GUI.XML ../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/ ../../../bin/