SampleMoneyModule.cs 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Net;
  31. using System.Net.Sockets;
  32. using System.Reflection;
  33. using System.Xml;
  34. using OpenMetaverse;
  35. using log4net;
  36. using Nini.Config;
  37. using Nwc.XmlRpc;
  38. using OpenSim.Framework;
  39. using OpenSim.Region.Environment.Interfaces;
  40. using OpenSim.Region.Interfaces;
  41. using OpenSim.Region.Environment.Scenes;
  42. using OpenSim.Framework.Communications.Cache;
  43. namespace OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney
  44. {
  45. /// <summary>
  46. /// Demo Economy/Money Module. This is not a production quality money/economy module!
  47. /// This is a demo for you to use when making one that works for you.
  48. /// // To use the following you need to add:
  49. /// -helperuri <ADDRESS TO HERE OR grid MONEY SERVER>
  50. /// to the command line parameters you use to start up your client
  51. /// This commonly looks like -helperuri http://127.0.0.1:9000/
  52. ///
  53. /// Centralized grid structure example using OpenSimWi Redux revision 9+
  54. /// svn co https://opensimwiredux.svn.sourceforge.net/svnroot/opensimwiredux
  55. /// </summary>
  56. public class SampleMoneyModule : IMoneyModule, IRegionModule
  57. {
  58. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  59. /// <summary>
  60. /// Where Stipends come from and Fees go to.
  61. /// </summary>
  62. // private UUID EconomyBaseAccount = UUID.Zero;
  63. private float EnergyEfficiency = 0f;
  64. private bool gridmode = false;
  65. // private ObjectPaid handerOnObjectPaid;
  66. private bool m_enabled = true;
  67. private IConfigSource m_gConfig;
  68. private bool m_keepMoneyAcrossLogins = true;
  69. private Dictionary<UUID, int> m_KnownClientFunds = new Dictionary<UUID, int>();
  70. // private string m_LandAddress = String.Empty;
  71. private int m_minFundsBeforeRefresh = 100;
  72. private string m_MoneyAddress = String.Empty;
  73. /// <summary>
  74. /// Region UUIDS indexed by AgentID
  75. /// </summary>
  76. private Dictionary<UUID, UUID> m_rootAgents = new Dictionary<UUID, UUID>();
  77. /// <summary>
  78. /// Scenes by Region Handle
  79. /// </summary>
  80. private Dictionary<ulong, Scene> m_scenel = new Dictionary<ulong, Scene>();
  81. private int m_stipend = 1000;
  82. private int ObjectCapacity = 45000;
  83. private int ObjectCount = 0;
  84. private int PriceEnergyUnit = 0;
  85. private int PriceGroupCreate = 0;
  86. private int PriceObjectClaim = 0;
  87. private float PriceObjectRent = 0f;
  88. private float PriceObjectScaleFactor = 0f;
  89. private int PriceParcelClaim = 0;
  90. private float PriceParcelClaimFactor = 0f;
  91. private int PriceParcelRent = 0;
  92. private int PricePublicObjectDecay = 0;
  93. private int PricePublicObjectDelete = 0;
  94. private int PriceRentLight = 0;
  95. private int PriceUpload = 0;
  96. private int TeleportMinPrice = 0;
  97. private float TeleportPriceExponent = 0f;
  98. // private int UserLevelPaysFees = 2;
  99. // private Scene XMLRPCHandler;
  100. #region IMoneyModule Members
  101. public event ObjectPaid OnObjectPaid;
  102. /// <summary>
  103. /// Startup
  104. /// </summary>
  105. /// <param name="scene"></param>
  106. /// <param name="config"></param>
  107. public void Initialise(Scene scene, IConfigSource config)
  108. {
  109. m_gConfig = config;
  110. IConfig startupConfig = m_gConfig.Configs["Startup"];
  111. IConfig economyConfig = m_gConfig.Configs["Economy"];
  112. ReadConfigAndPopulate(scene, startupConfig, "Startup");
  113. ReadConfigAndPopulate(scene, economyConfig, "Economy");
  114. if (m_enabled)
  115. {
  116. scene.RegisterModuleInterface<IMoneyModule>(this);
  117. lock (m_scenel)
  118. {
  119. if (m_scenel.Count == 0)
  120. {
  121. // XMLRPCHandler = scene;
  122. // To use the following you need to add:
  123. // -helperuri <ADDRESS TO HERE OR grid MONEY SERVER>
  124. // to the command line parameters you use to start up your client
  125. // This commonly looks like -helperuri http://127.0.0.1:9000/
  126. if (m_MoneyAddress.Length > 0)
  127. {
  128. // Centralized grid structure using OpenSimWi Redux revision 9+
  129. // https://opensimwiredux.svn.sourceforge.net/svnroot/opensimwiredux
  130. scene.AddXmlRPCHandler("balanceUpdateRequest", GridMoneyUpdate);
  131. scene.AddXmlRPCHandler("userAlert", UserAlert);
  132. }
  133. else
  134. {
  135. // Local Server.. enables functionality only.
  136. scene.AddXmlRPCHandler("getCurrencyQuote", quote_func);
  137. scene.AddXmlRPCHandler("buyCurrency", buy_func);
  138. scene.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func);
  139. scene.AddXmlRPCHandler("buyLandPrep", landBuy_func);
  140. }
  141. }
  142. if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle))
  143. {
  144. m_scenel[scene.RegionInfo.RegionHandle] = scene;
  145. }
  146. else
  147. {
  148. m_scenel.Add(scene.RegionInfo.RegionHandle, scene);
  149. }
  150. }
  151. scene.EventManager.OnNewClient += OnNewClient;
  152. scene.EventManager.OnMoneyTransfer += MoneyTransferAction;
  153. scene.EventManager.OnClientClosed += ClientClosed;
  154. scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
  155. scene.EventManager.OnMakeChildAgent += MakeChildAgent;
  156. scene.EventManager.OnClientClosed += ClientLoggedOut;
  157. scene.EventManager.OnValidateLandBuy += ValidateLandBuy;
  158. scene.EventManager.OnLandBuy += processLandBuy;
  159. }
  160. }
  161. // Please do not refactor these to be just one method
  162. // Existing implementations need the distinction
  163. //
  164. public void ApplyUploadCharge(UUID agentID)
  165. {
  166. }
  167. public void ApplyGroupCreationCharge(UUID agentID)
  168. {
  169. }
  170. public void ApplyCharge(UUID agentID, int amount, string text)
  171. {
  172. }
  173. public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount)
  174. {
  175. string description = String.Format("Object {0} pays {1}", resolveObjectName(objectID), resolveAgentName(toID));
  176. bool give_result = doMoneyTransfer(fromID, toID, amount, 2, description);
  177. if (m_MoneyAddress.Length == 0)
  178. BalanceUpdate(fromID, toID, give_result, description);
  179. return give_result;
  180. }
  181. public void PostInitialise()
  182. {
  183. }
  184. public void Close()
  185. {
  186. }
  187. public string Name
  188. {
  189. get { return "BetaGridLikeMoneyModule"; }
  190. }
  191. public bool IsSharedModule
  192. {
  193. get { return true; }
  194. }
  195. #endregion
  196. /// <summary>
  197. /// Parse Configuration
  198. /// </summary>
  199. /// <param name="scene"></param>
  200. /// <param name="startupConfig"></param>
  201. /// <param name="config"></param>
  202. private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string config)
  203. {
  204. if (config == "Startup" && startupConfig != null)
  205. {
  206. gridmode = startupConfig.GetBoolean("gridmode", false);
  207. m_enabled = (startupConfig.GetString("economymodule", "BetaGridLikeMoneyModule") == "BetaGridLikeMoneyModule");
  208. }
  209. if (config == "Economy" && startupConfig != null)
  210. {
  211. ObjectCapacity = startupConfig.GetInt("ObjectCapacity", 45000);
  212. PriceEnergyUnit = startupConfig.GetInt("PriceEnergyUnit", 100);
  213. PriceObjectClaim = startupConfig.GetInt("PriceObjectClaim", 10);
  214. PricePublicObjectDecay = startupConfig.GetInt("PricePublicObjectDecay", 4);
  215. PricePublicObjectDelete = startupConfig.GetInt("PricePublicObjectDelete", 4);
  216. PriceParcelClaim = startupConfig.GetInt("PriceParcelClaim", 1);
  217. PriceParcelClaimFactor = startupConfig.GetFloat("PriceParcelClaimFactor", 1f);
  218. PriceUpload = startupConfig.GetInt("PriceUpload", 0);
  219. PriceRentLight = startupConfig.GetInt("PriceRentLight", 5);
  220. TeleportMinPrice = startupConfig.GetInt("TeleportMinPrice", 2);
  221. TeleportPriceExponent = startupConfig.GetFloat("TeleportPriceExponent", 2f);
  222. EnergyEfficiency = startupConfig.GetFloat("EnergyEfficiency", 1);
  223. PriceObjectRent = startupConfig.GetFloat("PriceObjectRent", 1);
  224. PriceObjectScaleFactor = startupConfig.GetFloat("PriceObjectScaleFactor", 10);
  225. PriceParcelRent = startupConfig.GetInt("PriceParcelRent", 1);
  226. PriceGroupCreate = startupConfig.GetInt("PriceGroupCreate", -1);
  227. // string EBA = startupConfig.GetString("EconomyBaseAccount", UUID.Zero.ToString());
  228. // Helpers.TryParse(EBA, out EconomyBaseAccount);
  229. // UserLevelPaysFees = startupConfig.GetInt("UserLevelPaysFees", -1);
  230. m_stipend = startupConfig.GetInt("UserStipend", 500);
  231. m_minFundsBeforeRefresh = startupConfig.GetInt("IssueStipendWhenClientIsBelowAmount", 10);
  232. m_keepMoneyAcrossLogins = startupConfig.GetBoolean("KeepMoneyAcrossLogins", true);
  233. m_MoneyAddress = startupConfig.GetString("CurrencyServer", String.Empty);
  234. // m_LandAddress = startupConfig.GetString("LandServer", String.Empty);
  235. }
  236. // Send ObjectCapacity to Scene.. Which sends it to the SimStatsReporter.
  237. scene.SetObjectCapacity(ObjectCapacity);
  238. }
  239. private void GetClientFunds(IClientAPI client)
  240. {
  241. // Here we check if we're in grid mode
  242. // I imagine that the 'check balance'
  243. // function for the client should be here or shortly after
  244. if (gridmode)
  245. {
  246. if (m_MoneyAddress.Length == 0)
  247. {
  248. CheckExistAndRefreshFunds(client.AgentId);
  249. }
  250. else
  251. {
  252. bool childYN = true;
  253. ScenePresence agent = null;
  254. //client.SecureSessionId;
  255. Scene s = LocateSceneClientIn(client.AgentId);
  256. if (s != null)
  257. {
  258. agent = s.GetScenePresence(client.AgentId);
  259. if (agent != null)
  260. childYN = agent.IsChildAgent;
  261. }
  262. if (s != null && agent != null && childYN == false)
  263. {
  264. //s.RegionInfo.RegionHandle;
  265. UUID agentID = UUID.Zero;
  266. int funds = 0;
  267. Hashtable hbinfo =
  268. GetBalanceForUserFromMoneyServer(client.AgentId, client.SecureSessionId, s.RegionInfo.originRegionID,
  269. s.RegionInfo.regionSecret);
  270. if ((bool) hbinfo["success"] == true)
  271. {
  272. UUID.TryParse((string)hbinfo["agentId"], out agentID);
  273. try
  274. {
  275. funds = (Int32) hbinfo["funds"];
  276. }
  277. catch (ArgumentException)
  278. {
  279. }
  280. catch (FormatException)
  281. {
  282. }
  283. catch (OverflowException)
  284. {
  285. m_log.ErrorFormat("[MONEY]: While getting the Currency for user {0}, the return funds overflowed.", agentID);
  286. client.SendAlertMessage("Unable to get your money balance, money operations will be unavailable");
  287. }
  288. catch (InvalidCastException)
  289. {
  290. funds = 0;
  291. }
  292. m_KnownClientFunds[agentID] = funds;
  293. }
  294. else
  295. {
  296. m_log.WarnFormat("[MONEY]: Getting Money for user {0} failed with the following message:{1}", agentID,
  297. (string) hbinfo["errorMessage"]);
  298. client.SendAlertMessage((string) hbinfo["errorMessage"]);
  299. }
  300. SendMoneyBalance(client, agentID, client.SessionId, UUID.Zero);
  301. }
  302. }
  303. }
  304. else
  305. {
  306. CheckExistAndRefreshFunds(client.AgentId);
  307. }
  308. }
  309. /// <summary>
  310. /// New Client Event Handler
  311. /// </summary>
  312. /// <param name="client"></param>
  313. private void OnNewClient(IClientAPI client)
  314. {
  315. GetClientFunds(client);
  316. // Subscribe to Money messages
  317. client.OnEconomyDataRequest += EconomyDataRequestHandler;
  318. client.OnMoneyBalanceRequest += SendMoneyBalance;
  319. client.OnRequestPayPrice += requestPayPrice;
  320. client.OnObjectBuy += ObjectBuy;
  321. client.OnLogout += ClientClosed;
  322. }
  323. /// <summary>
  324. /// Transfer money
  325. /// </summary>
  326. /// <param name="Sender"></param>
  327. /// <param name="Receiver"></param>
  328. /// <param name="amount"></param>
  329. /// <returns></returns>
  330. private bool doMoneyTransfer(UUID Sender, UUID Receiver, int amount, int transactiontype, string description)
  331. {
  332. bool result = false;
  333. if (amount >= 0)
  334. {
  335. lock (m_KnownClientFunds)
  336. {
  337. // If we don't know about the sender, then the sender can't
  338. // actually be here and therefore this is likely fraud or outdated.
  339. if (m_MoneyAddress.Length == 0)
  340. {
  341. if (m_KnownClientFunds.ContainsKey(Sender))
  342. {
  343. // Does the sender have enough funds to give?
  344. if (m_KnownClientFunds[Sender] >= amount)
  345. {
  346. // Subtract the funds from the senders account
  347. m_KnownClientFunds[Sender] -= amount;
  348. // do we know about the receiver?
  349. if (!m_KnownClientFunds.ContainsKey(Receiver))
  350. {
  351. // Make a record for them so they get the updated balance when they login
  352. CheckExistAndRefreshFunds(Receiver);
  353. }
  354. if (m_enabled)
  355. {
  356. //Add the amount to the Receiver's funds
  357. m_KnownClientFunds[Receiver] += amount;
  358. result = true;
  359. }
  360. }
  361. else
  362. {
  363. // These below are redundant to make this clearer to read
  364. result = false;
  365. }
  366. }
  367. else
  368. {
  369. result = false;
  370. }
  371. }
  372. else
  373. {
  374. result = TransferMoneyonMoneyServer(Sender, Receiver, amount, transactiontype, description);
  375. }
  376. }
  377. }
  378. return result;
  379. }
  380. /// <summary>
  381. /// Sends the the stored money balance to the client
  382. /// </summary>
  383. /// <param name="client"></param>
  384. /// <param name="agentID"></param>
  385. /// <param name="SessionID"></param>
  386. /// <param name="TransactionID"></param>
  387. public void SendMoneyBalance(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID)
  388. {
  389. if (client.AgentId == agentID && client.SessionId == SessionID)
  390. {
  391. int returnfunds = 0;
  392. try
  393. {
  394. returnfunds = GetFundsForAgentID(agentID);
  395. }
  396. catch (Exception e)
  397. {
  398. client.SendAlertMessage(e.Message + " ");
  399. }
  400. client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds);
  401. }
  402. else
  403. {
  404. client.SendAlertMessage("Unable to send your money balance to you!");
  405. }
  406. }
  407. /// <summary>
  408. /// Gets the current balance for the user from the Grid Money Server
  409. /// </summary>
  410. /// <param name="agentId"></param>
  411. /// <param name="secureSessionID"></param>
  412. /// <param name="regionId"></param>
  413. /// <param name="regionSecret"></param>
  414. /// <returns></returns>
  415. public Hashtable GetBalanceForUserFromMoneyServer(UUID agentId, UUID secureSessionID, UUID regionId, string regionSecret)
  416. {
  417. Hashtable MoneyBalanceRequestParams = new Hashtable();
  418. MoneyBalanceRequestParams["agentId"] = agentId.ToString();
  419. MoneyBalanceRequestParams["secureSessionId"] = secureSessionID.ToString();
  420. MoneyBalanceRequestParams["regionId"] = regionId.ToString();
  421. MoneyBalanceRequestParams["secret"] = regionSecret;
  422. MoneyBalanceRequestParams["currencySecret"] = ""; // per - region/user currency secret gotten from the money system
  423. Hashtable MoneyRespData = genericCurrencyXMLRPCRequest(MoneyBalanceRequestParams, "simulatorUserBalanceRequest");
  424. return MoneyRespData;
  425. }
  426. /// <summary>
  427. /// Generic XMLRPC client abstraction
  428. /// </summary>
  429. /// <param name="ReqParams">Hashtable containing parameters to the method</param>
  430. /// <param name="method">Method to invoke</param>
  431. /// <returns>Hashtable with success=>bool and other values</returns>
  432. public Hashtable genericCurrencyXMLRPCRequest(Hashtable ReqParams, string method)
  433. {
  434. ArrayList SendParams = new ArrayList();
  435. SendParams.Add(ReqParams);
  436. // Send Request
  437. XmlRpcResponse MoneyResp;
  438. try
  439. {
  440. XmlRpcRequest BalanceRequestReq = new XmlRpcRequest(method, SendParams);
  441. MoneyResp = BalanceRequestReq.Send(m_MoneyAddress, 30000);
  442. }
  443. catch (WebException ex)
  444. {
  445. m_log.ErrorFormat(
  446. "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
  447. m_MoneyAddress, ex);
  448. Hashtable ErrorHash = new Hashtable();
  449. ErrorHash["success"] = false;
  450. ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
  451. ErrorHash["errorURI"] = "";
  452. return ErrorHash;
  453. //throw (ex);
  454. }
  455. catch (SocketException ex)
  456. {
  457. m_log.ErrorFormat(
  458. "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
  459. m_MoneyAddress, ex);
  460. Hashtable ErrorHash = new Hashtable();
  461. ErrorHash["success"] = false;
  462. ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
  463. ErrorHash["errorURI"] = "";
  464. return ErrorHash;
  465. //throw (ex);
  466. }
  467. catch (XmlException ex)
  468. {
  469. m_log.ErrorFormat(
  470. "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
  471. m_MoneyAddress, ex);
  472. Hashtable ErrorHash = new Hashtable();
  473. ErrorHash["success"] = false;
  474. ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
  475. ErrorHash["errorURI"] = "";
  476. return ErrorHash;
  477. }
  478. if (MoneyResp.IsFault)
  479. {
  480. Hashtable ErrorHash = new Hashtable();
  481. ErrorHash["success"] = false;
  482. ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
  483. ErrorHash["errorURI"] = "";
  484. return ErrorHash;
  485. }
  486. Hashtable MoneyRespData = (Hashtable) MoneyResp.Value;
  487. return MoneyRespData;
  488. }
  489. /// <summary>
  490. /// This informs the Money Grid Server that the avatar is in this simulator
  491. /// </summary>
  492. /// <param name="agentId"></param>
  493. /// <param name="secureSessionID"></param>
  494. /// <param name="regionId"></param>
  495. /// <param name="regionSecret"></param>
  496. /// <returns></returns>
  497. public Hashtable claim_user(UUID agentId, UUID secureSessionID, UUID regionId, string regionSecret)
  498. {
  499. Hashtable MoneyBalanceRequestParams = new Hashtable();
  500. MoneyBalanceRequestParams["agentId"] = agentId.ToString();
  501. MoneyBalanceRequestParams["secureSessionId"] = secureSessionID.ToString();
  502. MoneyBalanceRequestParams["regionId"] = regionId.ToString();
  503. MoneyBalanceRequestParams["secret"] = regionSecret;
  504. Hashtable MoneyRespData = genericCurrencyXMLRPCRequest(MoneyBalanceRequestParams, "simulatorClaimUserRequest");
  505. IClientAPI sendMoneyBal = LocateClientObject(agentId);
  506. if (sendMoneyBal != null)
  507. {
  508. SendMoneyBalance(sendMoneyBal, agentId, sendMoneyBal.SessionId, UUID.Zero);
  509. }
  510. return MoneyRespData;
  511. }
  512. private SceneObjectPart findPrim(UUID objectID)
  513. {
  514. lock (m_scenel)
  515. {
  516. foreach (Scene s in m_scenel.Values)
  517. {
  518. SceneObjectPart part = s.GetSceneObjectPart(objectID);
  519. if (part != null)
  520. {
  521. return part;
  522. }
  523. }
  524. }
  525. return null;
  526. }
  527. private string resolveObjectName(UUID objectID)
  528. {
  529. SceneObjectPart part = findPrim(objectID);
  530. if (part != null)
  531. {
  532. return part.Name;
  533. }
  534. return String.Empty;
  535. }
  536. private string resolveAgentName(UUID agentID)
  537. {
  538. // try avatar username surname
  539. Scene scene = GetRandomScene();
  540. CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
  541. if (profile != null && profile.UserProfile != null)
  542. {
  543. string avatarname = profile.UserProfile.FirstName + " " + profile.UserProfile.SurName;
  544. return avatarname;
  545. }
  546. else
  547. {
  548. m_log.ErrorFormat(
  549. "[MONEY]: Could not resolve user {0}",
  550. agentID);
  551. }
  552. return String.Empty;
  553. }
  554. private void BalanceUpdate(UUID senderID, UUID receiverID, bool transactionresult, string description)
  555. {
  556. IClientAPI sender = LocateClientObject(senderID);
  557. IClientAPI receiver = LocateClientObject(receiverID);
  558. if (senderID != receiverID)
  559. {
  560. if (sender != null)
  561. {
  562. sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID));
  563. }
  564. if (receiver != null)
  565. {
  566. receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID));
  567. }
  568. }
  569. }
  570. /// <summary>
  571. /// Informs the Money Grid Server of a transfer.
  572. /// </summary>
  573. /// <param name="sourceId"></param>
  574. /// <param name="destId"></param>
  575. /// <param name="amount"></param>
  576. /// <returns></returns>
  577. public bool TransferMoneyonMoneyServer(UUID sourceId, UUID destId, int amount, int transactiontype, string description)
  578. {
  579. int aggregatePermInventory = 0;
  580. int aggregatePermNextOwner = 0;
  581. int flags = 0;
  582. bool rvalue = false;
  583. IClientAPI cli = LocateClientObject(sourceId);
  584. if (cli != null)
  585. {
  586. Scene userScene = null;
  587. lock (m_rootAgents)
  588. {
  589. userScene = GetSceneByUUID(m_rootAgents[sourceId]);
  590. }
  591. if (userScene != null)
  592. {
  593. Hashtable ht = new Hashtable();
  594. ht["agentId"] = sourceId.ToString();
  595. ht["secureSessionId"] = cli.SecureSessionId.ToString();
  596. ht["regionId"] = userScene.RegionInfo.originRegionID.ToString();
  597. ht["secret"] = userScene.RegionInfo.regionSecret;
  598. ht["currencySecret"] = " ";
  599. ht["destId"] = destId.ToString();
  600. ht["cash"] = amount;
  601. ht["aggregatePermInventory"] = aggregatePermInventory;
  602. ht["aggregatePermNextOwner"] = aggregatePermNextOwner;
  603. ht["flags"] = flags;
  604. ht["transactionType"] = transactiontype;
  605. ht["description"] = description;
  606. Hashtable hresult = genericCurrencyXMLRPCRequest(ht, "regionMoveMoney");
  607. if ((bool) hresult["success"] == true)
  608. {
  609. int funds1 = 0;
  610. int funds2 = 0;
  611. try
  612. {
  613. funds1 = (Int32) hresult["funds"];
  614. }
  615. catch (InvalidCastException)
  616. {
  617. funds1 = 0;
  618. }
  619. SetLocalFundsForAgentID(sourceId, funds1);
  620. if (m_KnownClientFunds.ContainsKey(destId))
  621. {
  622. try
  623. {
  624. funds2 = (Int32) hresult["funds2"];
  625. }
  626. catch (InvalidCastException)
  627. {
  628. funds2 = 0;
  629. }
  630. SetLocalFundsForAgentID(destId, funds2);
  631. }
  632. rvalue = true;
  633. }
  634. else
  635. {
  636. cli.SendAgentAlertMessage((string) hresult["errorMessage"], true);
  637. }
  638. }
  639. }
  640. else
  641. {
  642. m_log.ErrorFormat("[MONEY]: Client {0} not found", sourceId.ToString());
  643. }
  644. return rvalue;
  645. }
  646. public int GetRemoteBalance(UUID agentId)
  647. {
  648. int funds = 0;
  649. IClientAPI aClient = LocateClientObject(agentId);
  650. if (aClient != null)
  651. {
  652. Scene s = LocateSceneClientIn(agentId);
  653. if (s != null)
  654. {
  655. if (m_MoneyAddress.Length > 0)
  656. {
  657. Hashtable hbinfo =
  658. GetBalanceForUserFromMoneyServer(aClient.AgentId, aClient.SecureSessionId, s.RegionInfo.originRegionID,
  659. s.RegionInfo.regionSecret);
  660. if ((bool) hbinfo["success"] == true)
  661. {
  662. try
  663. {
  664. funds = (Int32) hbinfo["funds"];
  665. }
  666. catch (ArgumentException)
  667. {
  668. }
  669. catch (FormatException)
  670. {
  671. }
  672. catch (OverflowException)
  673. {
  674. m_log.ErrorFormat("[MONEY]: While getting the Currency for user {0}, the return funds overflowed.", agentId);
  675. aClient.SendAlertMessage("Unable to get your money balance, money operations will be unavailable");
  676. }
  677. catch (InvalidCastException)
  678. {
  679. funds = 0;
  680. }
  681. }
  682. else
  683. {
  684. m_log.WarnFormat("[MONEY]: Getting Money for user {0} failed with the following message:{1}", agentId,
  685. (string) hbinfo["errorMessage"]);
  686. aClient.SendAlertMessage((string) hbinfo["errorMessage"]);
  687. }
  688. }
  689. SetLocalFundsForAgentID(agentId, funds);
  690. SendMoneyBalance(aClient, agentId, aClient.SessionId, UUID.Zero);
  691. }
  692. else
  693. {
  694. m_log.Debug("[MONEY]: Got balance request update for agent that is here, but couldn't find which scene.");
  695. }
  696. }
  697. else
  698. {
  699. m_log.Debug("[MONEY]: Got balance request update for agent that isn't here.");
  700. }
  701. return funds;
  702. }
  703. public XmlRpcResponse GridMoneyUpdate(XmlRpcRequest request)
  704. {
  705. m_log.Debug("[MONEY]: Dynamic balance update called.");
  706. Hashtable requestData = (Hashtable) request.Params[0];
  707. if (requestData.ContainsKey("agentId"))
  708. {
  709. UUID agentId = UUID.Zero;
  710. UUID.TryParse((string) requestData["agentId"], out agentId);
  711. if (agentId != UUID.Zero)
  712. {
  713. GetRemoteBalance(agentId);
  714. }
  715. else
  716. {
  717. m_log.Debug("[MONEY]: invalid agentId specified, dropping.");
  718. }
  719. }
  720. else
  721. {
  722. m_log.Debug("[MONEY]: no agentId specified, dropping.");
  723. }
  724. XmlRpcResponse r = new XmlRpcResponse();
  725. Hashtable rparms = new Hashtable();
  726. rparms["success"] = true;
  727. r.Value = rparms;
  728. return r;
  729. }
  730. /// <summary>
  731. /// XMLRPC handler to send alert message and sound to client
  732. /// </summary>
  733. public XmlRpcResponse UserAlert(XmlRpcRequest request)
  734. {
  735. XmlRpcResponse ret = new XmlRpcResponse();
  736. Hashtable retparam = new Hashtable();
  737. Hashtable requestData = (Hashtable) request.Params[0];
  738. UUID agentId;
  739. UUID soundId;
  740. UUID regionId;
  741. UUID.TryParse((string) requestData["agentId"], out agentId);
  742. UUID.TryParse((string) requestData["soundId"], out soundId);
  743. UUID.TryParse((string) requestData["regionId"], out regionId);
  744. string text = (string) requestData["text"];
  745. string secret = (string) requestData["secret"];
  746. Scene userScene = GetSceneByUUID(regionId);
  747. if (userScene != null)
  748. {
  749. if (userScene.RegionInfo.regionSecret == secret)
  750. {
  751. IClientAPI client = LocateClientObject(agentId);
  752. if (client != null)
  753. {
  754. if (soundId != UUID.Zero)
  755. client.SendPlayAttachedSound(soundId, UUID.Zero, UUID.Zero, 1.0f, 0);
  756. client.SendBlueBoxMessage(UUID.Zero, "", text);
  757. retparam.Add("success", true);
  758. }
  759. else
  760. {
  761. retparam.Add("success", false);
  762. }
  763. }
  764. else
  765. {
  766. retparam.Add("success", false);
  767. }
  768. }
  769. ret.Value = retparam;
  770. return ret;
  771. }
  772. # region Standalone box enablers only
  773. public XmlRpcResponse quote_func(XmlRpcRequest request)
  774. {
  775. Hashtable requestData = (Hashtable) request.Params[0];
  776. UUID agentId = UUID.Zero;
  777. int amount = 0;
  778. Hashtable quoteResponse = new Hashtable();
  779. XmlRpcResponse returnval = new XmlRpcResponse();
  780. if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
  781. {
  782. UUID.TryParse((string) requestData["agentId"], out agentId);
  783. try
  784. {
  785. amount = (Int32) requestData["currencyBuy"];
  786. }
  787. catch (InvalidCastException)
  788. {
  789. }
  790. Hashtable currencyResponse = new Hashtable();
  791. currencyResponse.Add("estimatedCost", 0);
  792. currencyResponse.Add("currencyBuy", amount);
  793. quoteResponse.Add("success", true);
  794. quoteResponse.Add("currency", currencyResponse);
  795. quoteResponse.Add("confirm", "asdfad9fj39ma9fj");
  796. returnval.Value = quoteResponse;
  797. return returnval;
  798. }
  799. quoteResponse.Add("success", false);
  800. quoteResponse.Add("errorMessage", "Invalid parameters passed to the quote box");
  801. quoteResponse.Add("errorURI", "http://www.opensimulator.org/wiki");
  802. returnval.Value = quoteResponse;
  803. return returnval;
  804. }
  805. public XmlRpcResponse buy_func(XmlRpcRequest request)
  806. {
  807. Hashtable requestData = (Hashtable) request.Params[0];
  808. UUID agentId = UUID.Zero;
  809. int amount = 0;
  810. if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
  811. {
  812. UUID.TryParse((string) requestData["agentId"], out agentId);
  813. try
  814. {
  815. amount = (Int32) requestData["currencyBuy"];
  816. }
  817. catch (InvalidCastException)
  818. {
  819. }
  820. if (agentId != UUID.Zero)
  821. {
  822. lock (m_KnownClientFunds)
  823. {
  824. if (m_KnownClientFunds.ContainsKey(agentId))
  825. {
  826. m_KnownClientFunds[agentId] += amount;
  827. }
  828. else
  829. {
  830. m_KnownClientFunds.Add(agentId, amount);
  831. }
  832. }
  833. IClientAPI client = LocateClientObject(agentId);
  834. if (client != null)
  835. {
  836. SendMoneyBalance(client, agentId, client.SessionId, UUID.Zero);
  837. }
  838. }
  839. }
  840. XmlRpcResponse returnval = new XmlRpcResponse();
  841. Hashtable returnresp = new Hashtable();
  842. returnresp.Add("success", true);
  843. returnval.Value = returnresp;
  844. return returnval;
  845. }
  846. public XmlRpcResponse preflightBuyLandPrep_func(XmlRpcRequest request)
  847. {
  848. XmlRpcResponse ret = new XmlRpcResponse();
  849. Hashtable retparam = new Hashtable();
  850. Hashtable membershiplevels = new Hashtable();
  851. ArrayList levels = new ArrayList();
  852. Hashtable level = new Hashtable();
  853. level.Add("id", "00000000-0000-0000-0000-000000000000");
  854. level.Add("description", "some level");
  855. levels.Add(level);
  856. //membershiplevels.Add("levels",levels);
  857. Hashtable landuse = new Hashtable();
  858. landuse.Add("upgrade", false);
  859. landuse.Add("action", "http://invaliddomaininvalid.com/");
  860. Hashtable currency = new Hashtable();
  861. currency.Add("estimatedCost", 0);
  862. Hashtable membership = new Hashtable();
  863. membershiplevels.Add("upgrade", false);
  864. membershiplevels.Add("action", "http://invaliddomaininvalid.com/");
  865. membershiplevels.Add("levels", membershiplevels);
  866. retparam.Add("success", true);
  867. retparam.Add("currency", currency);
  868. retparam.Add("membership", membership);
  869. retparam.Add("landuse", landuse);
  870. retparam.Add("confirm", "asdfajsdkfjasdkfjalsdfjasdf");
  871. ret.Value = retparam;
  872. return ret;
  873. }
  874. public XmlRpcResponse landBuy_func(XmlRpcRequest request)
  875. {
  876. XmlRpcResponse ret = new XmlRpcResponse();
  877. Hashtable retparam = new Hashtable();
  878. Hashtable requestData = (Hashtable) request.Params[0];
  879. UUID agentId = UUID.Zero;
  880. int amount = 0;
  881. if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
  882. {
  883. UUID.TryParse((string) requestData["agentId"], out agentId);
  884. try
  885. {
  886. amount = (Int32) requestData["currencyBuy"];
  887. }
  888. catch (InvalidCastException)
  889. {
  890. }
  891. if (agentId != UUID.Zero)
  892. {
  893. lock (m_KnownClientFunds)
  894. {
  895. if (m_KnownClientFunds.ContainsKey(agentId))
  896. {
  897. m_KnownClientFunds[agentId] += amount;
  898. }
  899. else
  900. {
  901. m_KnownClientFunds.Add(agentId, amount);
  902. }
  903. }
  904. IClientAPI client = LocateClientObject(agentId);
  905. if (client != null)
  906. {
  907. SendMoneyBalance(client, agentId, client.SessionId, UUID.Zero);
  908. }
  909. }
  910. }
  911. retparam.Add("success", true);
  912. ret.Value = retparam;
  913. return ret;
  914. }
  915. #endregion
  916. #region local Fund Management
  917. /// <summary>
  918. /// Ensures that the agent accounting data is set up in this instance.
  919. /// </summary>
  920. /// <param name="agentID"></param>
  921. private void CheckExistAndRefreshFunds(UUID agentID)
  922. {
  923. lock (m_KnownClientFunds)
  924. {
  925. if (!m_KnownClientFunds.ContainsKey(agentID))
  926. {
  927. m_KnownClientFunds.Add(agentID, m_stipend);
  928. }
  929. else
  930. {
  931. if (m_KnownClientFunds[agentID] <= m_minFundsBeforeRefresh)
  932. {
  933. m_KnownClientFunds[agentID] = m_stipend;
  934. }
  935. }
  936. }
  937. }
  938. /// <summary>
  939. /// Gets the amount of Funds for an agent
  940. /// </summary>
  941. /// <param name="AgentID"></param>
  942. /// <returns></returns>
  943. private int GetFundsForAgentID(UUID AgentID)
  944. {
  945. int returnfunds = 0;
  946. lock (m_KnownClientFunds)
  947. {
  948. if (m_KnownClientFunds.ContainsKey(AgentID))
  949. {
  950. returnfunds = m_KnownClientFunds[AgentID];
  951. }
  952. else
  953. {
  954. //throw new Exception("Unable to get funds.");
  955. }
  956. }
  957. return returnfunds;
  958. }
  959. private void SetLocalFundsForAgentID(UUID AgentID, int amount)
  960. {
  961. lock (m_KnownClientFunds)
  962. {
  963. if (m_KnownClientFunds.ContainsKey(AgentID))
  964. {
  965. m_KnownClientFunds[AgentID] = amount;
  966. }
  967. else
  968. {
  969. m_KnownClientFunds.Add(AgentID, amount);
  970. }
  971. }
  972. }
  973. #endregion
  974. #region Utility Helpers
  975. /// <summary>
  976. /// Locates a IClientAPI for the client specified
  977. /// </summary>
  978. /// <param name="AgentID"></param>
  979. /// <returns></returns>
  980. private IClientAPI LocateClientObject(UUID AgentID)
  981. {
  982. ScenePresence tPresence = null;
  983. IClientAPI rclient = null;
  984. lock (m_scenel)
  985. {
  986. foreach (Scene _scene in m_scenel.Values)
  987. {
  988. tPresence = _scene.GetScenePresence(AgentID);
  989. if (tPresence != null)
  990. {
  991. if (!tPresence.IsChildAgent)
  992. {
  993. rclient = tPresence.ControllingClient;
  994. }
  995. }
  996. if (rclient != null)
  997. {
  998. return rclient;
  999. }
  1000. }
  1001. }
  1002. return null;
  1003. }
  1004. private Scene LocateSceneClientIn(UUID AgentId)
  1005. {
  1006. lock (m_scenel)
  1007. {
  1008. foreach (Scene _scene in m_scenel.Values)
  1009. {
  1010. ScenePresence tPresence = _scene.GetScenePresence(AgentId);
  1011. if (tPresence != null)
  1012. {
  1013. if (!tPresence.IsChildAgent)
  1014. {
  1015. return _scene;
  1016. }
  1017. }
  1018. }
  1019. }
  1020. return null;
  1021. }
  1022. /// <summary>
  1023. /// Utility function Gets a Random scene in the instance. For when which scene exactly you're doing something with doesn't matter
  1024. /// </summary>
  1025. /// <returns></returns>
  1026. public Scene GetRandomScene()
  1027. {
  1028. lock (m_scenel)
  1029. {
  1030. foreach (Scene rs in m_scenel.Values)
  1031. return rs;
  1032. }
  1033. return null;
  1034. }
  1035. /// <summary>
  1036. /// Utility function to get a Scene by RegionID in a module
  1037. /// </summary>
  1038. /// <param name="RegionID"></param>
  1039. /// <returns></returns>
  1040. public Scene GetSceneByUUID(UUID RegionID)
  1041. {
  1042. lock (m_scenel)
  1043. {
  1044. foreach (Scene rs in m_scenel.Values)
  1045. {
  1046. if (rs.RegionInfo.originRegionID == RegionID)
  1047. {
  1048. return rs;
  1049. }
  1050. }
  1051. }
  1052. return null;
  1053. }
  1054. #endregion
  1055. #region event Handlers
  1056. public void requestPayPrice(IClientAPI client, UUID objectID)
  1057. {
  1058. Scene scene = LocateSceneClientIn(client.AgentId);
  1059. if (scene == null)
  1060. return;
  1061. SceneObjectPart task = scene.GetSceneObjectPart(objectID);
  1062. if (task == null)
  1063. return;
  1064. SceneObjectGroup group = task.ParentGroup;
  1065. SceneObjectPart root = group.RootPart;
  1066. client.SendPayPrice(objectID, root.PayPrice);
  1067. }
  1068. /// <summary>
  1069. /// When the client closes the connection we remove their accounting info from memory to free up resources.
  1070. /// </summary>
  1071. /// <param name="AgentID"></param>
  1072. public void ClientClosed(UUID AgentID)
  1073. {
  1074. lock (m_KnownClientFunds)
  1075. {
  1076. if (m_keepMoneyAcrossLogins && m_MoneyAddress.Length == 0)
  1077. {
  1078. }
  1079. else
  1080. {
  1081. m_KnownClientFunds.Remove(AgentID);
  1082. }
  1083. }
  1084. }
  1085. /// <summary>
  1086. /// Event called Economy Data Request handler.
  1087. /// </summary>
  1088. /// <param name="agentId"></param>
  1089. public void EconomyDataRequestHandler(UUID agentId)
  1090. {
  1091. IClientAPI user = LocateClientObject(agentId);
  1092. if (user != null)
  1093. {
  1094. user.SendEconomyData(EnergyEfficiency, ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
  1095. PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
  1096. PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
  1097. TeleportMinPrice, TeleportPriceExponent);
  1098. }
  1099. }
  1100. private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e)
  1101. {
  1102. if (m_MoneyAddress.Length == 0)
  1103. {
  1104. lock (m_KnownClientFunds)
  1105. {
  1106. if (m_KnownClientFunds.ContainsKey(e.agentId))
  1107. {
  1108. // Does the sender have enough funds to give?
  1109. if (m_KnownClientFunds[e.agentId] >= e.parcelPrice)
  1110. {
  1111. lock (e)
  1112. {
  1113. e.economyValidated = true;
  1114. }
  1115. }
  1116. }
  1117. }
  1118. }
  1119. else
  1120. {
  1121. if (GetRemoteBalance(e.agentId) >= e.parcelPrice)
  1122. {
  1123. lock (e)
  1124. {
  1125. e.economyValidated = true;
  1126. }
  1127. }
  1128. }
  1129. }
  1130. private void processLandBuy(Object osender, EventManager.LandBuyArgs e)
  1131. {
  1132. lock (e)
  1133. {
  1134. if (e.economyValidated == true && e.transactionID == 0)
  1135. {
  1136. e.transactionID = Util.UnixTimeSinceEpoch();
  1137. if (doMoneyTransfer(e.agentId, e.parcelOwnerID, e.parcelPrice, 0, "Land purchase"))
  1138. {
  1139. lock (e)
  1140. {
  1141. e.amountDebited = e.parcelPrice;
  1142. }
  1143. }
  1144. }
  1145. }
  1146. }
  1147. /// <summary>
  1148. /// THis method gets called when someone pays someone else as a gift.
  1149. /// </summary>
  1150. /// <param name="osender"></param>
  1151. /// <param name="e"></param>
  1152. private void MoneyTransferAction(Object osender, EventManager.MoneyTransferArgs e)
  1153. {
  1154. IClientAPI sender = null;
  1155. IClientAPI receiver = null;
  1156. if (m_MoneyAddress.Length > 0) // Handled on server
  1157. e.description = String.Empty;
  1158. if (e.transactiontype == 5008) // Object gets paid
  1159. {
  1160. sender = LocateClientObject(e.sender);
  1161. if (sender != null)
  1162. {
  1163. SceneObjectPart part = findPrim(e.receiver);
  1164. if (part == null)
  1165. return;
  1166. string name = resolveAgentName(part.OwnerID);
  1167. if (name == String.Empty)
  1168. name = "(hippos)";
  1169. receiver = LocateClientObject(part.OwnerID);
  1170. string description = String.Format("Paid {0} via object {1}", name, e.description);
  1171. bool transactionresult = doMoneyTransfer(e.sender, part.OwnerID, e.amount, e.transactiontype, description);
  1172. if (transactionresult)
  1173. {
  1174. ObjectPaid handlerOnObjectPaid = OnObjectPaid;
  1175. if (handlerOnObjectPaid != null)
  1176. {
  1177. handlerOnObjectPaid(e.receiver, e.sender, e.amount);
  1178. }
  1179. }
  1180. if (e.sender != e.receiver)
  1181. {
  1182. sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(e.sender));
  1183. }
  1184. if (receiver != null)
  1185. {
  1186. receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(part.OwnerID));
  1187. }
  1188. }
  1189. return;
  1190. }
  1191. sender = LocateClientObject(e.sender);
  1192. if (sender != null)
  1193. {
  1194. receiver = LocateClientObject(e.receiver);
  1195. bool transactionresult = doMoneyTransfer(e.sender, e.receiver, e.amount, e.transactiontype, e.description);
  1196. if (e.sender != e.receiver)
  1197. {
  1198. if (sender != null)
  1199. {
  1200. sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(e.sender));
  1201. }
  1202. }
  1203. if (receiver != null)
  1204. {
  1205. receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(e.receiver));
  1206. }
  1207. }
  1208. else
  1209. {
  1210. m_log.Warn("[MONEY]: Potential Fraud Warning, got money transfer request for avatar that isn't in this simulator - Details; Sender:" +
  1211. e.sender.ToString() + " Receiver: " + e.receiver.ToString() + " Amount: " + e.amount.ToString());
  1212. }
  1213. }
  1214. /// <summary>
  1215. /// Event Handler for when a root agent becomes a child agent
  1216. /// </summary>
  1217. /// <param name="avatar"></param>
  1218. private void MakeChildAgent(ScenePresence avatar)
  1219. {
  1220. lock (m_rootAgents)
  1221. {
  1222. if (m_rootAgents.ContainsKey(avatar.UUID))
  1223. {
  1224. if (m_rootAgents[avatar.UUID] == avatar.Scene.RegionInfo.originRegionID)
  1225. {
  1226. m_rootAgents.Remove(avatar.UUID);
  1227. m_log.Info("[MONEY]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent");
  1228. }
  1229. }
  1230. }
  1231. }
  1232. /// <summary>
  1233. /// Event Handler for when the client logs out.
  1234. /// </summary>
  1235. /// <param name="AgentId"></param>
  1236. private void ClientLoggedOut(UUID AgentId)
  1237. {
  1238. lock (m_rootAgents)
  1239. {
  1240. if (m_rootAgents.ContainsKey(AgentId))
  1241. {
  1242. m_rootAgents.Remove(AgentId);
  1243. //m_log.Info("[MONEY]: Removing " + AgentId + ". Agent logged out.");
  1244. }
  1245. }
  1246. }
  1247. /// <summary>
  1248. /// Call this when the client disconnects.
  1249. /// </summary>
  1250. /// <param name="client"></param>
  1251. public void ClientClosed(IClientAPI client)
  1252. {
  1253. ClientClosed(client.AgentId);
  1254. }
  1255. /// <summary>
  1256. /// Event Handler for when an Avatar enters one of the parcels in the simulator.
  1257. /// </summary>
  1258. /// <param name="avatar"></param>
  1259. /// <param name="localLandID"></param>
  1260. /// <param name="regionID"></param>
  1261. private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
  1262. {
  1263. lock (m_rootAgents)
  1264. {
  1265. if (m_rootAgents.ContainsKey(avatar.UUID))
  1266. {
  1267. if (avatar.Scene.RegionInfo.originRegionID != m_rootAgents[avatar.UUID])
  1268. {
  1269. m_rootAgents[avatar.UUID] = avatar.Scene.RegionInfo.originRegionID;
  1270. //m_log.Info("[MONEY]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
  1271. // Claim User! my user! Mine mine mine!
  1272. if (m_MoneyAddress.Length > 0)
  1273. {
  1274. Scene RegionItem = GetSceneByUUID(regionID);
  1275. if (RegionItem != null)
  1276. {
  1277. Hashtable hresult =
  1278. claim_user(avatar.UUID, avatar.ControllingClient.SecureSessionId, regionID, RegionItem.RegionInfo.regionSecret);
  1279. if ((bool)hresult["success"] == true)
  1280. {
  1281. int funds = 0;
  1282. try
  1283. {
  1284. funds = (Int32)hresult["funds"];
  1285. }
  1286. catch (InvalidCastException)
  1287. {
  1288. }
  1289. SetLocalFundsForAgentID(avatar.UUID, funds);
  1290. }
  1291. else
  1292. {
  1293. avatar.ControllingClient.SendAgentAlertMessage((string)hresult["errorMessage"], true);
  1294. }
  1295. }
  1296. }
  1297. }
  1298. else
  1299. {
  1300. ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
  1301. if ((obj.landData.Flags & (uint)Parcel.ParcelFlags.AllowDamage) != 0)
  1302. {
  1303. avatar.Invulnerable = false;
  1304. }
  1305. else
  1306. {
  1307. avatar.Invulnerable = true;
  1308. }
  1309. }
  1310. }
  1311. else
  1312. {
  1313. lock (m_rootAgents)
  1314. {
  1315. m_rootAgents.Add(avatar.UUID, avatar.Scene.RegionInfo.originRegionID);
  1316. }
  1317. if (m_MoneyAddress.Length > 0)
  1318. {
  1319. Scene RegionItem = GetSceneByUUID(regionID);
  1320. if (RegionItem != null)
  1321. {
  1322. Hashtable hresult = claim_user(avatar.UUID, avatar.ControllingClient.SecureSessionId, regionID, RegionItem.RegionInfo.regionSecret);
  1323. if ((bool) hresult["success"] == true)
  1324. {
  1325. int funds = 0;
  1326. try
  1327. {
  1328. funds = (Int32) hresult["funds"];
  1329. }
  1330. catch (InvalidCastException)
  1331. {
  1332. }
  1333. SetLocalFundsForAgentID(avatar.UUID, funds);
  1334. }
  1335. else
  1336. {
  1337. avatar.ControllingClient.SendAgentAlertMessage((string) hresult["errorMessage"], true);
  1338. }
  1339. }
  1340. }
  1341. //m_log.Info("[MONEY]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
  1342. }
  1343. }
  1344. //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString());
  1345. }
  1346. public int GetBalance(IClientAPI client)
  1347. {
  1348. GetClientFunds(client);
  1349. lock (m_KnownClientFunds)
  1350. {
  1351. if (!m_KnownClientFunds.ContainsKey(client.AgentId))
  1352. return 0;
  1353. return m_KnownClientFunds[client.AgentId];
  1354. }
  1355. }
  1356. // Please do not refactor these to be just one method
  1357. // Existing implementations need the distinction
  1358. //
  1359. public bool UploadCovered(IClientAPI client)
  1360. {
  1361. return AmountCovered(client, PriceUpload);
  1362. }
  1363. public bool GroupCreationCovered(IClientAPI client)
  1364. {
  1365. return AmountCovered(client, PriceGroupCreate);
  1366. }
  1367. public bool AmountCovered(IClientAPI client, int amount)
  1368. {
  1369. if (GetBalance(client) < amount)
  1370. return false;
  1371. return true;
  1372. }
  1373. #endregion
  1374. public void ObjectBuy(IClientAPI remoteClient, UUID agentID,
  1375. UUID sessionID, UUID groupID, UUID categoryID,
  1376. uint localID, byte saleType, int salePrice)
  1377. {
  1378. GetClientFunds(remoteClient);
  1379. if (!m_KnownClientFunds.ContainsKey(remoteClient.AgentId))
  1380. {
  1381. remoteClient.SendAgentAlertMessage("Unable to buy now. Your account balance was not found.", false);
  1382. return;
  1383. }
  1384. int funds = m_KnownClientFunds[remoteClient.AgentId];
  1385. if (salePrice != 0 && funds < salePrice)
  1386. {
  1387. remoteClient.SendAgentAlertMessage("Unable to buy now. You don't have sufficient funds.", false);
  1388. return;
  1389. }
  1390. Scene s = LocateSceneClientIn(remoteClient.AgentId);
  1391. SceneObjectPart part = s.GetSceneObjectPart(localID);
  1392. if (part == null)
  1393. {
  1394. remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found.", false);
  1395. return;
  1396. }
  1397. if (s.PerformObjectBuy(remoteClient, categoryID, localID, saleType))
  1398. doMoneyTransfer(remoteClient.AgentId, part.OwnerID, salePrice, 5000, "Object buy");
  1399. }
  1400. }
  1401. public enum TransactionType : int
  1402. {
  1403. SystemGenerated = 0,
  1404. RegionMoneyRequest = 1,
  1405. Gift = 2,
  1406. Purchase = 3
  1407. }
  1408. }