/* Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp * * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ 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. Funktion DTLNSLMoneyModule ist ein OpenSim-Regionmodul für die Verwaltung eines eigenen Währungssystems und die Anbindung an einen externen MoneyServer. Es implementiert die Schnittstellen IMoneyModule und ISharedRegionModule. Kernfunktionen: Verwaltung von Guthaben (Balance), Transaktionen und Gebühren für verschiedene In-World-Aktionen (z.B. Objektkauf, Landkauf, Uploads). Kommunikation mit einem externen MoneyServer via XML-RPC (Transfer, Login, Logoff, Balance-Abfrage, etc.). Ereignis- und Event-Handling für Inworld-Transaktionen. Zertifikatsverwaltung für sichere Kommunikation. Null Pointer Checks Konfigurationswerte: Werden mit Defaultwerten initialisiert (string.Empty, false, 0 usw.). Viele Konfigurationswerte werden mit Fallback-Werten geladen. Methoden mit Objektrückgabe wie GetLocateClient, GetLocateScene, GetLocatePrim: Es wird geprüft, ob Rückgabewerte null sind, bevor sie genutzt werden (z.B. in ObjectGiveMoney, Transfer, etc.). Client- und Scene-Objekte: Wird ein Objekt nicht gefunden, wird mit return oder Fehlerwerten sauber abgebrochen. RPC-Handler: Prüfen, ob erforderliche Felder im Parameter-Hashtable existieren, bevor sie genutzt werden. Try-Catch bei XML-RPC: Netzwerkfehler und Exceptions werden sauber abgefangen und führen zu Fehler-Hash als Rückgabe. Event-Handler: Überall wird geprüft, ob das Event-Objekt oder der Client existiert, bevor darauf zugegriffen wird. Beispiel: C# SceneObjectPart sceneObj = GetLocatePrim(objectID); if (sceneObj == null) return false; Rückgabewerte können null sein: Es wird überall mit null als Fehlerfall gerechnet (besonders bei Lookups und DB/Network-Kommunikation). Fehlerquellen und deren Behandlung Konfiguration: Fehlende oder falsche Konfiguration wird geloggt und führt zum Abbruch der Initialisierung. RPC-Fehler: Bei Netzwerkproblemen oder fehlerhaften Antworten vom MoneyServer wird immer ein Fehlerobjekt erstellt und ausführlich geloggt. Fehlende Objekte/Clients: Fast überall wird geprüft, ob Objekte, Clients oder Rückgabewerte wirklich existieren, bevor sie verwendet werden. Fehlende Berechtigungen oder unzulässige Aktionen: Z.B. if (!m_sellEnabled) return; – Aktionen werden abgebrochen, wenn sie nicht erlaubt sind. Transaktionsfehler: Jede Transaktion prüft, ob die Übertragung erfolgreich war, und gibt false zurück oder loggt den Fehler. Typische Pattern für Sicherheit und Fehlervermeidung Locking: Zugriff auf die Szenenliste ist mit lock (m_sceneList) geschützt. Null-Checks: Überall vor der Nutzung von Rückgabewerten, Event-Objekten, Parametern. Logging: Fehler und Sonderfälle werden ausführlich geloggt. Try/Catch: Insbesondere bei externen Netzwerkzugriffen. Zusammenfassung & Bewertung Null Pointer: Der gesamte Code ist sehr gewissenhaft in Bezug auf Null Pointer – überall werden Objekte auf null geprüft, bevor sie verwendet werden. Fehlerquellen: Externe Fehler (Netzwerk, Konfiguration) werden geloggt und führen zu sauberem Abbruch. Rückgabewerte im Fehlerfall (z.B. null oder false) sind klar definiert und werden behandelt. Funktion: Sehr umfangreiches Modul zur sicheren Verwaltung von Währungen und Transaktionen in OpenSim, mit Anbindung an einen externen Server und vielen Schutzmechanismen. Fazit: Der Code ist robust gegenüber NullPointerException und typischen Fehlern. Fehlerquellen werden gut abgefangen, Logging ist umfassend. Die gesamte Struktur entspricht gängiger C#-Best-Practice für modulare, fehlertolerante Server-Module. */ using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Reflection; using System.Net; using System.Security.Cryptography; using log4net; using Nini.Config; using Nwc.XmlRpc; using Mono.Addins; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; using NSL.Certificate.Tools; using NSL.Network.XmlRpc; using System.IO; [assembly: Addin("DTLNSLMoneyModule", "1.0")] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] namespace OpenSim.Modules.Currency { /// /// Transaction Type /// public enum TransactionType : int { None = 0, // Extend BirthGift = 900, AwardPoints = 901, // One-Time Charges ObjectClaim = 1000, LandClaim = 1001, GroupCreate = 1002, GroupJoin = 1004, TeleportCharge = 1100, UploadCharge = 1101, LandAuction = 1102, ClassifiedCharge = 1103, // Recurrent Charges ObjectTax = 2000, LandTax = 2001, LightTax = 2002, ParcelDirFee = 2003, GroupTax = 2004, ClassifiedRenew = 2005, ScheduledFee = 2900, // Inventory Transactions GiveInventory = 3000, // Transfers Between Users ObjectSale = 5000, Gift = 5001, LandSale = 5002, ReferBonus = 5003, InvntorySale = 5004, RefundPurchase = 5005, LandPassSale = 5006, DwellBonus = 5007, PayObject = 5008, ObjectPays = 5009, BuyMoney = 5010, MoveMoney = 5011, SendMoney = 5012, // Group Transactions GroupLandDeed = 6001, GroupObjectDeed = 6002, GroupLiability = 6003, GroupDividend = 6004, GroupMembershipDues = 6005, // Stipend Credits StipendBasic = 10000 } [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")] public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule { // Constant memebers private const int MONEYMODULE_REQUEST_TIMEOUT = 10000; // Private data members. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); //private bool m_enabled = true; private bool m_sellEnabled = false; private bool m_enable_server = true; // enable Money Server private IConfigSource m_config; private string m_moneyServURL = string.Empty; public BaseHttpServer HttpServer; private string m_certFilename = ""; private string m_certPassword = ""; private bool m_checkServerCert = false; private string m_cacertFilename = ""; private bool m_use_web_settle = false; private string m_settle_url = ""; private string m_settle_message = ""; private bool m_settle_user = false; private int m_hg_avatarClass = (int)AvatarType.HG_AVATAR; private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // For server authentication private Dictionary m_sceneList = new Dictionary(); private Dictionary m_moneyServer = new Dictionary(); // Events public event ObjectPaid OnObjectPaid; // Price private int ObjectCount = 0; private int PriceEnergyUnit = 100; private int PriceObjectClaim = 10; private int PricePublicObjectDecay = 4; private int PricePublicObjectDelete = 4; private int PriceParcelClaim = 1; private float PriceParcelClaimFactor = 1.0f; private int PriceUpload = 0; private int PriceRentLight = 5; private float PriceObjectRent = 1.0f; private float PriceObjectScaleFactor = 10.0f; private int PriceParcelRent = 1; private int PriceGroupCreate = 0; private int TeleportMinPrice = 2; private float TeleportPriceExponent = 2.0f; private float EnergyEfficiency = 1.0f; private int PriceLandTax = 0; private int PriceLand = 0; private int PriceCurrency = 0; /// The m RPC handlers private Dictionary m_rpcHandlers; /// /// Initializes the specified scene. /// /// The scene to initialize. /// The source of the configuration. /// /// This method calls the Initialize method with the source parameter, /// then checks if the money server URL is null or empty. If so, it sets /// the enable_server flag to false. Finally, it adds the scene to the region. /// public void Initialise(Scene scene, IConfigSource source) { // Call the Initialize method with the source parameter Initialise(source); // Check if the money server URL is null or empty //if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false; if (string.IsNullOrEmpty(m_moneyServURL)) { m_log.ErrorFormat("[MONEY MODULE]: CurrencyServer URL not set."); m_enable_server = false; } // Add the scene to the region AddRegion(scene); } /// /// This is called to initialize the region module. For shared modules, this is called /// exactly once, after creating the single (shared) instance. For non-shared modules, /// this is called once on each instance, after the instace for the region has been created. /// /// A public void Initialise(IConfigSource source) { m_log.InfoFormat("[MONEY MODULE]: Initialise started."); // Überprüfen, ob die Konfigurationsquelle null ist. if (source == null) { m_log.ErrorFormat("[MONEY MODULE]: Initialise aborted - source is null."); return; } try { m_config = source; // Economy-Konfiguration abrufen IConfig economyConfig = m_config.Configs["Economy"]; if (economyConfig == null) { m_log.ErrorFormat("[MONEY MODULE]: Initialise aborted - [Economy] section is missing in configuration."); return; } // Überprüfen, ob das Modul aktiviert ist if (economyConfig.GetString("EconomyModule") != Name) { m_log.InfoFormat("[MONEY MODULE]: Initialise - DTL/NSL MoneyModule is disabled."); return; } m_log.InfoFormat("[MONEY MODULE]: Initialise - DTL/NSL MoneyModule is enabled."); // Konfiguration für Verkauf und MoneyServer-URL m_sellEnabled = economyConfig.GetBoolean("SellEnabled", m_sellEnabled); m_log.InfoFormat("[MONEY MODULE]: SellEnabled set to {0}", m_sellEnabled); m_moneyServURL = economyConfig.GetString("CurrencyServer", m_moneyServURL); m_log.InfoFormat("[MONEY MODULE]: CurrencyServer set to {0}", m_moneyServURL); // Konfiguration für Client-Zertifizierung m_certFilename = economyConfig.GetString("ClientCertFilename", m_certFilename); m_certPassword = economyConfig.GetString("ClientCertPassword", m_certPassword); if (!string.IsNullOrEmpty(m_certFilename)) { m_certVerify.SetPrivateCert(m_certFilename, m_certPassword); m_log.InfoFormat("[MONEY MODULE]: Client certificate set from file {0}", m_certFilename); } else { m_log.Warn("[MONEY MODULE]: No client certificate filename provided."); } // Konfiguration für Server-Zertifikatüberprüfung m_checkServerCert = economyConfig.GetBoolean("CheckServerCert", m_checkServerCert); m_cacertFilename = economyConfig.GetString("CACertFilename", m_cacertFilename); if (!string.IsNullOrEmpty(m_cacertFilename)) { m_certVerify.SetPrivateCA(m_cacertFilename); m_log.InfoFormat("[MONEY MODULE]: Server CA certificate loaded from {0}", m_cacertFilename); } else { m_checkServerCert = false; m_log.Warn("[MONEY MODULE]: No CA certificate filename provided; server certificate check disabled."); } // Konfiguration für Settlement m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", m_use_web_settle); m_log.InfoFormat("[MONEY MODULE]: SettlementByWeb set to {0}", m_use_web_settle); m_settle_url = economyConfig.GetString("SettlementURL", m_settle_url); m_log.InfoFormat("[MONEY MODULE]: SettlementURL set to {0}", m_settle_url); m_settle_message = economyConfig.GetString("SettlementMessage", m_settle_message); m_log.InfoFormat("[MONEY MODULE]: SettlementMessage set to {0}", m_settle_message); // Preise konfigurieren PriceEnergyUnit = economyConfig.GetInt("PriceEnergyUnit", PriceEnergyUnit); PriceObjectClaim = economyConfig.GetInt("PriceObjectClaim", PriceObjectClaim); PricePublicObjectDecay = economyConfig.GetInt("PricePublicObjectDecay", PricePublicObjectDecay); PricePublicObjectDelete = economyConfig.GetInt("PricePublicObjectDelete", PricePublicObjectDelete); PriceParcelClaim = economyConfig.GetInt("PriceParcelClaim", PriceParcelClaim); PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", PriceParcelClaimFactor); PriceUpload = economyConfig.GetInt("PriceUpload", PriceUpload); PriceRentLight = economyConfig.GetInt("PriceRentLight", PriceRentLight); PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", PriceObjectRent); PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", PriceObjectScaleFactor); PriceParcelRent = economyConfig.GetInt("PriceParcelRent", PriceParcelRent); PriceLand = economyConfig.GetInt("PriceLand", PriceLand); // Test PriceCurrency = economyConfig.GetInt("PriceCurrency", PriceCurrency); // Test PriceLandTax = economyConfig.GetInt("PriceLandTax", PriceLandTax); // Test PriceGroupCreate = economyConfig.GetInt("PriceGroupCreate", PriceGroupCreate); TeleportMinPrice = economyConfig.GetInt("TeleportMinPrice", TeleportMinPrice); TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", TeleportPriceExponent); EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", EnergyEfficiency); m_log.InfoFormat("[MONEY MODULE]: Price settings loaded successfully."); // Konfiguration für HG-Avatar-Typ string avatarClass = economyConfig.GetString("HGAvatarAs", "HGAvatar").ToLower(); m_hg_avatarClass = avatarClass switch { "localavatar" => (int)AvatarType.LOCAL_AVATAR, "guestavatar" => (int)AvatarType.GUEST_AVATAR, "hgavatar" => (int)AvatarType.HG_AVATAR, "foreignavatar" => (int)AvatarType.FOREIGN_AVATAR, _ => (int)AvatarType.UNKNOWN_AVATAR }; m_log.InfoFormat("[MONEY MODULE]: Initialise - Configuration loaded successfully."); } catch (Exception ex) { m_log.ErrorFormat("[MONEY MODULE]: Initialise - Failed to load configuration. Error: {0}", ex); } } /// /// This is called whenever a is added. For shared modules, this can happen several times. /// For non-shared modules, this happens exactly once, after has been called. /// /// A public void AddRegion(Scene scene) { m_log.InfoFormat("[MONEY MODULE]: AddRegion:"); if (scene == null) return; scene.RegisterModuleInterface(this); // Eliminate conflicting modules lock (m_sceneList) { if (m_sceneList.Count == 0) { if (m_enable_server) { HttpServer = new BaseHttpServer(9000); HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo)); HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler); HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); HttpServer.AddXmlRPCHandler("SendMoney", SendMoneyHandler); HttpServer.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); m_rpcHandlers = new Dictionary(); MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler); MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); MainServer.Instance.AddXmlRPCHandler("SendMoney", SendMoneyHandler); MainServer.Instance.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); } } if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle)) { m_sceneList[scene.RegionInfo.RegionHandle] = scene; } else { m_sceneList.Add(scene.RegionInfo.RegionHandle, scene); } } scene.EventManager.OnNewClient += OnNewClient; scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; scene.EventManager.OnMakeChildAgent += MakeChildAgent; // for OpenSim scene.EventManager.OnMoneyTransfer += MoneyTransferAction; scene.EventManager.OnValidateLandBuy += ValidateLandBuy; scene.EventManager.OnLandBuy += processLandBuy; m_log.InfoFormat("[MONEY MODULE]: AddRegion: {0}", scene.RegionInfo.RegionName); } /// /// This is called whenever a is removed. For shared modules, this can happen several times. /// For non-shared modules, this happens exactly once, if the scene this instance is associated with is removed. /// /// A public void RemoveRegion(Scene scene) { if (scene == null) return; lock (m_sceneList) { scene.EventManager.OnNewClient -= OnNewClient; scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; scene.EventManager.OnMakeChildAgent -= MakeChildAgent; // for OpenSim scene.EventManager.OnMoneyTransfer -= MoneyTransferAction; scene.EventManager.OnValidateLandBuy -= ValidateLandBuy; scene.EventManager.OnLandBuy -= processLandBuy; m_log.InfoFormat("[MONEY MODULE]: RemoveRegion: {0}", scene.RegionInfo.RegionName); } } /// /// This will be called once for every scene loaded. In a shared module /// this will be multiple times in one instance, while a nonshared /// module instance will only be called once. /// This method is called after AddRegion has been called in all /// modules for that scene, providing an opportunity to request /// another module's interface, or hook an event from another module. /// /// A public void RegionLoaded(Scene scene) { m_log.InfoFormat("[MONEY MODULE] region loaded {0}", scene.RegionInfo.RegionID.ToString()); } /// /// If this returns non-null, it is the type of an interface that /// this module intends to register. /// This will cause the loader to defer loading of this module /// until all other modules have been loaded. If no other module /// has registered the interface by then, this module will be /// activated, else it will remain inactive, letting the other module /// take over. This should return non-null ONLY in modules that are /// intended to be easily replaceable, e.g. stub implementations /// that the developer expects to be replaced by third party provided /// modules. /// public Type ReplaceableInterface { get { return null; } } /// Gets a value indicating whether this instance is shared module. /// /// true if this instance is shared module; otherwise, false. public bool IsSharedModule { get { return true; } } /// ///
///
/// The name of the module public string Name { get { return "DTLNSLMoneyModule"; } } /// /// This is called exactly once after all the shared region-modules have been instanciated and /// d. /// public void PostInitialise() { } /// /// This is the inverse to . After a Close(), this instance won't be usable anymore. /// public void Close() { } /// Objects the give money. /// The object identifier. /// From identifier. /// To identifier. /// The amount. /// The TXN. /// The result. /// ///
///
public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result) { result = string.Empty; if (!m_sellEnabled) { result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; return false; } string objName = string.Empty; string avatarName = string.Empty; SceneObjectPart sceneObj = GetLocatePrim(objectID); if (sceneObj == null) { result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; return false; } objName = sceneObj.Name; Scene scene = GetLocateScene(toID); if (scene != null) { UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID); if (account != null) { avatarName = account.FirstName + " " + account.LastName; } } bool ret = false; string description = String.Format("Object {0} pays {1}", objName, avatarName); if (sceneObj.OwnerID == fromID) { ulong regionHandle = sceneObj.RegionHandle; UUID regionUUID = sceneObj.RegionID; if (GetLocateClient(fromID) != null) { ret = TransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); } else { ret = ForceTransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); } } if (!ret) result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; m_log.InfoFormat("[MONEY MODULE] ObjectGiveMoney: {0} {1} {2} {3} {4} {5} {6}", objectID, fromID, toID, amount, txn, result, ret); return ret; } // /// Gets the upload charge. /// The upload charge. public int UploadCharge { get { return PriceUpload; } } // /// Gets the group creation charge. /// The group creation charge. public int GroupCreationCharge { get { return PriceGroupCreate; } } /// Gets the balance. /// The agent identifier. public int GetBalance(UUID agentID) { IClientAPI client = GetLocateClient(agentID); return QueryBalanceFromMoneyServer(client); } /// Uploads the covered. /// The agent identifier. /// The amount. public bool UploadCovered(UUID agentID, int amount) { IClientAPI client = GetLocateClient(agentID); if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { int balance = QueryBalanceFromMoneyServer(client); if (balance >= amount) return true; } m_log.InfoFormat("[MONEY MODULE] UploadCovered: {0} {1}", agentID, amount); return false; } /// Amounts the covered. /// The agent identifier. /// The amount. public bool AmountCovered(UUID agentID, int amount) { IClientAPI client = GetLocateClient(agentID); if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { int balance = QueryBalanceFromMoneyServer(client); if (balance >= amount) return true; } m_log.InfoFormat("[MONEY MODULE] AmountCovered: {0} {1}", agentID, amount); return false; } /// Applies the upload charge. /// The agent identifier. /// The amount. /// The text. public void ApplyUploadCharge(UUID agentID, int amount, string text) { ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; PayMoneyCharge(agentID, amount, (int)TransactionType.UploadCharge, regionHandle, regionUUID, text); m_log.InfoFormat("[MONEY MODULE] ApplyUploadCharge: {0} {1} {2}", agentID, amount, text); } /// Applies the charge. /// The agent identifier. /// The amount. /// The type. public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type) { ApplyCharge(agentID, amount, type, string.Empty); m_log.InfoFormat("[MONEY MODULE] ApplyCharge: {0} {1} {2}", agentID, amount, type); } /// Applies the charge. /// The agent identifier. /// The amount. /// The type. /// The text. public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string text) { ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; PayMoneyCharge(agentID, amount, (int)type, regionHandle, regionUUID, text); m_log.InfoFormat("[MONEY MODULE] ApplyCharge: {0} {1} {2} {3}", agentID, amount, type, text); } /// Transfers the specified from identifier. /// From identifier. /// To identifier. /// The region handle. /// The amount. /// The type. /// The text. /// ///
///
public bool Transfer(UUID fromID, UUID toID, int regionHandle, int amount, MoneyTransactionType type, string text) { return TransferMoney(fromID, toID, amount, (int)type, UUID.Zero, (ulong)regionHandle, UUID.Zero, text); } /// Transfers the specified from identifier. /// From identifier. /// To identifier. /// The object identifier. /// The amount. /// The type. /// The text. /// ///
///
public bool Transfer(UUID fromID, UUID toID, UUID objectID, int amount, MoneyTransactionType type, string text) { SceneObjectPart sceneObj = GetLocatePrim(objectID); if (sceneObj == null) return false; ulong regionHandle = sceneObj.ParentGroup.Scene.RegionInfo.RegionHandle; UUID regionUUID = sceneObj.ParentGroup.Scene.RegionInfo.RegionID; return TransferMoney(fromID, toID, amount, (int)type, objectID, (ulong)regionHandle, regionUUID, text); } // for 0.8.3 over /// Moves the money. /// From agent identifier. /// To agent identifier. /// The amount. /// The text. public void MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, string text) { ForceTransferMoney(fromAgentID, toAgentID, amount, (int)TransactionType.MoveMoney, UUID.Zero, (ulong)0, UUID.Zero, text); m_log.InfoFormat("[MONEY MODULE] MoveMoney: {0} {1} {2}", fromAgentID, toAgentID, amount); } // for 0.9.1 over /// Moves the money. /// From agent identifier. /// To agent identifier. /// The amount. /// The type. /// The text. /// ///
///
public bool MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, MoneyTransactionType type, string text) { bool ret = ForceTransferMoney(fromAgentID, toAgentID, amount, (int)type, UUID.Zero, (ulong)0, UUID.Zero, text); m_log.InfoFormat("[MONEY MODULE] MoveMoney: {0} {1} {2} {3}", fromAgentID, toAgentID, amount, type); return ret; } /// Called when [new client]. /// The client. private void OnNewClient(IClientAPI client) { client.OnEconomyDataRequest += OnEconomyDataRequest; client.OnLogout += ClientClosed; client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; client.OnRequestPayPrice += OnRequestPayPrice; client.OnObjectBuy += OnObjectBuy; m_log.InfoFormat("[MONEY MODULE] OnNewClient: {0}", client.AgentId); } /// Called when [make root agent]. /// The agent. public void OnMakeRootAgent(ScenePresence agent) { int balance = 0; IClientAPI client = agent.ControllingClient; m_enable_server = LoginMoneyServer(agent, out balance); client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); m_log.InfoFormat("[MONEY MODULE] OnMakeRootAgent: {0} {1}", client.AgentId, balance); } // for OnClientClosed event /// Clients the closed. /// The client. private void ClientClosed(IClientAPI client) { if (m_enable_server && client != null) { LogoffMoneyServer(client); m_log.InfoFormat("[MONEY MODULE] ClientClosed: {0}", client.AgentId); } } // for OnMakeChildAgent event /// Makes the child agent. /// The avatar. private void MakeChildAgent(ScenePresence avatar) { } // for OnMoneyTransfer event /// Moneys the transfer action. /// The sender. /// The money event. private void MoneyTransferAction(Object sender, EventManager.MoneyTransferArgs moneyEvent) { if (!m_sellEnabled) return; // Check the money transaction is necessary. if (moneyEvent.sender == moneyEvent.receiver) { return; } UUID receiver = moneyEvent.receiver; // Pay for the object. if (moneyEvent.transactiontype == (int)TransactionType.PayObject) { SceneObjectPart sceneObj = GetLocatePrim(moneyEvent.receiver); if (sceneObj != null) { receiver = sceneObj.OwnerID; } else { return; } } // Before paying for the object, save the object local ID for current transaction. UUID objectID = UUID.Zero; ulong regionHandle = 0; UUID regionUUID = UUID.Zero; if (sender is Scene) { Scene scene = (Scene)sender; regionHandle = scene.RegionInfo.RegionHandle; regionUUID = scene.RegionInfo.RegionID; if (moneyEvent.transactiontype == (int)TransactionType.PayObject) { objectID = scene.GetSceneObjectPart(moneyEvent.receiver).UUID; } } TransferMoney(moneyEvent.sender, receiver, moneyEvent.amount, moneyEvent.transactiontype, objectID, regionHandle, regionUUID, "OnMoneyTransfer event"); return; } // for OnValidateLandBuy event /// Validates the land buy. /// The sender. /// The land buy event. private void ValidateLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) { IClientAPI senderClient = GetLocateClient(landBuyEvent.agentId); if (senderClient != null) { int balance = QueryBalanceFromMoneyServer(senderClient); if (balance >= landBuyEvent.parcelPrice) { lock (landBuyEvent) { landBuyEvent.economyValidated = true; } } } return; } // for LandBuy even /// Processes the land buy. /// The sender. /// The land buy event. private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) { if (!m_sellEnabled) return; lock (landBuyEvent) { if (landBuyEvent.economyValidated == true && landBuyEvent.transactionID == 0) { landBuyEvent.transactionID = Util.UnixTimeSinceEpoch(); ulong parcelID = (ulong)landBuyEvent.parcelLocalID; UUID regionUUID = UUID.Zero; if (sender is Scene) regionUUID = ((Scene)sender).RegionInfo.RegionID; if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID, landBuyEvent.parcelPrice, (int)TransactionType.LandSale, regionUUID, parcelID, regionUUID, "Land Purchase")) { landBuyEvent.amountDebited = landBuyEvent.parcelPrice; } } } return; } // for OnObjectBuy event /// Called when [object buy]. /// The remote client. /// The agent identifier. /// The session identifier. /// The group identifier. /// The category identifier. /// The local identifier. /// Type of the sale. /// The sale price. public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID, UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice) { m_log.InfoFormat("[MONEY MODULE]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId); // Handle the parameters error. if (!m_sellEnabled) return; if (remoteClient == null || salePrice < 0) return; // Get the balance from money server. int balance = QueryBalanceFromMoneyServer(remoteClient); if (balance < salePrice) { remoteClient.SendAgentAlertMessage("Unable to buy now. You don't have sufficient funds", false); m_log.InfoFormat("[MONEY MODULE]: OnObjectBuy: agent = {0}, balance = {1}, salePrice = {2}", agentID, balance, salePrice); return; } Scene scene = GetLocateScene(remoteClient.AgentId); if (scene != null) { SceneObjectPart sceneObj = scene.GetSceneObjectPart(localID); if (sceneObj != null) { IBuySellModule mod = scene.RequestModuleInterface(); if (mod != null) { UUID receiverId = sceneObj.OwnerID; ulong regionHandle = sceneObj.RegionHandle; UUID regionUUID = sceneObj.RegionID; bool ret = false; // if (salePrice >= 0) { if (!string.IsNullOrEmpty(m_moneyServURL)) { ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice, (int)TransactionType.PayObject, sceneObj.UUID, regionHandle, regionUUID, "Object Buy"); } else if (salePrice == 0) { // amount is 0 with No Money Server ret = true; } } if (ret) { mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); } } } else { remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false); m_log.InfoFormat("[MONEY MODULE]: OnObjectBuy: Unable to buy now. The object was not found"); return; } } return; } /// /// Sends the the stored money balance to the client /// /// /// /// /// private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID) { m_log.InfoFormat("[MONEY MODULE]: OnMoneyBalanceRequest:"); if (client.AgentId == agentID && client.SessionId == SessionID) { int balance = 0; // if (m_enable_server) { balance = QueryBalanceFromMoneyServer(client); } client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); } else { client.SendAlertMessage("Unable to send your money balance"); } } /// Called when [request pay price]. /// The client. /// The object identifier. private void OnRequestPayPrice(IClientAPI client, UUID objectID) { m_log.InfoFormat("[MONEY MODULE]: OnRequestPayPrice:"); Scene scene = GetLocateScene(client.AgentId); if (scene == null) return; SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID); if (sceneObj == null) return; SceneObjectGroup group = sceneObj.ParentGroup; SceneObjectPart root = group.RootPart; client.SendPayPrice(objectID, root.PayPrice); } // //private void OnEconomyDataRequest(UUID agentId) /// Called when [economy data request]. /// The user. private void OnEconomyDataRequest(IClientAPI user) { if (user != null) { if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { //Scene s = GetLocateScene(user.AgentId); Scene s = (Scene)user.Scene; user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, TeleportMinPrice, TeleportPriceExponent); } } } // "OnMoneyTransfered" RPC from MoneyServer /// Called when [money transfered handler]. /// The request. /// The remote client. /// ///
///
public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient) { m_log.InfoFormat("[MONEY MODULE]: OnMoneyTransferedHandler:"); bool ret = false; if (request.Params.Count > 0) { Hashtable requestParam = (Hashtable)request.Params[0]; if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { UUID clientUUID = UUID.Zero; UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); if (clientUUID != UUID.Zero) { IClientAPI client = GetLocateClient(clientUUID); string sessionid = (string)requestParam["clientSessionID"]; string secureid = (string)requestParam["clientSecureSessionID"]; if (client != null && secureid == client.SecureSessionId.ToString() && (sessionid == UUID.Zero.ToString() || sessionid == client.SessionId.ToString())) { if (requestParam.Contains("transactionType") && requestParam.Contains("objectID") && requestParam.Contains("amount")) { m_log.InfoFormat("[MONEY MODULE]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]); // Pay for the object. if ((int)requestParam["transactionType"] == (int)TransactionType.PayObject) { // Send notify to the client(viewer) for Money Event Trigger. ObjectPaid handlerOnObjectPaid = OnObjectPaid; if (handlerOnObjectPaid != null) { UUID objectID = UUID.Zero; UUID.TryParse((string)requestParam["objectID"], out objectID); handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money() } ret = true; } } } } } } // Send the response to money server. XmlRpcResponse resp = new XmlRpcResponse(); Hashtable paramTable = new Hashtable(); paramTable["success"] = ret; if (!ret) { m_log.ErrorFormat("[MONEY MODULE]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback"); } resp.Value = paramTable; return resp; } // "UpdateBalance" RPC from MoneyServer or Script /// Balances the update handler. /// The request. /// The remote client. /// ///
///
public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient) { bool ret = false; if (request.Params.Count > 0) { Hashtable requestParam = (Hashtable)request.Params[0]; if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { UUID clientUUID = UUID.Zero; UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); // if (clientUUID != UUID.Zero) { IClientAPI client = GetLocateClient(clientUUID); string sessionid = (string)requestParam["clientSessionID"]; string secureid = (string)requestParam["clientSecureSessionID"]; if (client != null && secureid == client.SecureSessionId.ToString() && (sessionid == UUID.Zero.ToString() || sessionid == client.SessionId.ToString())) { // if (requestParam.Contains("Balance")) { // Send notify to the client. string msg = ""; if (requestParam.Contains("Message")) msg = (string)requestParam["Message"]; client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"], 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); // Dialog if (msg != "") { Scene scene = (Scene)client.Scene; IDialogModule dlg = scene.RequestModuleInterface(); dlg.SendAlertToUser(client.AgentId, msg); } ret = true; } } } } } // Send the response to money server. XmlRpcResponse resp = new XmlRpcResponse(); Hashtable paramTable = new Hashtable(); paramTable["success"] = ret; if (!ret) { m_log.ErrorFormat("[MONEY MODULE]: BalanceUpdateHandler: Cannot update client balance from MoneyServer"); } resp.Value = paramTable; return resp; } // "UserAlert" RPC from Script /// Users the alert handler. /// The request. /// The remote client. /// ///
///
public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient) { m_log.InfoFormat("[MONEY MODULE]: UserAlertHandler:"); bool ret = false; if (request.Params.Count > 0) { Hashtable requestParam = (Hashtable)request.Params[0]; if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { UUID clientUUID = UUID.Zero; UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); // if (clientUUID != UUID.Zero) { IClientAPI client = GetLocateClient(clientUUID); string sessionid = (string)requestParam["clientSessionID"]; string secureid = (string)requestParam["clientSecureSessionID"]; if (client != null && secureid == client.SecureSessionId.ToString() && (sessionid == UUID.Zero.ToString() || sessionid == client.SessionId.ToString())) { if (requestParam.Contains("Description")) { string description = (string)requestParam["Description"]; // Show the notice dialog with money server message. GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()), (byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3()); client.SendInstantMessage(gridMsg); ret = true; } } } } } // Send the response to money server. XmlRpcResponse resp = new XmlRpcResponse(); Hashtable paramTable = new Hashtable(); paramTable["success"] = ret; resp.Value = paramTable; return resp; } // "GetBalance" RPC from Script /// Gets the balance handler. /// The request. /// The remote client. /// ///
///
public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient) { bool ret = false; int balance = -1; if (request.Params.Count > 0) { Hashtable requestParam = (Hashtable)request.Params[0]; if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { UUID clientUUID = UUID.Zero; UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); // if (clientUUID != UUID.Zero) { IClientAPI client = GetLocateClient(clientUUID); string sessionid = (string)requestParam["clientSessionID"]; string secureid = (string)requestParam["clientSecureSessionID"]; if (client != null && secureid == client.SecureSessionId.ToString() && (sessionid == UUID.Zero.ToString() || sessionid == client.SessionId.ToString())) { balance = QueryBalanceFromMoneyServer(client); } } } } // Send the response to caller. if (balance < 0) { m_log.ErrorFormat("[MONEY MODULE]: GetBalanceHandler: GetBalance transaction is failed"); ret = false; } XmlRpcResponse resp = new XmlRpcResponse(); Hashtable paramTable = new Hashtable(); paramTable["success"] = ret; paramTable["balance"] = balance; resp.Value = paramTable; return resp; } // "AddBankerMoney" RPC from Script /// Adds the banker money handler. /// The request. /// The remote client. /// ///
///
public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) { m_log.InfoFormat("[MONEY MODULE]: AddBankerMoneyHandler:"); bool ret = false; if (request.Params.Count > 0) { Hashtable requestParam = (Hashtable)request.Params[0]; if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { UUID bankerUUID = UUID.Zero; UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID); // if (bankerUUID != UUID.Zero) { IClientAPI client = GetLocateClient(bankerUUID); string sessionid = (string)requestParam["clientSessionID"]; string secureid = (string)requestParam["clientSecureSessionID"]; if (client != null && secureid == client.SecureSessionId.ToString() && (sessionid == UUID.Zero.ToString() || sessionid == client.SessionId.ToString())) { if (requestParam.Contains("amount")) { Scene scene = (Scene)client.Scene; int amount = (int)requestParam["amount"]; ulong regionHandle = scene.RegionInfo.RegionHandle; UUID regionUUID = scene.RegionInfo.RegionID; ret = AddBankerMoney(bankerUUID, amount, regionHandle, regionUUID); if (m_use_web_settle && m_settle_user) { ret = true; IDialogModule dlg = scene.RequestModuleInterface(); if (dlg != null) { dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url); } } } } } } } if (!ret) m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoneyHandler: Add Banker Money transaction is failed"); // Send the response to caller. XmlRpcResponse resp = new XmlRpcResponse(); Hashtable paramTable = new Hashtable(); paramTable["settle"] = false; paramTable["success"] = ret; if (m_use_web_settle && m_settle_user) paramTable["settle"] = true; resp.Value = paramTable; return resp; } // "SendMoney" RPC from Script /// Sends the money handler. /// The request. /// The remote client. /// ///
///
public XmlRpcResponse SendMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) { bool ret = false; if (request.Params.Count > 0) { Hashtable requestParam = (Hashtable)request.Params[0]; if (requestParam.Contains("agentUUID") && requestParam.Contains("secretAccessCode")) { UUID agentUUID = UUID.Zero; UUID.TryParse((string)requestParam["agentUUID"], out agentUUID); if (agentUUID != UUID.Zero) { if (requestParam.Contains("amount")) { int amount = (int)requestParam["amount"]; int type = -1; if (requestParam.Contains("type")) type = (int)requestParam["type"]; string secretCode = (string)requestParam["secretAccessCode"]; string scriptIP = remoteClient.Address.ToString(); MD5 md5 = MD5.Create(); byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); string hash = BitConverter.ToString(code).ToLower().Replace("-", ""); m_log.InfoFormat("[MONEY MODULE]: SendMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); ret = SendMoneyTo(agentUUID, amount, type, hash); } } else { m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: amount is missed"); } } else { if (!requestParam.Contains("agentUUID")) { m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: agentUUID is missed"); } if (!requestParam.Contains("secretAccessCode")) { m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: secretAccessCode is missed"); } } } else { m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: Params count is under 0"); } if (!ret) m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: Send Money transaction is failed"); // Send the response to caller. XmlRpcResponse resp = new XmlRpcResponse(); Hashtable paramTable = new Hashtable(); paramTable["success"] = ret; resp.Value = paramTable; return resp; } // "MoveMoney" RPC from Script /// Moves the money handler. /// The request. /// The remote client. /// ///
///
public XmlRpcResponse MoveMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) { bool ret = false; if (request.Params.Count > 0) { Hashtable requestParam = (Hashtable)request.Params[0]; if ((requestParam.Contains("fromUUID") || requestParam.Contains("toUUID")) && requestParam.Contains("secretAccessCode")) { UUID fromUUID = UUID.Zero; UUID toUUID = UUID.Zero; // UUID.Zero means System if (requestParam.Contains("fromUUID")) UUID.TryParse((string)requestParam["fromUUID"], out fromUUID); if (requestParam.Contains("toUUID")) UUID.TryParse((string)requestParam["toUUID"], out toUUID); if (requestParam.Contains("amount")) { int amount = (int)requestParam["amount"]; string secretCode = (string)requestParam["secretAccessCode"]; string scriptIP = remoteClient.Address.ToString(); MD5 md5 = MD5.Create(); byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); string hash = BitConverter.ToString(code).ToLower().Replace("-", ""); m_log.InfoFormat("[MONEY MODULE]: MoveMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); ret = MoveMoneyFromTo(fromUUID, toUUID, amount, hash); } else { m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: amount is missed"); } } else { if (!requestParam.Contains("fromUUID") && !requestParam.Contains("toUUID")) { m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: fromUUID and toUUID are missed"); } if (!requestParam.Contains("secretAccessCode")) { m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: secretAccessCode is missed"); } } } else { m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: Params count is under 0"); } if (!ret) m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: Move Money transaction is failed"); // Send the response to caller. XmlRpcResponse resp = new XmlRpcResponse(); Hashtable paramTable = new Hashtable(); paramTable["success"] = ret; resp.Value = paramTable; return resp; } /// /// Transfer the money from one user to another. Need to notify money server to update. /// /// /// The amount of money. /// /// /// return true, if successfully. /// private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) { bool ret = false; IClientAPI senderClient = GetLocateClient(sender); // Handle the illegal transaction. // receiverClient could be null. if (senderClient == null) { m_log.InfoFormat("[MONEY MODULE]: TransferMoney: Client {0} not found", sender.ToString()); return false; } if (QueryBalanceFromMoneyServer(senderClient) < amount) { m_log.InfoFormat("[MONEY MODULE]: TransferMoney: No insufficient balance in client [{0}]", sender.ToString()); return false; } if (m_enable_server) { string objName = string.Empty; SceneObjectPart sceneObj = GetLocatePrim(objectID); if (sceneObj != null) objName = sceneObj.Name; // Fill parameters for money transfer XML-RPC. Hashtable paramTable = new Hashtable(); paramTable["senderID"] = sender.ToString(); paramTable["receiverID"] = receiver.ToString(); paramTable["senderSessionID"] = senderClient.SessionId.ToString(); paramTable["senderSecureSessionID"] = senderClient.SecureSessionId.ToString(); paramTable["transactionType"] = type; paramTable["objectID"] = objectID.ToString(); paramTable["objectName"] = objName; paramTable["regionHandle"] = regionHandle.ToString(); paramTable["regionUUID"] = regionUUID.ToString(); paramTable["amount"] = amount; paramTable["description"] = description; // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "TransferMoney"); // Handle the return values from Money Server. if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { ret = true; } } else m_log.ErrorFormat("[MONEY MODULE]: TransferMoney: Can not money transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString()); } return ret; } /// /// Force transfer the money from one user to another. /// This function does not check sender login. /// Need to notify money server to update. /// /// /// The amount of money. /// /// /// return true, if successfully. /// private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) { bool ret = false; if (m_enable_server) { string objName = string.Empty; SceneObjectPart sceneObj = GetLocatePrim(objectID); if (sceneObj != null) objName = sceneObj.Name; // Fill parameters for money transfer XML-RPC. Hashtable paramTable = new Hashtable(); paramTable["senderID"] = sender.ToString(); paramTable["receiverID"] = receiver.ToString(); paramTable["transactionType"] = type; paramTable["objectID"] = objectID.ToString(); paramTable["objectName"] = objName; paramTable["regionHandle"] = regionHandle.ToString(); paramTable["regionUUID"] = regionUUID.ToString(); paramTable["amount"] = amount; paramTable["description"] = description; // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney"); // Handle the return values from Money Server. if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { ret = true; } } else m_log.ErrorFormat("[MONEY MODULE]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString()); } return ret; } /// /// Send the money to avatar. Need to notify money server to update. /// /// /// The amount of money. /// /// /// return true, if successfully. /// private bool SendMoneyTo(UUID avatarID, int amount, int type, string secretCode) { bool ret = false; if (m_enable_server) { // Fill parameters for money transfer XML-RPC. if (type < 0) type = (int)TransactionType.ReferBonus; Hashtable paramTable = new Hashtable(); paramTable["receiverID"] = avatarID.ToString(); paramTable["transactionType"] = type; paramTable["amount"] = amount; paramTable["secretAccessCode"] = secretCode; paramTable["description"] = "Bonus to Avatar"; // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoney"); // Handle the return values from Money Server. if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { ret = true; } else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Fail Message is {0}", resultTable["message"]); } else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Money Server is not responce"); } return ret; } /// /// Move the money from avatar to other avatar. Need to notify money server to update. /// /// /// The amount of money. /// /// /// return true, if successfully. /// private bool MoveMoneyFromTo(UUID senderID, UUID receiverID, int amount, string secretCode) { bool ret = false; if (m_enable_server) { // Fill parameters for money transfer XML-RPC. Hashtable paramTable = new Hashtable(); paramTable["senderID"] = senderID.ToString(); paramTable["receiverID"] = receiverID.ToString(); paramTable["transactionType"] = (int)TransactionType.MoveMoney; paramTable["amount"] = amount; paramTable["secretAccessCode"] = secretCode; paramTable["description"] = "Move Money"; // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "MoveMoney"); // Handle the return values from Money Server. if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { ret = true; } else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Fail Message is {0}", resultTable["message"]); } else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Money Server is not responce"); } return ret; } /// /// Add the money to banker avatar. Need to notify money server to update. /// /// /// The amount of money. /// /// /// return true, if successfully. /// private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle, UUID regionUUID) { bool ret = false; m_settle_user = false; if (m_enable_server) { // Fill parameters for money transfer XML-RPC. Hashtable paramTable = new Hashtable(); paramTable["bankerID"] = bankerID.ToString(); paramTable["transactionType"] = (int)TransactionType.BuyMoney; paramTable["amount"] = amount; paramTable["regionHandle"] = regionHandle.ToString(); paramTable["regionUUID"] = regionUUID.ToString(); paramTable["description"] = "Add Money to Avatar"; // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney"); // Handle the return values from Money Server. if (resultTable != null) { if (resultTable.Contains("success") && (bool)resultTable["success"] == true) { ret = true; } else { if (resultTable.Contains("banker")) { m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used. if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used."); } else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Fail Message {0}", resultTable["message"]); } } else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Money Server is not responce"); } return ret; } /// /// Pay the money of charge. /// /// /// The amount of money. /// /// /// return true, if successfully. /// private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, UUID regionUUID, string description) { bool ret = false; IClientAPI senderClient = GetLocateClient(sender); // Handle the illegal transaction. // receiverClient could be null. if (senderClient == null) { m_log.InfoFormat("[MONEY MODULE]: PayMoneyCharge: Client {0} is not found", sender.ToString()); return false; } if (QueryBalanceFromMoneyServer(senderClient) < amount) { m_log.InfoFormat("[MONEY MODULE]: PayMoneyCharge: No insufficient balance in client [{0}]", sender.ToString()); return false; } if (m_enable_server) { // Fill parameters for money transfer XML-RPC. Hashtable paramTable = new Hashtable(); paramTable["senderID"] = sender.ToString(); paramTable["senderSessionID"] = senderClient.SessionId.ToString(); paramTable["senderSecureSessionID"] = senderClient.SecureSessionId.ToString(); paramTable["transactionType"] = type; paramTable["amount"] = amount; paramTable["regionHandle"] = regionHandle.ToString(); paramTable["regionUUID"] = regionUUID.ToString(); paramTable["description"] = description; // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "PayMoneyCharge"); // Handle the return values from Money Server. if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { ret = true; } } else m_log.ErrorFormat("[MONEY MODULE]: PayMoneyCharge: Can not pay money of charge request from [{0}]", sender.ToString()); } return ret; } /// Queries the balance from money server. /// The client. /// ///
///
private int QueryBalanceFromMoneyServer(IClientAPI client) { int balance = 0; if (client != null) { if (m_enable_server) { Hashtable paramTable = new Hashtable(); paramTable["clientUUID"] = client.AgentId.ToString(); paramTable["clientSessionID"] = client.SessionId.ToString(); paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetBalance"); // Handle the return result if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { balance = (int)resultTable["clientBalance"]; m_log.InfoFormat("[MONEY MODULE]: QueryBalanceFromMoneyServer: Balance {0}", balance); } } } else { if (m_moneyServer.ContainsKey(client.AgentId)) { balance = m_moneyServer[client.AgentId]; m_log.InfoFormat("[MONEY MODULE]: QueryBalanceFromMoneyServer: Balance {0}", balance); } } } return balance; } /// /// Login the money server when the new client login. /// /// /// Indicate user ID of the new client. /// /// /// return true, if successfully. /// private bool LoginMoneyServer(ScenePresence avatar, out int balance) { balance = 0; bool ret = false; bool isNpc = avatar.IsNPC; IClientAPI client = avatar.ControllingClient; if (!string.IsNullOrEmpty(m_moneyServURL)) { Scene scene = (Scene)client.Scene; string userName = string.Empty; // Get the username for the login user. if (client.Scene is Scene) { if (scene != null) { UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId); if (account != null) { userName = account.FirstName + " " + account.LastName; m_log.InfoFormat("[MONEY MODULE]: LoginMoneyServer: User {0} logged in.", userName); } } } // User Universal Identifer for Grid Avatar, HG Avatar or NPC string universalID = string.Empty; string firstName = string.Empty; string lastName = string.Empty; string serverURL = string.Empty; int avatarType = (int)AvatarType.LOCAL_AVATAR; int avatarClass = (int)AvatarType.LOCAL_AVATAR; AgentCircuitData agent = scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); if (agent != null) { universalID = Util.ProduceUserUniversalIdentifier(agent); if (!String.IsNullOrEmpty(universalID)) { UUID uuid; string tmp; Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out tmp); } // if serverURL is empty, avatar is a NPC if (isNpc || String.IsNullOrEmpty(serverURL)) { avatarType = (int)AvatarType.NPC_AVATAR; } // if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 || String.IsNullOrEmpty(userName)) { avatarType = (int)AvatarType.HG_AVATAR; } } if (String.IsNullOrEmpty(userName)) { userName = firstName + " " + lastName; m_log.InfoFormat("[MONEY MODULE]: LoginMoneyServer: User {0} logged in.", userName); } // avatarClass = avatarType; if (avatarType == (int)AvatarType.NPC_AVATAR) return false; if (avatarType == (int)AvatarType.HG_AVATAR) avatarClass = m_hg_avatarClass; // // Login the Money Server. Hashtable paramTable = new Hashtable(); paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(), scene.RegionInfo.HttpPort.ToString()); paramTable["avatarType"] = avatarType.ToString(); paramTable["avatarClass"] = avatarClass.ToString(); paramTable["userName"] = userName; paramTable["universalID"] = universalID; paramTable["clientUUID"] = client.AgentId.ToString(); paramTable["clientSessionID"] = client.SessionId.ToString(); paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin"); // Handle the return result if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { balance = (int)resultTable["clientBalance"]; m_log.InfoFormat("[MONEY MODULE]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL); ret = true; } } else m_log.ErrorFormat("[MONEY MODULE]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString()); } else m_log.ErrorFormat("[MONEY MODULE]: LoginMoneyServer: Money Server is not available!!"); // Notifies the Viewer of the setting. if (ret || string.IsNullOrEmpty(m_moneyServURL)) { OnEconomyDataRequest(client); } return ret; } /// /// Log off from the money server. /// /// /// Indicate user ID of the new client. /// /// /// return true, if successfully. /// private bool LogoffMoneyServer(IClientAPI client) { bool ret = false; if (!string.IsNullOrEmpty(m_moneyServURL)) { // Log off from the Money Server. Hashtable paramTable = new Hashtable(); paramTable["clientUUID"] = client.AgentId.ToString(); paramTable["clientSessionID"] = client.SessionId.ToString(); paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout"); // Handle the return result if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { ret = true; } } m_log.InfoFormat("[MONEY MODULE]: LogoffMoneyServer: Client [{0}] logoff Money Server {1}", client.AgentId.ToString(), m_moneyServURL); } return ret; } // /// Gets the transaction information. /// The client. /// The transaction identifier. /// ///
///
private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID) { EventManager.MoneyTransferArgs args = null; if (m_enable_server) { Hashtable paramTable = new Hashtable(); paramTable["clientUUID"] = client.AgentId.ToString(); paramTable["clientSessionID"] = client.SessionId.ToString(); paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); paramTable["transactionID"] = transactionID; // Generate the request for transfer. Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction"); // Handle the return result if (resultTable != null && resultTable.Contains("success")) { if ((bool)resultTable["success"] == true) { int amount = (int)resultTable["amount"]; int type = (int)resultTable["type"]; string desc = (string)resultTable["description"]; UUID sender = UUID.Zero; UUID recver = UUID.Zero; UUID.TryParse((string)resultTable["sender"], out sender); UUID.TryParse((string)resultTable["receiver"], out recver); args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc); } else { m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]); } } else { m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: Invalid Response"); } } else { m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: Invalid Money Server URL"); } return args; } /// /// Generic XMLRPC client abstraction /// /// Hashtable containing parameters to the method /// Method to invoke /// Hashtable with success=>bool and other values private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method) { if (reqParams.Count <= 0 || string.IsNullOrEmpty(method)) return null; if (m_checkServerCert) { if (!m_moneyServURL.StartsWith("https://")) { m_log.InfoFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file"); //return null; } } else { if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://")) { m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL); return null; } } ArrayList arrayParams = new ArrayList(); arrayParams.Add(reqParams); XmlRpcResponse moneyServResp = null; try { NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); //moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_certVerify, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); } catch (Exception ex) { m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL); m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: {0}", ex); Hashtable ErrorHash = new Hashtable(); ErrorHash["success"] = false; ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; ErrorHash["errorURI"] = ""; return ErrorHash; } if (moneyServResp == null || moneyServResp.IsFault) { Hashtable ErrorHash = new Hashtable(); ErrorHash["success"] = false; ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; ErrorHash["errorURI"] = ""; return ErrorHash; } Hashtable moneyRespData = (Hashtable)moneyServResp.Value; return moneyRespData; } /// Locates a IClientAPI for the client specified /// /// /// private IClientAPI GetLocateClient(UUID AgentID) { IClientAPI client = null; lock (m_sceneList) { if (m_sceneList.Count > 0) { foreach (Scene _scene in m_sceneList.Values) { ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID); if (tPresence != null && !tPresence.IsChildAgent) { IClientAPI rclient = tPresence.ControllingClient; if (rclient != null) { client = rclient; break; } } } } } m_log.DebugFormat("[MONEY MODULE]: GetLocateClient: {0}", client); return client; } /// Gets the locate scene. /// The agent identifier. /// ///
///
private Scene GetLocateScene(UUID AgentId) { Scene scene = null; lock (m_sceneList) { if (m_sceneList.Count > 0) { foreach (Scene _scene in m_sceneList.Values) { ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId); if (tPresence != null && !tPresence.IsChildAgent) { scene = _scene; break; } } } } m_log.DebugFormat("[MONEY MODULE]: GetLocateScene: {0}", scene); return scene; } /// Gets the locate prim. /// The object identifier. /// ///
///
private SceneObjectPart GetLocatePrim(UUID objectID) { SceneObjectPart sceneObj = null; lock (m_sceneList) { if (m_sceneList.Count > 0) { foreach (Scene _scene in m_sceneList.Values) { SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID); if (part != null) { sceneObj = part; break; } } } } return sceneObj; } } }