diff --git a/OpenSim/Region/Environment/Modules/AgentAssetTransactionModule.cs b/OpenSim/Region/Environment/Modules/AgentAssetTransactionModule.cs new file mode 100644 index 0000000000..99d6db1880 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/AgentAssetTransactionModule.cs @@ -0,0 +1,286 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using System.Text; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class AgentAssetTransactionModule : IRegionModule, IAgentAssetTransactions + { + private Dictionary RegisteredScenes = new Dictionary(); + private Scene m_scene = null; + private bool m_dumpAssetsToFile = false; + + private AgentAssetTransactionsManager m_transactionManager; + + public AgentAssetTransactionModule() + { + // System.Console.WriteLine("creating AgentAssetTransactionModule"); + } + + public void Initialise(Scene scene, IConfigSource config) + { + if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) + { + // System.Console.WriteLine("initialising AgentAssetTransactionModule"); + RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); + scene.RegisterModuleInterface(this); + + scene.EventManager.OnNewClient += NewClient; + } + + if (m_scene == null) + { + m_scene = scene; + if (config.Configs["StandAlone"] != null) + { + try + { + m_dumpAssetsToFile = config.Configs["StandAlone"].GetBoolean("dump_assets_to_file", false); + m_transactionManager = new AgentAssetTransactionsManager(m_scene, m_dumpAssetsToFile); + } + catch (Exception) + { + m_transactionManager = new AgentAssetTransactionsManager(m_scene, false); + } + } + else + { + m_transactionManager = new AgentAssetTransactionsManager(m_scene, false); + } + + } + } + + public void PostInitialise() + { + + } + + public void Close() + { + } + + public string Name + { + get { return "AgentTransactionModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public void NewClient(IClientAPI client) + { + client.OnAssetUploadRequest += m_transactionManager.HandleUDPUploadRequest; + client.OnXferReceive += m_transactionManager.HandleXfer; + } + + public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + m_transactionManager.HandleItemCreationFromTransaction(remoteClient, transactionID, folderID, callbackID, description, name, invType, type, wearableType, nextOwnerMask); + } + + public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + m_transactionManager.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); + } + + public void RemoveAgentAssetTransactions(LLUUID userID) + { + m_transactionManager.RemoveAgentAssetTransactions(userID); + } + } + + //should merge this classes and clean up + public class AgentAssetTransactionsManager + { + private static readonly log4net.ILog m_log + = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + // Fields + public Scene MyScene; + + /// + /// Each agent has its own singleton collection of transactions + /// + private Dictionary AgentTransactions = + new Dictionary(); + + /// + /// Should we dump uploaded assets to the filesystem? + /// + private bool m_dumpAssetsToFile; + + public AgentAssetTransactionsManager(Scene scene, bool dumpAssetsToFile) + { + MyScene = scene; + m_dumpAssetsToFile = dumpAssetsToFile; + } + + /// + /// Get the collection of asset transactions for the given user. If one does not already exist, it + /// is created. + /// + /// + /// + private AgentAssetTransactions GetUserTransactions(LLUUID userID) + { + lock (AgentTransactions) + { + if (!AgentTransactions.ContainsKey(userID)) + { + AgentAssetTransactions transactions + = new AgentAssetTransactions(userID, this, m_dumpAssetsToFile); + AgentTransactions.Add(userID, transactions); + } + + return AgentTransactions[userID]; + } + } + + /// + /// Remove the given agent asset transactions. This should be called when a client is departing + /// from a scene (and hence won't be making any more transactions here). + /// + /// + public void RemoveAgentAssetTransactions(LLUUID userID) + { + // m_log.DebugFormat("Removing agent asset transactions structure for agent {0}", userID); + + lock (AgentTransactions) + { + AgentTransactions.Remove(userID); + } + } + + /// + /// Create an inventory item from data that has been received through a transaction. + /// + /// This is called when new clothing or body parts are created. It may also be called in other + /// situations. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void HandleItemCreationFromTransaction(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + m_log.DebugFormat( + "[TRANSACTIONS MANAGER] Called HandleItemCreationFromTransaction with item {0}", name); + + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); + + transactions.RequestCreateInventoryItem( + remoteClient, transactionID, folderID, callbackID, description, + name, invType, type, wearableType, nextOwnerMask); + } + + /// + /// Update an inventory item with data that has been received through a transaction. + /// + /// This is called when clothing or body parts are updated (for instance, with new textures or + /// colours). It may also be called in other situations. + /// + /// + /// + /// + public void HandleItemUpdateFromTransaction(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + m_log.DebugFormat( + "[TRANSACTIONS MANAGER] Called HandleItemUpdateFromTransaction with item {0}", + item.inventoryName); + + AgentAssetTransactions transactions + = GetUserTransactions(remoteClient.AgentId); + + transactions.RequestUpdateInventoryItem(remoteClient, transactionID, item); + } + + /// + /// Request that a client (agent) begin an asset transfer. + /// + /// + /// + /// + /// + /// + /// + public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, + byte[] data, bool storeLocal, bool tempFile) + { + // Console.WriteLine("asset upload of " + assetID); + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); + + AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction); + if (uploader != null) + { + + if (uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile)) + { + + } + } + } + + /// + /// Handle asset transfer data packets received in response to the asset upload request in + /// HandleUDPUploadRequest() + /// + /// + /// + /// + /// + public void HandleXfer(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) + { + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); + + transactions.HandleXfer(xferID, packetID, data); + } + } +} diff --git a/OpenSim/Region/Environment/Modules/AgentAssetsTransactions.cs b/OpenSim/Region/Environment/Modules/AgentAssetsTransactions.cs new file mode 100644 index 0000000000..bfca1a2f59 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/AgentAssetsTransactions.cs @@ -0,0 +1,408 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using System.Text; +using System.IO; +using libsecondlife; +using libsecondlife.Packets; +using OpenSim.Framework.Servers; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; + +namespace OpenSim.Region.Environment.Modules +{ + + /// + /// Manage asset transactions for a single agent. + /// + public class AgentAssetTransactions + { + //private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + // Fields + public LLUUID UserID; + public Dictionary XferUploaders = new Dictionary(); + public AgentAssetTransactionsManager Manager; + private bool m_dumpAssetsToFile; + + // Methods + public AgentAssetTransactions(LLUUID agentID, AgentAssetTransactionsManager manager, bool dumpAssetsToFile) + { + UserID = agentID; + Manager = manager; + m_dumpAssetsToFile = dumpAssetsToFile; + } + + public AssetXferUploader RequestXferUploader(LLUUID transactionID) + { + if (!XferUploaders.ContainsKey(transactionID)) + { + AssetXferUploader uploader = new AssetXferUploader(this, m_dumpAssetsToFile); + + lock (XferUploaders) + { + XferUploaders.Add(transactionID, uploader); + } + + return uploader; + } + return null; + } + + public void HandleXfer(ulong xferID, uint packetID, byte[] data) + { + // AssetXferUploader uploaderFound = null; + + lock (XferUploaders) + { + foreach (AssetXferUploader uploader in XferUploaders.Values) + { + if (uploader.XferID == xferID) + { + uploader.HandleXferPacket(xferID, packetID, data); + break; + } + } + } + } + + public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + if (XferUploaders.ContainsKey(transactionID)) + { + XferUploaders[transactionID].RequestCreateInventoryItem(remoteClient, transactionID, folderID, + callbackID, description, name, invType, type, + wearableType, nextOwnerMask); + } + } + + public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + if (XferUploaders.ContainsKey(transactionID)) + { + XferUploaders[transactionID].RequestUpdateInventoryItem(remoteClient, transactionID, item); + } + } + + /// + /// Get an uploaded asset. If the data is successfully retrieved, the transaction will be removed. + /// + /// + /// The asset if the upload has completed, null if it has not. + public AssetBase GetTransactionAsset(LLUUID transactionID) + { + if (XferUploaders.ContainsKey(transactionID)) + { + AssetXferUploader uploader = XferUploaders[transactionID]; + AssetBase asset = uploader.GetAssetData(); + + lock (XferUploaders) + { + XferUploaders.Remove(transactionID); + } + + return asset; + } + + return null; + } + + // Nested Types + public class AssetXferUploader + { + // Fields + public bool AddToInventory; + public AssetBase Asset; + public LLUUID InventFolder = LLUUID.Zero; + private IClientAPI ourClient; + public LLUUID TransactionID = LLUUID.Zero; + public bool UploadComplete; + public ulong XferID; + private string m_name = String.Empty; + private string m_description = String.Empty; + private sbyte type = 0; + private sbyte invType = 0; + private uint nextPerm = 0; + private bool m_finished = false; + private bool m_createItem = false; + private AgentAssetTransactions m_userTransactions; + private bool m_storeLocal; + private bool m_dumpAssetToFile; + + public AssetXferUploader(AgentAssetTransactions transactions, bool dumpAssetToFile) + { + m_userTransactions = transactions; + m_dumpAssetToFile = dumpAssetToFile; + } + + /// + /// Process transfer data received from the client. + /// + /// + /// + /// + /// True if the transfer is complete, false otherwise or if the xferID was not valid + public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data) + { + if (XferID == xferID) + { + if (Asset.Data.Length > 1) + { + byte[] destinationArray = new byte[Asset.Data.Length + data.Length]; + Array.Copy(Asset.Data, 0, destinationArray, 0, Asset.Data.Length); + Array.Copy(data, 0, destinationArray, Asset.Data.Length, data.Length); + Asset.Data = destinationArray; + } + else + { + byte[] buffer2 = new byte[data.Length - 4]; + Array.Copy(data, 4, buffer2, 0, data.Length - 4); + Asset.Data = buffer2; + } + ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket(); + newPack.XferID.ID = xferID; + newPack.XferID.Packet = packetID; + ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); + if ((packetID & 0x80000000) != 0) + { + SendCompleteMessage(); + return true; + } + } + + return false; + } + + /// + /// Initialise asset transfer from the client + /// + /// + /// + /// + /// True if the transfer is complete, false otherwise + public bool Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, + bool storeLocal, bool tempFile) + { + ourClient = remoteClient; + Asset = new AssetBase(); + Asset.FullID = assetID; + Asset.InvType = type; + Asset.Type = type; + Asset.Data = data; + Asset.Name = "blank"; + Asset.Description = "empty"; + Asset.Local = storeLocal; + Asset.Temporary = tempFile; + + TransactionID = transaction; + m_storeLocal = storeLocal; + if (Asset.Data.Length > 2) + { + SendCompleteMessage(); + return true; + } + else + { + RequestStartXfer(); + } + + return false; + } + + protected void RequestStartXfer() + { + UploadComplete = false; + XferID = Util.GetNextXferID(); + RequestXferPacket newPack = new RequestXferPacket(); + newPack.XferID.ID = XferID; + newPack.XferID.VFileType = Asset.Type; + newPack.XferID.VFileID = Asset.FullID; + newPack.XferID.FilePath = 0; + newPack.XferID.Filename = new byte[0]; + ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); + } + + protected void SendCompleteMessage() + { + UploadComplete = true; + AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); + newPack.AssetBlock.Type = Asset.Type; + newPack.AssetBlock.Success = true; + newPack.AssetBlock.UUID = Asset.FullID; + ourClient.OutPacket(newPack, ThrottleOutPacketType.Asset); + m_finished = true; + if (m_createItem) + { + DoCreateItem(); + } + else if (m_storeLocal) + { + m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); + } + + // Console.WriteLine("upload complete "+ this.TransactionID); + + if (m_dumpAssetToFile) + { + DateTime now = DateTime.Now; + string filename = + String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat", now.Year, now.Month, now.Day, + now.Hour, now.Minute, now.Second, Asset.Name, Asset.Type); + SaveAssetToFile(filename, Asset.Data); + } + } + + ///Left this in and commented in case there are unforseen issues + //private void SaveAssetToFile(string filename, byte[] data) + //{ + // FileStream fs = File.Create(filename); + // BinaryWriter bw = new BinaryWriter(fs); + // bw.Write(data); + // bw.Close(); + // fs.Close(); + //} + private void SaveAssetToFile(string filename, byte[] data) + { + string assetPath = "UserAssets"; + if (!Directory.Exists(assetPath)) + { + Directory.CreateDirectory(assetPath); + } + FileStream fs = File.Create(Path.Combine(assetPath, filename)); + BinaryWriter bw = new BinaryWriter(fs); + bw.Write(data); + bw.Close(); + fs.Close(); + } + + public void RequestCreateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, LLUUID folderID, + uint callbackID, string description, string name, sbyte invType, + sbyte type, byte wearableType, uint nextOwnerMask) + { + if (TransactionID == transactionID) + { + InventFolder = folderID; + m_name = name; + m_description = description; + this.type = type; + this.invType = invType; + nextPerm = nextOwnerMask; + Asset.Name = name; + Asset.Description = description; + Asset.Type = type; + Asset.InvType = invType; + m_createItem = true; + if (m_finished) + { + DoCreateItem(); + } + } + } + + public void RequestUpdateInventoryItem(IClientAPI remoteClient, LLUUID transactionID, + InventoryItemBase item) + { + if (TransactionID == transactionID) + { + CachedUserInfo userInfo = + m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails( + remoteClient.AgentId); + + if (userInfo != null) + { + LLUUID assetID = LLUUID.Combine(transactionID, remoteClient.SecureSessionId); + + AssetBase asset + = m_userTransactions.Manager.MyScene.CommsManager.AssetCache.GetAsset( + assetID, (item.assetType == (int) AssetType.Texture ? true : false)); + + if (asset == null) + { + asset = m_userTransactions.GetTransactionAsset(transactionID); + } + + if (asset != null && asset.FullID == assetID) + { + asset.Name = item.inventoryName; + asset.Description = item.inventoryDescription; + asset.InvType = (sbyte) item.invType; + asset.Type = (sbyte) item.assetType; + item.assetID = asset.FullID; + + m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); + } + + userInfo.UpdateItem(remoteClient.AgentId, item); + } + } + } + + private void DoCreateItem() + { + //really need to fix this call, if lbsa71 saw this he would die. + m_userTransactions.Manager.MyScene.CommsManager.AssetCache.AddAsset(Asset); + CachedUserInfo userInfo = + m_userTransactions.Manager.MyScene.CommsManager.UserProfileCacheService.GetUserDetails(ourClient.AgentId); + if (userInfo != null) + { + InventoryItemBase item = new InventoryItemBase(); + item.avatarID = ourClient.AgentId; + item.creatorsID = ourClient.AgentId; + item.inventoryID = LLUUID.Random(); + item.assetID = Asset.FullID; + item.inventoryDescription = m_description; + item.inventoryName = m_name; + item.assetType = type; + item.invType = invType; + item.parentFolderID = InventFolder; + item.inventoryBasePermissions = 2147483647; + item.inventoryCurrentPermissions = 2147483647; + item.inventoryNextPermissions = nextPerm; + + userInfo.AddItem(ourClient.AgentId, item); + ourClient.SendInventoryItemCreateUpdate(item); + } + } + + public AssetBase GetAssetData() + { + if (m_finished) + { + return Asset; + } + return null; + } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/AppearanceTableMapper.cs b/OpenSim/Region/Environment/Modules/AppearanceTableMapper.cs new file mode 100644 index 0000000000..6a0eef19e2 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/AppearanceTableMapper.cs @@ -0,0 +1,244 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using System.Text; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework; +using TribalMedia.Framework.Data; + +namespace OpenSim.Region.Environment.Modules +{ + public class AppearanceRowMapper : BaseRowMapper + { + + public AppearanceRowMapper(BaseSchema schema, AvatarAppearance obj) + : base(schema, obj) + { + } + } + + public class AppearanceTableMapper : BaseTableMapper + { + public AppearanceTableMapper(BaseDatabaseConnector database, string tableName) + : base(database, tableName) + { + BaseSchema rowMapperSchema = new BaseSchema(this); + m_schema = rowMapperSchema; + + m_keyFieldMapper = rowMapperSchema.AddMapping("UUID", + delegate(AppearanceRowMapper mapper) { return mapper.Object.ScenePresenceID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.ScenePresenceID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("Serial", + delegate(AppearanceRowMapper mapper) { return (uint)mapper.Object.WearablesSerial; }, + delegate(AppearanceRowMapper mapper, uint value) { mapper.Object.WearablesSerial = (int)value; }); + + rowMapperSchema.AddMapping("WearableItem0", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[0].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { + if (mapper.Object.Wearables == null) + { + mapper.Object.Wearables = new OpenSim.Framework.AvatarWearable[13]; + for (int i = 0; i < 13; i++) + { + mapper.Object.Wearables[i] = new AvatarWearable(); + } + } + mapper.Object.Wearables[0].ItemID = new libsecondlife.LLUUID(value.ToString()); + }); + + rowMapperSchema.AddMapping("WearableAsset0", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[0].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[0].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem1", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[1].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[1].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset1", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[1].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[1].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem2", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[2].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[2].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset2", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[2].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[2].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem3", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[3].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[3].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset3", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[3].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[3].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem4", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[4].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[4].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset4", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[4].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[4].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem5", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[5].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[5].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset5", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[5].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[5].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem6", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[6].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[6].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset6", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[6].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[6].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem7", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[7].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[7].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset7", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[7].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[7].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem8", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[8].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[8].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset8", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[8].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[8].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem9", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[9].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[9].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset9", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[9].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[9].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem10", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[10].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[10].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset10", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[10].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[10].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem11", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[11].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[11].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset11", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[11].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[11].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableItem12", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[12].ItemID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) { mapper.Object.Wearables[12].ItemID = new libsecondlife.LLUUID(value.ToString()); }); + + rowMapperSchema.AddMapping("WearableAsset12", + delegate(AppearanceRowMapper mapper) { return mapper.Object.Wearables[12].AssetID.UUID; }, + delegate(AppearanceRowMapper mapper, Guid value) + { mapper.Object.Wearables[12].AssetID = new libsecondlife.LLUUID(value.ToString()); }); + + } + + public bool Add(Guid userID, AvatarAppearance appearance) + { + AppearanceRowMapper mapper = CreateRowMapper(appearance); + return Add(mapper); + } + + public bool Update(Guid userID, AvatarAppearance appearance) + { + AppearanceRowMapper mapper = CreateRowMapper(appearance); + return Update(appearance.ScenePresenceID.UUID, mapper); + } + + protected AppearanceRowMapper CreateRowMapper(AvatarAppearance appearance) + { + return new AppearanceRowMapper(m_schema, appearance); + } + + protected AppearanceRowMapper CreateRowMapper() + { + return CreateRowMapper(new AvatarAppearance()); + } + + protected AppearanceRowMapper FromReader(BaseDataReader reader, AvatarAppearance appearance) + { + AppearanceRowMapper mapper = CreateRowMapper(appearance); + mapper.FillObject(reader); + return mapper; + } + + public override AppearanceRowMapper FromReader(BaseDataReader reader) + { + AppearanceRowMapper mapper = CreateRowMapper(); + mapper.FillObject(reader); + return mapper; + } + + public bool TryGetValue(Guid presenceID, out AvatarAppearance val) + { + AppearanceRowMapper mapper; + if (TryGetValue(presenceID, out mapper)) + { + val = mapper.Object; + return true; + } + else + { + val = null; + return false; + } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs b/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs index 840b539429..96c667965c 100644 --- a/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs +++ b/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs @@ -1,72 +1,72 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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 Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class AssetDownloadModule : IRegionModule - { - private Scene m_scene; - - public AssetDownloadModule() - { - } - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "AssetDownloadModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public void NewClient(IClientAPI client) - { - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class AssetDownloadModule : IRegionModule + { + private Scene m_scene; + + public AssetDownloadModule() + { + } + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + m_scene.EventManager.OnNewClient += NewClient; + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "AssetDownloadModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public void NewClient(IClientAPI client) + { + } + } +} diff --git a/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs b/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs index 778cce58fb..24afdb4dc7 100644 --- a/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs +++ b/OpenSim/Region/Environment/Modules/AvatarFactoryModule.cs @@ -1,162 +1,339 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Cache; -using OpenSim.Framework.Console; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class AvatarFactoryModule : IAvatarFactory - { - private Scene m_scene = null; - private Dictionary m_avatarsAppearance = new Dictionary(); - - public bool TryGetAvatarAppearance(LLUUID avatarId, out AvatarAppearance appearance) - { - if (m_avatarsAppearance.ContainsKey(avatarId)) - { - appearance = m_avatarsAppearance[avatarId]; - return true; - } - else - { - AvatarWearable[] wearables; - byte[] visualParams; - GetDefaultAvatarAppearance(out wearables, out visualParams); - appearance = new AvatarAppearance(avatarId, wearables, visualParams); - try - { - m_avatarsAppearance[avatarId] = appearance; - } - catch (NullReferenceException) - { - MainLog.Instance.Error("AVATAR", "Unable to load appearance for uninitialized avatar"); - } - return true; - } - } - - public void Initialise(Scene scene, IConfigSource source) - { - scene.RegisterModuleInterface(this); - scene.EventManager.OnNewClient += NewClient; - - if (m_scene == null) - { - m_scene = scene; - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "Default Avatar Factory"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public void NewClient(IClientAPI client) - { - client.OnAvatarNowWearing += AvatarIsWearing; - } - - public void RemoveClient(IClientAPI client) - { - // client.OnAvatarNowWearing -= AvatarIsWearing; - } - - public void AvatarIsWearing(Object sender, AvatarWearingArgs e) - { - IClientAPI clientView = (IClientAPI) sender; - CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(clientView.AgentId); - if (profile != null) - { - if (profile.RootFolder != null) - { - //Todo look up the assetid from the inventory cache for each itemId that is in AvatarWearingArgs - // then store assetid and itemId and wearable type in a database - foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) - { - if (wear.Type < 13) - { - LLUUID assetId; - - InventoryItemBase baseItem = profile.RootFolder.HasItem(wear.ItemID); - if (baseItem != null) - { - assetId = baseItem.assetID; - //temporary dictionary storage. This should be storing to a database - - if (m_avatarsAppearance.ContainsKey(clientView.AgentId)) - { - AvatarAppearance avatAppearance = m_avatarsAppearance[clientView.AgentId]; - avatAppearance.Wearables[wear.Type].AssetID = assetId; - avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID; - } - } - } - } - } - } - } - - public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams) - { - visualParams = GetDefaultVisualParams(); - wearables = AvatarWearable.DefaultWearables; - } - - private static byte[] GetDefaultVisualParams() - { - byte[] visualParams; - visualParams = new byte[218]; - for (int i = 0; i < 218; i++) - { - visualParams[i] = 100; - } - return visualParams; - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using System.Threading; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework.Data; +using TribalMedia.Framework.Data; + +namespace OpenSim.Region.Environment.Modules +{ + public class AvatarFactoryModule : IAvatarFactory + { + private Scene m_scene = null; + private readonly Dictionary m_avatarsAppearance = new Dictionary(); + + private bool m_enablePersist = false; + private string m_connectionString; + private bool m_configured = false; + private BaseDatabaseConnector m_databaseMapper; + private AppearanceTableMapper m_appearanceMapper; + + private Dictionary m_fetchesInProgress = new Dictionary(); + private object m_syncLock = new object(); + + public bool TryGetAvatarAppearance(LLUUID avatarId, out AvatarAppearance appearance) + { + + //should only let one thread at a time do this part + EventWaitHandle waitHandle = null; + bool fetchInProgress = false; + lock (m_syncLock) + { + appearance = CheckCache(avatarId); + if (appearance != null) + { + return true; + } + + //not in cache so check to see if another thread is already fetching it + if (m_fetchesInProgress.TryGetValue(avatarId, out waitHandle)) + { + fetchInProgress = true; + } + else + { + fetchInProgress = false; + + //no thread already fetching this appearance, so add a wait handle to list + //for any following threads that want the same appearance + waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); + m_fetchesInProgress.Add(avatarId, waitHandle); + } + } + + if (fetchInProgress) + { + waitHandle.WaitOne(); + appearance = CheckCache(avatarId); + if (appearance != null) + { + waitHandle = null; + return true; + } + else + { + waitHandle = null; + return false; + } + } + else + { + Thread.Sleep(5000); + + //this is the first thread to request this appearance + //so let it check the db and if not found then create a default appearance + //and add that to the cache + appearance = CheckDatabase(avatarId); + if (appearance != null) + { + //appearance has now been added to cache so lets pulse any waiting threads + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + // waitHandle.Close(); + waitHandle = null; + return true; + } + + //not found a appearance for the user, so create a new default one + appearance = CreateDefault(avatarId); + if (appearance != null) + { + //update database + if (m_enablePersist) + { + m_appearanceMapper.Add(avatarId.UUID, appearance); + } + + //add appearance to dictionary cache + lock (m_avatarsAppearance) + { + m_avatarsAppearance[avatarId] = appearance; + } + + //appearance has now been added to cache so lets pulse any waiting threads + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + // waitHandle.Close(); + waitHandle = null; + return true; + } + else + { + //something went wrong, so release the wait handle and remove it + //all waiting threads will fail to find cached appearance + //but its better for them to fail than wait for ever + lock (m_syncLock) + { + m_fetchesInProgress.Remove(avatarId); + waitHandle.Set(); + } + //waitHandle.Close(); + waitHandle = null; + return false; + } + } + } + + private AvatarAppearance CreateDefault(LLUUID avatarId) + { + AvatarAppearance appearance = null; + AvatarWearable[] wearables; + byte[] visualParams; + GetDefaultAvatarAppearance(out wearables, out visualParams); + appearance = new AvatarAppearance(avatarId, wearables, visualParams); + + return appearance; + } + + private AvatarAppearance CheckDatabase(LLUUID avatarId) + { + AvatarAppearance appearance = null; + if (m_enablePersist) + { + if (m_appearanceMapper.TryGetValue(avatarId.UUID, out appearance)) + { + appearance.VisualParams = GetDefaultVisualParams(); + appearance.TextureEntry = AvatarAppearance.GetDefaultTextureEntry(); + lock (m_avatarsAppearance) + { + m_avatarsAppearance[avatarId] = appearance; + } + } + } + return appearance; + } + + private AvatarAppearance CheckCache(LLUUID avatarId) + { + AvatarAppearance appearance = null; + lock (m_avatarsAppearance) + { + if (m_avatarsAppearance.ContainsKey(avatarId)) + { + appearance = m_avatarsAppearance[avatarId]; + } + } + return appearance; + } + + public void Initialise(Scene scene, IConfigSource source) + { + scene.RegisterModuleInterface(this); + scene.EventManager.OnNewClient += NewClient; + + if (m_scene == null) + { + m_scene = scene; + } + + if (!m_configured) + { + m_configured = true; + try + { + m_enablePersist = source.Configs["Startup"].GetBoolean("appearance_persist", false); + m_connectionString = source.Configs["Startup"].GetString("appearance_connection_string", ""); + } + catch (Exception) + { + } + if (m_enablePersist) + { + m_databaseMapper = new MySQLDatabaseMapper(m_connectionString); + m_appearanceMapper = new AppearanceTableMapper(m_databaseMapper, "AvatarAppearance"); + } + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "Default Avatar Factory"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public void NewClient(IClientAPI client) + { + client.OnAvatarNowWearing += AvatarIsWearing; + } + + public void RemoveClient(IClientAPI client) + { + // client.OnAvatarNowWearing -= AvatarIsWearing; + } + + public void AvatarIsWearing(Object sender, AvatarWearingArgs e) + { + IClientAPI clientView = (IClientAPI)sender; + CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(clientView.AgentId); + if (profile != null) + { + if (profile.RootFolder != null) + { + if (m_avatarsAppearance.ContainsKey(clientView.AgentId)) + { + AvatarAppearance avatAppearance = null; + lock (m_avatarsAppearance) + { + avatAppearance = m_avatarsAppearance[clientView.AgentId]; + } + + foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) + { + if (wear.Type < 13) + { + if (wear.ItemID == LLUUID.Zero) + { + avatAppearance.Wearables[wear.Type].ItemID = LLUUID.Zero; + avatAppearance.Wearables[wear.Type].AssetID = LLUUID.Zero; + + UpdateDatabase(clientView.AgentId, avatAppearance); + } + else + { + LLUUID assetId; + + InventoryItemBase baseItem = profile.RootFolder.HasItem(wear.ItemID); + if (baseItem != null) + { + assetId = baseItem.assetID; + avatAppearance.Wearables[wear.Type].AssetID = assetId; + avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID; + + UpdateDatabase(clientView.AgentId, avatAppearance); + } + } + } + } + } + } + } + } + + public void UpdateDatabase(LLUUID userID, AvatarAppearance avatAppearance) + { + if (m_enablePersist) + { + m_appearanceMapper.Update(userID.UUID, avatAppearance); + } + } + + public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams) + { + visualParams = GetDefaultVisualParams(); + wearables = AvatarWearable.DefaultWearables; + } + + private static byte[] GetDefaultVisualParams() + { + byte[] visualParams; + visualParams = new byte[218]; + for (int i = 0; i < 218; i++) + { + visualParams[i] = 100; + } + return visualParams; + } + } +} diff --git a/OpenSim/Region/Environment/Modules/AvatarProfilesModule.cs b/OpenSim/Region/Environment/Modules/AvatarProfilesModule.cs index cd1bd6f551..0d22acabf9 100644 --- a/OpenSim/Region/Environment/Modules/AvatarProfilesModule.cs +++ b/OpenSim/Region/Environment/Modules/AvatarProfilesModule.cs @@ -1,94 +1,94 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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 libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class AvatarProfilesModule : IRegionModule - { - private Scene m_scene; - - public AvatarProfilesModule() - { - } - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "AvatarProfilesModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - - public void NewClient(IClientAPI client) - { - client.OnRequestAvatarProperties += RequestAvatarProperty; - } - - public void RemoveClient(IClientAPI client) - { - client.OnRequestAvatarProperties -= RequestAvatarProperty; - } - - /// - /// - /// - /// - /// - public void RequestAvatarProperty(IClientAPI remoteClient, LLUUID avatarID) - { - string about = "OpenSim crash test dummy"; - string bornOn = "Before now"; - string flAbout = "First life? What is one of those? OpenSim is my life!"; - LLUUID partner = new LLUUID("11111111-1111-0000-0000-000100bba000"); - remoteClient.SendAvatarProperties(avatarID, about, bornOn, "", flAbout, 0, LLUUID.Zero, LLUUID.Zero, "", - partner); - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class AvatarProfilesModule : IRegionModule + { + private Scene m_scene; + + public AvatarProfilesModule() + { + } + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + m_scene.EventManager.OnNewClient += NewClient; + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "AvatarProfilesModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + public void NewClient(IClientAPI client) + { + client.OnRequestAvatarProperties += RequestAvatarProperty; + } + + public void RemoveClient(IClientAPI client) + { + client.OnRequestAvatarProperties -= RequestAvatarProperty; + } + + /// + /// + /// + /// + /// + public void RequestAvatarProperty(IClientAPI remoteClient, LLUUID avatarID) + { + string about = "OpenSim crash test dummy"; + string bornOn = "Before now"; + string flAbout = "First life? What is one of those? OpenSim is my life!"; + LLUUID partner = new LLUUID("11111111-1111-0000-0000-000100bba000"); + remoteClient.SendAvatarProperties(avatarID, about, bornOn, System.String.Empty, flAbout, 0, LLUUID.Zero, LLUUID.Zero, System.String.Empty, + partner); + } + } +} diff --git a/OpenSim/Region/Environment/Modules/BetaGridLikeMoneyModule.cs b/OpenSim/Region/Environment/Modules/BetaGridLikeMoneyModule.cs new file mode 100644 index 0000000000..649b80ef11 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/BetaGridLikeMoneyModule.cs @@ -0,0 +1,318 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 Nini.Config; +using System; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using libsecondlife; +using MoneyTransferArgs = OpenSim.Region.Environment.Scenes.EventManager.MoneyTransferArgs; + +namespace OpenSim.Region.Environment.Modules +{ + public class BetaGridLikeMoneyModule: IRegionModule + { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private Dictionary m_scenel = new Dictionary(); + + private IConfigSource m_gConfig; + + private bool m_keepMoneyAcrossLogins = true; + + private int m_minFundsBeforeRefresh = 100; + + private int m_stipend = 1000; + + private bool m_enabled = true; + + + + private Dictionary m_KnownClientFunds = new Dictionary(); + + + + private bool gridmode = false; + + public void Initialise(Scene scene, IConfigSource config) + { + m_gConfig = config; + ReadConfigAndPopulate(); + + if (m_enabled) + { + lock (m_scenel) + { + + if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle)) + { + m_scenel[scene.RegionInfo.RegionHandle] = scene; + } + else + { + m_scenel.Add(scene.RegionInfo.RegionHandle, scene); + } + } + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMoneyTransfer += MoneyTransferAction; + scene.EventManager.OnClientClosed += ClientClosed; + } + } + private void ReadConfigAndPopulate() + { + IConfig startupConfig = m_gConfig.Configs["Startup"]; + gridmode = startupConfig.GetBoolean("gridmode", false); + m_enabled = (startupConfig.GetString("moneymodule", "BetaGridLikeMoneyModule") == "BetaGridLikeMoneyModule"); + + } + + private void OnNewClient(IClientAPI client) + { + // Here we check if we're in grid mode + // I imagine that the 'check balance' + // function for the client should be here or shortly after + + if (gridmode) + { + CheckExistAndRefreshFunds(client.AgentId); + } + else + { + CheckExistAndRefreshFunds(client.AgentId); + } + + // Subscribe to Money messages + client.OnMoneyBalanceRequest += SendMoneyBalance; + client.OnLogout += ClientClosed; + + } + + public void ClientClosed(LLUUID AgentID) + { + lock (m_KnownClientFunds) + { + if (!m_keepMoneyAcrossLogins) + m_KnownClientFunds.Remove(AgentID); + } + + } + + private void MoneyTransferAction (Object osender, MoneyTransferArgs e) + { + IClientAPI sender = null; + IClientAPI receiver = null; + + sender = LocateClientObject(e.sender); + if (sender != null) + { + + + receiver = LocateClientObject(e.reciever); + bool transactionresult = doMoneyTranfer(e.sender, e.reciever, e.amount); + + if (e.sender != e.reciever) + { + if (sender != null) + { + sender.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(e.sender)); + } + } + + if (receiver != null) + { + receiver.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(e.reciever)); + } + + + } + else + { + m_log.Warn("[MONEY]: Potential Fraud Warning, got money transfer request for avatar that isn't in this simulator - Details; Sender:" + e.sender.ToString() + " Reciver: " + e.reciever.ToString() + " Amount: " + e.amount.ToString()); + } + } + + private bool doMoneyTranfer(LLUUID Sender, LLUUID Receiver, int amount) + { + bool result = false; + if (amount >= 0) + { + lock (m_KnownClientFunds) + { + // If we don't know about the sender, then the sender can't + // actually be here and therefore this is likely fraud or outdated. + if (m_KnownClientFunds.ContainsKey(Sender)) + { + // Does the sender have enough funds to give? + if (m_KnownClientFunds[Sender] >= amount) + { + // Subtract the funds from the senders account + m_KnownClientFunds[Sender] -= amount; + + // do we know about the receiver? + if (!m_KnownClientFunds.ContainsKey(Receiver)) + { + // Make a record for them so they get the updated balance when they login + CheckExistAndRefreshFunds(Receiver); + } + + //Add the amount to the Receiver's funds + m_KnownClientFunds[Receiver] += amount; + result = true; + } + else + { + // These below are redundant to make this clearer to read + result = false; + } + } + else + { + result = false; + } + } + } + return result; + } + + private IClientAPI LocateClientObject(LLUUID AgentID) + { + ScenePresence tPresence = null; + IClientAPI rclient = null; + + lock (m_scenel) + { + foreach (Scene _scene in m_scenel.Values) + { + tPresence = _scene.GetScenePresence(AgentID); + if (tPresence != null) + { + if (!tPresence.IsChildAgent) + { + rclient = tPresence.ControllingClient; + } + } + if (rclient != null) + { + return rclient; + } + } + + } + return null; + } + + public void ClientClosed(IClientAPI client) + { + ClientClosed(client.AgentId); + } + + public void SendMoneyBalance(IClientAPI client, LLUUID agentID, LLUUID SessionID, LLUUID TransactionID) + { + if (client.AgentId == agentID && client.SessionId == SessionID) + { + + int returnfunds = 0; + + try + { + returnfunds = GetFundsForAgentID(agentID); + } + catch (System.Exception e) + { + client.SendAlertMessage(e.Message + " "); + } + + client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds); + } + else + { + client.SendAlertMessage("Unable to send your money balance to you!"); + } + } + + private void CheckExistAndRefreshFunds(LLUUID agentID) + { + lock (m_KnownClientFunds) + { + if (!m_KnownClientFunds.ContainsKey(agentID)) + { + m_KnownClientFunds.Add(agentID, m_stipend); + } + else + { + if (m_KnownClientFunds[agentID] <= m_minFundsBeforeRefresh) + { + m_KnownClientFunds[agentID] = m_stipend; + } + } + } + } + private int GetFundsForAgentID(LLUUID AgentID) + { + int returnfunds = 0; + lock (m_KnownClientFunds) + { + if (m_KnownClientFunds.ContainsKey(AgentID)) + { + returnfunds = m_KnownClientFunds[AgentID]; + } + else + { + throw new Exception("Unable to get funds."); + } + } + return returnfunds; + } + + public void PostInitialise() + { + } + + + + public void Close() + { + } + + public string Name + { + get { return "BetaGridLikeMoneyModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + } + +} diff --git a/OpenSim/Region/Environment/Modules/ChatModule.cs b/OpenSim/Region/Environment/Modules/ChatModule.cs index 255bc6e238..c146941beb 100644 --- a/OpenSim/Region/Environment/Modules/ChatModule.cs +++ b/OpenSim/Region/Environment/Modules/ChatModule.cs @@ -1,376 +1,838 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Generic; -using System.IO; -using System.Net.Sockets; -using System.Text.RegularExpressions; -using System.Threading; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class ChatModule : IRegionModule, ISimChat - { - private List m_scenes = new List(); - private LogBase m_log; - - private int m_whisperdistance = 10; - private int m_saydistance = 30; - private int m_shoutdistance = 100; - - private IRCChatModule m_irc = null; - - public ChatModule() - { - m_log = MainLog.Instance; - } - - public void Initialise(Scene scene, IConfigSource config) - { - // wrap this in a try block so that defaults will work if - // the config file doesn't specify otherwise. - try - { - m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); - m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); - m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); - } - catch (Exception) - { - } - - if (!m_scenes.Contains(scene)) - { - m_scenes.Add(scene); - scene.EventManager.OnNewClient += NewClient; - scene.RegisterModuleInterface(this); - } - - // setup IRC Relay - m_irc = new IRCChatModule(config); - } - - public void PostInitialise() - { - if (m_irc.Enabled) - { - m_irc.Connect(m_scenes); - } - } - - public void Close() - { - m_irc.Close(); - } - - public string Name - { - get { return "ChatModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public void NewClient(IClientAPI client) - { - client.OnChatFromViewer += SimChat; - } - - private void TrySendChatMessage(ScenePresence presence, LLVector3 fromPos, LLVector3 regionPos, - LLUUID fromAgentID, string fromName, ChatTypeEnum type, string message) - { - if (!presence.IsChildAgent) - { - LLVector3 fromRegionPos = fromPos + regionPos; - LLVector3 toRegionPos = presence.AbsolutePosition + regionPos; - int dis = Math.Abs((int) Util.GetDistanceTo(toRegionPos, fromRegionPos)); - - if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance || - type == ChatTypeEnum.Say && dis > m_saydistance || - type == ChatTypeEnum.Shout && dis > m_shoutdistance) - { - return; - } - - // TODO: should change so the message is sent through the avatar rather than direct to the ClientView - presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName, fromAgentID); - } - } - - public void SimChat(Object sender, ChatFromViewerArgs e) - { - ScenePresence avatar = null; - - //TODO: Move ForEachScenePresence and others into IScene. - Scene scene = (Scene) e.Scene; - - //TODO: Remove the need for this check - if (scene == null) - scene = m_scenes[0]; - - // Filled in since it's easier than rewriting right now. - LLVector3 fromPos = e.Position; - LLVector3 regionPos = new LLVector3(scene.RegionInfo.RegionLocX*256, scene.RegionInfo.RegionLocY*256, 0); - - string fromName = e.From; - string message = e.Message; - LLUUID fromAgentID = LLUUID.Zero; - - if (e.Sender != null) - { - avatar = scene.GetScenePresence(e.Sender.AgentId); - } - - if (avatar != null) - { - fromPos = avatar.AbsolutePosition; - regionPos = new LLVector3(scene.RegionInfo.RegionLocX*256, scene.RegionInfo.RegionLocY*256, 0); - fromName = avatar.Firstname + " " + avatar.Lastname; - fromAgentID = e.Sender.AgentId; - } - - if (e.Message.Length > 0) - { - if (m_irc.Connected && (avatar != null)) // this is to keep objects from talking to IRC - { - m_irc.PrivMsg(fromName, scene.RegionInfo.RegionName, e.Message); - } - } - - if (e.Channel == 0) - { - foreach (Scene s in m_scenes) - { - s.ForEachScenePresence(delegate(ScenePresence presence) - { - TrySendChatMessage(presence, fromPos, regionPos, - fromAgentID, fromName, e.Type, message); - }); - } - } - } - } - - internal class IRCChatModule - { - private string m_server = null; - private uint m_port = 6668; - private string m_user = "USER OpenSimBot 8 * :I'm a OpenSim to irc bot"; - private string m_nick = null; - private string m_channel = null; - - private NetworkStream m_stream; - private TcpClient m_tcp; - private StreamWriter m_writer; - private StreamReader m_reader; - - private Thread pingSender; - private Thread listener; - - private bool m_enabled = false; - private bool m_connected = false; - - private List m_scenes = null; - private LogBase m_log; - - public IRCChatModule(IConfigSource config) - { - m_nick = "OSimBot" + Util.RandomClass.Next(1, 99); - m_tcp = null; - m_writer = null; - m_reader = null; - - try - { - m_server = config.Configs["IRC"].GetString("server"); - m_nick = config.Configs["IRC"].GetString("nick"); - m_channel = config.Configs["IRC"].GetString("channel"); - m_port = (uint) config.Configs["IRC"].GetInt("port", (int) m_port); - m_user = config.Configs["IRC"].GetString("username", m_user); - if (m_server != null && m_nick != null && m_channel != null) - { - m_enabled = true; - } - } - catch (Exception) - { - MainLog.Instance.Verbose("CHAT", "No IRC config information, skipping IRC bridge configuration"); - } - m_log = MainLog.Instance; - } - - public bool Connect(List scenes) - { - try - { - m_scenes = scenes; - - m_tcp = new TcpClient(m_server, (int) m_port); - m_log.Verbose("IRC", "Connecting..."); - m_stream = m_tcp.GetStream(); - m_log.Verbose("IRC", "Connected to " + m_server); - m_reader = new StreamReader(m_stream); - m_writer = new StreamWriter(m_stream); - - pingSender = new Thread(new ThreadStart(PingRun)); - pingSender.Start(); - - listener = new Thread(new ThreadStart(ListenerRun)); - listener.Start(); - - m_writer.WriteLine(m_user); - m_writer.Flush(); - m_writer.WriteLine("NICK " + m_nick); - m_writer.Flush(); - m_writer.WriteLine("JOIN " + m_channel); - m_writer.Flush(); - m_log.Verbose("IRC", "Connection fully established"); - m_connected = true; - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - } - return m_connected; - } - - public bool Enabled - { - get { return m_enabled; } - } - - public bool Connected - { - get { return m_connected; } - } - - public void PrivMsg(string from, string region, string msg) - { - try - { - m_writer.WriteLine("PRIVMSG {0} :<{1} in {2}>: {3}", m_channel, from, region, msg); - m_writer.Flush(); - } - catch (IOException) - { - m_log.Error("IRC", "Disconnected from IRC server."); - listener.Abort(); - pingSender.Abort(); - m_connected = false; - } - } - - private Dictionary ExtractMsg(string input) - { - Dictionary result = null; - string regex = @":(?\w*)!~(?\S*) PRIVMSG (?\S+) :(?.*)"; - Regex RE = new Regex(regex, RegexOptions.Multiline); - MatchCollection matches = RE.Matches(input); - // Get some direct matches $1 $4 is a - if ((matches.Count == 1) && (matches[0].Groups.Count == 5)) - { - result = new Dictionary(); - result.Add("nick", matches[0].Groups[1].Value); - result.Add("user", matches[0].Groups[2].Value); - result.Add("channel", matches[0].Groups[3].Value); - result.Add("msg", matches[0].Groups[4].Value); - } - else - { - m_log.Verbose("IRC", "Number of matches: " + matches.Count); - if (matches.Count > 0) - { - m_log.Verbose("IRC", "Number of groups: " + matches[0].Groups.Count); - } - } - return result; - } - - public void PingRun() - { - while (true) - { - m_writer.WriteLine("PING :" + m_server); - m_writer.Flush(); - Thread.Sleep(15000); - } - } - - public void ListenerRun() - { - string inputLine; - LLVector3 pos = new LLVector3(128, 128, 20); - while (true) - { - while ((inputLine = m_reader.ReadLine()) != null) - { - // Console.WriteLine(inputLine); - if (inputLine.Contains(m_channel)) - { - Dictionary data = ExtractMsg(inputLine); - if (data != null) - { - foreach (Scene m_scene in m_scenes) - { - m_scene.ForEachScenePresence(delegate(ScenePresence avatar) - { - if (!avatar.IsChildAgent) - { - avatar.ControllingClient.SendChatMessage( - Helpers.StringToField(data["msg"]), 255, - pos, data["nick"], - LLUUID.Zero); - } - }); - } - } - } - } - Thread.Sleep(50); - } - } - - public void Close() - { - listener.Abort(); - pingSender.Abort(); - m_writer.Close(); - m_reader.Close(); - m_tcp.Close(); - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using System.IO; +using System.Net.Sockets; +using System.Text.RegularExpressions; +using System.Threading; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class ChatModule : IRegionModule, ISimChat + { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private List m_scenes = new List(); + + private int m_whisperdistance = 10; + private int m_saydistance = 30; + private int m_shoutdistance = 100; + + private IRCChatModule m_irc = null; + + private string m_last_new_user = null; + private string m_last_leaving_user = null; + private string m_defaultzone = null; + internal object m_syncInit = new object(); + internal object m_syncLogout = new object(); + private Thread m_irc_connector=null; + + public void Initialise(Scene scene, IConfigSource config) + { + lock (m_syncInit) + { + // wrap this in a try block so that defaults will work if + // the config file doesn't specify otherwise. + try + { + m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); + m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); + m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); + } + catch (Exception) + { + } + try + { + m_defaultzone = config.Configs["IRC"].GetString("nick","Sim"); + } + catch (Exception) + { + } + + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + scene.EventManager.OnNewClient += NewClient; + scene.RegisterModuleInterface(this); + } + + // setup IRC Relay + if (m_irc == null) { m_irc = new IRCChatModule(config); } + if (m_irc_connector == null) { + m_irc_connector = new Thread(IRCConnectRun); + m_irc_connector.Name = "IRCConnectorThread"; + m_irc_connector.IsBackground = true; + } + + } + } + + public void PostInitialise() + { + if (m_irc.Enabled) + { + try + { + //m_irc.Connect(m_scenes); + if (m_irc_connector == null) { + m_irc_connector = new Thread(IRCConnectRun); + m_irc_connector.Name = "IRCConnectorThread"; + m_irc_connector.IsBackground = true; + } + if (!m_irc_connector.IsAlive) { + m_irc_connector.Start(); + OpenSim.Framework.ThreadTracker.Add(m_irc_connector); + } + } + catch (Exception ex) + { + } + + } + } + + public void Close() + { + m_irc.Close(); + } + + public string Name + { + get { return "ChatModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public void NewClient(IClientAPI client) + { + try + { + client.OnChatFromViewer += SimChat; + + if ((m_irc.Enabled) && (m_irc.Connected)) + { + string clientName = client.FirstName + " " + client.LastName; + // handles simple case. May not work for hundred connecting in per second. + // and the NewClients calles getting interleved + // but filters out multiple reports + if (clientName != m_last_new_user) + { + m_last_new_user = clientName; + string clientRegion = FindClientRegion(client.FirstName, client.LastName); + m_irc.PrivMsg(m_irc.Nick, "Sim", "notices " + clientName + " in "+clientRegion); + } + } + client.OnLogout += ClientLoggedOut; + client.OnConnectionClosed += ClientLoggedOut; + //client.OnDisconnectUser += ClientLoggedOut; + client.OnLogout += ClientLoggedOut; + } + catch (Exception ex) + { + m_log.Error("[IRC]: NewClient exception trap:" + ex.ToString()); + } + } + + public void ClientLoggedOut(IClientAPI client) + { + lock (m_syncLogout) + { + try + { + if ((m_irc.Enabled) && (m_irc.Connected)) + { + string clientName = client.FirstName + " " + client.LastName; + string clientRegion = FindClientRegion(client.FirstName, client.LastName); + // handles simple case. May not work for hundred connecting in per second. + // and the NewClients calles getting interleved + // but filters out multiple reports + if (clientName != m_last_leaving_user) + { + m_last_leaving_user = clientName; + m_irc.PrivMsg(m_irc.Nick, "Sim", "notices " + clientName + " left " + clientRegion); + m_log.Info("[IRC]: IRC watcher notices " + clientName + " left " + clientRegion); + } + } + } + catch (Exception ex) + { + m_log.Error("[IRC]: ClientLoggedOut exception trap:" + ex.ToString()); + } + } + + } + private void TrySendChatMessage(ScenePresence presence, LLVector3 fromPos, LLVector3 regionPos, + LLUUID fromAgentID, string fromName, ChatTypeEnum type, string message) + { + if (!presence.IsChildAgent) + { + LLVector3 fromRegionPos = fromPos + regionPos; + LLVector3 toRegionPos = presence.AbsolutePosition + regionPos; + int dis = Math.Abs((int) Util.GetDistanceTo(toRegionPos, fromRegionPos)); + + if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance || + type == ChatTypeEnum.Say && dis > m_saydistance || + type == ChatTypeEnum.Shout && dis > m_shoutdistance) + { + return; + } + + // TODO: should change so the message is sent through the avatar rather than direct to the ClientView + presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName, fromAgentID); + } + } + + public void SimChat(Object sender, ChatFromViewerArgs e) + { + // FROM: Sim TO: IRC + + ScenePresence avatar = null; + + //TODO: Move ForEachScenePresence and others into IScene. + Scene scene = (Scene) e.Scene; + + //TODO: Remove the need for this check + if (scene == null) + scene = m_scenes[0]; + + // Filled in since it's easier than rewriting right now. + LLVector3 fromPos = e.Position; + LLVector3 regionPos = new LLVector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); + + string fromName = e.From; + string message = e.Message; + LLUUID fromAgentID = LLUUID.Zero; + + if (e.Sender != null) + { + avatar = scene.GetScenePresence(e.Sender.AgentId); + } + + if (avatar != null) + { + fromPos = avatar.AbsolutePosition; + regionPos = new LLVector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); + fromName = avatar.Firstname + " " + avatar.Lastname; + fromAgentID = e.Sender.AgentId; + } + + // Try to reconnect to server if not connected + if ((m_irc.Enabled)&&(!m_irc.Connected)) + { + // In a non-blocking way. Eventually the connector will get it started + try + { + if (m_irc_connector == null) { m_irc_connector = new Thread(IRCConnectRun); + m_irc_connector.Name = "IRCConnectorThread"; + m_irc_connector.IsBackground = true; + } + if (!m_irc_connector.IsAlive) { + m_irc_connector.Start(); + OpenSim.Framework.ThreadTracker.Add(m_irc_connector); + } + } + catch (Exception ex) + { + } + } + + if (e.Message.Length > 0) + { + if (m_irc.Connected && (avatar != null)) // this is to keep objects from talking to IRC + { + m_irc.PrivMsg(fromName, scene.RegionInfo.RegionName, e.Message); + } + } + + if (e.Channel == 0) + { + foreach (Scene s in m_scenes) + { + s.ForEachScenePresence(delegate(ScenePresence presence) + { + TrySendChatMessage(presence, fromPos, regionPos, + fromAgentID, fromName, e.Type, message); + }); + } + } + } + + // if IRC is enabled then just keep trying using a monitor thread + public void IRCConnectRun() + { + while(true) + { + if ((m_irc.Enabled)&&(!m_irc.Connected)) + { + m_irc.Connect(m_scenes); + + } + Thread.Sleep(15000); + } + } + + public string FindClientRegion(string client_FirstName,string client_LastName) + { + string sourceRegion = null; + foreach (Scene s in m_scenes) + { + s.ForEachScenePresence(delegate(ScenePresence presence) + { + if ((presence.IsChildAgent==false) + &&(presence.Firstname==client_FirstName) + &&(presence.Lastname==client_LastName)) + { + sourceRegion = presence.Scene.RegionInfo.RegionName; + //sourceRegion= s.RegionInfo.RegionName; + } + }); + if (sourceRegion != null) return sourceRegion; + } + if (m_defaultzone == null) { m_defaultzone = "Sim"; } + return m_defaultzone; + } + } + + internal class IRCChatModule + { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private string m_server = null; + private uint m_port = 6668; + private string m_user = "USER OpenSimBot 8 * :I'm a OpenSim to irc bot"; + private string m_nick = null; + private string m_basenick = null; + private string m_channel = null; + private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"; + + private NetworkStream m_stream; + private TcpClient m_tcp; + private StreamWriter m_writer; + private StreamReader m_reader; + + private Thread pingSender; + private Thread listener; + internal object m_syncConnect = new object(); + + private bool m_enabled = false; + private bool m_connected = false; + + private List m_scenes = null; + private List m_last_scenes = null; + + public IRCChatModule(IConfigSource config) + { + m_nick = "OSimBot" + Util.RandomClass.Next(1, 99); + m_tcp = null; + m_writer = null; + m_reader = null; + + // configuration in OpenSim.ini + // [IRC] + // server = chat.freenode.net + // nick = OSimBot_mysim + // ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot + // ; username is the IRC command line sent + // ; USER * : + // channel = #opensim-regions + // port = 6667 + // ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message + // ;for : : + // ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}" + // ;for : - : + // ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}" + // ;for : - from : + // ;msgformat = "PRIVMSG {0} : {3} - from {1}" + // Traps I/O disconnects so it does not crash the sim + // Trys to reconnect if disconnected and someone says something + // Tells IRC server "QUIT" when doing a close (just to be nice) + // Default port back to 6667 + + try + { + m_server = config.Configs["IRC"].GetString("server"); + m_nick = config.Configs["IRC"].GetString("nick"); + m_basenick = m_nick; + m_channel = config.Configs["IRC"].GetString("channel"); + m_port = (uint) config.Configs["IRC"].GetInt("port", (int) m_port); + m_user = config.Configs["IRC"].GetString("username", m_user); + m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat); + if (m_server != null && m_nick != null && m_channel != null) + { + m_nick = m_nick + Util.RandomClass.Next(1, 99); + m_enabled = true; + } + } + catch (Exception) + { + m_log.Info("[CHAT]: No IRC config information, skipping IRC bridge configuration"); + } + } + + public bool Connect(List scenes) + { + lock (m_syncConnect) + { + try + { + if (m_connected) return true; + m_scenes = scenes; + if (m_last_scenes == null) { m_last_scenes = scenes; } + + m_tcp = new TcpClient(m_server, (int)m_port); + m_log.Info("[IRC]: Connecting..."); + m_stream = m_tcp.GetStream(); + m_log.Info("[IRC]: Connected to " + m_server); + m_reader = new StreamReader(m_stream); + m_writer = new StreamWriter(m_stream); + + pingSender = new Thread(new ThreadStart(PingRun)); + pingSender.Name = "PingSenderThread"; + pingSender.IsBackground = true; + pingSender.Start(); + OpenSim.Framework.ThreadTracker.Add(pingSender); + + listener = new Thread(new ThreadStart(ListenerRun)); + listener.Name = "IRCChatModuleListenerThread"; + listener.IsBackground = true; + listener.Start(); + OpenSim.Framework.ThreadTracker.Add(listener); + + m_writer.WriteLine(m_user); + m_writer.Flush(); + m_writer.WriteLine("NICK " + m_nick); + m_writer.Flush(); + m_writer.WriteLine("JOIN " + m_channel); + m_writer.Flush(); + m_log.Info("[IRC]: Connection fully established"); + m_connected = true; + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + return m_connected; + } + } + + public bool Enabled + { + get { return m_enabled; } + } + + public bool Connected + { + get { return m_connected; } + } + + public string Nick + { + get { return m_nick; } + } + + public void Reconnect() + { + m_connected = false; + listener.Abort(); + pingSender.Abort(); + m_writer.Close(); + m_reader.Close(); + m_tcp.Close(); + if (m_enabled) { Connect(m_last_scenes); } + + } + + public void PrivMsg(string from, string region, string msg) + { + // One message to the IRC server + + try + { + if (m_privmsgformat == null) + { + m_writer.WriteLine("PRIVMSG {0} :<{1} in {2}>: {3}", m_channel, from, region, msg); + } + else + { + m_writer.WriteLine(m_privmsgformat, m_channel, from, region, msg); + } + m_writer.Flush(); + m_log.Info("[IRC]: PrivMsg " + from + " in " + region + " :" + msg); + } + catch (IOException) + { + m_log.Error("[IRC]: Disconnected from IRC server.(PrivMsg)"); + Reconnect(); + } + catch (Exception ex) + { + m_log.Error("[IRC]: PrivMsg exception trap:" + ex.ToString()); + } + } + + private Dictionary ExtractMsg(string input) + { + //examines IRC commands and extracts any private messages + // which will then be reboadcast in the Sim + + m_log.Info("[IRC]: ExtractMsg: " + input); + Dictionary result = null; + //string regex = @":(?\w*)!~(?\S*) PRIVMSG (?\S+) :(?.*)"; + string regex = @":(?\w*)!(?\S*) PRIVMSG (?\S+) :(?.*)"; + Regex RE = new Regex(regex, RegexOptions.Multiline); + MatchCollection matches = RE.Matches(input); + // Get some direct matches $1 $4 is a + if ((matches.Count == 1) && (matches[0].Groups.Count == 5)) + { + result = new Dictionary(); + result.Add("nick", matches[0].Groups[1].Value); + result.Add("user", matches[0].Groups[2].Value); + result.Add("channel", matches[0].Groups[3].Value); + result.Add("msg", matches[0].Groups[4].Value); + } + else + { + m_log.Info("[IRC]: Number of matches: " + matches.Count); + if (matches.Count > 0) + { + m_log.Info("[IRC]: Number of groups: " + matches[0].Groups.Count); + } + } + return result; + } + + public void PingRun() + { + // IRC keep alive thread + // send PING ever 15 seconds + while (true) + { + try + { + if (m_connected == true) + { + m_writer.WriteLine("PING :" + m_server); + m_writer.Flush(); + Thread.Sleep(15000); + } + } + catch (IOException) + { + m_log.Error("[IRC]: Disconnected from IRC server.(PingRun)"); + Reconnect(); + } + catch (Exception ex) + { + m_log.Error("[IRC]: PingRun exception trap:" + ex.ToString() + "\n" + ex.StackTrace); + } + } + } + + public void ListenerRun() + { + string inputLine; + LLVector3 pos = new LLVector3(128, 128, 20); + while (true) + { + try + { + while ((m_connected == true) && ((inputLine = m_reader.ReadLine()) != null)) + { + // Console.WriteLine(inputLine); + if (inputLine.Contains(m_channel)) + { + Dictionary data = ExtractMsg(inputLine); + // Any chat ??? + if (data != null) + { + foreach (Scene m_scene in m_scenes) + { + m_scene.ForEachScenePresence(delegate(ScenePresence avatar) + { + if (!avatar.IsChildAgent) + { + avatar.ControllingClient.SendChatMessage( + Helpers.StringToField(data["msg"]), 255, + pos, data["nick"], + LLUUID.Zero); + } + }); + } + + + } + else + { + // Was an command from the IRC server + ProcessIRCCommand(inputLine); + } + } + else + { + // Was an command from the IRC server + ProcessIRCCommand(inputLine); + } + Thread.Sleep(150); + } + } + catch (IOException) + { + m_log.Error("[IRC]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)"); + Reconnect(); + } + catch (Exception ex) + { + m_log.Error("[IRC]: ListenerRun exception trap:" + ex.ToString() + "\n" + ex.StackTrace); + } + } + } + + public void BroadcastSim(string message,string sender) + { + LLVector3 pos = new LLVector3(128, 128, 20); + try + { + foreach (Scene m_scene in m_scenes) + { + m_scene.ForEachScenePresence(delegate(ScenePresence avatar) + { + if (!avatar.IsChildAgent) + { + avatar.ControllingClient.SendChatMessage( + Helpers.StringToField(message), 255, + pos, sender, + LLUUID.Zero); + } + }); + } + } + catch (Exception ex) // IRC gate should not crash Sim + { + m_log.Error("[IRC]: BroadcastSim Exception Trap:" + ex.ToString() + "\n" + ex.StackTrace); + + } + } + + public enum ErrorReplies + { + NotRegistered = 451, // ":You have not registered" + NicknameInUse = 433 // " :Nickname is already in use" + } + + public enum Replies + { + MotdStart = 375, // ":- Message of the day - " + Motd = 372, // ":- " + EndOfMotd = 376 // ":End of /MOTD command" + } + + public void ProcessIRCCommand(string command) + { + //m_log.Info("[IRC]: ProcessIRCCommand:" + command); + + string[] commArgs = new string[command.Split(' ').Length]; + string c_server = m_server; + + commArgs = command.Split(' '); + if (commArgs[0].Substring(0, 1) == ":") + { + commArgs[0] = commArgs[0].Remove(0, 1); + } + + if (commArgs[1] == "002") + { + // fetch the correct servername + // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/... + // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch + + c_server = (commArgs[6].Split('['))[0]; + m_server = c_server; + } + + if (commArgs[0] == "ERROR") + { + m_log.Error("[IRC]: IRC SERVER ERROR:" + command); + } + + if (commArgs[0] == "PING") + { + string p_reply = ""; + + for (int i = 1; i < commArgs.Length; i++) + { + p_reply += commArgs[i] + " "; + } + + m_writer.WriteLine("PONG " + p_reply); + m_writer.Flush(); + + } + else if (commArgs[0] == c_server) + { + // server message + try + { + Int32 commandCode = Int32.Parse(commArgs[1]); + switch (commandCode) + { + case (int)ErrorReplies.NicknameInUse: + // Gen a new name + m_nick = m_basenick + Util.RandomClass.Next(1, 99); + m_log.Error("[IRC]: IRC SERVER reports NicknameInUse, trying " + m_nick); + // Retry + m_writer.WriteLine("NICK " + m_nick); + m_writer.Flush(); + m_writer.WriteLine("JOIN " + m_channel); + m_writer.Flush(); + break; + case (int)ErrorReplies.NotRegistered: + break; + case (int)Replies.EndOfMotd: + break; + } + } + catch (Exception ex) + { + } + + } + else + { + // Normal message + string commAct = commArgs[1]; + switch (commAct) + { + case "JOIN": eventIrcJoin(commArgs); break; + case "PART": eventIrcPart(commArgs); break; + case "MODE": eventIrcMode(commArgs); break; + case "NICK": eventIrcNickChange(commArgs); break; + case "KICK": eventIrcKick(commArgs); break; + case "QUIT": eventIrcQuit(commArgs); break; + case "PONG": break; // that's nice + } + + + } + } + + public void eventIrcJoin(string[] commArgs) + { + string IrcChannel = commArgs[2]; + string IrcUser = commArgs[0].Split('!')[0]; + BroadcastSim(IrcUser + " is joining " + IrcChannel, m_nick); + + } + + public void eventIrcPart(string[] commArgs) + { + string IrcChannel = commArgs[2]; + string IrcUser = commArgs[0].Split('!')[0]; + BroadcastSim(IrcUser + " is parting " + IrcChannel, m_nick); + + } + public void eventIrcMode(string[] commArgs) + { + string IrcChannel = commArgs[2]; + string IrcUser = commArgs[0].Split('!')[0]; + string UserMode = ""; + for (int i = 3; i < commArgs.Length; i++) + { + UserMode += commArgs[i] + " "; + } + + if (UserMode.Substring(0, 1) == ":") + { + UserMode = UserMode.Remove(0, 1); + } + + } + public void eventIrcNickChange(string[] commArgs) + { + string UserOldNick = commArgs[0].Split('!')[0]; + string UserNewNick = commArgs[2].Remove(0, 1); + BroadcastSim(UserOldNick + " changed their nick to " + UserNewNick, m_nick); + + } + + public void eventIrcKick(string[] commArgs) + { + string UserKicker = commArgs[0].Split('!')[0]; + string UserKicked = commArgs[3]; + string IrcChannel = commArgs[2]; + string KickMessage = ""; + for (int i = 4; i < commArgs.Length; i++) + { + KickMessage += commArgs[i] + " "; + } + BroadcastSim(UserKicker + " kicked " + UserKicked +" on "+IrcChannel+" saying "+KickMessage, m_nick); + if (UserKicked == m_nick) + { + BroadcastSim("Hey, that was me!!!", m_nick); + + } + } + + public void eventIrcQuit(string[] commArgs) + { + string IrcUser = commArgs[0].Split('!')[0]; + string QuitMessage = ""; + + for (int i = 2; i < commArgs.Length; i++) + { + QuitMessage += commArgs[i] + " "; + } + BroadcastSim(IrcUser + " quits saying " + QuitMessage, m_nick); + + } + + + public void Close() + { + m_connected = false; + m_writer.WriteLine("QUIT :" + m_nick + " to " + m_channel + " wormhole with " + m_server + " closing"); + m_writer.Flush(); + listener.Abort(); + pingSender.Abort(); + m_writer.Close(); + m_reader.Close(); + m_tcp.Close(); + } + } +} diff --git a/OpenSim/Region/Environment/Modules/DynamicTextureModule.cs b/OpenSim/Region/Environment/Modules/DynamicTextureModule.cs index 26ff22a523..169451a026 100644 --- a/OpenSim/Region/Environment/Modules/DynamicTextureModule.cs +++ b/OpenSim/Region/Environment/Modules/DynamicTextureModule.cs @@ -1,190 +1,190 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Generic; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class DynamicTextureModule : IRegionModule, IDynamicTextureManager - { - private Dictionary RegisteredScenes = new Dictionary(); - - private Dictionary RenderPlugins = - new Dictionary(); - - private Dictionary Updaters = new Dictionary(); - - public void Initialise(Scene scene, IConfigSource config) - { - if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) - { - RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); - scene.RegisterModuleInterface(this); - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "DynamicTextureModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public void RegisterRender(string handleType, IDynamicTextureRender render) - { - if (!RenderPlugins.ContainsKey(handleType)) - { - RenderPlugins.Add(handleType, render); - } - } - - public void ReturnData(LLUUID id, byte[] data) - { - if (Updaters.ContainsKey(id)) - { - DynamicTextureUpdater updater = Updaters[id]; - if (RegisteredScenes.ContainsKey(updater.SimUUID)) - { - Scene scene = RegisteredScenes[updater.SimUUID]; - updater.DataReceived(data, scene); - } - } - } - - public LLUUID AddDynamicTextureURL(LLUUID simID, LLUUID primID, string contentType, string url, - string extraParams, int updateTimer) - { - if (RenderPlugins.ContainsKey(contentType)) - { - //Console.WriteLine("dynamic texture being created: " + url + " of type " + contentType); - - DynamicTextureUpdater updater = new DynamicTextureUpdater(); - updater.SimUUID = simID; - updater.PrimID = primID; - updater.ContentType = contentType; - updater.Url = url; - updater.UpdateTimer = updateTimer; - updater.UpdaterID = LLUUID.Random(); - updater.Params = extraParams; - - if (!Updaters.ContainsKey(updater.UpdaterID)) - { - Updaters.Add(updater.UpdaterID, updater); - } - - RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams); - return updater.UpdaterID; - } - return LLUUID.Zero; - } - - public LLUUID AddDynamicTextureData(LLUUID simID, LLUUID primID, string contentType, string data, - string extraParams, int updateTimer) - { - if (RenderPlugins.ContainsKey(contentType)) - { - DynamicTextureUpdater updater = new DynamicTextureUpdater(); - updater.SimUUID = simID; - updater.PrimID = primID; - updater.ContentType = contentType; - updater.BodyData = data; - updater.UpdateTimer = updateTimer; - updater.UpdaterID = LLUUID.Random(); - updater.Params = extraParams; - - if (!Updaters.ContainsKey(updater.UpdaterID)) - { - Updaters.Add(updater.UpdaterID, updater); - } - - RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); - return updater.UpdaterID; - } - return LLUUID.Zero; - } - - public class DynamicTextureUpdater - { - public LLUUID SimUUID; - public LLUUID UpdaterID; - public string ContentType; - public string Url; - public string BodyData; - public LLUUID PrimID; - public int UpdateTimer; - public LLUUID LastAssetID; - public string Params; - - public DynamicTextureUpdater() - { - LastAssetID = LLUUID.Zero; - UpdateTimer = 0; - BodyData = null; - } - - public void DataReceived(byte[] data, Scene scene) - { - //TODO delete the last asset(data), if it was a dynamic texture - byte[] assetData = new byte[data.Length]; - Array.Copy(data, assetData, data.Length); - AssetBase asset = new AssetBase(); - asset.FullID = LLUUID.Random(); - asset.Data = assetData; - asset.Name = "DynamicImage" + Util.RandomClass.Next(1, 10000); - asset.Type = 0; - asset.Description = "dynamic image"; - asset.Local = false; - asset.Temporary = false; - scene.AssetCache.AddAsset(asset); - - LastAssetID = asset.FullID; - - SceneObjectPart part = scene.GetSceneObjectPart(PrimID); - part.Shape.Textures = new LLObject.TextureEntry(asset.FullID); - part.ScheduleFullUpdate(); - } - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class DynamicTextureModule : IRegionModule, IDynamicTextureManager + { + private Dictionary RegisteredScenes = new Dictionary(); + + private Dictionary RenderPlugins = + new Dictionary(); + + private Dictionary Updaters = new Dictionary(); + + public void Initialise(Scene scene, IConfigSource config) + { + if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) + { + RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); + scene.RegisterModuleInterface(this); + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "DynamicTextureModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public void RegisterRender(string handleType, IDynamicTextureRender render) + { + if (!RenderPlugins.ContainsKey(handleType)) + { + RenderPlugins.Add(handleType, render); + } + } + + public void ReturnData(LLUUID id, byte[] data) + { + if (Updaters.ContainsKey(id)) + { + DynamicTextureUpdater updater = Updaters[id]; + if (RegisteredScenes.ContainsKey(updater.SimUUID)) + { + Scene scene = RegisteredScenes[updater.SimUUID]; + updater.DataReceived(data, scene); + } + } + } + + public LLUUID AddDynamicTextureURL(LLUUID simID, LLUUID primID, string contentType, string url, + string extraParams, int updateTimer) + { + if (RenderPlugins.ContainsKey(contentType)) + { + //Console.WriteLine("dynamic texture being created: " + url + " of type " + contentType); + + DynamicTextureUpdater updater = new DynamicTextureUpdater(); + updater.SimUUID = simID; + updater.PrimID = primID; + updater.ContentType = contentType; + updater.Url = url; + updater.UpdateTimer = updateTimer; + updater.UpdaterID = LLUUID.Random(); + updater.Params = extraParams; + + if (!Updaters.ContainsKey(updater.UpdaterID)) + { + Updaters.Add(updater.UpdaterID, updater); + } + + RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams); + return updater.UpdaterID; + } + return LLUUID.Zero; + } + + public LLUUID AddDynamicTextureData(LLUUID simID, LLUUID primID, string contentType, string data, + string extraParams, int updateTimer) + { + if (RenderPlugins.ContainsKey(contentType)) + { + DynamicTextureUpdater updater = new DynamicTextureUpdater(); + updater.SimUUID = simID; + updater.PrimID = primID; + updater.ContentType = contentType; + updater.BodyData = data; + updater.UpdateTimer = updateTimer; + updater.UpdaterID = LLUUID.Random(); + updater.Params = extraParams; + + if (!Updaters.ContainsKey(updater.UpdaterID)) + { + Updaters.Add(updater.UpdaterID, updater); + } + + RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); + return updater.UpdaterID; + } + return LLUUID.Zero; + } + + public class DynamicTextureUpdater + { + public LLUUID SimUUID; + public LLUUID UpdaterID; + public string ContentType; + public string Url; + public string BodyData; + public LLUUID PrimID; + public int UpdateTimer; + public LLUUID LastAssetID; + public string Params; + + public DynamicTextureUpdater() + { + LastAssetID = LLUUID.Zero; + UpdateTimer = 0; + BodyData = null; + } + + public void DataReceived(byte[] data, Scene scene) + { + //TODO delete the last asset(data), if it was a dynamic texture + byte[] assetData = new byte[data.Length]; + Array.Copy(data, assetData, data.Length); + AssetBase asset = new AssetBase(); + asset.FullID = LLUUID.Random(); + asset.Data = assetData; + asset.Name = "DynamicImage" + Util.RandomClass.Next(1, 10000); + asset.Type = 0; + asset.Description = "dynamic image"; + asset.Local = false; + asset.Temporary = true; + scene.AssetCache.AddAsset(asset); + + LastAssetID = asset.FullID; + + SceneObjectPart part = scene.GetSceneObjectPart(PrimID); + part.Shape.Textures = new LLObject.TextureEntry(asset.FullID); + part.ScheduleFullUpdate(); + } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/EmailModule.cs b/OpenSim/Region/Environment/Modules/EmailModule.cs index 8333229cae..2db4611b70 100644 --- a/OpenSim/Region/Environment/Modules/EmailModule.cs +++ b/OpenSim/Region/Environment/Modules/EmailModule.cs @@ -1,34 +1,34 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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. -* -*/ - -namespace OpenSim.Region.Environment.Modules -{ - internal class EmailModule - { - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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. +* +*/ + +namespace OpenSim.Region.Environment.Modules +{ + internal class EmailModule + { + } +} diff --git a/OpenSim/Region/Environment/Modules/FriendsModule.cs b/OpenSim/Region/Environment/Modules/FriendsModule.cs index e96f62d623..9a03aaf923 100644 --- a/OpenSim/Region/Environment/Modules/FriendsModule.cs +++ b/OpenSim/Region/Environment/Modules/FriendsModule.cs @@ -1,233 +1,222 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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 Nini.Config; -using System; -using System.Collections; -using System.Collections.Generic; -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; -using libsecondlife; - -namespace OpenSim.Region.Environment.Modules -{ - public class FriendsModule : IRegionModule - { - - private LogBase m_log; - - private Scene m_scene; - - Dictionary m_pendingFriendRequests = new Dictionary(); - - public void Initialise(Scene scene, IConfigSource config) - { - m_log = MainLog.Instance; - m_scene = scene; - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnGridInstantMessageToFriendsModule += OnGridInstantMessage; - } - - private void OnNewClient(IClientAPI client) - { - // All friends establishment protocol goes over instant message - // There's no way to send a message from the sim - // to a user to 'add a friend' without causing dialog box spam - // - // The base set of friends are added when the user signs on in their XMLRPC response - // Generated by LoginService. The friends are retreived from the database by the UserManager - - // Subscribe to instant messages - client.OnInstantMessage += OnInstantMessage; - client.OnApproveFriendRequest += OnApprovedFriendRequest; - client.OnDenyFriendRequest += OnDenyFriendRequest; - client.OnTerminateFriendship += OnTerminateFriendship; - - - } - private void OnInstantMessage(IClientAPI client,LLUUID fromAgentID, - LLUUID fromAgentSession, LLUUID toAgentID, - LLUUID imSessionID, uint timestamp, string fromAgentName, - string message, byte dialog, bool fromGroup, byte offline, - uint ParentEstateID, LLVector3 Position, LLUUID RegionID, - byte[] binaryBucket) - { - // Friend Requests go by Instant Message.. using the dialog param - // https://wiki.secondlife.com/wiki/ImprovedInstantMessage - - // 38 == Offer friendship - if (dialog == (byte)38) - { - LLUUID friendTransactionID = LLUUID.Random(); - - m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); - - m_log.Verbose("FRIEND", "38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message); - GridInstantMessage msg = new GridInstantMessage(); - msg.fromAgentID = fromAgentID.UUID; - msg.fromAgentSession = fromAgentSession.UUID; - msg.toAgentID = toAgentID.UUID; - msg.imSessionID = friendTransactionID.UUID; // This is the item we're mucking with here - m_log.Verbose("FRIEND","Filling Session: " + msg.imSessionID.ToString()); - msg.timestamp = timestamp; - if (client != null) - { - msg.fromAgentName = client.FirstName + " " + client.LastName;// fromAgentName; - } - else - { - msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it - } - msg.message = message; - msg.dialog = dialog; - msg.fromGroup = fromGroup; - msg.offline = offline; - msg.ParentEstateID = ParentEstateID; - msg.Position = new sLLVector3(Position); - msg.RegionID = RegionID.UUID; - msg.binaryBucket = binaryBucket; - m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule); - } - if (dialog == (byte)39) - { - m_log.Verbose("FRIEND", "38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message); - - } - if (dialog == (byte)40) - { - m_log.Verbose("FRIEND", "38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message); - } - - // 39 == Accept Friendship - - // 40 == Decline Friendship - - } - - private void OnApprovedFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List callingCardFolders) - { - if (m_pendingFriendRequests.ContainsKey(transactionID)) - { - // Found Pending Friend Request with that Transaction.. - - // Compose response to other agent. - GridInstantMessage msg = new GridInstantMessage(); - msg.toAgentID = m_pendingFriendRequests[transactionID].UUID; - msg.fromAgentID = agentID.UUID; - msg.fromAgentName = client.FirstName + " " + client.LastName; - msg.fromAgentSession = client.SessionId.UUID; - msg.fromGroup = false; - msg.imSessionID = transactionID.UUID; - msg.message = agentID.UUID.ToString(); - msg.ParentEstateID = 0; - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - msg.RegionID = m_scene.RegionInfo.RegionID.UUID; - msg.dialog = (byte)39;// Approved friend request - msg.Position = new sLLVector3(); - msg.offline = (byte)0; - msg.binaryBucket = new byte[0]; - m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule); - m_scene.StoreAddFriendship(m_pendingFriendRequests[transactionID], agentID, (uint)1); - m_pendingFriendRequests.Remove(transactionID); - - // TODO: Inform agent that the friend is online - } - } - private void OnDenyFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List callingCardFolders) - { - if (m_pendingFriendRequests.ContainsKey(transactionID)) - { - // Found Pending Friend Request with that Transaction.. - - // Compose response to other agent. - GridInstantMessage msg = new GridInstantMessage(); - msg.toAgentID = m_pendingFriendRequests[transactionID].UUID; - msg.fromAgentID = agentID.UUID; - msg.fromAgentName = client.FirstName + " " + client.LastName; - msg.fromAgentSession = client.SessionId.UUID; - msg.fromGroup = false; - msg.imSessionID = transactionID.UUID; - msg.message = agentID.UUID.ToString(); - msg.ParentEstateID = 0; - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - msg.RegionID = m_scene.RegionInfo.RegionID.UUID; - msg.dialog = (byte)40;// Deny friend request - msg.Position = new sLLVector3(); - msg.offline = (byte)0; - msg.binaryBucket = new byte[0]; - m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule); - m_pendingFriendRequests.Remove(transactionID); - - } - - - } - - private void OnTerminateFriendship(IClientAPI client, LLUUID agent, LLUUID exfriendID) - { - m_scene.StoreRemoveFriendship(agent, exfriendID); - // TODO: Inform the client that the ExFriend is offline - - } - - - private void OnGridInstantMessage(GridInstantMessage msg) - { - // Trigger the above event handler - OnInstantMessage(null,new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession), - new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName, - msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID, - new LLVector3(msg.Position.x, msg.Position.y, msg.Position.z), new LLUUID(msg.RegionID), - msg.binaryBucket); - - } - - - public void PostInitialise() - { - } - - - - public void Close() - { - } - - public string Name - { - get { return "FriendsModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 Nini.Config; +using System; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using libsecondlife; + +namespace OpenSim.Region.Environment.Modules +{ + public class FriendsModule : IRegionModule + { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + + Dictionary m_pendingFriendRequests = new Dictionary(); + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnGridInstantMessageToFriendsModule += OnGridInstantMessage; + } + + private void OnNewClient(IClientAPI client) + { + // All friends establishment protocol goes over instant message + // There's no way to send a message from the sim + // to a user to 'add a friend' without causing dialog box spam + // + // The base set of friends are added when the user signs on in their XMLRPC response + // Generated by LoginService. The friends are retreived from the database by the UserManager + + // Subscribe to instant messages + client.OnInstantMessage += OnInstantMessage; + client.OnApproveFriendRequest += OnApprovedFriendRequest; + client.OnDenyFriendRequest += OnDenyFriendRequest; + client.OnTerminateFriendship += OnTerminateFriendship; + + + } + + private void OnInstantMessage(IClientAPI client,LLUUID fromAgentID, + LLUUID fromAgentSession, LLUUID toAgentID, + LLUUID imSessionID, uint timestamp, string fromAgentName, + string message, byte dialog, bool fromGroup, byte offline, + uint ParentEstateID, LLVector3 Position, LLUUID RegionID, + byte[] binaryBucket) + { + // Friend Requests go by Instant Message.. using the dialog param + // https://wiki.secondlife.com/wiki/ImprovedInstantMessage + + // 38 == Offer friendship + if (dialog == (byte)38) + { + LLUUID friendTransactionID = LLUUID.Random(); + + m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); + + m_log.Info("[FRIEND]: 38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message); + GridInstantMessage msg = new GridInstantMessage(); + msg.fromAgentID = fromAgentID.UUID; + msg.fromAgentSession = fromAgentSession.UUID; + msg.toAgentID = toAgentID.UUID; + msg.imSessionID = friendTransactionID.UUID; // This is the item we're mucking with here + m_log.Info("[FRIEND]: Filling Session: " + msg.imSessionID.ToString()); + msg.timestamp = timestamp; + if (client != null) + { + msg.fromAgentName = client.FirstName + " " + client.LastName;// fromAgentName; + } + else + { + msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it + } + msg.message = message; + msg.dialog = dialog; + msg.fromGroup = fromGroup; + msg.offline = offline; + msg.ParentEstateID = ParentEstateID; + msg.Position = new sLLVector3(Position); + msg.RegionID = RegionID.UUID; + msg.binaryBucket = binaryBucket; + m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule); + } + + // 39 == Accept Friendship + if (dialog == (byte)39) + { + m_log.Info("[FRIEND]: 39 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message); + } + + // 40 == Decline Friendship + if (dialog == (byte)40) + { + m_log.Info("[FRIEND]: 40 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message); + } + } + + private void OnApprovedFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List callingCardFolders) + { + if (m_pendingFriendRequests.ContainsKey(transactionID)) + { + // Found Pending Friend Request with that Transaction.. + + // Compose response to other agent. + GridInstantMessage msg = new GridInstantMessage(); + msg.toAgentID = m_pendingFriendRequests[transactionID].UUID; + msg.fromAgentID = agentID.UUID; + msg.fromAgentName = client.FirstName + " " + client.LastName; + msg.fromAgentSession = client.SessionId.UUID; + msg.fromGroup = false; + msg.imSessionID = transactionID.UUID; + msg.message = agentID.UUID.ToString(); + msg.ParentEstateID = 0; + msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + msg.RegionID = m_scene.RegionInfo.RegionID.UUID; + msg.dialog = (byte)39;// Approved friend request + msg.Position = new sLLVector3(); + msg.offline = (byte)0; + msg.binaryBucket = new byte[0]; + m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule); + m_scene.StoreAddFriendship(m_pendingFriendRequests[transactionID], agentID, (uint)1); + m_pendingFriendRequests.Remove(transactionID); + + // TODO: Inform agent that the friend is online + } + } + + private void OnDenyFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List callingCardFolders) + { + if (m_pendingFriendRequests.ContainsKey(transactionID)) + { + // Found Pending Friend Request with that Transaction.. + + // Compose response to other agent. + GridInstantMessage msg = new GridInstantMessage(); + msg.toAgentID = m_pendingFriendRequests[transactionID].UUID; + msg.fromAgentID = agentID.UUID; + msg.fromAgentName = client.FirstName + " " + client.LastName; + msg.fromAgentSession = client.SessionId.UUID; + msg.fromGroup = false; + msg.imSessionID = transactionID.UUID; + msg.message = agentID.UUID.ToString(); + msg.ParentEstateID = 0; + msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + msg.RegionID = m_scene.RegionInfo.RegionID.UUID; + msg.dialog = (byte)40;// Deny friend request + msg.Position = new sLLVector3(); + msg.offline = (byte)0; + msg.binaryBucket = new byte[0]; + m_scene.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule); + m_pendingFriendRequests.Remove(transactionID); + } + } + + private void OnTerminateFriendship(IClientAPI client, LLUUID agent, LLUUID exfriendID) + { + m_scene.StoreRemoveFriendship(agent, exfriendID); + // TODO: Inform the client that the ExFriend is offline + } + + private void OnGridInstantMessage(GridInstantMessage msg) + { + // Trigger the above event handler + OnInstantMessage(null,new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession), + new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName, + msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID, + new LLVector3(msg.Position.x, msg.Position.y, msg.Position.z), new LLUUID(msg.RegionID), + msg.binaryBucket); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "FriendsModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/GroupsModule.cs b/OpenSim/Region/Environment/Modules/GroupsModule.cs index 0922ca8303..b0892dd1d3 100644 --- a/OpenSim/Region/Environment/Modules/GroupsModule.cs +++ b/OpenSim/Region/Environment/Modules/GroupsModule.cs @@ -1,62 +1,279 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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 Nini.Config; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class GroupsModule : IRegionModule - { - private Scene m_scene; - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "GroupsModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 Nini.Config; +using System; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using libsecondlife; + +namespace OpenSim.Region.Environment.Modules +{ + public class GroupsModule : IRegionModule + { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private List m_scene = new List(); + private Dictionary m_iclientmap = new Dictionary(); + private Dictionary m_groupmap = new Dictionary(); + private Dictionary m_grouplistmap = new Dictionary(); + + public void Initialise(Scene scene, IConfigSource config) + { + lock (m_scene) + { + m_scene.Add(scene); + } + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnClientClosed += OnClientClosed; + scene.EventManager.OnGridInstantMessageToGroupsModule += OnGridInstantMessage; + //scene.EventManager. + } + private void OnNewClient(IClientAPI client) + { + // All friends establishment protocol goes over instant message + // There's no way to send a message from the sim + // to a user to 'add a friend' without causing dialog box spam + // + // The base set of friends are added when the user signs on in their XMLRPC response + // Generated by LoginService. The friends are retreived from the database by the UserManager + + // Subscribe to instant messages + client.OnInstantMessage += OnInstantMessage; + client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; + lock (m_iclientmap) + { + if (!m_iclientmap.ContainsKey(client.AgentId)) + { + m_iclientmap.Add(client.AgentId, client); + } + } + GroupData OpenSimulatorGroup = new GroupData(); + OpenSimulatorGroup.ActiveGroupTitle = "OpenSimulator Tester"; + OpenSimulatorGroup.GroupID = new LLUUID("00000000-68f9-1111-024e-222222111120"); + OpenSimulatorGroup.GroupMembers.Add(client.AgentId); + OpenSimulatorGroup.groupName = "OpenSimulator Testing"; + OpenSimulatorGroup.ActiveGroupPowers = GroupPowers.LandAllowSetHome; + OpenSimulatorGroup.GroupTitles.Add("OpenSimulator Tester"); + lock (m_groupmap) + { + if (!m_groupmap.ContainsKey(client.AgentId)) + { + m_groupmap.Add(client.AgentId, OpenSimulatorGroup); + } + } + GroupList testGroupList = new GroupList(); + testGroupList.m_GroupList.Add(new LLUUID("00000000-68f9-1111-024e-222222111120")); + + lock (m_grouplistmap) + { + if (!m_grouplistmap.ContainsKey(client.AgentId)) + { + m_grouplistmap.Add(client.AgentId, testGroupList); + } + } + m_log.Info("[GROUP]: Adding " + client.FirstName + " " + client.LastName + " to OpenSimulator Tester group"); + + + } + + private void OnAgentDataUpdateRequest(IClientAPI remoteClient, LLUUID AgentID, LLUUID SessionID) + { + string firstname = remoteClient.FirstName; + string lastname = remoteClient.LastName; + + LLUUID ActiveGroupID = LLUUID.Zero; + uint ActiveGroupPowers = 0; + string ActiveGroupName = ""; + string ActiveGroupTitle = ""; + + bool foundUser = false; + + lock (m_iclientmap) + { + if (m_iclientmap.ContainsKey(remoteClient.AgentId)) + { + foundUser = true; + } + } + if (foundUser) + { + lock (m_groupmap) + { + if (m_groupmap.ContainsKey(remoteClient.AgentId)) + { + GroupData grp = m_groupmap[remoteClient.AgentId]; + if (grp != null) + { + ActiveGroupID = grp.GroupID; + ActiveGroupName = grp.groupName; + ActiveGroupPowers = grp.groupPowers; + ActiveGroupTitle = grp.ActiveGroupTitle; + } + + //remoteClient.SendAgentDataUpdate(AgentID, ActiveGroupID, firstname, lastname, ActiveGroupPowers, ActiveGroupName, ActiveGroupTitle); + + } + } + } + + } + + private void OnInstantMessage(IClientAPI client, LLUUID fromAgentID, + LLUUID fromAgentSession, LLUUID toAgentID, + LLUUID imSessionID, uint timestamp, string fromAgentName, + string message, byte dialog, bool fromGroup, byte offline, + uint ParentEstateID, LLVector3 Position, LLUUID RegionID, + byte[] binaryBucket) + { + + } + + private void OnGridInstantMessage(GridInstantMessage msg) + { + // Trigger the above event handler + OnInstantMessage(null, new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession), + new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName, + msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID, + new LLVector3(msg.Position.x, msg.Position.y, msg.Position.z), new LLUUID(msg.RegionID), + msg.binaryBucket); + } + + private void OnClientClosed(LLUUID agentID) + { + lock (m_iclientmap) + { + if (m_iclientmap.ContainsKey(agentID)) + { + IClientAPI cli = m_iclientmap[agentID]; + if (cli != null) + { + m_log.Info("[GROUP]: Removing all reference to groups for " + cli.FirstName + " " + cli.LastName); + } + else + { + m_log.Info("[GROUP]: Removing all reference to groups for " + agentID.ToString()); + } + m_iclientmap.Remove(agentID); + } + } + + lock (m_groupmap) + { + if (m_groupmap.ContainsKey(agentID)) + { + m_groupmap.Remove(agentID); + } + } + + lock (m_grouplistmap) + { + if (m_grouplistmap.ContainsKey(agentID)) + { + m_grouplistmap.Remove(agentID); + } + } + GC.Collect(); + } + + public void PostInitialise() + { + } + + public void Close() + { + m_log.Info("[GROUP]: Shutting down group module."); + lock (m_iclientmap) + { + m_iclientmap.Clear(); + } + + lock (m_groupmap) + { + m_groupmap.Clear(); + } + + lock (m_grouplistmap) + { + m_grouplistmap.Clear(); + } + GC.Collect(); + } + + public string Name + { + get { return "GroupsModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + } + public class GroupData + { + public LLUUID GroupID; + public string groupName; + public string ActiveGroupTitle; + public List GroupTitles; + public List GroupMembers; + public uint groupPowers = (uint)(GroupPowers.LandAllowLandmark | GroupPowers.LandAllowSetHome); + + public GroupPowers ActiveGroupPowers + { + set + { + groupPowers = (uint) value; + } + get + { + return (GroupPowers)groupPowers; + } + } + + public GroupData() + { + GroupTitles = new List(); + GroupMembers = new List(); + } + + } + public class GroupList + { + public List m_GroupList; + public GroupList() + { + m_GroupList = new List(); + } + } +} diff --git a/OpenSim/Region/Environment/Modules/InstantMessageModule.cs b/OpenSim/Region/Environment/Modules/InstantMessageModule.cs index d45e642d8e..8df2acb95a 100644 --- a/OpenSim/Region/Environment/Modules/InstantMessageModule.cs +++ b/OpenSim/Region/Environment/Modules/InstantMessageModule.cs @@ -1,134 +1,127 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Collections.Generic; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class InstantMessageModule : IRegionModule - { - private List m_scenes = new List(); - private LogBase m_log; - - public InstantMessageModule() - { - m_log = MainLog.Instance; - } - - public void Initialise(Scene scene, IConfigSource config) - { - if (!m_scenes.Contains(scene)) - { - m_scenes.Add(scene); - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnGridInstantMessageToIMModule += OnGridInstantMessage; - } - } - - private void OnNewClient(IClientAPI client) - { - client.OnInstantMessage += OnInstantMessage; - } - - private void OnInstantMessage(IClientAPI client,LLUUID fromAgentID, - LLUUID fromAgentSession, LLUUID toAgentID, - LLUUID imSessionID, uint timestamp, string fromAgentName, - string message, byte dialog, bool fromGroup, byte offline, - uint ParentEstateID, LLVector3 Position, LLUUID RegionID, - byte[] binaryBucket) - { - - bool FriendDialog = ((dialog == (byte)38) || (dialog == (byte)39) || (dialog == (byte)40)); - - // IM dialogs need to be pre-processed and have their sessionID filled by the server - // so the sim can match the transaction on the return packet. - - // Don't send a Friend Dialog IM with a LLUUID.Zero session. - if (!(FriendDialog && imSessionID == LLUUID.Zero)) - { - foreach (Scene scene in m_scenes) - { - if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence) - { - // Local message - ScenePresence user = (ScenePresence)scene.Entities[toAgentID]; - if (!user.IsChildAgent) - { - user.ControllingClient.SendInstantMessage(fromAgentID, fromAgentSession, message, - toAgentID, imSessionID, fromAgentName, dialog, - timestamp); - // Message sent - return; - } - } - } - } - - // Still here, try send via Grid - // TODO - } - - // Trusty OSG1 called method. This method also gets called from the FriendsModule - // Turns out the sim has to send an instant message to the user to get it to show an accepted friend. - - private void OnGridInstantMessage(GridInstantMessage msg) - { - // Trigger the above event handler - OnInstantMessage(null,new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession), - new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName, - msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID, - new LLVector3(msg.Position.x,msg.Position.y,msg.Position.z), new LLUUID(msg.RegionID), - msg.binaryBucket); - - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "InstantMessageModule"; } - } - - public bool IsSharedModule - { - get { return true; } - } - } -} +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Collections.Generic; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class InstantMessageModule : IRegionModule + { + private List m_scenes = new List(); + + public void Initialise(Scene scene, IConfigSource config) + { + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnGridInstantMessageToIMModule += OnGridInstantMessage; + } + } + + private void OnNewClient(IClientAPI client) + { + client.OnInstantMessage += OnInstantMessage; + } + + private void OnInstantMessage(IClientAPI client,LLUUID fromAgentID, + LLUUID fromAgentSession, LLUUID toAgentID, + LLUUID imSessionID, uint timestamp, string fromAgentName, + string message, byte dialog, bool fromGroup, byte offline, + uint ParentEstateID, LLVector3 Position, LLUUID RegionID, + byte[] binaryBucket) + { + bool FriendDialog = ((dialog == (byte)38) || (dialog == (byte)39) || (dialog == (byte)40)); + + // IM dialogs need to be pre-processed and have their sessionID filled by the server + // so the sim can match the transaction on the return packet. + + // Don't send a Friend Dialog IM with a LLUUID.Zero session. + if (!(FriendDialog && imSessionID == LLUUID.Zero)) + { + foreach (Scene scene in m_scenes) + { + if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence) + { + // Local message + ScenePresence user = (ScenePresence)scene.Entities[toAgentID]; + if (!user.IsChildAgent) + { + user.ControllingClient.SendInstantMessage(fromAgentID, fromAgentSession, message, + toAgentID, imSessionID, fromAgentName, dialog, + timestamp); + // Message sent + return; + } + } + } + } + + // Still here, try send via Grid + // TODO + } + + // Trusty OSG1 called method. This method also gets called from the FriendsModule + // Turns out the sim has to send an instant message to the user to get it to show an accepted friend. + + private void OnGridInstantMessage(GridInstantMessage msg) + { + // Trigger the above event handler + OnInstantMessage(null,new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession), + new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName, + msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID, + new LLVector3(msg.Position.x,msg.Position.y,msg.Position.z), new LLUUID(msg.RegionID), + msg.binaryBucket); + + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "InstantMessageModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/InventoryModule.cs b/OpenSim/Region/Environment/Modules/InventoryModule.cs index 7b2a81783c..2af4525c39 100644 --- a/OpenSim/Region/Environment/Modules/InventoryModule.cs +++ b/OpenSim/Region/Environment/Modules/InventoryModule.cs @@ -1,62 +1,62 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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 Nini.Config; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class InventoryModule : IRegionModule - { - private Scene m_scene; - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "InventoryModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 Nini.Config; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class InventoryModule : IRegionModule + { + private Scene m_scene; + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "InventoryModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/LoadImageURLModule.cs b/OpenSim/Region/Environment/Modules/LoadImageURLModule.cs index d48b9d4dbc..0548b9d2d2 100644 --- a/OpenSim/Region/Environment/Modules/LoadImageURLModule.cs +++ b/OpenSim/Region/Environment/Modules/LoadImageURLModule.cs @@ -1,149 +1,177 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.IO; -using System.Net; -using libsecondlife; -using Nini.Config; -using OpenJPEGNet; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class LoadImageURLModule : IRegionModule, IDynamicTextureRender - { - private string m_name = "LoadImageURL"; - private IDynamicTextureManager m_textureManager; - private Scene m_scene; - - public void Initialise(Scene scene, IConfigSource config) - { - if (m_scene == null) - { - m_scene = scene; - } - } - - public void PostInitialise() - { - m_textureManager = m_scene.RequestModuleInterface(); - m_textureManager.RegisterRender(GetContentType(), this); - } - - public void Close() - { - } - - public string Name - { - get { return m_name; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public string GetName() - { - return m_name; - } - - public string GetContentType() - { - return ("image"); - } - - public bool SupportsAsynchronous() - { - return true; - } - - public byte[] ConvertUrl(string url, string extraParams) - { - return null; - } - - public byte[] ConvertStream(Stream data, string extraParams) - { - return null; - } - - public bool AsyncConvertUrl(LLUUID id, string url, string extraParams) - { - MakeHttpRequest(url, id); - return true; - } - - public bool AsyncConvertData(LLUUID id, string bodyData, string extraParams) - { - return false; - } - - private void MakeHttpRequest(string url, LLUUID requestID) - { - WebRequest request = HttpWebRequest.Create(url); - RequestState state = new RequestState((HttpWebRequest) request, requestID); - IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state); - - TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); - state.TimeOfRequest = (int) t.TotalSeconds; - } - - private void HttpRequestReturn(IAsyncResult result) - { - RequestState state = (RequestState) result.AsyncState; - WebRequest request = (WebRequest) state.Request; - HttpWebResponse response = (HttpWebResponse) request.EndGetResponse(result); - if (response.StatusCode == HttpStatusCode.OK) - { - Bitmap image = new Bitmap(response.GetResponseStream()); - Bitmap resize = new Bitmap(image, new Size(512, 512)); - byte[] imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); - - m_textureManager.ReturnData(state.RequestID, imageJ2000); - } - } - - public class RequestState - { - public HttpWebRequest Request = null; - public LLUUID RequestID = LLUUID.Zero; - public int TimeOfRequest = 0; - - public RequestState(HttpWebRequest request, LLUUID requestID) - { - Request = request; - RequestID = requestID; - } - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.IO; +using System.Net; +using libsecondlife; +using Nini.Config; +using OpenJPEGNet; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class LoadImageURLModule : IRegionModule, IDynamicTextureRender + { + private string m_name = "LoadImageURL"; + private IDynamicTextureManager m_textureManager; + private Scene m_scene; + + public void Initialise(Scene scene, IConfigSource config) + { + if (m_scene == null) + { + m_scene = scene; + } + } + + public void PostInitialise() + { + m_textureManager = m_scene.RequestModuleInterface(); + m_textureManager.RegisterRender(GetContentType(), this); + } + + public void Close() + { + } + + public string Name + { + get { return m_name; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public string GetName() + { + return m_name; + } + + public string GetContentType() + { + return ("image"); + } + + public bool SupportsAsynchronous() + { + return true; + } + + public byte[] ConvertUrl(string url, string extraParams) + { + return null; + } + + public byte[] ConvertStream(Stream data, string extraParams) + { + return null; + } + + public bool AsyncConvertUrl(LLUUID id, string url, string extraParams) + { + MakeHttpRequest(url, id); + return true; + } + + public bool AsyncConvertData(LLUUID id, string bodyData, string extraParams) + { + return false; + } + + private void MakeHttpRequest(string url, LLUUID requestID) + { + WebRequest request = HttpWebRequest.Create(url); + RequestState state = new RequestState((HttpWebRequest) request, requestID); + IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state); + + TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); + state.TimeOfRequest = (int) t.TotalSeconds; + } + + private void HttpRequestReturn(IAsyncResult result) + { + RequestState state = (RequestState) result.AsyncState; + WebRequest request = (WebRequest) state.Request; + HttpWebResponse response = (HttpWebResponse) request.EndGetResponse(result); + if (response.StatusCode == HttpStatusCode.OK) + { + Bitmap image = new Bitmap(response.GetResponseStream()); + Size newsize; + + // TODO: make this a bit less hard coded + if ((image.Height < 64) && (image.Width < 64)) + { + newsize = new Size(32, 32); + } + else if ((image.Height < 128) && (image.Width < 128)) + { + newsize = new Size(64, 64); + } + else if ((image.Height <256) && (image.Width < 256)) + { + newsize = new Size(128, 128); + } + else if ((image.Height < 512 && image.Width < 512)) + { + newsize = new Size(256, 256); + } + else if ((image.Height < 1024 && image.Width < 1024)) + { + newsize = new Size(512, 512); + } + else + { + newsize = new Size(1024,1024); + } + + Bitmap resize = new Bitmap(image, newsize); + byte[] imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); + + m_textureManager.ReturnData(state.RequestID, imageJ2000); + } + } + + public class RequestState + { + public HttpWebRequest Request = null; + public LLUUID RequestID = LLUUID.Zero; + public int TimeOfRequest = 0; + + public RequestState(HttpWebRequest request, LLUUID requestID) + { + Request = request; + RequestID = requestID; + } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs b/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs index ac77812c52..e1dcd0f2c2 100644 --- a/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs +++ b/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs @@ -1,343 +1,361 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Generic; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using libsecondlife; -using Nini.Config; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -/***************************************************** - * - * ScriptsHttpRequests - * - * Implements the llHttpRequest and http_response - * callback. - * - * Some stuff was already in LSLLongCmdHandler, and then - * there was this file with a stub class in it. So, - * I am moving some of the objects and functions out of - * LSLLongCmdHandler, such as the HttpRequestClass, the - * start and stop methods, and setting up pending and - * completed queues. These are processed in the - * LSLLongCmdHandler polling loop. Similiar to the - * XMLRPCModule, since that seems to work. - * - * //TODO - * - * This probably needs some throttling mechanism but - * its wide open right now. This applies to both - * number of requests and data volume. - * - * Linden puts all kinds of header fields in the requests. - * Not doing any of that: - * User-Agent - * X-SecondLife-Shard - * X-SecondLife-Object-Name - * X-SecondLife-Object-Key - * X-SecondLife-Region - * X-SecondLife-Local-Position - * X-SecondLife-Local-Velocity - * X-SecondLife-Local-Rotation - * X-SecondLife-Owner-Name - * X-SecondLife-Owner-Key - * - * HTTPS support - * - * Configurable timeout? - * Configurable max repsonse size? - * Configurable - * - * **************************************************/ - -namespace OpenSim.Region.Environment.Modules -{ - public class ScriptHTTPRequests : IRegionModule, IHttpRequests - { - private Scene m_scene; - private Queue rpcQueue = new Queue(); - private object HttpListLock = new object(); - private string m_name = "HttpScriptRequests"; - private int httpTimeout = 300; - - // - private Dictionary m_pendingRequests; - - public ScriptHTTPRequests() - { - } - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - - m_scene.RegisterModuleInterface(this); - - m_pendingRequests = new Dictionary(); - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return m_name; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public LLUUID MakeHttpRequest(string url, string parameters, string body) - { - return LLUUID.Zero; - } - - public LLUUID StartHttpRequest(uint localID, LLUUID itemID, string url, List parameters, string body) - { - LLUUID reqID = LLUUID.Random(); - HttpRequestClass htc = new HttpRequestClass(); - - // Parameters are expected in {key, value, ... , key, value} - if (parameters != null) - { - string[] parms = parameters.ToArray(); - for (int i = 0; i < parms.Length/2; i += 2) - { - switch (Int32.Parse(parms[i])) - { - case HttpRequestClass.HTTP_METHOD: - - htc.httpMethod = parms[i + 1]; - break; - - case HttpRequestClass.HTTP_MIMETYPE: - - htc.httpMIMEType = parms[i + 1]; - break; - - case HttpRequestClass.HTTP_BODY_MAXLENGTH: - - // TODO implement me - break; - - case HttpRequestClass.HTTP_VERIFY_CERT: - - // TODO implement me - break; - } - } - } - - htc.localID = localID; - htc.itemID = itemID; - htc.url = url; - htc.reqID = reqID; - htc.httpTimeout = httpTimeout; - htc.outbound_body = body; - - lock (HttpListLock) - { - m_pendingRequests.Add(reqID, htc); - } - - htc.process(); - - return reqID; - } - - public void StopHttpRequest(uint m_localID, LLUUID m_itemID) - { - lock (HttpListLock) - { - HttpRequestClass tmpReq; - if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) - { - tmpReq.Stop(); - m_pendingRequests.Remove(m_itemID); - } - } - } - - /* - * TODO - * Not sure how important ordering is is here - the next first - * one completed in the list is returned, based soley on its list - * position, not the order in which the request was started or - * finsihed. I thought about setting up a queue for this, but - * it will need some refactoring and this works 'enough' right now - */ - - public HttpRequestClass GetNextCompletedRequest() - { - lock (HttpListLock) - { - foreach (LLUUID luid in m_pendingRequests.Keys) - { - HttpRequestClass tmpReq; - - if (m_pendingRequests.TryGetValue(luid, out tmpReq)) - { - if (tmpReq.finished) - { - m_pendingRequests.Remove(luid); - return tmpReq; - } - } - } - } - return null; - } - } - - // - // HTTP REAQUEST - // This class was originally in LSLLongCmdHandler - // - // TODO: setter/getter methods, maybe pass some in - // constructor - // - - public class HttpRequestClass - { - // Constants for parameters - public const int HTTP_METHOD = 0; - public const int HTTP_MIMETYPE = 1; - public const int HTTP_BODY_MAXLENGTH = 2; - public const int HTTP_VERIFY_CERT = 3; - - // Parameter members and default values - public string httpMethod = "GET"; - public string httpMIMEType = "text/plain;charset=utf-8"; - public int httpBodyMaxLen = 2048; // not implemented - public bool httpVerifyCert = true; // not implemented - - // Request info - public uint localID; - public LLUUID itemID; - public LLUUID reqID; - public int httpTimeout; - public string url; - public string outbound_body; - public DateTime next; - public int status; - public bool finished; - public List response_metadata; - public string response_body; - public HttpWebRequest request; - private Thread httpThread; - - public void process() - { - httpThread = new Thread(SendRequest); - httpThread.Name = "HttpRequestThread"; - httpThread.Priority = ThreadPriority.BelowNormal; - httpThread.IsBackground = true; - httpThread.Start(); - } - - /* - * TODO: More work on the response codes. Right now - * returning 200 for success or 499 for exception - */ - - public void SendRequest() - { - HttpWebResponse response = null; - StringBuilder sb = new StringBuilder(); - byte[] buf = new byte[8192]; - string tempString = null; - int count = 0; - - try - { - request = (HttpWebRequest) - WebRequest.Create(url); - request.Method = httpMethod; - request.ContentType = httpMIMEType; - - request.Timeout = httpTimeout; - // execute the request - response = (HttpWebResponse) - request.GetResponse(); - - Stream resStream = response.GetResponseStream(); - - do - { - // fill the buffer with data - count = resStream.Read(buf, 0, buf.Length); - - // make sure we read some data - if (count != 0) - { - // translate from bytes to ASCII text - tempString = Encoding.ASCII.GetString(buf, 0, count); - - // continue building the string - sb.Append(tempString); - } - } while (count > 0); // any more data to read? - - response_body = sb.ToString(); - } - catch (Exception e) - { - status = 499; - response_body = e.Message; - finished = true; - return; - } - - status = 200; - finished = true; - } - - public void Stop() - { - try - { - httpThread.Abort(); - } - catch (Exception) - { - } - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using libsecondlife; +using Nini.Config; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +/***************************************************** + * + * ScriptsHttpRequests + * + * Implements the llHttpRequest and http_response + * callback. + * + * Some stuff was already in LSLLongCmdHandler, and then + * there was this file with a stub class in it. So, + * I am moving some of the objects and functions out of + * LSLLongCmdHandler, such as the HttpRequestClass, the + * start and stop methods, and setting up pending and + * completed queues. These are processed in the + * LSLLongCmdHandler polling loop. Similiar to the + * XMLRPCModule, since that seems to work. + * + * //TODO + * + * This probably needs some throttling mechanism but + * its wide open right now. This applies to both + * number of requests and data volume. + * + * Linden puts all kinds of header fields in the requests. + * Not doing any of that: + * User-Agent + * X-SecondLife-Shard + * X-SecondLife-Object-Name + * X-SecondLife-Object-Key + * X-SecondLife-Region + * X-SecondLife-Local-Position + * X-SecondLife-Local-Velocity + * X-SecondLife-Local-Rotation + * X-SecondLife-Owner-Name + * X-SecondLife-Owner-Key + * + * HTTPS support + * + * Configurable timeout? + * Configurable max repsonse size? + * Configurable + * + * **************************************************/ + +namespace OpenSim.Region.Environment.Modules +{ + public class ScriptHTTPRequests : IRegionModule, IHttpRequests + { + private Scene m_scene; + private Queue rpcQueue = new Queue(); + private object HttpListLock = new object(); + private string m_name = "HttpScriptRequests"; + private int httpTimeout = 30000; + + // + private Dictionary m_pendingRequests; + + public ScriptHTTPRequests() + { + } + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + + m_scene.RegisterModuleInterface(this); + + m_pendingRequests = new Dictionary(); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return m_name; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public LLUUID MakeHttpRequest(string url, string parameters, string body) + { + return LLUUID.Zero; + } + + public LLUUID StartHttpRequest(uint localID, LLUUID itemID, string url, List parameters, string body) + { + LLUUID reqID = LLUUID.Random(); + HttpRequestClass htc = new HttpRequestClass(); + + // Parameters are expected in {key, value, ... , key, value} + if (parameters != null) + { + string[] parms = parameters.ToArray(); + for (int i = 0; i < parms.Length/2; i += 2) + { + switch (Int32.Parse(parms[i])) + { + case HttpRequestClass.HTTP_METHOD: + + htc.httpMethod = parms[i + 1]; + break; + + case HttpRequestClass.HTTP_MIMETYPE: + + htc.httpMIMEType = parms[i + 1]; + break; + + case HttpRequestClass.HTTP_BODY_MAXLENGTH: + + // TODO implement me + break; + + case HttpRequestClass.HTTP_VERIFY_CERT: + + // TODO implement me + break; + } + } + } + + htc.localID = localID; + htc.itemID = itemID; + htc.url = url; + htc.reqID = reqID; + htc.httpTimeout = httpTimeout; + htc.outbound_body = body; + + lock (HttpListLock) + { + m_pendingRequests.Add(reqID, htc); + } + + htc.process(); + + return reqID; + } + + public void StopHttpRequest(uint m_localID, LLUUID m_itemID) + { + if(m_pendingRequests != null) { + lock (HttpListLock) + { + HttpRequestClass tmpReq; + if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) + { + tmpReq.Stop(); + m_pendingRequests.Remove(m_itemID); + } + } + } + } + + /* + * TODO + * Not sure how important ordering is is here - the next first + * one completed in the list is returned, based soley on its list + * position, not the order in which the request was started or + * finsihed. I thought about setting up a queue for this, but + * it will need some refactoring and this works 'enough' right now + */ + + public HttpRequestClass GetNextCompletedRequest() + { + lock (HttpListLock) + { + foreach (LLUUID luid in m_pendingRequests.Keys) + { + HttpRequestClass tmpReq; + + if (m_pendingRequests.TryGetValue(luid, out tmpReq)) + { + if (tmpReq.finished) + { + return tmpReq; + } + } + } + } + return null; + } + + public void RemoveCompletedRequest(LLUUID id) + { + lock (HttpListLock) + { + HttpRequestClass tmpReq; + if (m_pendingRequests.TryGetValue(id, out tmpReq)) + { + tmpReq.Stop(); + tmpReq = null; + m_pendingRequests.Remove(id); + } + } + } + + } + + // + // HTTP REAQUEST + // This class was originally in LSLLongCmdHandler + // + // TODO: setter/getter methods, maybe pass some in + // constructor + // + + public class HttpRequestClass + { + // Constants for parameters + public const int HTTP_METHOD = 0; + public const int HTTP_MIMETYPE = 1; + public const int HTTP_BODY_MAXLENGTH = 2; + public const int HTTP_VERIFY_CERT = 3; + + // Parameter members and default values + public string httpMethod = "GET"; + public string httpMIMEType = "text/plain;charset=utf-8"; + public int httpBodyMaxLen = 2048; // not implemented + public bool httpVerifyCert = true; // not implemented + + // Request info + public uint localID; + public LLUUID itemID; + public LLUUID reqID; + public int httpTimeout; + public string url; + public string outbound_body; + public DateTime next; + public int status; + public bool finished; + public List response_metadata; + public string response_body; + public HttpWebRequest request; + private Thread httpThread; + + public void process() + { + httpThread = new Thread(SendRequest); + httpThread.Name = "HttpRequestThread"; + httpThread.Priority = ThreadPriority.BelowNormal; + httpThread.IsBackground = true; + finished = false; + httpThread.Start(); + OpenSim.Framework.ThreadTracker.Add(httpThread); + } + + /* + * TODO: More work on the response codes. Right now + * returning 200 for success or 499 for exception + */ + + public void SendRequest() + { + HttpWebResponse response = null; + StringBuilder sb = new StringBuilder(); + byte[] buf = new byte[8192]; + string tempString = null; + int count = 0; + + try + { + request = (HttpWebRequest) + WebRequest.Create(url); + request.Method = httpMethod; + request.ContentType = httpMIMEType; + + request.Timeout = httpTimeout; + // execute the request + response = (HttpWebResponse) + request.GetResponse(); + + Stream resStream = response.GetResponseStream(); + + do + { + // fill the buffer with data + count = resStream.Read(buf, 0, buf.Length); + + // make sure we read some data + if (count != 0) + { + // translate from bytes to ASCII text + tempString = Encoding.ASCII.GetString(buf, 0, count); + + // continue building the string + sb.Append(tempString); + } + } while (count > 0); // any more data to read? + + response_body = sb.ToString(); + } + catch (Exception e) + { + status = 499; + response_body = e.Message; + finished = true; + return; + } + + status = 200; + finished = true; + } + + public void Stop() + { + try + { + httpThread.Abort(); + } + catch (Exception) + { + } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/SunModule.cs b/OpenSim/Region/Environment/Modules/SunModule.cs index bbbe88f84e..fb80f68524 100644 --- a/OpenSim/Region/Environment/Modules/SunModule.cs +++ b/OpenSim/Region/Environment/Modules/SunModule.cs @@ -1,194 +1,194 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Generic; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class SunModule : IRegionModule - { - private const double m_real_day = 24.0; - private const int m_default_frame = 100; - private int m_frame_mod; - private double m_day_length; - private int m_dilation; - private int m_frame; - private long m_start; - - private Scene m_scene; - private LogBase m_log; - - public void Initialise(Scene scene, IConfigSource config) - { - m_start = DateTime.Now.Ticks; - m_frame = 0; - - // Just in case they don't have the stanzas - try - { - m_day_length = config.Configs["Sun"].GetDouble("day_length", m_real_day); - m_frame_mod = config.Configs["Sun"].GetInt("frame_rate", m_default_frame); - } - catch (Exception) - { - m_day_length = m_real_day; - m_frame_mod = m_default_frame; - } - - m_dilation = (int) (m_real_day/m_day_length); - m_scene = scene; - m_log = MainLog.Instance; - scene.EventManager.OnFrame += SunUpdate; - scene.EventManager.OnNewClient += SunToClient; - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "SunModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - - public void SunToClient(IClientAPI client) - { - client.SendSunPos(SunPos(HourOfTheDay()), new LLVector3(0, 0.0f, 10.0f)); - } - - public void SunUpdate() - { - if (m_frame < m_frame_mod) - { - m_frame++; - return; - } - // m_log.Verbose("SUN","I've got an update {0} => {1}", m_scene.RegionsInfo.RegionName, HourOfTheDay()); - List avatars = m_scene.GetAvatars(); - foreach (ScenePresence avatar in avatars) - { - avatar.ControllingClient.SendSunPos(SunPos(HourOfTheDay()), new LLVector3(0, 0.0f, 10.0f)); - } - m_frame = 0; - } - - // Hour of the Day figures out the hour of the day as a float. - // The intent here is that we seed hour of the day with real - // time when the simulator starts, then run time forward - // faster based on time dilation factor. This means that - // ticks don't get out of hand - private double HourOfTheDay() - { - long m_addticks = (DateTime.Now.Ticks - m_start)*m_dilation; - DateTime dt = new DateTime(m_start + m_addticks); - return (double) dt.Hour + ((double) dt.Minute/60.0); - } - - private LLVector3 SunPos(double hour) - { - // now we have our radian position - double rad = (hour/m_real_day)*2*Math.PI - (Math.PI/2.0); - double z = Math.Sin(rad); - double x = Math.Cos(rad); - return new LLVector3((float) x, 0f, (float) z); - } - - // TODO: clear this out. This is here so that I remember to - // figure out if we need those other packet fields that I've - // left out so far - // - // public void SendViewerTime(int phase) - // { - // Console.WriteLine("SunPhase: {0}", phase); - // SimulatorViewerTimeMessagePacket viewertime = new SimulatorViewerTimeMessagePacket(); - // //viewertime.TimeInfo.SecPerDay = 86400; - // // viewertime.TimeInfo.SecPerYear = 31536000; - // viewertime.TimeInfo.SecPerDay = 1000; - // viewertime.TimeInfo.SecPerYear = 365000; - // viewertime.TimeInfo.SunPhase = 1; - // int sunPhase = (phase + 2)/2; - // if ((sunPhase < 6) || (sunPhase > 36)) - // { - // viewertime.TimeInfo.SunDirection = new LLVector3(0f, 0.8f, -0.8f); - // Console.WriteLine("sending night"); - // } - // else - // { - // if (sunPhase < 12) - // { - // sunPhase = 12; - // } - // sunPhase = sunPhase - 12; - // - // float yValue = 0.1f*(sunPhase); - // Console.WriteLine("Computed SunPhase: {0}, yValue: {1}", sunPhase, yValue); - // if (yValue > 1.2f) - // { - // yValue = yValue - 1.2f; - // } - // if (yValue > 1) - // { - // yValue = 1; - // } - // if (yValue < 0) - // { - // yValue = 0; - // } - // if (sunPhase < 14) - // { - // yValue = 1 - yValue; - // } - // if (sunPhase < 12) - // { - // yValue *= -1; - // } - // viewertime.TimeInfo.SunDirection = new LLVector3(0f, yValue, 0.3f); - // Console.WriteLine("sending sun update " + yValue); - // } - // viewertime.TimeInfo.SunAngVelocity = new LLVector3(0, 0.0f, 10.0f); - // viewertime.TimeInfo.UsecSinceStart = (ulong) Util.UnixTimeSinceEpoch(); - // // OutPacket(viewertime); - // } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class SunModule : IRegionModule + { + //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private const double m_real_day = 24.0; + private const int m_default_frame = 100; + private int m_frame_mod; + private double m_day_length; + private int m_dilation; + private int m_frame; + private long m_start; + + private Scene m_scene; + + public void Initialise(Scene scene, IConfigSource config) + { + m_start = DateTime.Now.Ticks; + m_frame = 0; + + // Just in case they don't have the stanzas + try + { + m_day_length = config.Configs["Sun"].GetDouble("day_length", m_real_day); + m_frame_mod = config.Configs["Sun"].GetInt("frame_rate", m_default_frame); + } + catch (Exception) + { + m_day_length = m_real_day; + m_frame_mod = m_default_frame; + } + + m_dilation = (int) (m_real_day/m_day_length); + m_scene = scene; + scene.EventManager.OnFrame += SunUpdate; + scene.EventManager.OnNewClient += SunToClient; + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "SunModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + public void SunToClient(IClientAPI client) + { + client.SendSunPos(SunPos(HourOfTheDay()), new LLVector3(0, 0.0f, 10.0f)); + } + + public void SunUpdate() + { + if (m_frame < m_frame_mod) + { + m_frame++; + return; + } + // m_log.InfoFormat("[SUN]: I've got an update {0} => {1}", m_scene.RegionsInfo.RegionName, HourOfTheDay()); + List avatars = m_scene.GetAvatars(); + foreach (ScenePresence avatar in avatars) + { + avatar.ControllingClient.SendSunPos(SunPos(HourOfTheDay()), new LLVector3(0, 0.0f, 10.0f)); + } + m_frame = 0; + } + + // Hour of the Day figures out the hour of the day as a float. + // The intent here is that we seed hour of the day with real + // time when the simulator starts, then run time forward + // faster based on time dilation factor. This means that + // ticks don't get out of hand + private double HourOfTheDay() + { + long m_addticks = (DateTime.Now.Ticks - m_start)*m_dilation; + DateTime dt = new DateTime(m_start + m_addticks); + return (double) dt.Hour + ((double) dt.Minute/60.0); + } + + private LLVector3 SunPos(double hour) + { + // now we have our radian position + double rad = (hour/m_real_day)*2*Math.PI - (Math.PI/2.0); + double z = Math.Sin(rad); + double x = Math.Cos(rad); + return new LLVector3((float) x, 0f, (float) z); + } + + // TODO: clear this out. This is here so that I remember to + // figure out if we need those other packet fields that I've + // left out so far + // + // public void SendViewerTime(int phase) + // { + // Console.WriteLine("SunPhase: {0}", phase); + // SimulatorViewerTimeMessagePacket viewertime = new SimulatorViewerTimeMessagePacket(); + // //viewertime.TimeInfo.SecPerDay = 86400; + // // viewertime.TimeInfo.SecPerYear = 31536000; + // viewertime.TimeInfo.SecPerDay = 1000; + // viewertime.TimeInfo.SecPerYear = 365000; + // viewertime.TimeInfo.SunPhase = 1; + // int sunPhase = (phase + 2)/2; + // if ((sunPhase < 6) || (sunPhase > 36)) + // { + // viewertime.TimeInfo.SunDirection = new LLVector3(0f, 0.8f, -0.8f); + // Console.WriteLine("sending night"); + // } + // else + // { + // if (sunPhase < 12) + // { + // sunPhase = 12; + // } + // sunPhase = sunPhase - 12; + // + // float yValue = 0.1f*(sunPhase); + // Console.WriteLine("Computed SunPhase: {0}, yValue: {1}", sunPhase, yValue); + // if (yValue > 1.2f) + // { + // yValue = yValue - 1.2f; + // } + // if (yValue > 1) + // { + // yValue = 1; + // } + // if (yValue < 0) + // { + // yValue = 0; + // } + // if (sunPhase < 14) + // { + // yValue = 1 - yValue; + // } + // if (sunPhase < 12) + // { + // yValue *= -1; + // } + // viewertime.TimeInfo.SunDirection = new LLVector3(0f, yValue, 0.3f); + // Console.WriteLine("sending sun update " + yValue); + // } + // viewertime.TimeInfo.SunAngVelocity = new LLVector3(0, 0.0f, 10.0f); + // viewertime.TimeInfo.UsecSinceStart = (ulong) Util.UnixTimeSinceEpoch(); + // // OutPacket(viewertime); + // } + } +} diff --git a/OpenSim/Region/Environment/Modules/TeleportModule.cs b/OpenSim/Region/Environment/Modules/TeleportModule.cs index 3b67272f27..455004df2a 100644 --- a/OpenSim/Region/Environment/Modules/TeleportModule.cs +++ b/OpenSim/Region/Environment/Modules/TeleportModule.cs @@ -1,34 +1,34 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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. -* -*/ - -namespace OpenSim.Region.Environment.Modules -{ - internal class TeleportModule - { - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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. +* +*/ + +namespace OpenSim.Region.Environment.Modules +{ + internal class TeleportModule + { + } +} diff --git a/OpenSim/Region/Environment/Modules/Terrain/TerrainModule.cs b/OpenSim/Region/Environment/Modules/Terrain/TerrainModule.cs new file mode 100644 index 0000000000..1b765eb63b --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Terrain/TerrainModule.cs @@ -0,0 +1,126 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 Nini.Config; +using System; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Modules; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using libsecondlife; + +namespace OpenSim.Region.Environment.Modules.Terrain +{ + /// + /// A new version of the old Channel class, simplified + /// + public class TerrainChannel : ITerrainChannel + { + private double[,] map; + + public int Width + { + get { return map.GetLength(0); } + } + + public int Height + { + get { return map.GetLength(1); } + } + + public TerrainChannel Copy() + { + TerrainChannel copy = new TerrainChannel(false); + copy.map = (double[,])this.map.Clone(); + + return copy; + } + + public double this[int x, int y] + { + get + { + return map[x, y]; + } + set + { + map[x, y] = value; + } + } + + public TerrainChannel() + { + map = new double[Constants.RegionSize, Constants.RegionSize]; + } + + public TerrainChannel(bool createMap) + { + if (createMap) + map = new double[Constants.RegionSize, Constants.RegionSize]; + } + + public TerrainChannel(int w, int h) + { + map = new double[w, h]; + } + } + + public class TerrainModule : IRegionModule + { + Scene m_scene; + + private IConfigSource m_gConfig; + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + m_gConfig = config; + } + + public void Close() + { + } + + public string Name + { + get { return "TerrainModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + public void PostInitialise() + { + } + } +} diff --git a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs index e533812bea..c773f9ea2e 100644 --- a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs +++ b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs @@ -1,174 +1,216 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Generic; -using System.Threading; -using libsecondlife; -using libsecondlife.Packets; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - //this is a first attempt, to start breaking the mess thats called the assetcache up. - // basically this should be the texture sending (to clients) code moved out of assetcache - //and some small clean up - // but on first tests it didn't seem to work very well so is currently not in use. - public class TextureDownloadModule : IRegionModule - { - private Scene m_scene; - private List m_scenes = new List(); - - private readonly BlockingQueue m_queueSenders = new BlockingQueue(); - - private readonly Dictionary m_userTextureServices = - new Dictionary(); - - private Thread m_thread; - - public TextureDownloadModule() - { - } - - public void Initialise(Scene scene, IConfigSource config) - { - if (m_scene == null) - { - //Console.WriteLine("Creating Texture download module"); - m_thread = new Thread(new ThreadStart(ProcessTextureSenders)); - m_thread.IsBackground = true; - m_thread.Start(); - } - - if (!m_scenes.Contains(scene)) - { - m_scenes.Add(scene); - m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence; - } - } - - private void EventManager_OnRemovePresence(LLUUID agentId) - { - UserTextureDownloadService textureService; - - lock (m_userTextureServices) - { - if( m_userTextureServices.TryGetValue( agentId, out textureService )) - { - textureService.Close(); - - m_userTextureServices.Remove(agentId); - } - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "TextureDownloadModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - - public void NewClient(IClientAPI client) - { - client.OnRequestTexture += TextureRequest; - } - - private bool TryGetUserTextureService(LLUUID userID, out UserTextureDownloadService textureService) - { - lock (m_userTextureServices) - { - if (m_userTextureServices.TryGetValue(userID, out textureService)) - { - return true; - } - - textureService = new UserTextureDownloadService(m_scene, m_queueSenders); - m_userTextureServices.Add(userID, textureService); - return true; - } - } - - public void TextureRequest(Object sender, TextureRequestArgs e) - { - IClientAPI client = (IClientAPI) sender; - UserTextureDownloadService textureService; - if (TryGetUserTextureService(client.AgentId, out textureService)) - { - textureService.HandleTextureRequest(client, e); - } - } - - public void ProcessTextureSenders() - { - while (true) - { - TextureSender sender = m_queueSenders.Dequeue(); - if (sender.Cancel) - { - TextureSent(sender); - - sender.Cancel = false; - } - else - { - bool finished = sender.SendTexturePacket(); - if (finished) - { - TextureSent(sender); - } - else - { - m_queueSenders.Enqueue(sender); - } - } - } - } - - private void TextureSent(TextureSender sender) - { - sender.Sending = false; - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using System.Threading; +using libsecondlife; +using libsecondlife.Packets; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + //this is a first attempt, to start breaking the mess thats called the assetcache up. + // basically this should be the texture sending (to clients) code moved out of assetcache + //and some small clean up + public class TextureDownloadModule : IRegionModule + { + //private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + private List m_scenes = new List(); + + /// + /// There is one queue for all textures waiting to be sent, regardless of the requesting user. + /// + private readonly BlockingQueue m_queueSenders = new BlockingQueue(); + + /// + /// Each user has their own texture download service. + /// + private readonly Dictionary m_userTextureServices = + new Dictionary(); + + private Thread m_thread; + + public TextureDownloadModule() + { + } + + public void Initialise(Scene scene, IConfigSource config) + { + if (m_scene == null) + { + //Console.WriteLine("Creating Texture download module"); + m_thread = new Thread(new ThreadStart(ProcessTextureSenders)); + m_thread.Name = "ProcessTextureSenderThread"; + m_thread.IsBackground = true; + m_thread.Start(); + OpenSim.Framework.ThreadTracker.Add(m_thread); + } + + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + m_scene = scene; + m_scene.EventManager.OnNewClient += NewClient; + m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence; + } + } + + /// + /// Cleanup the texture service related objects for the removed presence. + /// + /// + private void EventManager_OnRemovePresence(LLUUID agentId) + { + UserTextureDownloadService textureService; + + lock (m_userTextureServices) + { + if (m_userTextureServices.TryGetValue(agentId, out textureService)) + { + textureService.Close(); + + m_userTextureServices.Remove(agentId); + } + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "TextureDownloadModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + public void NewClient(IClientAPI client) + { + client.OnRequestTexture += TextureRequest; + } + + /// + /// Does this user have a registered texture download service? + /// + /// + /// + /// Always returns true, since a service is created if one does not already exist + private bool TryGetUserTextureService(LLUUID userID, out UserTextureDownloadService textureService) + { + lock (m_userTextureServices) + { + if (m_userTextureServices.TryGetValue(userID, out textureService)) + { + return true; + } + + textureService = new UserTextureDownloadService(m_scene, m_queueSenders); + m_userTextureServices.Add(userID, textureService); + return true; + } + } + + /// + /// Start the process of requesting a given texture. + /// + /// + /// + public void TextureRequest(Object sender, TextureRequestArgs e) + { + IClientAPI client = (IClientAPI) sender; + UserTextureDownloadService textureService; + if (TryGetUserTextureService(client.AgentId, out textureService)) + { + textureService.HandleTextureRequest(client, e); + } + } + + /// + /// Entry point for the thread dedicated to processing the texture queue. + /// + public void ProcessTextureSenders() + { + TextureSender sender = null; + + while (true) + { + sender = m_queueSenders.Dequeue(); + + if (sender.Cancel) + { + TextureSent(sender); + + sender.Cancel = false; + } + else + { + bool finished = sender.SendTexturePacket(); + if (finished) + { + TextureSent(sender); + } + else + { + m_queueSenders.Enqueue(sender); + } + } + + // Make sure that any sender we currently have can get garbage collected + sender = null; + + //m_log.InfoFormat("[TEXTURE DOWNLOAD] Texture sender queue size: {0}", m_queueSenders.Count()); + } + } + + /// + /// Called when the texture has finished sending. + /// + /// + private void TextureSent(TextureSender sender) + { + sender.Sending = false; + //m_log.DebugFormat("[TEXTURE DOWNLOAD]: Removing download stat for {0}", sender.assetID); + m_scene.AddPendingDownloads(-1); + } + } +} diff --git a/OpenSim/Region/Environment/Modules/TextureSender.cs b/OpenSim/Region/Environment/Modules/TextureSender.cs index aba0126cbe..056b8e1dce 100644 --- a/OpenSim/Region/Environment/Modules/TextureSender.cs +++ b/OpenSim/Region/Environment/Modules/TextureSender.cs @@ -1,136 +1,204 @@ -using System; -using libsecondlife; -using libsecondlife.Packets; -using OpenSim.Framework; -using OpenSim.Framework.Console; - -namespace OpenSim.Region.Environment.Modules -{ - public class TextureSender - { - public int counter = 0; - private AssetBase m_asset; - public long DataPointer = 0; - public int NumPackets = 0; - public int PacketCounter = 0; - public bool Cancel = false; - public bool ImageLoaded = false; - - public bool Sending = false; - - public IClientAPI RequestUser; - public LLUUID RequestedAssetID; - public int RequestedDiscardLevel = -1; - public uint StartPacketNumber = 0; - - // private int m_sentDiscardLevel = -1; - - public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber) - { - RequestUser = client; - RequestedAssetID = textureID; - RequestedDiscardLevel = discardLevel; - StartPacketNumber = packetNumber; - } - - public void TextureReceived(AssetBase asset) - { - m_asset = asset; - NumPackets = CalculateNumPackets(asset.Data.Length); - PacketCounter = (int) StartPacketNumber; - ImageLoaded = true; - } - - public void UpdateRequest(int discardLevel, uint packetNumber) - { - RequestedDiscardLevel = discardLevel; - StartPacketNumber = packetNumber; - PacketCounter = (int) StartPacketNumber; - } - - public bool SendTexturePacket() - { - SendPacket(); - counter++; - if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || - ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets/(RequestedDiscardLevel + 1))))) - { - return true; - } - return false; - } - - private void SendPacket() - { - if (PacketCounter <= NumPackets) - { - if (PacketCounter == 0) - { - if (NumPackets == 0) - { - ImageDataPacket im = new ImageDataPacket(); - im.Header.Reliable = false; - im.ImageID.Packets = 1; - im.ImageID.ID = m_asset.FullID; - im.ImageID.Size = (uint) m_asset.Data.Length; - im.ImageData.Data = m_asset.Data; - im.ImageID.Codec = 2; - RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; - } - else - { - ImageDataPacket im = new ImageDataPacket(); - im.Header.Reliable = false; - im.ImageID.Packets = (ushort) (NumPackets); - im.ImageID.ID = m_asset.FullID; - im.ImageID.Size = (uint) m_asset.Data.Length; - im.ImageData.Data = new byte[600]; - Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); - im.ImageID.Codec = 2; - RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; - } - } - else - { - ImagePacketPacket im = new ImagePacketPacket(); - im.Header.Reliable = false; - im.ImageID.Packet = (ushort) (PacketCounter); - im.ImageID.ID = m_asset.FullID; - int size = m_asset.Data.Length - 600 - (1000*(PacketCounter - 1)); - if (size > 1000) size = 1000; - im.ImageData.Data = new byte[size]; - try - { - Array.Copy(m_asset.Data, 600 + (1000*(PacketCounter - 1)), im.ImageData.Data, 0, size); - } - catch (ArgumentOutOfRangeException) - { - MainLog.Instance.Error("TEXTURE", - "Unable to separate texture into multiple packets: Array bounds failure on asset:" + - m_asset.FullID.ToString() ); - return; - } - RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); - PacketCounter++; - } - } - } - - private int CalculateNumPackets(int length) - { - int numPackets = 0; - - if (length > 600) - { - //over 600 bytes so split up file - int restData = (length - 600); - int restPackets = ((restData + 999)/1000); - numPackets = restPackets; - } - - return numPackets; - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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 libsecondlife; +using libsecondlife.Packets; +using OpenSim.Framework; +using OpenSim.Framework.Console; + +namespace OpenSim.Region.Environment.Modules +{ + /// + /// A TextureSender handles the process of receiving a texture requested by the client from the + /// AssetCache, and then sending that texture back to the client. + /// + public class TextureSender + { + private static readonly log4net.ILog m_log + = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Records the number of times texture send has been called. + /// + public int counter = 0; + + /// + /// Holds the texture asset to send. + /// + private AssetBase m_asset; + + //public LLUUID assetID { get { return m_asset.FullID; } } + + /// + /// This is actually the number of extra packets required to send the texture data! We always assume + /// at least one is required. + /// + private int NumPackets = 0; + + /// + /// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts + /// at the 600th byte (0th indexed). + /// + private int PacketCounter = 0; + + public bool Cancel = false; + public bool ImageLoaded = false; + public bool Sending = false; + + private IClientAPI RequestUser; + + private int RequestedDiscardLevel = -1; + private uint StartPacketNumber = 0; + + public TextureSender(IClientAPI client, int discardLevel, uint packetNumber) + { + RequestUser = client; + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; + } + + /// + /// Load up the texture data to send. + /// + /// + /// A + /// + public void TextureReceived(AssetBase asset) + { + m_asset = asset; + NumPackets = CalculateNumPackets(asset.Data.Length); + PacketCounter = (int) StartPacketNumber; + ImageLoaded = true; + } + + public void UpdateRequest(int discardLevel, uint packetNumber) + { + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; + PacketCounter = (int) StartPacketNumber; + } + + /// + /// Send a texture packet to the client. + /// + /// True if the last packet has been sent, false otherwise. + public bool SendTexturePacket() + { + SendPacket(); + counter++; + if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || + ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets/(RequestedDiscardLevel + 1))))) + { + return true; + } + return false; + } + + /// + /// Sends a texture packet to the client. + /// + private void SendPacket() + { + if (PacketCounter <= NumPackets) + { + if (PacketCounter == 0) + { + if (NumPackets == 0) + { + ImageDataPacket im = new ImageDataPacket(); + im.Header.Reliable = false; + im.ImageID.Packets = 1; + im.ImageID.ID = m_asset.FullID; + im.ImageID.Size = (uint) m_asset.Data.Length; + im.ImageData.Data = m_asset.Data; + im.ImageID.Codec = 2; + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } + else + { + ImageDataPacket im = new ImageDataPacket(); + im.Header.Reliable = false; + im.ImageID.Packets = (ushort) (NumPackets); + im.ImageID.ID = m_asset.FullID; + im.ImageID.Size = (uint) m_asset.Data.Length; + im.ImageData.Data = new byte[600]; + Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); + im.ImageID.Codec = 2; + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } + } + else + { + ImagePacketPacket im = new ImagePacketPacket(); + im.Header.Reliable = false; + im.ImageID.Packet = (ushort) (PacketCounter); + im.ImageID.ID = m_asset.FullID; + int size = m_asset.Data.Length - 600 - (1000*(PacketCounter - 1)); + if (size > 1000) size = 1000; + im.ImageData.Data = new byte[size]; + try + { + Array.Copy(m_asset.Data, 600 + (1000*(PacketCounter - 1)), im.ImageData.Data, 0, size); + } + catch (ArgumentOutOfRangeException) + { + m_log.Error("[TEXTURE]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + + m_asset.FullID.ToString() ); + return; + } + RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); + PacketCounter++; + } + } + } + + /// + /// Calculate the number of packets that will be required to send the texture loaded into this sender + /// This is actually the number of 1000 byte packets not including an initial 600 byte packet... + /// + /// + /// + private int CalculateNumPackets(int length) + { + int numPackets = 0; + + if (length > 600) + { + //over 600 bytes so split up file + int restData = (length - 600); + int restPackets = ((restData + 999)/1000); + numPackets = restPackets; + } + + return numPackets; + } + } +} diff --git a/OpenSim/Region/Environment/Modules/TreePopulatorModule.cs b/OpenSim/Region/Environment/Modules/TreePopulatorModule.cs new file mode 100644 index 0000000000..c97d1d53d4 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/TreePopulatorModule.cs @@ -0,0 +1,246 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + /// + /// Version 2.0 - Very hacky compared to the original. Will fix original and release as 0.3 later. + /// + public class TreePopulatorModule : IRegionModule + { + private Scene m_scene; + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private List m_trees; + + public double m_tree_density = 50.0; // Aim for this many per region + public double m_tree_updates = 1000.0; // MS between updates + + public void Initialise(Scene scene, IConfigSource config) + { + try + { + m_tree_density = config.Configs["Trees"].GetDouble("tree_density", m_tree_density); + } + catch (Exception) + { } + + m_trees = new List(); + m_scene = scene; + + m_scene.EventManager.OnPluginConsole += new EventManager.OnPluginConsoleDelegate(EventManager_OnPluginConsole); + + System.Timers.Timer CalculateTrees = new System.Timers.Timer(m_tree_updates); + CalculateTrees.Elapsed += new System.Timers.ElapsedEventHandler(CalculateTrees_Elapsed); + CalculateTrees.Start(); + m_log.Debug("[TREES]: Initialised tree module"); + } + + void EventManager_OnPluginConsole(string[] args) + { + if (args[0] == "tree") + { + m_log.Debug("[TREES]: New tree planting"); + CreateTree(new LLVector3(128.0f, 128.0f, 0.0f)); + } + } + + void growTrees() + { + foreach (LLUUID tree in m_trees) + { + if (m_scene.Entities.ContainsKey(tree)) + { + SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + + // 100 seconds to grow 1m + s_tree.Scale += new LLVector3(0.1f, 0.1f, 0.1f); + s_tree.SendFullUpdateToAllClients(); + //s_tree.ScheduleTerseUpdate(); + } + else + { + m_trees.Remove(tree); + } + } + } + + void seedTrees() + { + foreach (LLUUID tree in m_trees) + { + if (m_scene.Entities.ContainsKey(tree)) + { + SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + + if (s_tree.Scale.X > 0.5) + { + if (Util.RandomClass.NextDouble() > 0.75) + { + SpawnChild(s_tree); + } + } + + } + else + { + m_trees.Remove(tree); + } + } + } + + void killTrees() + { + foreach (LLUUID tree in m_trees) + { + double killLikelyhood = 0.0; + + if (m_scene.Entities.ContainsKey(tree)) + { + SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) + + Math.Pow(selectedTree.Scale.Y, 2) + + Math.Pow(selectedTree.Scale.Z, 2)); + + foreach (LLUUID picktree in m_trees) + { + if (picktree != tree) + { + SceneObjectPart pickedTree = ((SceneObjectGroup)m_scene.Entities[picktree]).RootPart; + + double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) + + Math.Pow(pickedTree.Scale.Y, 2) + + Math.Pow(pickedTree.Scale.Z, 2)); + + double pickedTreeDistance = Math.Sqrt(Math.Pow(Math.Abs(pickedTree.AbsolutePosition.X - selectedTree.AbsolutePosition.X), 2) + + Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Y - selectedTree.AbsolutePosition.Y), 2) + + Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Z - selectedTree.AbsolutePosition.Z), 2)); + + killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1; + } + } + + if (Util.RandomClass.NextDouble() < killLikelyhood) + { + m_scene.RemoveEntity(selectedTree.ParentGroup); + m_trees.Remove(selectedTree.ParentGroup.UUID); + + m_scene.ForEachClient(delegate(IClientAPI controller) + { + controller.SendKillObject(m_scene.RegionInfo.RegionHandle, + selectedTree.LocalID); + }); + + break; + } + else + { + selectedTree.SetText(killLikelyhood.ToString(), new Axiom.Math.Vector3(1.0f, 1.0f, 1.0f), 1.0); + } + } + else + { + m_trees.Remove(tree); + } + } + } + + private void SpawnChild(SceneObjectPart s_tree) + { + LLVector3 position = new LLVector3(); + + position.X = s_tree.AbsolutePosition.X + (1 * (-1 * Util.RandomClass.Next(1))); + if (position.X > 255) + position.X = 255; + if (position.X < 0) + position.X = 0; + position.Y = s_tree.AbsolutePosition.Y + (1 * (-1 * Util.RandomClass.Next(1))); + if (position.Y > 255) + position.Y = 255; + if (position.Y < 0) + position.Y = 0; + + double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); + double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); + + position.X += (float)randX; + position.Y += (float)randY; + + CreateTree(position); + } + + private void CreateTree(LLVector3 position) + { + position.Z = (float)m_scene.Terrain.heightmap.Get((int)position.X, (int)position.Y); + + SceneObjectGroup tree = + m_scene.AddTree(new LLVector3(0.1f, 0.1f, 0.1f), + LLQuaternion.Identity, + position, + Tree.Cypress1, + false); + + m_trees.Add(tree.UUID); + tree.SendGroupFullUpdate(); + } + + void CalculateTrees_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + growTrees(); + seedTrees(); + killTrees(); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "TreePopulatorModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs index 3027132686..1ac6ad227d 100644 --- a/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs +++ b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs @@ -1,109 +1,191 @@ -using System; -using System.Collections.Generic; -using libsecondlife; -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class UserTextureDownloadService - { - private readonly Dictionary m_textureSenders = new Dictionary(); - private readonly BlockingQueue m_sharedSendersQueue; - private readonly Scene m_scene; - - public UserTextureDownloadService(Scene scene, BlockingQueue sharedQueue) - { - m_scene = scene; - m_sharedSendersQueue = sharedQueue; - } - - public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e) - { - TextureSender textureSender; - - //TODO: should be working out the data size/ number of packets to be sent for each discard level - if ((e.DiscardLevel >= 0) || (e.Priority != 0)) - { - lock (m_textureSenders) - { - if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) - { - textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); - - if ((textureSender.ImageLoaded) && - (textureSender.Sending == false)) - { - EnqueueTextureSender(textureSender); - } - } - else - { - TextureSender requestHandler = - new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber); - m_textureSenders.Add(e.RequestedAssetID, requestHandler); - m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback); - } - } - } - else - { - lock (m_textureSenders) - { - if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) - { - textureSender.Cancel = true; - } - } - } - } - - public void TextureCallback(LLUUID textureID, AssetBase asset) - { - lock (m_textureSenders) - { - TextureSender textureSender; - - if (m_textureSenders.TryGetValue(textureID, out textureSender)) - { - if (!textureSender.ImageLoaded) - { - textureSender.TextureReceived(asset); - - EnqueueTextureSender(textureSender); - } - } - else - { - throw new Exception("Got a texture with no sender object to handle it, this shouldn't happen"); - } - } - } - - private void EnqueueTextureSender(TextureSender textureSender) - { - textureSender.Cancel = false; - textureSender.Sending = true; - textureSender.counter = 0; - - if (!m_sharedSendersQueue.Contains(textureSender)) - { - m_sharedSendersQueue.Enqueue(textureSender); - } - } - - internal void Close() - { - lock (m_textureSenders) - { - foreach( TextureSender textureSender in m_textureSenders.Values ) - { - textureSender.Cancel = true; - } - - m_textureSenders.Clear(); - } - } - } -} +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using libsecondlife; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + /// + /// This module sets up texture senders in response to client texture requests, and places them on a + /// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the + /// asset cache). + /// + public class UserTextureDownloadService + { + private static readonly log4net.ILog m_log + = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Holds texture senders before they have received the appropriate texture from the asset cache. + /// + private readonly Dictionary m_textureSenders = new Dictionary(); + + /// + /// Texture Senders are placed in this queue once they have received their texture from the asset + /// cache. Another module actually invokes the send. + /// + private readonly BlockingQueue m_sharedSendersQueue; + + private readonly Scene m_scene; + + public UserTextureDownloadService(Scene scene, BlockingQueue sharedQueue) + { + m_scene = scene; + m_sharedSendersQueue = sharedQueue; + } + + /// + /// Handle a texture request. This involves creating a texture sender and placing it on the + /// previously passed in shared queue. + /// + /// + /// + public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e) + { + TextureSender textureSender; + + //TODO: should be working out the data size/ number of packets to be sent for each discard level + if ((e.DiscardLevel >= 0) || (e.Priority != 0)) + { + lock (m_textureSenders) + { + if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) + { + // If we've received new non UUID information for this request and it hasn't dispatched + // yet, then update the request accordingly. + textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); + } + else + { + //m_log.DebugFormat("[USER TEXTURE DOWNLOAD]: Adding download stat {0}", e.RequestedAssetID); + m_scene.AddPendingDownloads(1); + + TextureSender requestHandler = + new TextureSender(client, e.DiscardLevel, e.PacketNumber); + m_textureSenders.Add(e.RequestedAssetID, requestHandler); + + m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback, true); + } + } + } + else + { + lock (m_textureSenders) + { + if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) + { + textureSender.Cancel = true; + } + } + } + } + + /// + /// The callback for the asset cache when a texture has been retrieved. This method queues the + /// texture sender for processing. + /// + /// + /// + public void TextureCallback(LLUUID textureID, AssetBase texture) + { + lock (m_textureSenders) + { + TextureSender textureSender; + + if (m_textureSenders.TryGetValue(textureID, out textureSender)) + { + if (null != texture) + { + if (!textureSender.ImageLoaded) + { + textureSender.TextureReceived(texture); + EnqueueTextureSender(textureSender); + } + } + else + { + // Right now, leaving it up to lower level asset server code to post the fact that + // this texture could not be found + + // TODO Send packet back to the client telling it not to expect the texture + + //m_log.DebugFormat("[USER TEXTURE DOWNLOAD]: Removing download stat for {0}", textureID); + m_scene.AddPendingDownloads(-1); + } + + //m_log.InfoFormat("[TEXTURE SENDER] Removing texture sender with uuid {0}", textureID); + m_textureSenders.Remove(textureID); + //m_log.InfoFormat("[TEXTURE SENDER] Current texture senders in dictionary: {0}", m_textureSenders.Count); + } + else + { + m_log.WarnFormat( + "Got a texture uuid {0} with no sender object to handle it, this shouldn't happen", + textureID); + } + } + } + + /// + /// Place a ready texture sender on the processing queue. + /// + /// + private void EnqueueTextureSender(TextureSender textureSender) + { + textureSender.Cancel = false; + textureSender.Sending = true; + textureSender.counter = 0; + + if (!m_sharedSendersQueue.Contains(textureSender)) + { + m_sharedSendersQueue.Enqueue(textureSender); + } + } + + /// + /// Close this module. + /// + internal void Close() + { + lock (m_textureSenders) + { + foreach( TextureSender textureSender in m_textureSenders.Values ) + { + textureSender.Cancel = true; + } + + m_textureSenders.Clear(); + } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/WorldCommModule.cs index b6f49e9aa3..3979bdfe3a 100644 --- a/OpenSim/Region/Environment/Modules/WorldCommModule.cs +++ b/OpenSim/Region/Environment/Modules/WorldCommModule.cs @@ -1,495 +1,531 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Generic; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -/***************************************************** - * - * WorldCommModule - * - * - * Holding place for world comms - basically llListen - * function implementation. - * - * lLListen(integer channel, string name, key id, string msg) - * The name, id, and msg arguments specify the filtering - * criteria. You can pass the empty string - * (or NULL_KEY for id) for these to set a completely - * open filter; this causes the listen() event handler to be - * invoked for all chat on the channel. To listen only - * for chat spoken by a specific object or avatar, - * specify the name and/or id arguments. To listen - * only for a specific command, specify the - * (case-sensitive) msg argument. If msg is not empty, - * listener will only hear strings which are exactly equal - * to msg. You can also use all the arguments to establish - * the most restrictive filtering criteria. - * - * It might be useful for each listener to maintain a message - * digest, with a list of recent messages by UUID. This can - * be used to prevent in-world repeater loops. However, the - * linden functions do not have this capability, so for now - * thats the way it works. - * - * **************************************************/ - -namespace OpenSim.Region.Environment.Modules -{ - public class WorldCommModule : IRegionModule, IWorldComm - { - private Scene m_scene; - private object CommListLock = new object(); - private string m_name = "WorldCommModule"; - private ListenerManager m_listenerManager; - private Queue m_pending; - - public WorldCommModule() - { - } - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - m_scene.RegisterModuleInterface(this); - m_listenerManager = new ListenerManager(); - m_pending = new Queue(); - m_scene.EventManager.OnNewClient += NewClient; - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return m_name; } - } - - public bool IsSharedModule - { - get { return false; } - } - - public void NewClient(IClientAPI client) - { - client.OnChatFromViewer += DeliverClientMessage; - } - - private void DeliverClientMessage(Object sender, ChatFromViewerArgs e) - { - DeliverMessage(e.Sender.AgentId.ToString(), - e.Type, e.Channel, - e.Sender.FirstName + " " + e.Sender.LastName, - e.Message); - } - - public int Listen(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) - { - return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); - } - - public void ListenControl(int handle, int active) - { - if (active == 1) - m_listenerManager.Activate(handle); - else if (active == 0) - m_listenerManager.Dectivate(handle); - } - - public void ListenRemove(int handle) - { - m_listenerManager.Remove(handle); - } - - // This method scans nearby objects and determines if they are listeners, - // and if so if this message fits the filter. If it does, then - // enqueue the message for delivery to the objects listen event handler. - // Objects that do an llSay have their messages delivered here, and for - // nearby avatars, the SimChat function is used. - public void DeliverMessage(string sourceItemID, ChatTypeEnum type, int channel, string name, string msg) - { - SceneObjectPart source = null; - ScenePresence avatar = null; - - source = m_scene.GetSceneObjectPart(new LLUUID(sourceItemID)); - if (source == null) - { - avatar = m_scene.GetScenePresence(new LLUUID(sourceItemID)); - } - if ((avatar != null) || (source != null)) - { - // Loop through the objects in the scene - // If they are in proximity, then if they are - // listeners, if so add them to the pending queue - - lock (m_scene.Entities) - { - foreach (LLUUID eb in m_scene.Entities.Keys) - { - EntityBase sPart; - - m_scene.Entities.TryGetValue(eb, out sPart); - - // Dont process if this message is from itself! - if (eb.ToString().Equals(sourceItemID) || - sPart.UUID.ToString().Equals(sourceItemID)) - continue; - - double dis = 0; - - if (source != null) - dis = Util.GetDistanceTo(sPart.AbsolutePosition, source.AbsolutePosition); - else - dis = Util.GetDistanceTo(sPart.AbsolutePosition, avatar.AbsolutePosition); - - switch (type) - { - case ChatTypeEnum.Whisper: - - if ((dis < 10) && (dis > -10)) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) - { - m_pending.Enqueue(isListener); - } - } - break; - - case ChatTypeEnum.Say: - - if ((dis < 30) && (dis > -30)) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) - { - m_pending.Enqueue(isListener); - } - } - break; - - case ChatTypeEnum.Shout: - if ((dis < 100) && (dis > -100)) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) - { - m_pending.Enqueue(isListener); - } - } - break; - - case ChatTypeEnum.Broadcast: - ListenerInfo isListen = - m_listenerManager.IsListenerMatch(sourceItemID, eb, channel, name, msg); - if (isListen != null) - { - ListenerInfo isListener = m_listenerManager.IsListenerMatch( - sourceItemID, sPart.UUID, channel, name, msg - ); - if (isListener != null) - { - m_pending.Enqueue(isListener); - } - } - break; - } - } - } - } - } - - public bool HasMessages() - { - return (m_pending.Count > 0); - } - - public ListenerInfo GetNextMessage() - { - ListenerInfo li = null; - - lock (CommListLock) - { - li = m_pending.Dequeue(); - } - - return li; - } - } - - // hostID: the ID of the ScenePart - // itemID: the ID of the script host engine - // localID: local ID of host engine - public class ListenerManager - { - private Dictionary m_listeners; - private object ListenersLock = new object(); - private int m_MaxListeners = 100; - - public ListenerManager() - { - m_listeners = new Dictionary(); - } - - public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, - string msg) - { - if (m_listeners.Count < m_MaxListeners) - { - ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg); - - if (isListener == null) - { - int newHandle = GetNewHandle(); - - if (newHandle > -1) - { - ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg); - - lock (ListenersLock) - { - m_listeners.Add(newHandle, li); - } - - return newHandle; - } - } - } - - return -1; - } - - public void Remove(int handle) - { - m_listeners.Remove(handle); - } - - private int GetNewHandle() - { - for (int i = 0; i < int.MaxValue - 1; i++) - { - if (!m_listeners.ContainsKey(i)) - return i; - } - - return -1; - } - - public bool IsListener(LLUUID hostID) - { - foreach (ListenerInfo li in m_listeners.Values) - { - if (li.GetHostID().Equals(hostID)) - return true; - } - - return false; - } - - public void Activate(int handle) - { - ListenerInfo li; - - if (m_listeners.TryGetValue(handle, out li)) - { - li.Activate(); - } - } - - public void Dectivate(int handle) - { - ListenerInfo li; - - if (m_listeners.TryGetValue(handle, out li)) - { - li.Deactivate(); - } - } - - // Theres probably a more clever and efficient way to - // do this, maybe with regex. - public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name, - string msg) - { - bool isMatch = true; - - foreach (ListenerInfo li in m_listeners.Values) - { - if (li.GetHostID().Equals(listenerKey)) - { - if (li.IsActive()) - { - if (channel == li.GetChannel()) - { - if ((li.GetID().ToString().Length > 0) && - (!li.GetID().Equals(LLUUID.Zero))) - { - if (!li.GetID().ToString().Equals(sourceItemID)) - { - isMatch = false; - } - } - if (isMatch && (li.GetName().Length > 0)) - { - if (li.GetName().Equals(name)) - { - isMatch = false; - } - } - if (isMatch) - { - return new ListenerInfo( - li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(), - li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID) - ); - } - } - } - } - } - return null; - } - } - - public class ListenerInfo - { - private LLUUID m_itemID; // ID of the host script engine - private LLUUID m_hostID; // ID of the host/scene part - private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message - private int m_channel; // Channel - private int m_handle; // Assigned handle of this listener - private uint m_localID; // Local ID from script engine - private string m_name; // Object name to filter messages from - private LLUUID m_id; // ID to filter messages from - private string m_message; // The message - private bool m_active; // Listener is active or not - - public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, - string message) - { - Initialise(localID, handle, ItemID, hostID, channel, name, id, message); - } - - public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, - string message, LLUUID sourceItemID) - { - Initialise(localID, handle, ItemID, hostID, channel, name, id, message); - m_sourceItemID = sourceItemID; - } - - private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, - LLUUID id, string message) - { - m_handle = handle; - m_channel = channel; - m_itemID = ItemID; - m_hostID = hostID; - m_name = name; - m_id = id; - m_message = message; - m_active = true; - m_localID = localID; - } - - public LLUUID GetItemID() - { - return m_itemID; - } - - public LLUUID GetHostID() - { - return m_hostID; - } - - public LLUUID GetSourceItemID() - { - return m_sourceItemID; - } - - public int GetChannel() - { - return m_channel; - } - - public uint GetLocalID() - { - return m_localID; - } - - public int GetHandle() - { - return m_handle; - } - - public string GetMessage() - { - return m_message; - } - - public string GetName() - { - return m_name; - } - - public bool IsActive() - { - return m_active; - } - - public void Deactivate() - { - m_active = false; - } - - public void Activate() - { - m_active = true; - } - - public LLUUID GetID() - { - return m_id; - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +/***************************************************** + * + * WorldCommModule + * + * + * Holding place for world comms - basically llListen + * function implementation. + * + * lLListen(integer channel, string name, key id, string msg) + * The name, id, and msg arguments specify the filtering + * criteria. You can pass the empty string + * (or NULL_KEY for id) for these to set a completely + * open filter; this causes the listen() event handler to be + * invoked for all chat on the channel. To listen only + * for chat spoken by a specific object or avatar, + * specify the name and/or id arguments. To listen + * only for a specific command, specify the + * (case-sensitive) msg argument. If msg is not empty, + * listener will only hear strings which are exactly equal + * to msg. You can also use all the arguments to establish + * the most restrictive filtering criteria. + * + * It might be useful for each listener to maintain a message + * digest, with a list of recent messages by UUID. This can + * be used to prevent in-world repeater loops. However, the + * linden functions do not have this capability, so for now + * thats the way it works. + * + * **************************************************/ + +namespace OpenSim.Region.Environment.Modules +{ + public class WorldCommModule : IRegionModule, IWorldComm + { + private Scene m_scene; + private object CommListLock = new object(); + private object ListLock = new object(); + private string m_name = "WorldCommModule"; + private ListenerManager m_listenerManager; + private Queue m_pending; + + public WorldCommModule() + { + } + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + m_scene.RegisterModuleInterface(this); + m_listenerManager = new ListenerManager(); + m_scene.EventManager.OnNewClient += NewClient; + m_pending = new Queue(); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return m_name; } + } + + public bool IsSharedModule + { + get { return false; } + } + + public void NewClient(IClientAPI client) + { + client.OnChatFromViewer += DeliverClientMessage; + } + + private void DeliverClientMessage(Object sender, ChatFromViewerArgs e) + { + DeliverMessage(e.Sender.AgentId.ToString(), + e.Type, e.Channel, + e.Sender.FirstName + " " + e.Sender.LastName, + e.Message); + } + + public int Listen(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) + { + return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); + } + + public void ListenControl(int handle, int active) + { + if (active == 1) + m_listenerManager.Activate(handle); + else if (active == 0) + m_listenerManager.Dectivate(handle); + } + + public void ListenRemove(int handle) + { + m_listenerManager.Remove(handle); + } + + public void DeleteListener(LLUUID itemID) + { + if (m_listenerManager != null) + { + lock (ListLock) + { + m_listenerManager.DeleteListener(itemID); + } + } + + } + + // This method scans nearby objects and determines if they are listeners, + // and if so if this message fits the filter. If it does, then + // enqueue the message for delivery to the objects listen event handler. + // Objects that do an llSay have their messages delivered here, and for + // nearby avatars, the SimChat function is used. + public void DeliverMessage(string sourceItemID, ChatTypeEnum type, int channel, string name, string msg) + { + SceneObjectPart source = null; + ScenePresence avatar = null; + + source = m_scene.GetSceneObjectPart(new LLUUID(sourceItemID)); + if (source == null) + { + avatar = m_scene.GetScenePresence(new LLUUID(sourceItemID)); + } + if ((avatar != null) || (source != null)) + { + // Loop through the objects in the scene + // If they are in proximity, then if they are + // listeners, if so add them to the pending queue + + foreach (ListenerInfo li in m_listenerManager.GetListeners()) + { + foreach (LLUUID eb in m_scene.Entities.Keys) + { + EntityBase sPart; + + m_scene.Entities.TryGetValue(li.GetHostID(), out sPart); + + // Dont process if this message is from itself! + if (li.GetHostID().ToString().Equals(sourceItemID) || + sPart.UUID.ToString().Equals(sourceItemID)) + continue; + + double dis = 0; + + if (source != null) + dis = Util.GetDistanceTo(sPart.AbsolutePosition, source.AbsolutePosition); + else + dis = Util.GetDistanceTo(sPart.AbsolutePosition, avatar.AbsolutePosition); + + switch (type) + { + case ChatTypeEnum.Whisper: + + if ((dis < 10) && (dis > -10)) + { + lock (CommListLock) + { + m_pending.Enqueue(isListener); + } + } + break; + + case ChatTypeEnum.Say: + + if ((dis < 30) && (dis > -30)) + { + lock (CommListLock) + { + m_pending.Enqueue(isListener); + } + } + break; + + case ChatTypeEnum.Shout: + if ((dis < 100) && (dis > -100)) + { + lock (CommListLock) + { + m_pending.Enqueue(isListener); + } + } + break; + + case ChatTypeEnum.Broadcast: + ListenerInfo isListen = + m_listenerManager.IsListenerMatch(sourceItemID, li.GetItemID(), channel, name, msg); + if (isListen != null) + { + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + lock (CommListLock) + { + m_pending.Enqueue(isListener); + } + } + break; + } + } + } + } + } + + public bool HasMessages() + { + if (m_pending != null) + return (m_pending.Count > 0); + else + return false; + } + + public ListenerInfo GetNextMessage() + { + ListenerInfo li = null; + + lock (CommListLock) + { + li = m_pending.Dequeue(); + } + + return li; + } + + public uint PeekNextMessageLocalID() + { + return m_pending.Peek().GetLocalID(); + } + + public LLUUID PeekNextMessageItemID() + { + return m_pending.Peek().GetItemID(); + } + + } + + // hostID: the ID of the ScenePart + // itemID: the ID of the script host engine + // localID: local ID of host engine + public class ListenerManager + { + private Dictionary m_listeners; + private object ListenersLock = new object(); + private int m_MaxListeners = 100; + + public ListenerManager() + { + m_listeners = new Dictionary(); + } + + public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) + { + if (m_listeners.Count < m_MaxListeners) + { + ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg); + + if (isListener == null) + { + int newHandle = GetNewHandle(); + + if (newHandle > -1) + { + ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg); + + lock (ListenersLock) + { + m_listeners.Add(newHandle, li); + } + + return newHandle; + } + } + } + + return -1; + } + + public void Remove(int handle) + { + m_listeners.Remove(handle); + } + + public void DeleteListener(LLUUID itemID) + { + foreach (ListenerInfo li in m_listeners.Values) + { + if (li.GetItemID().Equals(itemID)) + { + Remove(li.GetHandle()); + return; + } + } + } + + private int GetNewHandle() + { + for (int i = 0; i < int.MaxValue - 1; i++) + { + if (!m_listeners.ContainsKey(i)) + return i; + } + + return -1; + } + + public bool IsListener(LLUUID hostID) + { + foreach (ListenerInfo li in m_listeners.Values) + { + if (li.GetHostID().Equals(hostID)) + return true; + } + + return false; + } + + public void Activate(int handle) + { + ListenerInfo li; + + if (m_listeners.TryGetValue(handle, out li)) + { + li.Activate(); + } + } + + public void Dectivate(int handle) + { + ListenerInfo li; + + if (m_listeners.TryGetValue(handle, out li)) + { + li.Deactivate(); + } + } + + // Theres probably a more clever and efficient way to + // do this, maybe with regex. + public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name, + string msg) + { + bool isMatch = true; + + foreach (ListenerInfo li in m_listeners.Values) + { + if (li.GetHostID().Equals(listenerKey)) + { + if (li.IsActive()) + { + if (channel == li.GetChannel()) + { + if ((li.GetID().ToString().Length > 0) && + (!li.GetID().Equals(LLUUID.Zero))) + { + if (!li.GetID().ToString().Equals(sourceItemID)) + { + isMatch = false; + } + } + if (isMatch && (li.GetName().Length > 0)) + { + if (li.GetName().Equals(name)) + { + isMatch = false; + } + } + if (isMatch) + { + return new ListenerInfo( + li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(), + li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID) + ); + } + } + } + } + } + return null; + } + + public Dictionary.ValueCollection GetListeners() + { + return m_listeners.Values; + } + } + + public class ListenerInfo + { + private LLUUID m_itemID; // ID of the host script engine + private LLUUID m_hostID; // ID of the host/scene part + private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message + private int m_channel; // Channel + private int m_handle; // Assigned handle of this listener + private uint m_localID; // Local ID from script engine + private string m_name; // Object name to filter messages from + private LLUUID m_id; // ID to filter messages from + private string m_message; // The message + private bool m_active; // Listener is active or not + + public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message) + { + Initialise(localID, handle, ItemID, hostID, channel, name, id, message); + } + + public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, + string message, LLUUID sourceItemID) + { + Initialise(localID, handle, ItemID, hostID, channel, name, id, message); + m_sourceItemID = sourceItemID; + } + + private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, + LLUUID id, string message) + { + m_handle = handle; + m_channel = channel; + m_itemID = ItemID; + m_hostID = hostID; + m_name = name; + m_id = id; + m_message = message; + m_active = true; + m_localID = localID; + } + + public LLUUID GetItemID() + { + return m_itemID; + } + + public LLUUID GetHostID() + { + return m_hostID; + } + + public LLUUID GetSourceItemID() + { + return m_sourceItemID; + } + + public int GetChannel() + { + return m_channel; + } + + public uint GetLocalID() + { + return m_localID; + } + + public int GetHandle() + { + return m_handle; + } + + public string GetMessage() + { + return m_message; + } + + public string GetName() + { + return m_name; + } + + public bool IsActive() + { + return m_active; + } + + public void Deactivate() + { + m_active = false; + } + + public void Activate() + { + m_active = true; + } + + public LLUUID GetID() + { + return m_id; + } + + } +} diff --git a/OpenSim/Region/Environment/Modules/XMLRPCModule.cs b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs index 7b82d901b0..2c4948c0d1 100644 --- a/OpenSim/Region/Environment/Modules/XMLRPCModule.cs +++ b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs @@ -1,416 +1,682 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Collections.Generic; -using System.Threading; -using libsecondlife; -using Nini.Config; -using Nwc.XmlRpc; -using OpenSim.Framework.Console; -using OpenSim.Framework.Servers; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -/***************************************************** - * - * XMLRPCModule - * - * Module for accepting incoming communications from - * external XMLRPC client and calling a remote data - * procedure for a registered data channel/prim. - * - * - * 1. On module load, open a listener port - * 2. Attach an XMLRPC handler - * 3. When a request is received: - * 3.1 Parse into components: channel key, int, string - * 3.2 Look up registered channel listeners - * 3.3 Call the channel (prim) remote data method - * 3.4 Capture the response (llRemoteDataReply) - * 3.5 Return response to client caller - * 3.6 If no response from llRemoteDataReply within - * RemoteReplyScriptTimeout, generate script timeout fault - * - * Prims in script must: - * 1. Open a remote data channel - * 1.1 Generate a channel ID - * 1.2 Register primid,channelid pair with module - * 2. Implement the remote data procedure handler - * - * llOpenRemoteDataChannel - * llRemoteDataReply - * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval) - * llCloseRemoteDataChannel - * - * **************************************************/ - -namespace OpenSim.Region.Environment.Modules -{ - public class XMLRPCModule : IRegionModule, IXMLRPC - { - private Scene m_scene; - private Queue rpcQueue = new Queue(); - private object XMLRPCListLock = new object(); - private string m_name = "XMLRPCModule"; - private int RemoteReplyScriptWait = 300; - private int RemoteReplyScriptTimeout = 900; - private int m_remoteDataPort = 0; - private List m_scenes = new List(); - private LogBase m_log; - - // - private Dictionary m_openChannels; - - // - private Dictionary m_pendingResponse; - - public XMLRPCModule() - { - m_log = MainLog.Instance; - } - - public void Initialise(Scene scene, IConfigSource config) - { - try - { - m_remoteDataPort = config.Configs["Network"].GetInt("remoteDataPort", m_remoteDataPort); - } - catch (Exception) - { - } - - if (!m_scenes.Contains(scene)) - { - m_scenes.Add(scene); - - scene.RegisterModuleInterface(this); - } - } - - public void PostInitialise() - { - if (IsEnabled()) - { - m_openChannels = new Dictionary(); - m_pendingResponse = new Dictionary(); - - // Start http server - // Attach xmlrpc handlers - m_log.Verbose("REMOTE_DATA", - "Starting XMLRPC Server on port " + m_remoteDataPort + " for llRemoteData commands."); - BaseHttpServer httpServer = new BaseHttpServer((uint) m_remoteDataPort); - httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData); - httpServer.Start(); - } - } - - public void Close() - { - } - - public string Name - { - get { return m_name; } - } - - public bool IsSharedModule - { - get { return true; } - } - - public bool IsEnabled() - { - return (m_remoteDataPort > 0); - } - - /********************************************** - * OpenXMLRPCChannel - * - * Generate a LLUUID channel key and add it and - * the prim id to dictionary - * - * First check if there is a channel assigned for - * this itemID. If there is, then someone called - * llOpenRemoteDataChannel twice. Just return the - * original channel. Other option is to delete the - * current channel and assign a new one. - * - * ********************************************/ - - public LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID) - { - LLUUID channel = null; - - //Is a dupe? - foreach (RPCChannelInfo ci in m_openChannels.Values) - { - if (ci.GetItemID().Equals(itemID)) - { - // return the original channel ID for this item - channel = ci.GetChannelID(); - break; - } - } - - if ((channel.Equals(null)) || (channel.Equals(LLUUID.Zero))) - { - channel = LLUUID.Random(); - RPCChannelInfo rpcChanInfo = new RPCChannelInfo(localID, itemID, channel); - lock (XMLRPCListLock) - { - m_openChannels.Add(channel, rpcChanInfo); - } - } - - return channel; - } - - /********************************************** - * Remote Data Reply - * - * Response to RPC message - * - *********************************************/ - - public void RemoteDataReply(string channel, string message_id, string sdata, int idata) - { - RPCRequestInfo rpcInfo; - LLUUID message_key = new LLUUID(message_id); - - if (m_pendingResponse.TryGetValue(message_key, out rpcInfo)) - { - rpcInfo.SetRetval(sdata); - rpcInfo.SetProcessed(true); - - lock (XMLRPCListLock) - { - m_pendingResponse.Remove(message_key); - } - } - } - - /********************************************** - * CloseXMLRPCChannel - * - * Remove channel from dictionary - * - *********************************************/ - - public void CloseXMLRPCChannel(LLUUID channelKey) - { - if (m_openChannels.ContainsKey(channelKey)) - m_openChannels.Remove(channelKey); - } - - - public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request) - { - XmlRpcResponse response = new XmlRpcResponse(); - - Hashtable requestData = (Hashtable) request.Params[0]; - bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") && - requestData.Contains("StringValue")); - - if (GoodXML) - { - LLUUID channel = new LLUUID((string) requestData["Channel"]); - RPCChannelInfo rpcChanInfo; - if (m_openChannels.TryGetValue(channel, out rpcChanInfo)) - { - string intVal = (string) requestData["IntValue"]; - string strVal = (string) requestData["StringValue"]; - - RPCRequestInfo rpcInfo; - - lock (XMLRPCListLock) - { - rpcInfo = - new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal, - intVal); - rpcQueue.Enqueue(rpcInfo); - } - - int timeoutCtr = 0; - - while (!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout)) - { - Thread.Sleep(RemoteReplyScriptWait); - timeoutCtr += RemoteReplyScriptWait; - } - if (rpcInfo.IsProcessed()) - { - response.Value = rpcInfo.GetRetval(); - rpcInfo = null; - } - else - { - response.SetFault(-1, "Script timeout"); - lock (XMLRPCListLock) - { - m_pendingResponse.Remove(rpcInfo.GetMessageID()); - } - } - } - else - { - response.SetFault(-1, "Invalid channel"); - } - } - - return response; - } - - public bool hasRequests() - { - return (rpcQueue.Count > 0); - } - - public RPCRequestInfo GetNextRequest() - { - lock (XMLRPCListLock) - { - RPCRequestInfo rpcInfo = rpcQueue.Dequeue(); - m_pendingResponse.Add(rpcInfo.GetMessageID(), rpcInfo); - return rpcInfo; - } - } - } - - /************************************************************** - * - * Class RPCRequestInfo - * - * Holds details about incoming requests until they are picked - * from the queue by LSLLongCmdHandler - * ***********************************************************/ - - public class RPCRequestInfo - { - private string m_StrVal; - private string m_IntVal; - private bool m_processed; - private string m_resp; - private uint m_localID; - private LLUUID m_ItemID; - private LLUUID m_MessageID; - private LLUUID m_ChannelKey; - - public RPCRequestInfo(uint localID, LLUUID itemID, LLUUID channelKey, string strVal, string intVal) - { - m_localID = localID; - m_StrVal = strVal; - m_IntVal = intVal; - m_ItemID = itemID; - m_ChannelKey = channelKey; - m_MessageID = LLUUID.Random(); - m_processed = false; - m_resp = ""; - } - - public bool IsProcessed() - { - return m_processed; - } - - public LLUUID GetChannelKey() - { - return m_ChannelKey; - } - - public void SetProcessed(bool processed) - { - m_processed = processed; - } - - public void SetRetval(string resp) - { - m_resp = resp; - } - - public string GetRetval() - { - return m_resp; - } - - public uint GetLocalID() - { - return m_localID; - } - - public LLUUID GetItemID() - { - return m_ItemID; - } - - public string GetStrVal() - { - return m_StrVal; - } - - public int GetIntValue() - { - return int.Parse(m_IntVal); - } - - public LLUUID GetMessageID() - { - return m_MessageID; - } - } - - public class RPCChannelInfo - { - private LLUUID m_itemID; - private uint m_localID; - private LLUUID m_ChannelKey; - - public RPCChannelInfo(uint localID, LLUUID itemID, LLUUID channelID) - { - m_ChannelKey = channelID; - m_localID = localID; - m_itemID = itemID; - } - - public LLUUID GetItemID() - { - return m_itemID; - } - - public LLUUID GetChannelID() - { - return m_ChannelKey; - } - - public uint GetLocalID() - { - return m_localID; - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Collections.Generic; +using System.Threading; +using libsecondlife; +using Nini.Config; +using Nwc.XmlRpc; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +/***************************************************** + * + * XMLRPCModule + * + * Module for accepting incoming communications from + * external XMLRPC client and calling a remote data + * procedure for a registered data channel/prim. + * + * + * 1. On module load, open a listener port + * 2. Attach an XMLRPC handler + * 3. When a request is received: + * 3.1 Parse into components: channel key, int, string + * 3.2 Look up registered channel listeners + * 3.3 Call the channel (prim) remote data method + * 3.4 Capture the response (llRemoteDataReply) + * 3.5 Return response to client caller + * 3.6 If no response from llRemoteDataReply within + * RemoteReplyScriptTimeout, generate script timeout fault + * + * Prims in script must: + * 1. Open a remote data channel + * 1.1 Generate a channel ID + * 1.2 Register primid,channelid pair with module + * 2. Implement the remote data procedure handler + * + * llOpenRemoteDataChannel + * llRemoteDataReply + * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval) + * llCloseRemoteDataChannel + * + * **************************************************/ + +namespace OpenSim.Region.Environment.Modules +{ + public class XMLRPCModule : IRegionModule, IXMLRPC + { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + private object XMLRPCListLock = new object(); + private string m_name = "XMLRPCModule"; + private int RemoteReplyScriptWait = 300; + private int RemoteReplyScriptTimeout = 9000; + private int m_remoteDataPort = 0; + private List m_scenes = new List(); + + // + private Dictionary m_openChannels; + + private Dictionary m_rpcPending; + private Dictionary m_rpcPendingResponses; + + private Dictionary m_pendingSRDResponses; + + public void Initialise(Scene scene, IConfigSource config) + { + try + { + m_remoteDataPort = config.Configs["Network"].GetInt("remoteDataPort", m_remoteDataPort); + } + catch (Exception) + { + } + + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + + scene.RegisterModuleInterface(this); + } + } + + public void PostInitialise() + { + if (IsEnabled()) + { + m_openChannels = new Dictionary(); + m_rpcPending = new Dictionary(); + m_rpcPendingResponses = new Dictionary(); + m_pendingSRDResponses = new Dictionary(); + + // Start http server + // Attach xmlrpc handlers + m_log.Info("[REMOTE_DATA]: " + + "Starting XMLRPC Server on port " + m_remoteDataPort + " for llRemoteData commands."); + BaseHttpServer httpServer = new BaseHttpServer((uint)m_remoteDataPort); + httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData); + httpServer.Start(); + } + } + + public void Close() + { + } + + public string Name + { + get { return m_name; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public bool IsEnabled() + { + return (m_remoteDataPort > 0); + } + + /********************************************** + * OpenXMLRPCChannel + * + * Generate a LLUUID channel key and add it and + * the prim id to dictionary + * + * First check if there is a channel assigned for + * this itemID. If there is, then someone called + * llOpenRemoteDataChannel twice. Just return the + * original channel. Other option is to delete the + * current channel and assign a new one. + * + * ********************************************/ + + public LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID) + { + LLUUID channel = null; + + //Is a dupe? + foreach (RPCChannelInfo ci in m_openChannels.Values) + { + if (ci.GetItemID().Equals(itemID)) + { + // return the original channel ID for this item + channel = ci.GetChannelID(); + break; + } + } + + if ((channel.Equals(null)) || (channel.Equals(LLUUID.Zero))) + { + channel = LLUUID.Random(); + RPCChannelInfo rpcChanInfo = new RPCChannelInfo(localID, itemID, channel); + lock (XMLRPCListLock) + { + m_openChannels.Add(channel, rpcChanInfo); + } + } + + return channel; + } + + // Delete channels based on itemID + // for when a script is deleted + public void DeleteChannels(LLUUID itemID) + { + + if (m_openChannels != null) + { + ArrayList tmp = new ArrayList(); + + lock (XMLRPCListLock) + { + foreach (RPCChannelInfo li in m_openChannels.Values) + { + if (li.GetItemID().Equals(itemID)) + { + tmp.Add(itemID); + } + } + + System.Collections.IEnumerator tmpEnumerator = tmp.GetEnumerator(); + while ( tmpEnumerator.MoveNext() ) + m_openChannels.Remove((LLUUID)tmpEnumerator.Current); + } + + } + + } + + /********************************************** + * Remote Data Reply + * + * Response to RPC message + * + *********************************************/ + + public void RemoteDataReply(string channel, string message_id, string sdata, int idata) + { + RPCRequestInfo rpcInfo; + LLUUID message_key = new LLUUID(message_id); + + if (m_rpcPendingResponses.TryGetValue(message_key, out rpcInfo)) + { + rpcInfo.SetStrRetval(sdata); + rpcInfo.SetIntRetval(idata); + rpcInfo.SetProcessed(true); + m_rpcPendingResponses.Remove(message_key); + } + } + + /********************************************** + * CloseXMLRPCChannel + * + * Remove channel from dictionary + * + *********************************************/ + + public void CloseXMLRPCChannel(LLUUID channelKey) + { + if (m_openChannels.ContainsKey(channelKey)) + m_openChannels.Remove(channelKey); + } + + + public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request) + { + XmlRpcResponse response = new XmlRpcResponse(); + + Hashtable requestData = (Hashtable)request.Params[0]; + bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") && + requestData.Contains("StringValue")); + + if (GoodXML) + { + LLUUID channel = new LLUUID((string)requestData["Channel"]); + RPCChannelInfo rpcChanInfo; + if (m_openChannels.TryGetValue(channel, out rpcChanInfo)) + { + string intVal = (string)requestData["IntValue"]; + string strVal = (string)requestData["StringValue"]; + + RPCRequestInfo rpcInfo; + + lock (XMLRPCListLock) + { + rpcInfo = + new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal, + intVal); + m_rpcPending.Add(rpcInfo.GetMessageID(), rpcInfo); + } + + int timeoutCtr = 0; + + while (!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout)) + { + Thread.Sleep(RemoteReplyScriptWait); + timeoutCtr += RemoteReplyScriptWait; + } + if (rpcInfo.IsProcessed()) + { + Hashtable param = new Hashtable(); + param["StringValue"] = rpcInfo.GetStrRetval(); + param["IntValue"] = Convert.ToString(rpcInfo.GetIntRetval()); + + ArrayList parameters = new ArrayList(); + parameters.Add(param); + + response.Value = parameters; + rpcInfo = null; + } + else + { + response.SetFault(-1, "Script timeout"); + rpcInfo = null; + } + } + else + { + response.SetFault(-1, "Invalid channel"); + } + } + + return response; + } + + public bool hasRequests() + { + lock (XMLRPCListLock) + { + if (m_rpcPending != null) + return (m_rpcPending.Count > 0); + else + return false; + } + } + + public RPCRequestInfo GetNextCompletedRequest() + { + if (m_rpcPending != null) + { + lock (XMLRPCListLock) + { + foreach (LLUUID luid in m_rpcPending.Keys) + { + RPCRequestInfo tmpReq; + + if (m_rpcPending.TryGetValue(luid, out tmpReq)) + { + + if (!tmpReq.IsProcessed()) return tmpReq; + } + } + } + } + return null; + } + + public void RemoveCompletedRequest(LLUUID id) + { + lock (XMLRPCListLock) + { + RPCRequestInfo tmp; + if (m_rpcPending.TryGetValue(id, out tmp)) + { + m_rpcPending.Remove(id); + m_rpcPendingResponses.Add(id, tmp); + } + else + { + Console.WriteLine("UNABLE TO REMOVE COMPLETED REQUEST"); + } + } + } + + public LLUUID SendRemoteData(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata) + { + + SendRemoteDataRequest req = new SendRemoteDataRequest( + localID, itemID, channel, dest, idata, sdata + ); + m_pendingSRDResponses.Add(req.GetReqID(), req); + return req.process(); + + } + + public SendRemoteDataRequest GetNextCompletedSRDRequest() + { + if (m_pendingSRDResponses != null) + { + lock (XMLRPCListLock) + { + foreach (LLUUID luid in m_pendingSRDResponses.Keys) + { + SendRemoteDataRequest tmpReq; + + if (m_pendingSRDResponses.TryGetValue(luid, out tmpReq)) + { + if (tmpReq.finished) + return tmpReq; + } + } + } + } + return null; + } + + public void RemoveCompletedSRDRequest(LLUUID id) + { + lock (XMLRPCListLock) + { + SendRemoteDataRequest tmpReq; + if (m_pendingSRDResponses.TryGetValue(id, out tmpReq)) + { + m_pendingSRDResponses.Remove(id); + } + } + } + + public void CancelSRDRequests(LLUUID itemID) + { + if (m_pendingSRDResponses != null) + { + lock (XMLRPCListLock) + { + foreach (SendRemoteDataRequest li in m_pendingSRDResponses.Values) + { + if (li.m_itemID.Equals(itemID)) + m_pendingSRDResponses.Remove(li.GetReqID()); + } + } + } + } + } + /************************************************************** + * + * Class RPCRequestInfo + * + * Holds details about incoming requests until they are picked + * from the queue by LSLLongCmdHandler + * ***********************************************************/ + + public class RPCRequestInfo + { + private string m_StrVal; + private string m_IntVal; + private bool m_processed; + private string m_respStr; + private int m_respInt; + private uint m_localID; + private LLUUID m_ItemID; + private LLUUID m_MessageID; + private LLUUID m_ChannelKey; + + public RPCRequestInfo(uint localID, LLUUID itemID, LLUUID channelKey, string strVal, string intVal) + { + m_localID = localID; + m_StrVal = strVal; + m_IntVal = intVal; + m_ItemID = itemID; + m_ChannelKey = channelKey; + m_MessageID = LLUUID.Random(); + m_processed = false; + m_respStr = String.Empty; + m_respInt = 0; + } + + public bool IsProcessed() + { + return m_processed; + } + + public LLUUID GetChannelKey() + { + return m_ChannelKey; + } + + public void SetProcessed(bool processed) + { + m_processed = processed; + } + + public void SetStrRetval(string resp) + { + m_respStr = resp; + } + + public string GetStrRetval() + { + return m_respStr; + } + public void SetIntRetval(int resp) + { + m_respInt = resp; + } + + public int GetIntRetval() + { + return m_respInt; + } + public uint GetLocalID() + { + return m_localID; + } + + public LLUUID GetItemID() + { + return m_ItemID; + } + + public string GetStrVal() + { + return m_StrVal; + } + + public int GetIntValue() + { + return int.Parse(m_IntVal); + } + + public LLUUID GetMessageID() + { + return m_MessageID; + } + } + + public class RPCChannelInfo + { + private LLUUID m_itemID; + private uint m_localID; + private LLUUID m_ChannelKey; + + public RPCChannelInfo(uint localID, LLUUID itemID, LLUUID channelID) + { + m_ChannelKey = channelID; + m_localID = localID; + m_itemID = itemID; + } + + public LLUUID GetItemID() + { + return m_itemID; + } + + public LLUUID GetChannelID() + { + return m_ChannelKey; + } + + public uint GetLocalID() + { + return m_localID; + } + + } + + public class SendRemoteDataRequest + { + + public LLUUID reqID; + public string destURL; + public string channel; + public string sdata; + public int idata; + public bool finished; + public string response_sdata; + public int response_idata; + public XmlRpcRequest request; + private Thread httpThread; + public LLUUID m_itemID; + public uint m_localID; + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + public SendRemoteDataRequest(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata) + { + + this.channel = channel; + this.destURL = dest; + this.idata = idata; + this.sdata = sdata; + m_itemID = itemID; + m_localID = localID; + + reqID = LLUUID.Random(); + + } + + public LLUUID process() + { + httpThread = new Thread(SendRequest); + httpThread.Name = "HttpRequestThread"; + httpThread.Priority = ThreadPriority.BelowNormal; + httpThread.IsBackground = true; + finished = false; + httpThread.Start(); + OpenSim.Framework.ThreadTracker.Add(httpThread); + + return reqID; + + } + + /* + * TODO: More work on the response codes. Right now + * returning 200 for success or 499 for exception + */ + + public void SendRequest() + { + + Hashtable param = new Hashtable(); + + // Check if channel is an LLUUID + // if not, use as method name + LLUUID parseUID; + string mName = "llRemoteData"; + if( (channel != null) && (channel != "") ) + if( !LLUUID.TryParse(channel, out parseUID) ) + mName = channel; + else + param["Channel"] = channel; + + param["StringValue"] = sdata; + param["IntValue"] = Convert.ToString(idata); + + ArrayList parameters = new ArrayList(); + parameters.Add(param); + XmlRpcRequest req = new XmlRpcRequest(mName, parameters); + try + { + XmlRpcResponse resp = req.Send(destURL, 30000); + if (resp != null) + { + Hashtable respParms; + if(resp.Value.GetType().Equals(Type.GetType("System.Collections.Hashtable"))) { + respParms = (Hashtable)resp.Value; + } + else { + ArrayList respData = (ArrayList)resp.Value; + respParms = (Hashtable)respData[0]; + } + if (respParms != null) + { + if (respParms.Contains("StringValue")) + { + sdata = (string)respParms["StringValue"]; + } + if (respParms.Contains("IntValue")) + { + idata = Convert.ToInt32((string)respParms["IntValue"]); + } + if (respParms.Contains("faultString")) + { + sdata = (string)respParms["faultString"]; + } + if (respParms.Contains("faultCode")) + { + idata = Convert.ToInt32(respParms["faultCode"]); + } + } + } + } + catch (System.Net.WebException we) + { + sdata = we.Message; + m_log.Warn("[SendRemoteDataRequest]: Request failed"); + m_log.Warn(we.StackTrace); + } + + finished = true; + + } + + public void Stop() + { + try + { + httpThread.Abort(); + } + catch (Exception) + { + } + } + + public LLUUID GetReqID() + { + return reqID; + } + + } + +} diff --git a/OpenSim/Region/Environment/Modules/XferModule.cs b/OpenSim/Region/Environment/Modules/XferModule.cs index 340b6d9e89..21f4941812 100644 --- a/OpenSim/Region/Environment/Modules/XferModule.cs +++ b/OpenSim/Region/Environment/Modules/XferModule.cs @@ -1,202 +1,226 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* 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. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSim Project 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 DEVELOPERS 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 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.Generic; -using libsecondlife; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Environment.Interfaces; -using OpenSim.Region.Environment.Scenes; - -namespace OpenSim.Region.Environment.Modules -{ - public class XferModule : IRegionModule, IXfer - { - public Dictionary NewFiles = new Dictionary(); - public Dictionary Transfers = new Dictionary(); - - private Scene m_scene; - - public XferModule() - { - } - - public void Initialise(Scene scene, IConfigSource config) - { - m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - - m_scene.RegisterModuleInterface(this); - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "XferModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - - public void NewClient(IClientAPI client) - { - client.OnRequestXfer += RequestXfer; - client.OnConfirmXfer += AckPacket; - } - - /// - /// - /// - /// - /// - /// - public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName) - { - lock (NewFiles) - { - if (NewFiles.ContainsKey(fileName)) - { - if (!Transfers.ContainsKey(xferID)) - { - byte[] fileData = NewFiles[fileName]; - XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient); - Transfers.Add(xferID, transaction); - NewFiles.Remove(fileName); - transaction.StartSend(); - } - } - } - } - - public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet) - { - if (Transfers.ContainsKey(xferID)) - { - Transfers[xferID].AckPacket(packet); - } - } - - public bool AddNewFile(string fileName, byte[] data) - { - lock (NewFiles) - { - if (NewFiles.ContainsKey(fileName)) - { - NewFiles[fileName] = data; - } - else - { - NewFiles.Add(fileName, data); - } - } - return true; - } - - - public class XferDownLoad - { - public byte[] Data = new byte[0]; - public string FileName = ""; - public ulong XferID = 0; - public int DataPointer = 0; - public uint Packet = 0; - public IClientAPI Client; - public uint Serial = 1; - private bool complete = false; - - public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client) - { - FileName = fileName; - Data = data; - XferID = xferID; - Client = client; - } - - public XferDownLoad() - { - } - - public void StartSend() - { - if (Data.Length < 1000) - { - // for now (testing ) we only support files under 1000 bytes - byte[] transferData = new byte[Data.Length + 4]; - Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); - Array.Copy(Data, 0, transferData, 4, Data.Length); - Client.SendXferPacket(XferID, 0 + 0x80000000, transferData); - complete = true; - } - else - { - byte[] transferData = new byte[1000 + 4]; - Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); - Array.Copy(Data, 0, transferData, 4, 1000); - Client.SendXferPacket(XferID, 0, transferData); - Packet++; - DataPointer = 1000; - } - } - - public void AckPacket(uint packet) - { - if (!complete) - { - if ((Data.Length - DataPointer) > 1000) - { - byte[] transferData = new byte[1000]; - Array.Copy(Data, DataPointer, transferData, 0, 1000); - Client.SendXferPacket(XferID, Packet, transferData); - Packet++; - DataPointer += 1000; - } - else - { - byte[] transferData = new byte[Data.Length - DataPointer]; - Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer); - uint endPacket = Packet |= (uint) 0x80000000; - Client.SendXferPacket(XferID, endPacket, transferData); - Packet++; - DataPointer += (Data.Length - DataPointer); - complete = true; - } - } - } - } - } -} \ No newline at end of file +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* 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. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.Generic; +using libsecondlife; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules +{ + public class XferModule : IRegionModule, IXfer + { + public Dictionary NewFiles = new Dictionary(); + public Dictionary Transfers = new Dictionary(); + + private Scene m_scene; + + public XferModule() + { + } + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + m_scene.EventManager.OnNewClient += NewClient; + + m_scene.RegisterModuleInterface(this); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "XferModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + public void NewClient(IClientAPI client) + { + client.OnRequestXfer += RequestXfer; + client.OnConfirmXfer += AckPacket; + } + + /// + /// + /// + /// + /// + /// + public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName) + { + lock (NewFiles) + { + if (NewFiles.ContainsKey(fileName)) + { + if (!Transfers.ContainsKey(xferID)) + { + byte[] fileData = NewFiles[fileName]; + XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient); + Transfers.Add(xferID, transaction); + NewFiles.Remove(fileName); + + if (transaction.StartSend()) + { + Transfers.Remove(xferID); + } + } + } + } + } + + public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet) + { + if (Transfers.ContainsKey(xferID)) + { + if (Transfers[xferID].AckPacket(packet)) + { + { + Transfers.Remove(xferID); + } + } + } + } + + public bool AddNewFile(string fileName, byte[] data) + { + lock (NewFiles) + { + if (NewFiles.ContainsKey(fileName)) + { + NewFiles[fileName] = data; + } + else + { + NewFiles.Add(fileName, data); + } + } + return true; + } + + + public class XferDownLoad + { + public byte[] Data = new byte[0]; + public string FileName = String.Empty; + public ulong XferID = 0; + public int DataPointer = 0; + public uint Packet = 0; + public IClientAPI Client; + public uint Serial = 1; + private bool complete; + + public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client) + { + FileName = fileName; + Data = data; + XferID = xferID; + Client = client; + } + + public XferDownLoad() + { + } + + /// + /// Start a transfer + /// + /// True if the transfer is complete, false if not + public bool StartSend() + { + if (Data.Length < 1000) + { + // for now (testing ) we only support files under 1000 bytes + byte[] transferData = new byte[Data.Length + 4]; + Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); + Array.Copy(Data, 0, transferData, 4, Data.Length); + Client.SendXferPacket(XferID, 0 + 0x80000000, transferData); + + complete = true; + } + else + { + byte[] transferData = new byte[1000 + 4]; + Array.Copy(Helpers.IntToBytes(Data.Length), 0, transferData, 0, 4); + Array.Copy(Data, 0, transferData, 4, 1000); + Client.SendXferPacket(XferID, 0, transferData); + Packet++; + DataPointer = 1000; + } + + return complete; + } + + /// + /// Respond to an ack packet from the client + /// + /// + /// True if the transfer is complete, false otherwise + public bool AckPacket(uint packet) + { + if (!complete) + { + if ((Data.Length - DataPointer) > 1000) + { + byte[] transferData = new byte[1000]; + Array.Copy(Data, DataPointer, transferData, 0, 1000); + Client.SendXferPacket(XferID, Packet, transferData); + Packet++; + DataPointer += 1000; + } + else + { + byte[] transferData = new byte[Data.Length - DataPointer]; + Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer); + uint endPacket = Packet |= (uint) 0x80000000; + Client.SendXferPacket(XferID, endPacket, transferData); + Packet++; + DataPointer += (Data.Length - DataPointer); + + complete = true; + } + } + + return complete; + } + } + } +}