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