// * 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.Text;
using System.Reflection;
using System.Net;
using log4net;
using Nini.Config;
using Nwc.XmlRpc;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
using OpenSim.Services.UserAccountService;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework;
namespace OpenSim.Forge.Currency
{
public class MoneyModule : IMoneyModule, IRegionModule
{
/* Memebers *************************************************************/
#region Constant numbers and members.
// Constant memebers
private const int MONEYMODULE_REQUEST_TIMEOUT = 50000;
public enum TransactionType : int
{
MONEY_TRANS_SYSTEMGENERATED = 0,
MONEY_TRANS_REGIONMONEYREQUEST,
MONEY_TRANS_GIFT,
MONEY_TRANS_PURCHASE,
}
// Private data members.
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IConfigSource m_config;
private string m_moneyServURL = string.Empty;
private string m_userServIP = string.Empty;
///
/// Scene dictionary indexed by Region Handle
///
private Dictionary m_sceneList = new Dictionary();
///
/// To cache the balance data while the money server is not available.
///
private Dictionary m_moneyServer = new Dictionary();
// Events
public event ObjectPaid OnObjectPaid;
public event PostObjectPaid OnPostObjectPaid;
public BaseHttpServer HttpServer;
#endregion
/* Public ***************************************************************/
#region IRegionModule interface
public void Initialise(Scene scene, IConfigSource source)
{
// Handle the parameters errors.
if (scene == null || source == null) return;
try
{
m_config = source;
// Refer to the [Startup] secion and check if current is grid mode or standalone.
IConfig networkConfig = m_config.Configs["Network"];
m_userServIP = "";
if (networkConfig.Contains("user_server_url")) {
m_userServIP = Util.GetHostFromURL(networkConfig.GetString("user_server_url")).ToString();
}
IConfig economyConfig = m_config.Configs["Economy"];
if (m_userServIP=="") {
m_userServIP = Util.GetHostFromURL(economyConfig.GetString("UserServer")).ToString();
}
m_moneyServURL = economyConfig.GetString("CurrencyServer").ToString();
// Check if the DTLMoneyModule is configured to load.
if (economyConfig.GetString("EconomyModule").ToString() != "DTLMoneyModule")
{
return;
}
}
catch
{
m_log.ErrorFormat("[MONEY]: Faile to read configuration file.");
}
scene.RegisterModuleInterface(this);
lock (m_sceneList)
{
if (m_sceneList.Count == 0)
{
if (!string.IsNullOrEmpty(m_moneyServURL))
{
HttpServer = new BaseHttpServer(9000);
HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo));
HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler);
HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler);
HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler);
HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added by Fumi.Iseki
HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added by Fumi.Iseki
//HttpServer.AddXmlRPCHandler("SendConfirmLink", SendConfirmLinkHandler);
//scene.CommsManager.HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler);
//scene.CommsManager.HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler);
//scene.CommsManager.HttpServer.AddXmlRPCHandler("SendConfirmLink", SendConfirmLinkHandler);
//scene.CommsManager.HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler);
MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler);
MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler);
MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler);
MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added by Fumi.Iseki
MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added by Fumi.Iseki
//MainServer.Instance.AddXmlRPCHandler("SendConfirmLink", SendConfirmLinkHandler);
}
}
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.OnMoneyTransfer += MoneyTransferAction;
scene.EventManager.OnClientClosed += ClientClosed;
scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
scene.EventManager.OnValidateLandBuy += ValidateLandBuy;
scene.EventManager.OnLandBuy += processLandBuy;
}
public void PostInitialise()
{
}
public bool IsSharedModule
{
get { return true; }
}
public string Name
{
get { return "DTLMoneyModule"; }
}
public void Close()
{
}
#endregion
// Since the economy data won't be used anymore,
// removed the related legacy code from interface implement.
#region IMoneyModule interface.
// for LSL ObjectGiveMoney() function
public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount)
{
//m_log.ErrorFormat("[Money] LSL ObjectGiveMoney. UUID = ", objectID.ToString());
string objName = string.Empty;
string avatarName = string.Empty;
SceneObjectPart sceneObj = FindPrim(objectID);
if (sceneObj != null)
{
objName = sceneObj.Name;
}
Scene scene = null;
if (m_sceneList.Count > 0)
{
//scene = m_sceneList[0];
foreach (Scene _scene in m_sceneList.Values)
{
scene = _scene;
break;
}
}
if (scene != null)
{
UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID);
if (account != null)
{
avatarName = account.FirstName + " " + account.LastName;
}
//CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(toID);
//if (profile != null && profile.UserProfile != null)
//{
// avatarName = profile.UserProfile.FirstName + " " + profile.UserProfile.SurName;
//}
}
bool ret = false;
string description = String.Format("Object {0} pays {1}", objName, avatarName);
if (sceneObj.OwnerID==fromID)
{
if (LocateClientObject(fromID)!=null)
{
ret = TransferMoney(fromID, toID, amount, 5009, objectID, sceneObj.RegionHandle, description);
}
else
{
ret = ForceTransferMoney(fromID, toID, amount, 5009, objectID, sceneObj.RegionHandle, description);
}
}
return ret;
}
public int GetBalance(IClientAPI client)
{
return QueryBalanceFromMoneyServer(client);
}
//public void ApplyUploadCharge(UUID agentID, int amount, string text)
public void ApplyUploadCharge(UUID agentID)
{
// Empty!
}
//public bool UploadCovered(IClientAPI client, int amount)
public bool UploadCovered(IClientAPI client)
{
return true;
}
public void ApplyGroupCreationCharge(UUID agentID)
{
// Empty!
}
public bool GroupCreationCovered(IClientAPI client)
{
return true;
}
public bool AmountCovered(IClientAPI client, int amount)
{
return true;
}
public void ApplyCharge(UUID agentID, int amount, string text)
{
// Empty!
}
public EconomyData GetEconomyData()
{
return new EconomyData();
}
public int UploadCharge
{
get { return 0; }
}
public int GroupCreationCharge
{
get { return 0; }
}
#endregion
#region MoneyModule event handlers
/*
// deleted by Fumi.Iseki
private void OnNewClient(IClientAPI client)
{
int balance = 0;
LoginMoneyServer(client, out balance);
client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance);
// Subscribe to Money messages
client.OnEconomyDataRequest += OnEconomyDataRequest;
client.OnMoneyBalanceRequest += OnMoneyBalanceRequest;
client.OnRequestPayPrice += OnRequestPayPrice;
client.OnObjectBuy += OnObjectBuy;
client.OnLogout += ClientClosed;
}
*/
// added by Fumi.Iseki
// for OnMakeRootAgent event
public void OnMakeRootAgent(ScenePresence agent)
{
int balance = 0;
IClientAPI client = agent.ControllingClient;
m_log.Debug("[MONEY]: OnMakeRootAgent.");
LoginMoneyServer(client, out balance);
client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance);
// Subscribe to Money messages
client.OnEconomyDataRequest += OnEconomyDataRequest;
client.OnMoneyBalanceRequest += OnMoneyBalanceRequest;
client.OnRequestPayPrice += OnRequestPayPrice;
client.OnObjectBuy += OnObjectBuy;
client.OnLogout += ClientClosed;
}
// for OnClientClosed event
private void ClientClosed(UUID clientID, Scene scene)
{
IClientAPI client = LocateClientObject(clientID);
if (client != null)
{
// If the User is just transferred to another region. No need to logoff from money server.
// LogoffMoneyServer(client);
}
}
// for OnClientClosed event
private void ClientClosed(IClientAPI client)
{
if (client != null)
{
LogoffMoneyServer(client);
}
}
// for OnMoneyTransfer event
private void MoneyTransferAction(Object sender, EventManager.MoneyTransferArgs moneyEvent)
{
//m_log.ErrorFormat("[Money] Event OnMoneyTransfer. type = {0}", moneyEvent.transactiontype);
// Check the money transaction is necessary.
if (moneyEvent.sender == moneyEvent.receiver)
{
return;
}
UUID receiver = moneyEvent.receiver;
if (moneyEvent.transactiontype==5008) // Pay for the object.
{
SceneObjectPart sceneObj = FindPrim(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;
if (sender is Scene)
{
Scene scene = (Scene)sender;
regionHandle = scene.RegionInfo.RegionHandle;
if (moneyEvent.transactiontype==5008)
{
objectID = scene.GetSceneObjectPart(moneyEvent.receiver).UUID;
m_log.Debug("Paying for object " + objectID.ToString());
}
}
TransferMoney(moneyEvent.sender, receiver, moneyEvent.amount, moneyEvent.transactiontype, objectID, regionHandle, "OnMoneyTransfer event");
}
// for OnAvatarEnteringNewParcel event
private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
{
ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
//if ((obj.landData.Flags & (uint)Parcel.ParcelFlags.AllowDamage) != 0) for r10084
if ((obj.LandData.Flags & (uint)RegionFlags.AllowDamage) != 0)
{
avatar.Invulnerable = false;
}
else
{
avatar.Invulnerable = true;
}
}
// for OnMakeChildAgent event
private void MakeChildAgent(ScenePresence avatar)
{
}
// for OnValidateLandBuy event
private void ValidateLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent)
{
//m_log.ErrorFormat("[Money] Event OniValidateLandBuy.");
IClientAPI senderClient = LocateClientObject(landBuyEvent.agentId);
if (senderClient != null)
{
int balance = QueryBalanceFromMoneyServer(senderClient);
if (balance >= landBuyEvent.parcelPrice)
{
lock (landBuyEvent)
{
landBuyEvent.economyValidated = true;
}
}
}
}
// for OnLandBuy event
private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent)
{
//m_log.ErrorFormat("[Money] Event OnLandBuy.");
lock (landBuyEvent)
{
if (landBuyEvent.economyValidated == true && landBuyEvent.transactionID == 0)
{
landBuyEvent.transactionID = Util.UnixTimeSinceEpoch();
ulong parcelID = (ulong)landBuyEvent.parcelLocalID;
UUID regionID = UUID.Zero;
if (sender is Scene) regionID = ((Scene)sender).RegionInfo.RegionID;
if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID, landBuyEvent.parcelPrice, 5002, regionID, parcelID, "Land Purchase"))
{
lock (landBuyEvent)
{
landBuyEvent.amountDebited = landBuyEvent.parcelPrice;
}
}
}
}
}
// for OnObjectBuy event
public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID,
UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice)
{
//m_log.ErrorFormat("[Money] Event OnObjectBuy. agent = {0}, {1}", agentID, remoteClient.AgentId);
// Handle the parameters error.
if (remoteClient == null || salePrice < 0) return; // for L$0 Sell by Fumi.Iseki
// 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);
return;
}
Scene scene = LocateSceneClientIn(remoteClient.AgentId);
if (scene != null)
{
SceneObjectPart sceneObj = scene.GetSceneObjectPart(localID);
if (sceneObj != null)
{
UUID receiverId = sceneObj.OwnerID;
if (scene.PerformObjectBuy(remoteClient, categoryID, localID, saleType))
{
TransferMoney(remoteClient.AgentId, receiverId, salePrice, 5008, sceneObj.UUID, sceneObj.RegionHandle, "Object Buy");
}
}
else
{
remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found.", false);
return;
}
}
}
#endregion
#region MoneyModule XML-RPC Handler
// for UpdateBlance RPC
// Money Server -> Region Server -> Viewer
public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
bool ret = false;
#region Update the balance from money server.
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 = LocateClientObject(clientUUID);
if (client != null &&
client.SessionId.ToString() == (string)requestParam["clientSessionID"] &&
client.SecureSessionId.ToString() == (string)requestParam["clientSecureSessionID"])
{
if (requestParam.Contains("Balance"))
{
// Send notify to the client.
client.SendMoneyBalance(UUID.Random(), true,
Utils.StringToBytes("Balance update event from money server"), (int)requestParam["Balance"]);
ret = true;
}
}
}
}
}
#endregion
// Send the response to money server.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
if (!ret)
{
m_log.ErrorFormat("[MONEY]: Cannot update client balance from MoneyServer.");
}
resp.Value = paramTable;
return resp;
}
// for UserAlert RPC
public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
bool ret = false;
#region confirm the request and show the notice from money server.
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 = LocateClientObject(clientUUID);
if (client != null &&
client.SessionId.ToString() == (string)requestParam["clientSessionID"] &&
client.SecureSessionId.ToString() == (string)requestParam["clientSecureSessionID"])
{
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;
}
}
}
}
}
//
#endregion
// Send the response to money server.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
resp.Value = paramTable;
return resp;
}
// for SendConfirmLink RPC (not used)
/*
public XmlRpcResponse SendConfirmLinkHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
bool ret = false;
#region confirm the request and send out confirm link.
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 = LocateClientObject(clientUUID);
if (client != null &&
client.SessionId.ToString() == (string)requestParam["clientSessionID"] &&
client.SecureSessionId.ToString() == (string)requestParam["clientSecureSessionID"])
{
if (requestParam.Contains("URI"))
{
// Show the notice for user to confirm the link in IM.
GridInstantMessage gridMsg_notice = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()),
(byte)InstantMessageDialog.MessageBox,
"Please clink the URI in IM window to confirm your purchase.",
false, new Vector3());
client.SendInstantMessage(gridMsg_notice);
// Show the confirm link in IM window.
GridInstantMessage gridMsg_link = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()),
(byte)InstantMessageDialog.MessageFromAgent,
(string)requestParam["URI"],
false, new Vector3());
client.SendInstantMessage(gridMsg_link);
ret = true;
}
}
}
}
}
#endregion
// Send the response to money server.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
if (!ret)
{
m_log.ErrorFormat("[MONEY]: Cannot get or deliver the confirm link from MoneyServer.");
}
resp.Value = paramTable;
return resp;
}
*/
// for OnMoneyTransfered RPC
public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
bool ret = false;
#region Confirm the transaction type and send out object paid event.
if (request.Params.Count > 0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("senderID") &&
requestParam.Contains("receiverID") &&
requestParam.Contains("senderSessionID") &&
requestParam.Contains("senderSecureSessionID"))
{
UUID senderID = UUID.Zero;
UUID receiverID = UUID.Zero;
UUID.TryParse((string)requestParam["senderID"], out senderID);
UUID.TryParse((string)requestParam["receiverID"], out receiverID);
if (senderID != UUID.Zero)
{
IClientAPI client = LocateClientObject(senderID);
if (client != null &&
client.SessionId.ToString() == (string)requestParam["senderSessionID"] &&
client.SecureSessionId.ToString() == (string)requestParam["senderSecureSessionID"])
{
if (requestParam.Contains("transactionType") &&
requestParam.Contains("objectID") &&
requestParam.Contains("amount"))
{
if ((int)requestParam["transactionType"]==5008) // Pay for the object.
{
// Send notify to the client(viewer).
PostObjectPaid handlerOnObjectPaid = OnPostObjectPaid;
if (handlerOnObjectPaid != null)
{
uint localID = 0;
UUID objectID = UUID.Zero;
UUID.TryParse((string)requestParam["objectID"], out objectID);
SceneObjectPart sceneObj = FindPrim(objectID);
if (sceneObj!=null) localID = sceneObj.LocalId;
ret = handlerOnObjectPaid(localID, ulong.Parse((string)requestParam["regionHandle"]),
senderID, (int)requestParam["amount"]);
ret = true;
}
}
}
}
}
}
}
#endregion
// Send the response to money server.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
if (!ret)
{
m_log.ErrorFormat("[MONEY]: Transaction is failed. MoneyServer will rollback.");
}
resp.Value = paramTable;
return resp;
}
// for AddBankerMoney RPC
public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient)
{
bool ret = false;
if (request.Params.Count > 0)
{
Hashtable requestParam = (Hashtable)request.Params[0];
if (requestParam.Contains("bankerID") &&
requestParam.Contains("bankerSessionID") &&
requestParam.Contains("bankerSecureSessionID"))
{
UUID bankerID = UUID.Zero;
UUID.TryParse((string)requestParam["bankerID"], out bankerID);
if (bankerID != UUID.Zero)
{
IClientAPI client = LocateClientObject(bankerID);
if (client != null &&
client.SessionId.ToString() == (string)requestParam["bankerSessionID"] &&
client.SecureSessionId.ToString() == (string)requestParam["bankerSecureSessionID"])
{
if (requestParam.Contains("amount"))
{
Scene scene = (Scene)client.Scene;
int amount = (int)requestParam["amount"];
ret = AddBankerMoney(bankerID, amount, scene.RegionInfo.RegionHandle);
}
}
}
}
}
// Send the response to caller.
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
if (!ret)
{
m_log.ErrorFormat("[MONEY]: Add Banker Money transaction is failed.");
}
resp.Value = paramTable;
return resp;
}
// for GetBalance RPC
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("clientID") &&
requestParam.Contains("clientSessionID") &&
requestParam.Contains("clientSecureSessionID"))
{
UUID clientID = UUID.Zero;
UUID.TryParse((string)requestParam["clientID"], out clientID);
if (clientID != UUID.Zero)
{
IClientAPI client = LocateClientObject(clientID);
if (client != null &&
client.SessionId.ToString() == (string)requestParam["clientSessionID"] &&
client.SecureSessionId.ToString() == (string)requestParam["clientSecureSessionID"])
{
balance = QueryBalanceFromMoneyServer(client);
}
}
}
}
// Send the response to caller.
if (balance<0)
{
m_log.ErrorFormat("[MONEY]: GetBlance transaction is failed.");
ret = false;
}
XmlRpcResponse resp = new XmlRpcResponse();
Hashtable paramTable = new Hashtable();
paramTable["success"] = ret;
paramTable["balance"] = balance;
resp.Value = paramTable;
return resp;
}
#endregion
#region MoneyModule private help functions
///
/// 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 transactiontype, UUID objectID, ulong regionHandle, string description)
{
bool ret = false;
IClientAPI senderClient = LocateClientObject(sender);
//IClientAPI receiverClient = LocateClientObject(receiver);
//int senderBalance = -1;
//int receiverBalance = -1;
// Handle the illegal transaction.
if (senderClient==null) // receiverClient could be null.
{
m_log.ErrorFormat("[MONEY]: Client {0} not found", sender.ToString());
return false;
}
if (QueryBalanceFromMoneyServer(senderClient)
/// 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 transactiontype, UUID objectID, ulong regionHandle, string description)
{
bool ret = false;
#region Force send transaction request to money server and parse the resultes.
if (!string.IsNullOrEmpty(m_moneyServURL))
{
// Fill parameters for money transfer XML-RPC.
Hashtable paramTable = new Hashtable();
paramTable["senderUserServIP"] = m_userServIP;
paramTable["senderID"] = sender.ToString();
paramTable["receiverUserServIP"] = m_userServIP;
paramTable["receiverID"] = receiver.ToString();
paramTable["transactionType"] = transactiontype;
paramTable["objectID"] = objectID.ToString();
paramTable["regionHandle"] = regionHandle.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)
{
m_log.DebugFormat("[MONEY]: Money force transfer from [{0}] to [{1}] is done.", sender.ToString(), receiver.ToString());
ret = true;
}
}
else
{
m_log.ErrorFormat("[MONEY]: Can not money force transfer request from [{0}] to [{1}].", sender.ToString(), receiver.ToString());
}
}
else // Money server is not available.
{
m_log.ErrorFormat("[MONEY]: Money Server is not available!!");
}
#endregion
return ret;
}
///
/// Add the money to banker avatarr. Need to notify money server to update.
///
///
/// The amount of money.
///
///
/// return true, if successfully.
///
private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle)
{
bool ret = false;
if (!string.IsNullOrEmpty(m_moneyServURL))
{
// Fill parameters for money transfer XML-RPC.
Hashtable paramTable = new Hashtable();
paramTable["bankerUserServIP"] = m_userServIP;
paramTable["bankerID"] = bankerID.ToString();
paramTable["transactionType"] = 5010; // BuyMoney
paramTable["amount"] = amount;
paramTable["regionHandle"] = regionHandle.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 && resultTable.Contains("success"))
{
if ((bool)resultTable["success"] == true)
{
m_log.DebugFormat("[MONEY]: Add money to banker [{0}] is done.", bankerID.ToString());
ret = true;
}
}
else
{
m_log.ErrorFormat("[MONEY]: Can not add money to banker [{0}].", bankerID.ToString());
}
}
else
{
m_log.ErrorFormat("[MONEY]: Money Server is not available!!");
}
return ret;
}
///
///
/// Login the money server when the new client login.
///
///
/// Indicate user ID of the new client.
///
///
/// return true, if successfully.
///
private bool LoginMoneyServer(IClientAPI client, out int balance)
{
bool ret = false;
balance = 0;
#region Send money server the client info for login.
Scene scene = (Scene)client.Scene;
string userName = string.Empty;
if (!string.IsNullOrEmpty(m_moneyServURL))
{
// 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;
}
//CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(client.AgentId);
//if (profile != null && profile.UserProfile != null)
//{
// userName = profile.UserProfile.FirstName + " " + profile.UserProfile.SurName;
//}
}
}
// Login the Money Server.
Hashtable paramTable = new Hashtable();
paramTable["userServIP"] = m_userServIP;
paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(),
scene.RegionInfo.HttpPort.ToString());
paramTable["userName"] = userName;
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]: Client [{0}] login Money Server {1}.", client.AgentId.ToString(), m_moneyServURL);
ret = true;
}
}
else
{
m_log.ErrorFormat("[MONEY]: Unable to login Money Server {0} for client [{1}].", m_moneyServURL, client.AgentId.ToString());
}
}
else
{
m_log.ErrorFormat("[MONEY]: Money Server is not available!!");
}
#endregion
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["userServIP"] = m_userServIP;
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;
}
}
}
return ret;
}
///
/// 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)
{
// Handle the error in parameter list.
if (reqParams.Count <= 0 || string.IsNullOrEmpty(method) || string.IsNullOrEmpty(m_moneyServURL))
{
return null;
}
ArrayList arrayParams = new ArrayList();
arrayParams.Add(reqParams);
XmlRpcResponse moneyServResp = null;
try
{
XmlRpcRequest moneyModuleReq = new XmlRpcRequest(method, arrayParams);
moneyServResp = moneyModuleReq.Send(m_moneyServURL, MONEYMODULE_REQUEST_TIMEOUT);
}
catch (Exception ex)
{
m_log.ErrorFormat( "[MONEY]: Unable to connect to Money Server {0}. Exception {1}", m_moneyServURL, 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.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 LocateClientObject(UUID AgentID)
{
ScenePresence tPresence = null;
IClientAPI rclient = null;
lock (m_sceneList)
{
foreach (Scene _scene in m_sceneList.Values)
{
tPresence = _scene.GetScenePresence(AgentID);
if (tPresence != null)
{
if (!tPresence.IsChildAgent)
{
rclient = tPresence.ControllingClient;
}
}
if (rclient != null)
{
return rclient;
}
}
}
return null;
}
private Scene LocateSceneClientIn(UUID AgentId)
{
lock (m_sceneList)
{
foreach (Scene _scene in m_sceneList.Values)
{
ScenePresence tPresence = _scene.GetScenePresence(AgentId);
if (tPresence != null)
{
if (!tPresence.IsChildAgent)
{
return _scene;
}
}
}
}
return null;
}
private SceneObjectPart FindPrim(UUID objectID)
{
lock (m_sceneList)
{
foreach (Scene scene in m_sceneList.Values)
{
SceneObjectPart part = scene.GetSceneObjectPart(objectID);
if (part != null)
{
return part;
}
}
}
return null;
}
private int QueryBalanceFromMoneyServer(IClientAPI client)
{
int ret = -1;
#region Send the request to get the balance from money server for cilent.
if (client != null)
{
if (!string.IsNullOrEmpty(m_moneyServURL))
{
Hashtable paramTable = new Hashtable();
paramTable["userServIP"] = m_userServIP;
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)
{
ret = (int)resultTable["clientBalance"];
}
}
}
else
{
if (m_moneyServer.ContainsKey(client.AgentId))
{
ret = m_moneyServer[client.AgentId];
}
}
if (ret < 0)
{
m_log.ErrorFormat("[MONEY]: Unable to query balance from Money Server {0} for client [{1}].",
m_moneyServURL, client.AgentId.ToString());
}
}
#endregion
return ret;
}
private void OnEconomyDataRequest(UUID agentId)
{
// Empty!
}
///
/// Sends the the stored money balance to the client
///
///
///
///
///
private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID)
{
if (client.AgentId == agentID && client.SessionId == SessionID)
{
int balance = -1;
if (!string.IsNullOrEmpty(m_moneyServURL))
{
balance = QueryBalanceFromMoneyServer(client);
}
//else if (m_moneyServer.ContainsKey(agentID))
//{
// balance = m_moneyServer[agentID];
//}
if (balance < 0)
{
client.SendAlertMessage("Fail to query the balance.");
}
else
{
client.SendMoneyBalance(TransactionID, true, new byte[0], balance);
}
}
else
{
client.SendAlertMessage("Unable to send your money balance.");
}
}
private void OnRequestPayPrice(IClientAPI client, UUID objectID)
{
Scene scene = LocateSceneClientIn(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);
}
#endregion
/* Private **************************************************************/
}
}