aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/Avatar
diff options
context:
space:
mode:
authorAdam Frisby2008-04-30 21:16:36 +0000
committerAdam Frisby2008-04-30 21:16:36 +0000
commitf5c312bc3c2567449c7268a54a08a54119f58d53 (patch)
tree424668a4bbec6873ebc5b8256f3671db102f5e9c /OpenSim/Region/Environment/Modules/Avatar
parent* Adds the AuthbuyerID field to sqlite and makes use of it. (diff)
downloadopensim-SC_OLD-f5c312bc3c2567449c7268a54a08a54119f58d53.zip
opensim-SC_OLD-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.gz
opensim-SC_OLD-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.bz2
opensim-SC_OLD-f5c312bc3c2567449c7268a54a08a54119f58d53.tar.xz
* Refactored Environment/Modules directory - modules now reside in their own directory with any associated module-specific classes.
* Each module directory is currently inside one of the following category folders: Agent (Anything relating to do with Client<->Server communications.), Avatar (Anything to do with the avatar or presence inworld), Framework (Classes modules can use), Grid (Grid traffic, new OGS2 grid comms), Scripting (Scripting functions, etc), World (The enrivonment/scene, IE Sun/Tree modules.) * This should be moved into a seperate project file.
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Avatar')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs338
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs831
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs1491
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs504
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs278
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs157
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Inventory/InventoryModule.cs216
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs129
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs285
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs197
10 files changed, 4426 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs
new file mode 100644
index 0000000..3614686
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -0,0 +1,338 @@
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
28/*
29using System;
30using System.Collections.Generic;
31using System.Threading;
32using libsecondlife;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Data.MySQLMapper;
37using OpenSim.Region.Environment.Interfaces;
38using OpenSim.Region.Environment.Scenes;
39using OpenSim.Data.Base;
40
41namespace OpenSim.Region.Environment.Modules
42{
43 public class AvatarFactoryModule : IAvatarFactory
44 {
45 private Scene m_scene = null;
46 private readonly Dictionary<LLUUID, AvatarAppearance> m_avatarsAppearance = new Dictionary<LLUUID, AvatarAppearance>();
47
48 private bool m_enablePersist = false;
49 private string m_connectionString;
50 private bool m_configured = false;
51 private BaseDatabaseConnector m_databaseMapper;
52 private AppearanceTableMapper m_appearanceMapper;
53
54 private Dictionary<LLUUID, EventWaitHandle> m_fetchesInProgress = new Dictionary<LLUUID, EventWaitHandle>();
55 private object m_syncLock = new object();
56
57 public bool TryGetAvatarAppearance(LLUUID avatarId, out AvatarAppearance appearance)
58 {
59
60 //should only let one thread at a time do this part
61 EventWaitHandle waitHandle = null;
62 bool fetchInProgress = false;
63 lock (m_syncLock)
64 {
65 appearance = CheckCache(avatarId);
66 if (appearance != null)
67 {
68 return true;
69 }
70
71 //not in cache so check to see if another thread is already fetching it
72 if (m_fetchesInProgress.TryGetValue(avatarId, out waitHandle))
73 {
74 fetchInProgress = true;
75 }
76 else
77 {
78 fetchInProgress = false;
79
80 //no thread already fetching this appearance, so add a wait handle to list
81 //for any following threads that want the same appearance
82 waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
83 m_fetchesInProgress.Add(avatarId, waitHandle);
84 }
85 }
86
87 if (fetchInProgress)
88 {
89 waitHandle.WaitOne();
90 appearance = CheckCache(avatarId);
91 if (appearance != null)
92 {
93 waitHandle = null;
94 return true;
95 }
96 else
97 {
98 waitHandle = null;
99 return false;
100 }
101 }
102 else
103 {
104 Thread.Sleep(5000);
105
106 //this is the first thread to request this appearance
107 //so let it check the db and if not found then create a default appearance
108 //and add that to the cache
109 appearance = CheckDatabase(avatarId);
110 if (appearance != null)
111 {
112 //appearance has now been added to cache so lets pulse any waiting threads
113 lock (m_syncLock)
114 {
115 m_fetchesInProgress.Remove(avatarId);
116 waitHandle.Set();
117 }
118 // waitHandle.Close();
119 waitHandle = null;
120 return true;
121 }
122
123 //not found a appearance for the user, so create a new default one
124 appearance = CreateDefault(avatarId);
125 if (appearance != null)
126 {
127 //update database
128 if (m_enablePersist)
129 {
130 m_appearanceMapper.Add(avatarId.UUID, appearance);
131 }
132
133 //add appearance to dictionary cache
134 lock (m_avatarsAppearance)
135 {
136 m_avatarsAppearance[avatarId] = appearance;
137 }
138
139 //appearance has now been added to cache so lets pulse any waiting threads
140 lock (m_syncLock)
141 {
142 m_fetchesInProgress.Remove(avatarId);
143 waitHandle.Set();
144 }
145 // waitHandle.Close();
146 waitHandle = null;
147 return true;
148 }
149 else
150 {
151 //something went wrong, so release the wait handle and remove it
152 //all waiting threads will fail to find cached appearance
153 //but its better for them to fail than wait for ever
154 lock (m_syncLock)
155 {
156 m_fetchesInProgress.Remove(avatarId);
157 waitHandle.Set();
158 }
159 //waitHandle.Close();
160 waitHandle = null;
161 return false;
162 }
163 }
164 }
165
166 private AvatarAppearance CreateDefault(LLUUID avatarId)
167 {
168 AvatarAppearance appearance = null;
169 AvatarWearable[] wearables;
170 byte[] visualParams;
171 GetDefaultAvatarAppearance(out wearables, out visualParams);
172 appearance = new AvatarAppearance(avatarId, wearables, visualParams);
173
174 return appearance;
175 }
176
177 private AvatarAppearance CheckDatabase(LLUUID avatarId)
178 {
179 AvatarAppearance appearance = null;
180 if (m_enablePersist)
181 {
182 if (m_appearanceMapper.TryGetValue(avatarId.UUID, out appearance))
183 {
184 appearance.VisualParams = GetDefaultVisualParams();
185 appearance.TextureEntry = AvatarAppearance.GetDefaultTextureEntry();
186 lock (m_avatarsAppearance)
187 {
188 m_avatarsAppearance[avatarId] = appearance;
189 }
190 }
191 }
192 return appearance;
193 }
194
195 private AvatarAppearance CheckCache(LLUUID avatarId)
196 {
197 AvatarAppearance appearance = null;
198 lock (m_avatarsAppearance)
199 {
200 if (m_avatarsAppearance.ContainsKey(avatarId))
201 {
202 appearance = m_avatarsAppearance[avatarId];
203 }
204 }
205 return appearance;
206 }
207
208 public void Initialise(Scene scene, IConfigSource source)
209 {
210 scene.RegisterModuleInterface<IAvatarFactory>(this);
211 scene.EventManager.OnNewClient += NewClient;
212
213 if (m_scene == null)
214 {
215 m_scene = scene;
216 }
217
218 if (!m_configured)
219 {
220 m_configured = true;
221 try
222 {
223 m_enablePersist = source.Configs["Startup"].GetBoolean("appearance_persist", false);
224 m_connectionString = source.Configs["Startup"].GetString("appearance_connection_string", "");
225 }
226 catch (Exception)
227 {
228 }
229 if (m_enablePersist)
230 {
231 m_databaseMapper = new MySQLDatabaseMapper(m_connectionString);
232 m_appearanceMapper = new AppearanceTableMapper(m_databaseMapper, "AvatarAppearance");
233 }
234 }
235 }
236
237 public void PostInitialise()
238 {
239 }
240
241 public void Close()
242 {
243 }
244
245 public string Name
246 {
247 get { return "Default Avatar Factory"; }
248 }
249
250 public bool IsSharedModule
251 {
252 get { return true; }
253 }
254
255 public void NewClient(IClientAPI client)
256 {
257 client.OnAvatarNowWearing += AvatarIsWearing;
258 }
259
260 public void RemoveClient(IClientAPI client)
261 {
262 // client.OnAvatarNowWearing -= AvatarIsWearing;
263 }
264
265 public void AvatarIsWearing(Object sender, AvatarWearingArgs e)
266 {
267 IClientAPI clientView = (IClientAPI)sender;
268 CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(clientView.AgentId);
269 if (profile != null)
270 {
271 if (profile.RootFolder != null)
272 {
273 if (m_avatarsAppearance.ContainsKey(clientView.AgentId))
274 {
275 AvatarAppearance avatAppearance = null;
276 lock (m_avatarsAppearance)
277 {
278 avatAppearance = m_avatarsAppearance[clientView.AgentId];
279 }
280
281 foreach (AvatarWearingArgs.Wearable wear in e.NowWearing)
282 {
283 if (wear.Type < 13)
284 {
285 if (wear.ItemID == LLUUID.Zero)
286 {
287 avatAppearance.Wearables[wear.Type].ItemID = LLUUID.Zero;
288 avatAppearance.Wearables[wear.Type].AssetID = LLUUID.Zero;
289
290 UpdateDatabase(clientView.AgentId, avatAppearance);
291 }
292 else
293 {
294 LLUUID assetId;
295
296 InventoryItemBase baseItem = profile.RootFolder.HasItem(wear.ItemID);
297 if (baseItem != null)
298 {
299 assetId = baseItem.assetID;
300 avatAppearance.Wearables[wear.Type].AssetID = assetId;
301 avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID;
302
303 UpdateDatabase(clientView.AgentId, avatAppearance);
304 }
305 }
306 }
307 }
308 }
309 }
310 }
311 }
312
313 public void UpdateDatabase(LLUUID userID, AvatarAppearance avatAppearance)
314 {
315 if (m_enablePersist)
316 {
317 m_appearanceMapper.Update(userID.UUID, avatAppearance);
318 }
319 }
320
321 public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams)
322 {
323 visualParams = GetDefaultVisualParams();
324 wearables = AvatarWearable.DefaultWearables;
325 }
326
327 private static byte[] GetDefaultVisualParams()
328 {
329 byte[] visualParams;
330 visualParams = new byte[218];
331 for (int i = 0; i < 218; i++)
332 {
333 visualParams[i] = 100;
334 }
335 return visualParams;
336 }
337 }
338}*/
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
new file mode 100644
index 0000000..1281873
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
@@ -0,0 +1,831 @@
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.Generic;
30using System.IO;
31using System.Net.Sockets;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using System.Threading;
35using libsecondlife;
36using log4net;
37using Nini.Config;
38using OpenSim.Framework;
39using OpenSim.Region.Environment.Interfaces;
40using OpenSim.Region.Environment.Scenes;
41
42namespace OpenSim.Region.Environment.Modules.Avatar.Chat
43{
44 public class ChatModule : IRegionModule, ISimChat
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private List<Scene> m_scenes = new List<Scene>();
49
50 private int m_whisperdistance = 10;
51 private int m_saydistance = 30;
52 private int m_shoutdistance = 100;
53
54 private IRCChatModule m_irc = null;
55
56 private string m_last_new_user = null;
57 private string m_last_leaving_user = null;
58 private string m_defaultzone = null;
59 internal object m_syncInit = new object();
60 internal object m_syncLogout = new object();
61 private Thread m_irc_connector=null;
62
63 public void Initialise(Scene scene, IConfigSource config)
64 {
65 lock (m_syncInit)
66 {
67 if (!m_scenes.Contains(scene))
68 {
69 m_scenes.Add(scene);
70 scene.EventManager.OnNewClient += NewClient;
71 scene.RegisterModuleInterface<ISimChat>(this);
72 }
73
74 // wrap this in a try block so that defaults will work if
75 // the config file doesn't specify otherwise.
76 try
77 {
78 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
79 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance);
80 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance);
81 }
82 catch (Exception)
83 {
84 }
85
86 try
87 {
88 m_defaultzone = config.Configs["IRC"].GetString("nick","Sim");
89 }
90 catch (Exception)
91 {
92 }
93
94 // setup IRC Relay
95 if (m_irc == null) { m_irc = new IRCChatModule(config); }
96 if (m_irc_connector == null)
97 {
98 m_irc_connector = new Thread(IRCConnectRun);
99 m_irc_connector.Name = "IRCConnectorThread";
100 m_irc_connector.IsBackground = true;
101 }
102 }
103 }
104
105 public void PostInitialise()
106 {
107 if (m_irc.Enabled)
108 {
109 try
110 {
111 //m_irc.Connect(m_scenes);
112 if (m_irc_connector == null)
113 {
114 m_irc_connector = new Thread(IRCConnectRun);
115 m_irc_connector.Name = "IRCConnectorThread";
116 m_irc_connector.IsBackground = true;
117 }
118 if (!m_irc_connector.IsAlive)
119 {
120 m_irc_connector.Start();
121 ThreadTracker.Add(m_irc_connector);
122 }
123 }
124 catch (Exception)
125 {
126 }
127 }
128 }
129
130 public void Close()
131 {
132 m_irc.Close();
133 }
134
135 public string Name
136 {
137 get { return "ChatModule"; }
138 }
139
140 public bool IsSharedModule
141 {
142 get { return true; }
143 }
144
145 public void NewClient(IClientAPI client)
146 {
147 try
148 {
149 client.OnChatFromViewer += SimChat;
150
151 if ((m_irc.Enabled) && (m_irc.Connected))
152 {
153 string clientName = client.FirstName + " " + client.LastName;
154 // handles simple case. May not work for hundred connecting in per second.
155 // and the NewClients calles getting interleved
156 // but filters out multiple reports
157 if (clientName != m_last_new_user)
158 {
159 m_last_new_user = clientName;
160 string clientRegion = FindClientRegion(client.FirstName, client.LastName);
161 m_irc.PrivMsg(m_irc.Nick, "Sim", "notices " + clientName + " in "+clientRegion);
162 }
163 }
164 client.OnLogout += ClientLoggedOut;
165 client.OnConnectionClosed += ClientLoggedOut;
166 client.OnLogout += ClientLoggedOut;
167 }
168 catch (Exception ex)
169 {
170 m_log.Error("[IRC]: NewClient exception trap:" + ex.ToString());
171 }
172 }
173
174 public void ClientLoggedOut(IClientAPI client)
175 {
176 lock (m_syncLogout)
177 {
178 try
179 {
180 if ((m_irc.Enabled) && (m_irc.Connected))
181 {
182 string clientName = client.FirstName + " " + client.LastName;
183 string clientRegion = FindClientRegion(client.FirstName, client.LastName);
184 // handles simple case. May not work for hundred connecting in per second.
185 // and the NewClients calles getting interleved
186 // but filters out multiple reports
187 if (clientName != m_last_leaving_user)
188 {
189 m_last_leaving_user = clientName;
190 m_irc.PrivMsg(m_irc.Nick, "Sim", "notices " + clientName + " left " + clientRegion);
191 m_log.Info("[IRC]: IRC watcher notices " + clientName + " left " + clientRegion);
192 }
193 }
194 }
195 catch (Exception ex)
196 {
197 m_log.Error("[IRC]: ClientLoggedOut exception trap:" + ex.ToString());
198 }
199 }
200 }
201
202 private void TrySendChatMessage(ScenePresence presence, LLVector3 fromPos, LLVector3 regionPos,
203 LLUUID fromAgentID, string fromName, ChatTypeEnum type, string message)
204 {
205 if (!presence.IsChildAgent)
206 {
207 LLVector3 fromRegionPos = fromPos + regionPos;
208 LLVector3 toRegionPos = presence.AbsolutePosition + regionPos;
209 int dis = Math.Abs((int) Util.GetDistanceTo(toRegionPos, fromRegionPos));
210
211 if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance ||
212 type == ChatTypeEnum.Say && dis > m_saydistance ||
213 type == ChatTypeEnum.Shout && dis > m_shoutdistance)
214 {
215 return;
216 }
217
218 // TODO: should change so the message is sent through the avatar rather than direct to the ClientView
219 presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName, fromAgentID);
220 }
221 }
222
223 public void SimChat(Object sender, ChatFromViewerArgs e)
224 {
225 // FROM: Sim TO: IRC
226
227 ScenePresence avatar = null;
228
229 //TODO: Move ForEachScenePresence and others into IScene.
230 Scene scene = (Scene) e.Scene;
231
232 //TODO: Remove the need for this check
233 if (scene == null)
234 scene = m_scenes[0];
235
236 // Filled in since it's easier than rewriting right now.
237 LLVector3 fromPos = e.Position;
238 LLVector3 regionPos = new LLVector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
239
240 string fromName = e.From;
241 string message = e.Message;
242 LLUUID fromAgentID = LLUUID.Zero;
243
244 if (e.Sender != null)
245 {
246 avatar = scene.GetScenePresence(e.Sender.AgentId);
247 }
248
249 if (avatar != null)
250 {
251 fromPos = avatar.AbsolutePosition;
252 regionPos = new LLVector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
253 fromName = avatar.Firstname + " " + avatar.Lastname;
254 fromAgentID = e.Sender.AgentId;
255 }
256
257 // Try to reconnect to server if not connected
258 if (m_irc.Enabled && !m_irc.Connected)
259 {
260 // In a non-blocking way. Eventually the connector will get it started
261 try
262 {
263 if (m_irc_connector == null)
264 {
265 m_irc_connector = new Thread(IRCConnectRun);
266 m_irc_connector.Name = "IRCConnectorThread";
267 m_irc_connector.IsBackground = true;
268 }
269 if (!m_irc_connector.IsAlive)
270 {
271 m_irc_connector.Start();
272 ThreadTracker.Add(m_irc_connector);
273 }
274 }
275 catch (Exception)
276 {
277 }
278 }
279
280
281 // We only want to relay stuff on channel 0
282 if (e.Channel == 0)
283 {
284 // IRC stuff
285 if (e.Message.Length > 0)
286 {
287 if (m_irc.Connected && (avatar != null)) // this is to keep objects from talking to IRC
288 {
289 m_irc.PrivMsg(fromName, scene.RegionInfo.RegionName, e.Message);
290 }
291 }
292
293 foreach (Scene s in m_scenes)
294 {
295 s.ForEachScenePresence(delegate(ScenePresence presence)
296 {
297 TrySendChatMessage(presence, fromPos, regionPos,
298 fromAgentID, fromName, e.Type, message);
299 });
300 }
301 }
302 }
303
304 // if IRC is enabled then just keep trying using a monitor thread
305 public void IRCConnectRun()
306 {
307 while(true)
308 {
309 if ((m_irc.Enabled)&&(!m_irc.Connected))
310 {
311 m_irc.Connect(m_scenes);
312 }
313 Thread.Sleep(15000);
314 }
315 }
316
317 public string FindClientRegion(string client_FirstName,string client_LastName)
318 {
319 string sourceRegion = null;
320 foreach (Scene s in m_scenes)
321 {
322 s.ForEachScenePresence(delegate(ScenePresence presence)
323 {
324 if ((presence.IsChildAgent==false)
325 &&(presence.Firstname==client_FirstName)
326 &&(presence.Lastname==client_LastName))
327 {
328 sourceRegion = presence.Scene.RegionInfo.RegionName;
329 //sourceRegion= s.RegionInfo.RegionName;
330 }
331 });
332 if (sourceRegion != null) return sourceRegion;
333 }
334 if (m_defaultzone == null) { m_defaultzone = "Sim"; }
335 return m_defaultzone;
336 }
337 }
338
339 internal class IRCChatModule
340 {
341 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
342
343 private string m_server = null;
344 private uint m_port = 6668;
345 private string m_user = "USER OpenSimBot 8 * :I'm a OpenSim to irc bot";
346 private string m_nick = null;
347 private string m_basenick = null;
348 private string m_channel = null;
349 private string m_privmsgformat = "PRIVMSG {0} :<{1} in {2}>: {3}";
350
351 private NetworkStream m_stream;
352 private TcpClient m_tcp;
353 private StreamWriter m_writer;
354 private StreamReader m_reader;
355
356 private Thread pingSender;
357 private Thread listener;
358 internal object m_syncConnect = new object();
359
360 private bool m_enabled = false;
361 private bool m_connected = false;
362
363 private List<Scene> m_scenes = null;
364 private List<Scene> m_last_scenes = null;
365
366 public IRCChatModule(IConfigSource config)
367 {
368 m_nick = "OSimBot" + Util.RandomClass.Next(1, 99);
369 m_tcp = null;
370 m_writer = null;
371 m_reader = null;
372
373 // configuration in OpenSim.ini
374 // [IRC]
375 // server = chat.freenode.net
376 // nick = OSimBot_mysim
377 // ;username = USER OpenSimBot 8 * :I'm a OpenSim to irc bot
378 // ; username is the IRC command line sent
379 // ; USER <irc_user> <visible=8,invisible=0> * : <IRC_realname>
380 // channel = #opensim-regions
381 // port = 6667
382 // ;MSGformat fields : 0=botnick, 1=user, 2=region, 3=message
383 // ;for <bot>:<user in region> :<message>
384 // ;msgformat = "PRIVMSG {0} :<{1} in {2}>: {3}"
385 // ;for <bot>:<message> - <user of region> :
386 // ;msgformat = "PRIVMSG {0} : {3} - {1} of {2}"
387 // ;for <bot>:<message> - from <user> :
388 // ;msgformat = "PRIVMSG {0} : {3} - from {1}"
389 // Traps I/O disconnects so it does not crash the sim
390 // Trys to reconnect if disconnected and someone says something
391 // Tells IRC server "QUIT" when doing a close (just to be nice)
392 // Default port back to 6667
393
394 try
395 {
396 m_server = config.Configs["IRC"].GetString("server");
397 m_nick = config.Configs["IRC"].GetString("nick");
398 m_basenick = m_nick;
399 m_channel = config.Configs["IRC"].GetString("channel");
400 m_port = (uint) config.Configs["IRC"].GetInt("port", (int) m_port);
401 m_user = config.Configs["IRC"].GetString("username", m_user);
402 m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
403 if (m_server != null && m_nick != null && m_channel != null)
404 {
405 m_nick = m_nick + Util.RandomClass.Next(1, 99);
406 m_enabled = true;
407 }
408 }
409 catch (Exception)
410 {
411 m_log.Info("[CHAT]: No IRC config information, skipping IRC bridge configuration");
412 }
413 }
414
415 public bool Connect(List<Scene> scenes)
416 {
417 lock (m_syncConnect)
418 {
419 try
420 {
421 if (m_connected) return true;
422 m_scenes = scenes;
423 if (m_last_scenes == null) { m_last_scenes = scenes; }
424
425 m_tcp = new TcpClient(m_server, (int)m_port);
426 m_log.Info("[IRC]: Connecting...");
427 m_stream = m_tcp.GetStream();
428 m_log.Info("[IRC]: Connected to " + m_server);
429 m_reader = new StreamReader(m_stream);
430 m_writer = new StreamWriter(m_stream);
431
432 pingSender = new Thread(new ThreadStart(PingRun));
433 pingSender.Name = "PingSenderThread";
434 pingSender.IsBackground = true;
435 pingSender.Start();
436 ThreadTracker.Add(pingSender);
437
438 listener = new Thread(new ThreadStart(ListenerRun));
439 listener.Name = "IRCChatModuleListenerThread";
440 listener.IsBackground = true;
441 listener.Start();
442 ThreadTracker.Add(listener);
443
444 m_writer.WriteLine(m_user);
445 m_writer.Flush();
446 m_writer.WriteLine("NICK " + m_nick);
447 m_writer.Flush();
448 m_writer.WriteLine("JOIN " + m_channel);
449 m_writer.Flush();
450 m_log.Info("[IRC]: Connection fully established");
451 m_connected = true;
452 }
453 catch (Exception e)
454 {
455 Console.WriteLine(e.ToString());
456 }
457 return m_connected;
458 }
459 }
460
461 public bool Enabled
462 {
463 get { return m_enabled; }
464 }
465
466 public bool Connected
467 {
468 get { return m_connected; }
469 }
470
471 public string Nick
472 {
473 get { return m_nick; }
474 }
475
476 public void Reconnect()
477 {
478 m_connected = false;
479 listener.Abort();
480 pingSender.Abort();
481 m_writer.Close();
482 m_reader.Close();
483 m_tcp.Close();
484 if (m_enabled) { Connect(m_last_scenes); }
485 }
486
487 public void PrivMsg(string from, string region, string msg)
488 {
489 // One message to the IRC server
490
491 try
492 {
493 if (m_privmsgformat == null)
494 {
495 m_writer.WriteLine("PRIVMSG {0} :<{1} in {2}>: {3}", m_channel, from, region, msg);
496 }
497 else
498 {
499 m_writer.WriteLine(m_privmsgformat, m_channel, from, region, msg);
500 }
501 m_writer.Flush();
502 m_log.Info("[IRC]: PrivMsg " + from + " in " + region + " :" + msg);
503 }
504 catch (IOException)
505 {
506 m_log.Error("[IRC]: Disconnected from IRC server.(PrivMsg)");
507 Reconnect();
508 }
509 catch (Exception ex)
510 {
511 m_log.Error("[IRC]: PrivMsg exception trap:" + ex.ToString());
512 }
513 }
514
515 private Dictionary<string, string> ExtractMsg(string input)
516 {
517 //examines IRC commands and extracts any private messages
518 // which will then be reboadcast in the Sim
519
520 m_log.Info("[IRC]: ExtractMsg: " + input);
521 Dictionary<string, string> result = null;
522 //string regex = @":(?<nick>\w*)!~(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
523 string regex = @":(?<nick>\w*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
524 Regex RE = new Regex(regex, RegexOptions.Multiline);
525 MatchCollection matches = RE.Matches(input);
526 // Get some direct matches $1 $4 is a
527 if ((matches.Count == 1) && (matches[0].Groups.Count == 5))
528 {
529 result = new Dictionary<string, string>();
530 result.Add("nick", matches[0].Groups[1].Value);
531 result.Add("user", matches[0].Groups[2].Value);
532 result.Add("channel", matches[0].Groups[3].Value);
533 result.Add("msg", matches[0].Groups[4].Value);
534 }
535 else
536 {
537 m_log.Info("[IRC]: Number of matches: " + matches.Count);
538 if (matches.Count > 0)
539 {
540 m_log.Info("[IRC]: Number of groups: " + matches[0].Groups.Count);
541 }
542 }
543 return result;
544 }
545
546 public void PingRun()
547 {
548 // IRC keep alive thread
549 // send PING ever 15 seconds
550 while (true)
551 {
552 try
553 {
554 if (m_connected == true)
555 {
556 m_writer.WriteLine("PING :" + m_server);
557 m_writer.Flush();
558 Thread.Sleep(15000);
559 }
560 }
561 catch (IOException)
562 {
563 m_log.Error("[IRC]: Disconnected from IRC server.(PingRun)");
564 Reconnect();
565 }
566 catch (Exception ex)
567 {
568 m_log.Error("[IRC]: PingRun exception trap:" + ex.ToString() + "\n" + ex.StackTrace);
569 }
570 }
571 }
572
573 public void ListenerRun()
574 {
575 string inputLine;
576 LLVector3 pos = new LLVector3(128, 128, 20);
577 while (true)
578 {
579 try
580 {
581 while ((m_connected == true) && ((inputLine = m_reader.ReadLine()) != null))
582 {
583 // Console.WriteLine(inputLine);
584 if (inputLine.Contains(m_channel))
585 {
586 Dictionary<string, string> data = ExtractMsg(inputLine);
587 // Any chat ???
588 if (data != null)
589 {
590 foreach (Scene m_scene in m_scenes)
591 {
592 m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
593 {
594 if (!avatar.IsChildAgent)
595 {
596 avatar.ControllingClient.SendChatMessage(
597 Helpers.StringToField(data["msg"]), 255,
598 pos, data["nick"],
599 LLUUID.Zero);
600 }
601 });
602 }
603 }
604 else
605 {
606 // Was an command from the IRC server
607 ProcessIRCCommand(inputLine);
608 }
609 }
610 else
611 {
612 // Was an command from the IRC server
613 ProcessIRCCommand(inputLine);
614 }
615 Thread.Sleep(150);
616 }
617 }
618 catch (IOException)
619 {
620 m_log.Error("[IRC]: ListenerRun IOException. Disconnected from IRC server ??? (ListenerRun)");
621 Reconnect();
622 }
623 catch (Exception ex)
624 {
625 m_log.Error("[IRC]: ListenerRun exception trap:" + ex.ToString() + "\n" + ex.StackTrace);
626 }
627 }
628 }
629
630 public void BroadcastSim(string message,string sender)
631 {
632 LLVector3 pos = new LLVector3(128, 128, 20);
633 try
634 {
635 foreach (Scene m_scene in m_scenes)
636 {
637 m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
638 {
639 if (!avatar.IsChildAgent)
640 {
641 avatar.ControllingClient.SendChatMessage(
642 Helpers.StringToField(message), 255,
643 pos, sender,
644 LLUUID.Zero);
645 }
646 });
647 }
648 }
649 catch (Exception ex) // IRC gate should not crash Sim
650 {
651 m_log.Error("[IRC]: BroadcastSim Exception Trap:" + ex.ToString() + "\n" + ex.StackTrace);
652 }
653 }
654
655 public enum ErrorReplies
656 {
657 NotRegistered = 451, // ":You have not registered"
658 NicknameInUse = 433 // "<nick> :Nickname is already in use"
659 }
660
661 public enum Replies
662 {
663 MotdStart = 375, // ":- <server> Message of the day - "
664 Motd = 372, // ":- <text>"
665 EndOfMotd = 376 // ":End of /MOTD command"
666 }
667
668 public void ProcessIRCCommand(string command)
669 {
670 //m_log.Info("[IRC]: ProcessIRCCommand:" + command);
671
672 string[] commArgs = new string[command.Split(' ').Length];
673 string c_server = m_server;
674
675 commArgs = command.Split(' ');
676 if (commArgs[0].Substring(0, 1) == ":")
677 {
678 commArgs[0] = commArgs[0].Remove(0, 1);
679 }
680
681 if (commArgs[1] == "002")
682 {
683 // fetch the correct servername
684 // ex: irc.freenode.net -> brown.freenode.net/kornbluth.freenode.net/...
685 // irc.bluewin.ch -> irc1.bluewin.ch/irc2.bluewin.ch
686
687 c_server = (commArgs[6].Split('['))[0];
688 m_server = c_server;
689 }
690
691 if (commArgs[0] == "ERROR")
692 {
693 m_log.Error("[IRC]: IRC SERVER ERROR:" + command);
694 }
695
696 if (commArgs[0] == "PING")
697 {
698 string p_reply = "";
699
700 for (int i = 1; i < commArgs.Length; i++)
701 {
702 p_reply += commArgs[i] + " ";
703 }
704
705 m_writer.WriteLine("PONG " + p_reply);
706 m_writer.Flush();
707 }
708 else if (commArgs[0] == c_server)
709 {
710 // server message
711 try
712 {
713 Int32 commandCode = Int32.Parse(commArgs[1]);
714 switch (commandCode)
715 {
716 case (int)ErrorReplies.NicknameInUse:
717 // Gen a new name
718 m_nick = m_basenick + Util.RandomClass.Next(1, 99);
719 m_log.Error("[IRC]: IRC SERVER reports NicknameInUse, trying " + m_nick);
720 // Retry
721 m_writer.WriteLine("NICK " + m_nick);
722 m_writer.Flush();
723 m_writer.WriteLine("JOIN " + m_channel);
724 m_writer.Flush();
725 break;
726 case (int)ErrorReplies.NotRegistered:
727 break;
728 case (int)Replies.EndOfMotd:
729 break;
730 }
731 }
732 catch (Exception)
733 {
734 }
735 }
736 else
737 {
738 // Normal message
739 string commAct = commArgs[1];
740 switch (commAct)
741 {
742 case "JOIN": eventIrcJoin(commArgs); break;
743 case "PART": eventIrcPart(commArgs); break;
744 case "MODE": eventIrcMode(commArgs); break;
745 case "NICK": eventIrcNickChange(commArgs); break;
746 case "KICK": eventIrcKick(commArgs); break;
747 case "QUIT": eventIrcQuit(commArgs); break;
748 case "PONG": break; // that's nice
749 }
750 }
751 }
752
753 public void eventIrcJoin(string[] commArgs)
754 {
755 string IrcChannel = commArgs[2];
756 string IrcUser = commArgs[0].Split('!')[0];
757 BroadcastSim(IrcUser + " is joining " + IrcChannel, m_nick);
758 }
759
760 public void eventIrcPart(string[] commArgs)
761 {
762 string IrcChannel = commArgs[2];
763 string IrcUser = commArgs[0].Split('!')[0];
764 BroadcastSim(IrcUser + " is parting " + IrcChannel, m_nick);
765 }
766
767 public void eventIrcMode(string[] commArgs)
768 {
769 string IrcChannel = commArgs[2];
770 string IrcUser = commArgs[0].Split('!')[0];
771 string UserMode = "";
772 for (int i = 3; i < commArgs.Length; i++)
773 {
774 UserMode += commArgs[i] + " ";
775 }
776
777 if (UserMode.Substring(0, 1) == ":")
778 {
779 UserMode = UserMode.Remove(0, 1);
780 }
781 }
782
783 public void eventIrcNickChange(string[] commArgs)
784 {
785 string UserOldNick = commArgs[0].Split('!')[0];
786 string UserNewNick = commArgs[2].Remove(0, 1);
787 BroadcastSim(UserOldNick + " changed their nick to " + UserNewNick, m_nick);
788 }
789
790 public void eventIrcKick(string[] commArgs)
791 {
792 string UserKicker = commArgs[0].Split('!')[0];
793 string UserKicked = commArgs[3];
794 string IrcChannel = commArgs[2];
795 string KickMessage = "";
796 for (int i = 4; i < commArgs.Length; i++)
797 {
798 KickMessage += commArgs[i] + " ";
799 }
800 BroadcastSim(UserKicker + " kicked " + UserKicked +" on "+IrcChannel+" saying "+KickMessage, m_nick);
801 if (UserKicked == m_nick)
802 {
803 BroadcastSim("Hey, that was me!!!", m_nick);
804 }
805 }
806
807 public void eventIrcQuit(string[] commArgs)
808 {
809 string IrcUser = commArgs[0].Split('!')[0];
810 string QuitMessage = "";
811
812 for (int i = 2; i < commArgs.Length; i++)
813 {
814 QuitMessage += commArgs[i] + " ";
815 }
816 BroadcastSim(IrcUser + " quits saying " + QuitMessage, m_nick);
817 }
818
819 public void Close()
820 {
821 m_connected = false;
822 m_writer.WriteLine("QUIT :" + m_nick + " to " + m_channel + " wormhole with " + m_server + " closing");
823 m_writer.Flush();
824 listener.Abort();
825 pingSender.Abort();
826 m_writer.Close();
827 m_reader.Close();
828 m_tcp.Close();
829 }
830 }
831} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs
new file mode 100644
index 0000000..0e058ec
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs
@@ -0,0 +1,1491 @@
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 libsecondlife;
36using log4net;
37using Nini.Config;
38using Nwc.XmlRpc;
39using OpenSim.Framework;
40using OpenSim.Region.Environment.Interfaces;
41using OpenSim.Region.Environment.Scenes;
42
43namespace 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
57 public delegate void ObjectPaid(LLUUID objectID, LLUUID agentID, int amount);
58
59 public interface IMoneyModule : IRegionModule
60 {
61 bool ObjectGiveMoney(LLUUID objectID, LLUUID fromID, LLUUID toID, int amount);
62
63 event ObjectPaid OnObjectPaid;
64 }
65
66 public class SampleMoneyModule : IMoneyModule
67 {
68 public event ObjectPaid OnObjectPaid;
69
70 private ObjectPaid handerOnObjectPaid;
71
72 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
73
74 /// <summary>
75 /// Region UUIDS indexed by AgentID
76 /// </summary>
77 Dictionary<LLUUID, LLUUID> m_rootAgents = new Dictionary<LLUUID, LLUUID>();
78
79 /// <summary>
80 /// Scenes by Region Handle
81 /// </summary>
82 private Dictionary<ulong,Scene> m_scenel = new Dictionary<ulong,Scene>();
83
84 private IConfigSource m_gConfig;
85
86 private bool m_keepMoneyAcrossLogins = true;
87
88 private int m_minFundsBeforeRefresh = 100;
89
90 private int m_stipend = 1000;
91
92 private bool m_enabled = true;
93
94 private Dictionary<LLUUID, int> m_KnownClientFunds = new Dictionary<LLUUID, int>();
95
96 private bool gridmode = false;
97 private Scene XMLRPCHandler;
98 private float EnergyEfficiency = 0f;
99 private int ObjectCapacity = 45000;
100 private int ObjectCount = 0;
101 private int PriceEnergyUnit = 0;
102 private int PriceGroupCreate = 0;
103 private int PriceObjectClaim = 0;
104 private float PriceObjectRent = 0f;
105 private float PriceObjectScaleFactor = 0f;
106 private int PriceParcelClaim = 0;
107 private float PriceParcelClaimFactor = 0f;
108 private int PriceParcelRent = 0;
109 private int PricePublicObjectDecay = 0;
110 private int PricePublicObjectDelete = 0;
111 private int PriceRentLight = 0;
112 private int PriceUpload = 0;
113 private int TeleportMinPrice = 0;
114 private int UserLevelPaysFees = 2;
115 private string m_MoneyAddress = String.Empty;
116 private string m_LandAddress = String.Empty;
117
118 float TeleportPriceExponent = 0f;
119
120 /// <summary>
121 /// Where Stipends come from and Fees go to.
122 /// </summary>
123 LLUUID EconomyBaseAccount = LLUUID.Zero;
124
125 /// <summary>
126 /// Startup
127 /// </summary>
128 /// <param name="scene"></param>
129 /// <param name="config"></param>
130 public void Initialise(Scene scene, IConfigSource config)
131 {
132 m_gConfig = config;
133
134 IConfig startupConfig = m_gConfig.Configs["Startup"];
135 IConfig economyConfig = m_gConfig.Configs["Economy"];
136
137 scene.RegisterModuleInterface<IMoneyModule>(this);
138
139 ReadConfigAndPopulate(scene, startupConfig, "Startup");
140 ReadConfigAndPopulate(scene, economyConfig, "Economy");
141
142 if (m_enabled)
143 {
144 lock (m_scenel)
145 {
146 if (m_scenel.Count == 0)
147 {
148 XMLRPCHandler = scene;
149
150 // To use the following you need to add:
151 // -helperuri <ADDRESS TO HERE OR grid MONEY SERVER>
152 // to the command line parameters you use to start up your client
153 // This commonly looks like -helperuri http://127.0.0.1:9000/
154
155 if (m_MoneyAddress.Length > 0)
156 {
157 // Centralized grid structure using OpenSimWi Redux revision 9+
158 // https://opensimwiredux.svn.sourceforge.net/svnroot/opensimwiredux
159 scene.AddXmlRPCHandler("balanceUpdateRequest", GridMoneyUpdate);
160 scene.AddXmlRPCHandler("userAlert", UserAlert);
161 }
162 else
163 {
164 // Local Server.. enables functionality only.
165 scene.AddXmlRPCHandler("getCurrencyQuote", quote_func);
166 scene.AddXmlRPCHandler("buyCurrency", buy_func);
167 scene.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func);
168 scene.AddXmlRPCHandler("buyLandPrep", landBuy_func);
169 }
170
171
172 }
173
174 if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle))
175 {
176 m_scenel[scene.RegionInfo.RegionHandle] = scene;
177 }
178 else
179 {
180 m_scenel.Add(scene.RegionInfo.RegionHandle, scene);
181 }
182 }
183
184 scene.EventManager.OnNewClient += OnNewClient;
185 scene.EventManager.OnMoneyTransfer += MoneyTransferAction;
186 scene.EventManager.OnClientClosed += ClientClosed;
187 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
188 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
189 scene.EventManager.OnClientClosed += ClientLoggedOut;
190 scene.EventManager.OnValidateLandBuy += ValidateLandBuy;
191 scene.EventManager.OnLandBuy += processLandBuy;
192
193 }
194 }
195 /// <summary>
196 /// Parse Configuration
197 /// </summary>
198 /// <param name="scene"></param>
199 /// <param name="startupConfig"></param>
200 /// <param name="config"></param>
201 private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string config)
202 {
203 if (config == "Startup" && startupConfig != null)
204 {
205 gridmode = startupConfig.GetBoolean("gridmode", false);
206 m_enabled = (startupConfig.GetString("economymodule", "BetaGridLikeMoneyModule") == "BetaGridLikeMoneyModule");
207 }
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", LLUUID.Zero.ToString());
228 Helpers.TryParse(EBA,out EconomyBaseAccount);
229
230 UserLevelPaysFees = startupConfig.GetInt("UserLevelPaysFees", -1);
231 m_stipend = startupConfig.GetInt("UserStipend", 500);
232 m_minFundsBeforeRefresh = startupConfig.GetInt("IssueStipendWhenClientIsBelowAmount", 10);
233 m_keepMoneyAcrossLogins = startupConfig.GetBoolean("KeepMoneyAcrossLogins", true);
234 m_MoneyAddress = startupConfig.GetString("CurrencyServer", String.Empty);
235 m_LandAddress = startupConfig.GetString("LandServer", String.Empty);
236 }
237
238 // Send ObjectCapacity to Scene.. Which sends it to the SimStatsReporter.
239 scene.SetObjectCapacity(ObjectCapacity);
240 }
241
242 /// <summary>
243 /// New Client Event Handler
244 /// </summary>
245 /// <param name="client"></param>
246 private void OnNewClient(IClientAPI client)
247 {
248 // Here we check if we're in grid mode
249 // I imagine that the 'check balance'
250 // function for the client should be here or shortly after
251
252 if (gridmode)
253 {
254 if (m_MoneyAddress.Length == 0)
255 {
256
257 CheckExistAndRefreshFunds(client.AgentId);
258 }
259 else
260 {
261 bool childYN = true;
262 ScenePresence agent = null;
263 //client.SecureSessionId;
264 Scene s = LocateSceneClientIn(client.AgentId);
265 if (s != null)
266 {
267 agent = s.GetScenePresence(client.AgentId);
268 if (agent != null)
269 childYN = agent.IsChildAgent;
270 }
271 if (s != null && agent != null && childYN == false)
272 {
273 //s.RegionInfo.RegionHandle;
274 LLUUID agentID = LLUUID.Zero;
275 int funds = 0;
276
277 Hashtable hbinfo = GetBalanceForUserFromMoneyServer(client.AgentId, client.SecureSessionId, s.RegionInfo.originRegionID.ToString(), s.RegionInfo.regionSecret);
278 if ((bool)hbinfo["success"] == true)
279 {
280
281 Helpers.TryParse((string)hbinfo["agentId"], out agentID);
282 try
283 {
284 funds = (Int32)hbinfo["funds"];
285 }
286 catch (ArgumentException)
287 {
288 }
289 catch (FormatException)
290 {
291 }
292 catch (OverflowException)
293 {
294 m_log.ErrorFormat("[MONEY]: While getting the Currency for user {0}, the return funds overflowed.", agentID);
295 client.SendAlertMessage("Unable to get your money balance, money operations will be unavailable");
296 }
297 catch (InvalidCastException)
298 {
299 funds = 0;
300 }
301
302 m_KnownClientFunds[agentID] = funds;
303 }
304 else
305 {
306 m_log.WarnFormat("[MONEY]: Getting Money for user {0} failed with the following message:{1}", agentID, (string)hbinfo["errorMessage"]);
307 client.SendAlertMessage((string)hbinfo["errorMessage"]);
308 }
309 SendMoneyBalance(client, agentID, client.SessionId, LLUUID.Zero);
310
311 }
312 }
313
314 }
315 else
316 {
317 CheckExistAndRefreshFunds(client.AgentId);
318 }
319
320 // Subscribe to Money messages
321 client.OnEconomyDataRequest += EconomyDataRequestHandler;
322 client.OnMoneyBalanceRequest += SendMoneyBalance;
323 client.OnRequestPayPrice += requestPayPrice;
324 client.OnLogout += ClientClosed;
325
326
327 }
328
329 #region event Handlers
330
331 public void requestPayPrice(IClientAPI client, LLUUID objectID)
332 {
333 Scene scene=LocateSceneClientIn(client.AgentId);
334 if(scene == null)
335 return;
336
337 SceneObjectPart task=scene.GetSceneObjectPart(objectID);
338 if(task == null)
339 return;
340 SceneObjectGroup group=task.ParentGroup;
341 SceneObjectPart root=group.RootPart;
342
343 client.SendPayPrice(objectID, root.PayPrice);
344 }
345
346 /// <summary>
347 /// When the client closes the connection we remove their accounting info from memory to free up resources.
348 /// </summary>
349 /// <param name="AgentID"></param>
350 public void ClientClosed(LLUUID AgentID)
351 {
352 lock (m_KnownClientFunds)
353 {
354 if (m_keepMoneyAcrossLogins && m_MoneyAddress.Length == 0)
355 {
356 }
357 else
358 {
359 m_KnownClientFunds.Remove(AgentID);
360 }
361 }
362 }
363
364 /// <summary>
365 /// Event called Economy Data Request handler.
366 /// </summary>
367 /// <param name="agentId"></param>
368 public void EconomyDataRequestHandler(LLUUID agentId)
369 {
370 IClientAPI user = LocateClientObject(agentId);
371
372 if (user != null)
373 {
374 user.SendEconomyData(EnergyEfficiency, ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
375 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
376 PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
377 TeleportMinPrice, TeleportPriceExponent);
378 }
379 }
380
381 private void ValidateLandBuy (Object osender, EventManager.LandBuyArgs e)
382 {
383 if (m_MoneyAddress.Length == 0)
384 {
385 lock (m_KnownClientFunds)
386 {
387 if (m_KnownClientFunds.ContainsKey(e.agentId))
388 {
389 // Does the sender have enough funds to give?
390 if (m_KnownClientFunds[e.agentId] >= e.parcelPrice)
391 {
392 lock(e)
393 {
394 e.economyValidated=true;
395 }
396 }
397 }
398 }
399 }
400 else
401 {
402 if(GetRemoteBalance(e.agentId) >= e.parcelPrice)
403 {
404 lock(e)
405 {
406 e.economyValidated=true;
407 }
408 }
409 }
410 }
411
412 private void processLandBuy(Object osender, EventManager.LandBuyArgs e)
413 {
414 lock(e)
415 {
416 if(e.economyValidated == true && e.transactionID == 0)
417 {
418 e.transactionID=Util.UnixTimeSinceEpoch();
419
420 if(doMoneyTransfer(e.agentId, e.parcelOwnerID, e.parcelPrice, 0, "Land purchase"))
421 {
422 lock (e)
423 {
424 e.amountDebited = e.parcelPrice;
425 }
426 }
427 }
428 }
429 }
430
431 /// <summary>
432 /// THis method gets called when someone pays someone else as a gift.
433 /// </summary>
434 /// <param name="osender"></param>
435 /// <param name="e"></param>
436 private void MoneyTransferAction (Object osender, EventManager.MoneyTransferArgs e)
437 {
438 IClientAPI sender = null;
439 IClientAPI receiver = null;
440
441 if(m_MoneyAddress.Length > 0) // Handled on server
442 e.description=String.Empty;
443
444 if(e.transactiontype == 5008) // Object gets paid
445 {
446 sender = LocateClientObject(e.sender);
447 if (sender != null)
448 {
449 SceneObjectPart part=findPrim(e.receiver);
450 if(part == null)
451 return;
452
453 string name=resolveAgentName(part.OwnerID);
454 if(name == String.Empty)
455 name="(hippos)";
456
457 receiver = LocateClientObject(part.OwnerID);
458
459 string description=String.Format("Paid {0} via object {1}", name, e.description);
460 bool transactionresult = doMoneyTransfer(e.sender, part.OwnerID, e.amount, e.transactiontype, description);
461
462 if(transactionresult)
463 {
464 ObjectPaid handlerOnObjectPaid = OnObjectPaid;
465 if(handlerOnObjectPaid != null)
466 {
467 handlerOnObjectPaid(e.receiver, e.sender, e.amount);
468 }
469 }
470
471 if (e.sender != e.receiver)
472 {
473 sender.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(e.sender));
474 }
475 if(receiver != null)
476 {
477 receiver.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(part.OwnerID));
478 }
479 }
480 return;
481 }
482
483 sender = LocateClientObject(e.sender);
484 if (sender != null)
485 {
486 receiver = LocateClientObject(e.receiver);
487
488 bool transactionresult = doMoneyTransfer(e.sender, e.receiver, e.amount, e.transactiontype, e.description);
489
490 if (e.sender != e.receiver)
491 {
492 if (sender != null)
493 {
494 sender.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(e.sender));
495 }
496 }
497
498 if (receiver != null)
499 {
500 receiver.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(e.description), GetFundsForAgentID(e.receiver));
501 }
502 }
503 else
504 {
505 m_log.Warn("[MONEY]: Potential Fraud Warning, got money transfer request for avatar that isn't in this simulator - Details; Sender:" + e.sender.ToString() + " Receiver: " + e.receiver.ToString() + " Amount: " + e.amount.ToString());
506 }
507 }
508
509 /// <summary>
510 /// Event Handler for when a root agent becomes a child agent
511 /// </summary>
512 /// <param name="avatar"></param>
513 private void MakeChildAgent(ScenePresence avatar)
514 {
515 lock (m_rootAgents)
516 {
517 if (m_rootAgents.ContainsKey(avatar.UUID))
518 {
519 if (m_rootAgents[avatar.UUID] == avatar.Scene.RegionInfo.originRegionID)
520 {
521 m_rootAgents.Remove(avatar.UUID);
522 m_log.Info("[MONEY]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent");
523 }
524
525 }
526 }
527
528 }
529
530 /// <summary>
531 /// Event Handler for when the client logs out.
532 /// </summary>
533 /// <param name="AgentId"></param>
534 private void ClientLoggedOut(LLUUID AgentId)
535 {
536 lock (m_rootAgents)
537 {
538 if (m_rootAgents.ContainsKey(AgentId))
539 {
540 m_rootAgents.Remove(AgentId);
541 //m_log.Info("[MONEY]: Removing " + AgentId + ". Agent logged out.");
542 }
543 }
544 }
545
546 /// <summary>
547 /// Call this when the client disconnects.
548 /// </summary>
549 /// <param name="client"></param>
550 public void ClientClosed(IClientAPI client)
551 {
552 ClientClosed(client.AgentId);
553 }
554
555 /// <summary>
556 /// Event Handler for when an Avatar enters one of the parcels in the simulator.
557 /// </summary>
558 /// <param name="avatar"></param>
559 /// <param name="localLandID"></param>
560 /// <param name="regionID"></param>
561 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
562 {
563 lock (m_rootAgents)
564 {
565 if (m_rootAgents.ContainsKey(avatar.UUID))
566 {
567 if (avatar.Scene.RegionInfo.originRegionID != m_rootAgents[avatar.UUID])
568 {
569 m_rootAgents[avatar.UUID] = avatar.Scene.RegionInfo.originRegionID;
570 //m_log.Info("[MONEY]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
571 // Claim User! my user! Mine mine mine!
572 if (m_MoneyAddress.Length > 0)
573 {
574 Scene RegionItem = GetSceneByUUID(regionID);
575 if (RegionItem != null)
576 {
577 Hashtable hresult = claim_user(avatar.UUID, avatar.ControllingClient.SecureSessionId, regionID, RegionItem.RegionInfo.regionSecret);
578 if ((bool)hresult["success"] == true)
579 {
580 int funds = 0;
581 try
582 {
583 funds = (Int32)hresult["funds"];
584 }
585 catch (InvalidCastException)
586 {
587
588 }
589 SetLocalFundsForAgentID(avatar.UUID, funds);
590 }
591 else
592 {
593 avatar.ControllingClient.SendAgentAlertMessage((string)hresult["errorMessage"], true);
594 }
595 }
596 }
597 }
598 }
599 else
600 {
601 lock (m_rootAgents)
602 {
603 m_rootAgents.Add(avatar.UUID, avatar.Scene.RegionInfo.originRegionID);
604 }
605 if (m_MoneyAddress.Length > 0)
606 {
607 Scene RegionItem = GetSceneByUUID(regionID);
608 if (RegionItem != null)
609 {
610 Hashtable hresult = claim_user(avatar.UUID, avatar.ControllingClient.SecureSessionId, regionID, RegionItem.RegionInfo.regionSecret);
611 if ((bool)hresult["success"] == true)
612 {
613 int funds = 0;
614 try
615 {
616 funds = (Int32)hresult["funds"];
617 }
618 catch (InvalidCastException)
619 {
620
621 }
622 SetLocalFundsForAgentID(avatar.UUID, funds);
623 }
624 else
625 {
626 avatar.ControllingClient.SendAgentAlertMessage((string)hresult["errorMessage"], true);
627 }
628 }
629 }
630
631 //m_log.Info("[MONEY]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
632 }
633 }
634 //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString());
635 }
636
637 #endregion
638
639 /// <summary>
640 /// Transfer money
641 /// </summary>
642 /// <param name="Sender"></param>
643 /// <param name="Receiver"></param>
644 /// <param name="amount"></param>
645 /// <returns></returns>
646 private bool doMoneyTransfer(LLUUID Sender, LLUUID Receiver, int amount, int transactiontype, string description)
647 {
648 bool result = false;
649 if (amount >= 0)
650 {
651 lock (m_KnownClientFunds)
652 {
653 // If we don't know about the sender, then the sender can't
654 // actually be here and therefore this is likely fraud or outdated.
655 if (m_MoneyAddress.Length == 0)
656 {
657 if (m_KnownClientFunds.ContainsKey(Sender))
658 {
659 // Does the sender have enough funds to give?
660 if (m_KnownClientFunds[Sender] >= amount)
661 {
662 // Subtract the funds from the senders account
663 m_KnownClientFunds[Sender] -= amount;
664
665 // do we know about the receiver?
666 if (!m_KnownClientFunds.ContainsKey(Receiver))
667 {
668 // Make a record for them so they get the updated balance when they login
669 CheckExistAndRefreshFunds(Receiver);
670 }
671 if (m_enabled)
672 {
673 //Add the amount to the Receiver's funds
674 m_KnownClientFunds[Receiver] += amount;
675 result = true;
676 }
677 }
678 else
679 {
680 // These below are redundant to make this clearer to read
681 result = false;
682 }
683 }
684 else
685 {
686 result = false;
687 }
688 }
689 else
690 {
691 result = TransferMoneyonMoneyServer(Sender, Receiver, amount, transactiontype, description);
692 }
693 }
694 }
695 return result;
696 }
697
698 #region Utility Helpers
699 /// <summary>
700 /// Locates a IClientAPI for the client specified
701 /// </summary>
702 /// <param name="AgentID"></param>
703 /// <returns></returns>
704 private IClientAPI LocateClientObject(LLUUID AgentID)
705 {
706 ScenePresence tPresence = null;
707 IClientAPI rclient = null;
708
709 lock (m_scenel)
710 {
711 foreach (Scene _scene in m_scenel.Values)
712 {
713 tPresence = _scene.GetScenePresence(AgentID);
714 if (tPresence != null)
715 {
716 if (!tPresence.IsChildAgent)
717 {
718 rclient = tPresence.ControllingClient;
719 }
720 }
721 if (rclient != null)
722 {
723 return rclient;
724 }
725 }
726
727 }
728 return null;
729 }
730
731 private Scene LocateSceneClientIn(LLUUID AgentId)
732 {
733 lock (m_scenel)
734 {
735 foreach (Scene _scene in m_scenel.Values)
736 {
737 ScenePresence tPresence = _scene.GetScenePresence(AgentId);
738 if (tPresence != null)
739 {
740 if (!tPresence.IsChildAgent)
741 {
742 return _scene;
743 }
744 }
745
746 }
747
748 }
749 return null;
750 }
751
752 /// <summary>
753 /// Utility function Gets a Random scene in the instance. For when which scene exactly you're doing something with doesn't matter
754 /// </summary>
755 /// <returns></returns>
756 public Scene GetRandomScene()
757 {
758 lock (m_scenel)
759 {
760 foreach (Scene rs in m_scenel.Values)
761 return rs;
762 }
763 return null;
764
765 }
766 /// <summary>
767 /// Utility function to get a Scene by RegionID in a module
768 /// </summary>
769 /// <param name="RegionID"></param>
770 /// <returns></returns>
771 public Scene GetSceneByUUID(LLUUID RegionID)
772 {
773 lock (m_scenel)
774 {
775 foreach (Scene rs in m_scenel.Values)
776 {
777 if (rs.RegionInfo.originRegionID == RegionID)
778 {
779 return rs;
780 }
781 }
782 }
783 return null;
784 }
785 #endregion
786
787
788
789 /// <summary>
790 /// Sends the the stored money balance to the client
791 /// </summary>
792 /// <param name="client"></param>
793 /// <param name="agentID"></param>
794 /// <param name="SessionID"></param>
795 /// <param name="TransactionID"></param>
796 public void SendMoneyBalance(IClientAPI client, LLUUID agentID, LLUUID SessionID, LLUUID TransactionID)
797 {
798 if (client.AgentId == agentID && client.SessionId == SessionID)
799 {
800 int returnfunds = 0;
801
802 try
803 {
804 returnfunds = GetFundsForAgentID(agentID);
805 }
806 catch (Exception e)
807 {
808 client.SendAlertMessage(e.Message + " ");
809 }
810
811 client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds);
812 }
813 else
814 {
815 client.SendAlertMessage("Unable to send your money balance to you!");
816 }
817 }
818
819 #region local Fund Management
820 /// <summary>
821 /// Ensures that the agent accounting data is set up in this instance.
822 /// </summary>
823 /// <param name="agentID"></param>
824 private void CheckExistAndRefreshFunds(LLUUID agentID)
825 {
826 lock (m_KnownClientFunds)
827 {
828 if (!m_KnownClientFunds.ContainsKey(agentID))
829 {
830 m_KnownClientFunds.Add(agentID, m_stipend);
831 }
832 else
833 {
834 if (m_KnownClientFunds[agentID] <= m_minFundsBeforeRefresh)
835 {
836 m_KnownClientFunds[agentID] = m_stipend;
837 }
838 }
839 }
840 }
841 /// <summary>
842 /// Gets the amount of Funds for an agent
843 /// </summary>
844 /// <param name="AgentID"></param>
845 /// <returns></returns>
846 private int GetFundsForAgentID(LLUUID AgentID)
847 {
848 int returnfunds = 0;
849 lock (m_KnownClientFunds)
850 {
851 if (m_KnownClientFunds.ContainsKey(AgentID))
852 {
853 returnfunds = m_KnownClientFunds[AgentID];
854 }
855 else
856 {
857 //throw new Exception("Unable to get funds.");
858 }
859 }
860 return returnfunds;
861 }
862 private void SetLocalFundsForAgentID(LLUUID AgentID, int amount)
863 {
864 lock (m_KnownClientFunds)
865 {
866 if (m_KnownClientFunds.ContainsKey(AgentID))
867 {
868 m_KnownClientFunds[AgentID] = amount;
869 }
870 else
871 {
872 m_KnownClientFunds.Add(AgentID, amount);
873 }
874 }
875
876 }
877
878 #endregion
879
880 /// <summary>
881 /// Gets the current balance for the user from the Grid Money Server
882 /// </summary>
883 /// <param name="agentId"></param>
884 /// <param name="secureSessionID"></param>
885 /// <param name="regionId"></param>
886 /// <param name="regionSecret"></param>
887 /// <returns></returns>
888 public Hashtable GetBalanceForUserFromMoneyServer(LLUUID agentId, LLUUID secureSessionID, LLUUID regionId, string regionSecret)
889 {
890
891 Hashtable MoneyBalanceRequestParams = new Hashtable();
892 MoneyBalanceRequestParams["agentId"] = agentId.ToString();
893 MoneyBalanceRequestParams["secureSessionId"] = secureSessionID.ToString();
894 MoneyBalanceRequestParams["regionId"] = regionId.ToString();
895 MoneyBalanceRequestParams["secret"] = regionSecret;
896 MoneyBalanceRequestParams["currencySecret"] = ""; // per - region/user currency secret gotten from the money system
897
898 Hashtable MoneyRespData = genericCurrencyXMLRPCRequest(MoneyBalanceRequestParams, "simulatorUserBalanceRequest");
899
900 return MoneyRespData;
901 }
902
903
904
905 /// <summary>
906 /// Generic XMLRPC client abstraction
907 /// </summary>
908 /// <param name="ReqParams">Hashtable containing parameters to the method</param>
909 /// <param name="method">Method to invoke</param>
910 /// <returns>Hashtable with success=>bool and other values</returns>
911 public Hashtable genericCurrencyXMLRPCRequest(Hashtable ReqParams, string method)
912 {
913 ArrayList SendParams = new ArrayList();
914 SendParams.Add(ReqParams);
915 // Send Request
916 XmlRpcResponse MoneyResp;
917 try
918 {
919 XmlRpcRequest BalanceRequestReq = new XmlRpcRequest(method, SendParams);
920 MoneyResp = BalanceRequestReq.Send(m_MoneyAddress, 30000);
921 }
922 catch (WebException ex)
923 {
924
925 m_log.ErrorFormat(
926 "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
927 m_MoneyAddress, ex);
928
929 Hashtable ErrorHash = new Hashtable();
930 ErrorHash["success"] = false;
931 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
932 ErrorHash["errorURI"] = "";
933
934 return ErrorHash;
935 //throw (ex);
936 }
937 catch (SocketException ex)
938 {
939
940 m_log.ErrorFormat(
941 "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
942 m_MoneyAddress, ex);
943
944 Hashtable ErrorHash = new Hashtable();
945 ErrorHash["success"] = false;
946 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
947 ErrorHash["errorURI"] = "";
948
949 return ErrorHash;
950 //throw (ex);
951 }
952 catch (XmlException ex)
953 {
954 m_log.ErrorFormat(
955 "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
956 m_MoneyAddress, ex);
957
958 Hashtable ErrorHash = new Hashtable();
959 ErrorHash["success"] = false;
960 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
961 ErrorHash["errorURI"] = "";
962
963 return ErrorHash;
964
965 }
966 if (MoneyResp.IsFault)
967 {
968 Hashtable ErrorHash = new Hashtable();
969 ErrorHash["success"] = false;
970 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
971 ErrorHash["errorURI"] = "";
972
973 return ErrorHash;
974
975 }
976 Hashtable MoneyRespData = (Hashtable)MoneyResp.Value;
977
978 return MoneyRespData;
979 }
980 /// <summary>
981 /// This informs the Money Grid Server that the avatar is in this simulator
982 /// </summary>
983 /// <param name="agentId"></param>
984 /// <param name="secureSessionID"></param>
985 /// <param name="regionId"></param>
986 /// <param name="regionSecret"></param>
987 /// <returns></returns>
988 public Hashtable claim_user(LLUUID agentId, LLUUID secureSessionID, LLUUID regionId, string regionSecret)
989 {
990
991 Hashtable MoneyBalanceRequestParams = new Hashtable();
992 MoneyBalanceRequestParams["agentId"] = agentId.ToString();
993 MoneyBalanceRequestParams["secureSessionId"] = secureSessionID.ToString();
994 MoneyBalanceRequestParams["regionId"] = regionId.ToString();
995 MoneyBalanceRequestParams["secret"] = regionSecret;
996
997 Hashtable MoneyRespData = genericCurrencyXMLRPCRequest(MoneyBalanceRequestParams, "simulatorClaimUserRequest");
998 IClientAPI sendMoneyBal = LocateClientObject(agentId);
999 if (sendMoneyBal != null)
1000 {
1001 SendMoneyBalance(sendMoneyBal, agentId, sendMoneyBal.SessionId, LLUUID.Zero);
1002 }
1003 return MoneyRespData;
1004 }
1005
1006 private SceneObjectPart findPrim(LLUUID objectID)
1007 {
1008 lock (m_scenel)
1009 {
1010 foreach (Scene s in m_scenel.Values)
1011 {
1012 SceneObjectPart part=s.GetSceneObjectPart(objectID);
1013 if(part != null)
1014 {
1015 return part;
1016 }
1017 }
1018 }
1019 return null;
1020 }
1021
1022 private string resolveObjectName(LLUUID objectID)
1023 {
1024 SceneObjectPart part=findPrim(objectID);
1025 if(part != null)
1026 {
1027 return part.Name;
1028 }
1029 return String.Empty;
1030 }
1031
1032 private string resolveAgentName(LLUUID agentID)
1033 {
1034 // try avatar username surname
1035 Scene scene=GetRandomScene();
1036 UserProfileData profile = scene.CommsManager.UserService.GetUserProfile(agentID);
1037 if (profile != null)
1038 {
1039 string avatarname = profile.FirstName + " " + profile.SurName;
1040 return avatarname;
1041 }
1042 return String.Empty;
1043 }
1044
1045 public bool ObjectGiveMoney(LLUUID objectID, LLUUID fromID, LLUUID toID, int amount)
1046 {
1047 string description=String.Format("Object {0} pays {1}", resolveObjectName(objectID), resolveAgentName(toID));
1048
1049 bool give_result = doMoneyTransfer(fromID, toID, amount, 2, description);
1050
1051 if (m_MoneyAddress.Length == 0)
1052 BalanceUpdate(fromID, toID, give_result, description);
1053
1054 return give_result;
1055
1056
1057 }
1058 private void BalanceUpdate(LLUUID senderID, LLUUID receiverID, bool transactionresult, string description)
1059 {
1060 IClientAPI sender = LocateClientObject(senderID);
1061 IClientAPI receiver = LocateClientObject(receiverID);
1062
1063 if (senderID != receiverID)
1064 {
1065 if (sender != null)
1066 {
1067 sender.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(description), GetFundsForAgentID(senderID));
1068 }
1069
1070 if (receiver != null)
1071 {
1072 receiver.SendMoneyBalance(LLUUID.Random(), transactionresult, Helpers.StringToField(description), GetFundsForAgentID(receiverID));
1073 }
1074 }
1075 }
1076
1077 /// <summary>
1078 /// Informs the Money Grid Server of a transfer.
1079 /// </summary>
1080 /// <param name="sourceId"></param>
1081 /// <param name="destId"></param>
1082 /// <param name="amount"></param>
1083 /// <returns></returns>
1084 public bool TransferMoneyonMoneyServer(LLUUID sourceId, LLUUID destId, int amount, int transactiontype, string description)
1085 {
1086 int aggregatePermInventory = 0;
1087 int aggregatePermNextOwner = 0;
1088 int flags = 0;
1089 bool rvalue = false;
1090
1091 IClientAPI cli = LocateClientObject(sourceId);
1092 if (cli != null)
1093 {
1094
1095 Scene userScene = null;
1096 lock (m_rootAgents)
1097 {
1098 userScene = GetSceneByUUID(m_rootAgents[sourceId]);
1099 }
1100 if (userScene != null)
1101 {
1102 Hashtable ht = new Hashtable();
1103 ht["agentId"] = sourceId.ToString();
1104 ht["secureSessionId"] = cli.SecureSessionId.ToString();
1105 ht["regionId"] = userScene.RegionInfo.originRegionID.ToString();
1106 ht["secret"] = userScene.RegionInfo.regionSecret;
1107 ht["currencySecret"] = " ";
1108 ht["destId"] = destId.ToString();
1109 ht["cash"] = amount;
1110 ht["aggregatePermInventory"] = aggregatePermInventory;
1111 ht["aggregatePermNextOwner"] = aggregatePermNextOwner;
1112 ht["flags"] = flags;
1113 ht["transactionType"] = transactiontype;
1114 ht["description"] = description;
1115
1116 Hashtable hresult = genericCurrencyXMLRPCRequest(ht, "regionMoveMoney");
1117
1118 if ((bool)hresult["success"] == true)
1119 {
1120 int funds1 = 0;
1121 int funds2 = 0;
1122 try
1123 {
1124 funds1 = (Int32)hresult["funds"];
1125 }
1126 catch(InvalidCastException)
1127 {
1128 funds1 = 0;
1129 }
1130 SetLocalFundsForAgentID(sourceId, funds1);
1131 if (m_KnownClientFunds.ContainsKey(destId))
1132 {
1133 try
1134 {
1135 funds2 = (Int32)hresult["funds2"];
1136 }
1137 catch (InvalidCastException)
1138 {
1139 funds2 = 0;
1140 }
1141 SetLocalFundsForAgentID(destId, funds2);
1142 }
1143
1144
1145 rvalue = true;
1146 }
1147 else
1148 {
1149 cli.SendAgentAlertMessage((string)hresult["errorMessage"], true);
1150 }
1151
1152 }
1153 }
1154 else
1155 {
1156 m_log.ErrorFormat("[MONEY]: Client {0} not found", sourceId.ToString());
1157 }
1158
1159 return rvalue;
1160
1161 }
1162
1163 public int GetRemoteBalance(LLUUID agentId)
1164 {
1165 int funds = 0;
1166
1167 IClientAPI aClient = LocateClientObject(agentId);
1168 if (aClient != null)
1169 {
1170 Scene s = LocateSceneClientIn(agentId);
1171 if (s != null)
1172 {
1173 if (m_MoneyAddress.Length > 0)
1174 {
1175 Hashtable hbinfo = GetBalanceForUserFromMoneyServer(aClient.AgentId, aClient.SecureSessionId, s.RegionInfo.originRegionID.ToString(), s.RegionInfo.regionSecret);
1176 if ((bool)hbinfo["success"] == true)
1177 {
1178 try
1179 {
1180 funds = (Int32)hbinfo["funds"];
1181 }
1182 catch (ArgumentException)
1183 {
1184 }
1185 catch (FormatException)
1186 {
1187 }
1188 catch (OverflowException)
1189 {
1190 m_log.ErrorFormat("[MONEY]: While getting the Currency for user {0}, the return funds overflowed.", agentId);
1191 aClient.SendAlertMessage("Unable to get your money balance, money operations will be unavailable");
1192 }
1193 catch (InvalidCastException)
1194 {
1195 funds = 0;
1196 }
1197
1198 }
1199 else
1200 {
1201 m_log.WarnFormat("[MONEY]: Getting Money for user {0} failed with the following message:{1}", agentId, (string)hbinfo["errorMessage"]);
1202 aClient.SendAlertMessage((string)hbinfo["errorMessage"]);
1203 }
1204 }
1205
1206 SetLocalFundsForAgentID(agentId, funds);
1207 SendMoneyBalance(aClient, agentId, aClient.SessionId, LLUUID.Zero);
1208 }
1209 else
1210 {
1211 m_log.Debug("[MONEY]: Got balance request update for agent that is here, but couldn't find which scene.");
1212 }
1213 }
1214 else
1215 {
1216 m_log.Debug("[MONEY]: Got balance request update for agent that isn't here.");
1217 }
1218 return funds;
1219 }
1220
1221 public XmlRpcResponse GridMoneyUpdate(XmlRpcRequest request)
1222 {
1223 m_log.Debug("[MONEY]: Dynamic balance update called.");
1224 Hashtable requestData = (Hashtable)request.Params[0];
1225
1226 if (requestData.ContainsKey("agentId"))
1227 {
1228 LLUUID agentId = LLUUID.Zero;
1229
1230 Helpers.TryParse((string)requestData["agentId"], out agentId);
1231 if (agentId != LLUUID.Zero)
1232 {
1233 GetRemoteBalance(agentId);
1234
1235 }
1236 else
1237 {
1238 m_log.Debug("[MONEY]: invalid agentId specified, dropping.");
1239 }
1240 }
1241 else
1242 {
1243 m_log.Debug("[MONEY]: no agentId specified, dropping.");
1244 }
1245 XmlRpcResponse r = new XmlRpcResponse();
1246 Hashtable rparms = new Hashtable();
1247 rparms["success"] = true;
1248
1249 r.Value = rparms;
1250 return r;
1251 }
1252
1253 /// <summary>
1254 /// XMLRPC handler to send alert message and sound to client
1255 /// </summary>
1256 public XmlRpcResponse UserAlert(XmlRpcRequest request)
1257 {
1258 XmlRpcResponse ret = new XmlRpcResponse();
1259 Hashtable retparam = new Hashtable();
1260 Hashtable requestData = (Hashtable)request.Params[0];
1261
1262 LLUUID agentId = LLUUID.Zero;
1263 LLUUID soundId = LLUUID.Zero;
1264
1265 Helpers.TryParse((string)requestData["agentId"], out agentId);
1266 Helpers.TryParse((string)requestData["soundId"], out soundId);
1267 string text=(string)requestData["text"];
1268 string secret=(string)requestData["secret"];
1269
1270 Scene userScene = GetRandomScene();
1271 if(userScene.RegionInfo.regionSecret.ToString() == secret)
1272 {
1273 IClientAPI client = LocateClientObject(agentId);
1274
1275 if (client != null)
1276 {
1277 if(soundId != LLUUID.Zero)
1278 client.SendPlayAttachedSound(soundId, LLUUID.Zero, LLUUID.Zero, 1.0f, 0);
1279 client.SendBlueBoxMessage(LLUUID.Zero, LLUUID.Zero, "", text);
1280 retparam.Add("success", true);
1281 }
1282 else
1283 {
1284 retparam.Add("success", false);
1285 }
1286 }
1287 else
1288 {
1289 retparam.Add("success", false);
1290 }
1291 ret.Value = retparam;
1292
1293 return ret;
1294 }
1295
1296
1297 # region Standalone box enablers only
1298
1299 public XmlRpcResponse quote_func(XmlRpcRequest request)
1300 {
1301 Hashtable requestData = (Hashtable)request.Params[0];
1302 LLUUID agentId = LLUUID.Zero;
1303 int amount = 0;
1304 Hashtable quoteResponse = new Hashtable();
1305 XmlRpcResponse returnval = new XmlRpcResponse();
1306
1307 if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
1308 {
1309 Helpers.TryParse((string)requestData["agentId"], out agentId);
1310 try
1311 {
1312 amount = (Int32)requestData["currencyBuy"];
1313 }
1314 catch (InvalidCastException)
1315 {
1316
1317 }
1318 Hashtable currencyResponse = new Hashtable();
1319 currencyResponse.Add("estimatedCost", 0);
1320 currencyResponse.Add("currencyBuy", amount);
1321
1322 quoteResponse.Add("success", true);
1323 quoteResponse.Add("currency", currencyResponse);
1324 quoteResponse.Add("confirm", "asdfad9fj39ma9fj");
1325
1326 returnval.Value = quoteResponse;
1327 return returnval;
1328 }
1329
1330
1331
1332 quoteResponse.Add("success", false);
1333 quoteResponse.Add("errorMessage", "Invalid parameters passed to the quote box");
1334 quoteResponse.Add("errorURI", "http://www.opensimulator.org/wiki");
1335 returnval.Value = quoteResponse;
1336 return returnval;
1337 }
1338 public XmlRpcResponse buy_func(XmlRpcRequest request)
1339 {
1340
1341 Hashtable requestData = (Hashtable)request.Params[0];
1342 LLUUID agentId = LLUUID.Zero;
1343 int amount = 0;
1344 if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
1345 {
1346 Helpers.TryParse((string)requestData["agentId"], out agentId);
1347 try
1348 {
1349 amount = (Int32)requestData["currencyBuy"];
1350 }
1351 catch (InvalidCastException)
1352 {
1353
1354 }
1355 if (agentId != LLUUID.Zero)
1356 {
1357 lock (m_KnownClientFunds)
1358 {
1359 if (m_KnownClientFunds.ContainsKey(agentId))
1360 {
1361 m_KnownClientFunds[agentId] += amount;
1362 }
1363 else
1364 {
1365 m_KnownClientFunds.Add(agentId, amount);
1366 }
1367 }
1368 IClientAPI client = LocateClientObject(agentId);
1369 if (client != null)
1370 {
1371 SendMoneyBalance(client, agentId, client.SessionId, LLUUID.Zero);
1372 }
1373 }
1374 }
1375 XmlRpcResponse returnval = new XmlRpcResponse();
1376 Hashtable returnresp = new Hashtable();
1377 returnresp.Add("success", true);
1378 returnval.Value = returnresp;
1379 return returnval;
1380 }
1381
1382 public XmlRpcResponse preflightBuyLandPrep_func(XmlRpcRequest request)
1383 {
1384 XmlRpcResponse ret = new XmlRpcResponse();
1385 Hashtable retparam = new Hashtable();
1386 Hashtable membershiplevels = new Hashtable();
1387 ArrayList levels = new ArrayList();
1388 Hashtable level = new Hashtable();
1389 level.Add("id", "00000000-0000-0000-0000-000000000000");
1390 level.Add("description", "some level");
1391 levels.Add(level);
1392 //membershiplevels.Add("levels",levels);
1393
1394 Hashtable landuse = new Hashtable();
1395 landuse.Add("upgrade", false);
1396 landuse.Add("action", "http://invaliddomaininvalid.com/");
1397
1398 Hashtable currency = new Hashtable();
1399 currency.Add("estimatedCost", 0);
1400
1401 Hashtable membership = new Hashtable();
1402 membershiplevels.Add("upgrade", false);
1403 membershiplevels.Add("action", "http://invaliddomaininvalid.com/");
1404 membershiplevels.Add("levels", membershiplevels);
1405
1406 retparam.Add("success", true);
1407 retparam.Add("currency", currency);
1408 retparam.Add("membership", membership);
1409 retparam.Add("landuse", landuse);
1410 retparam.Add("confirm", "asdfajsdkfjasdkfjalsdfjasdf");
1411
1412 ret.Value = retparam;
1413
1414 return ret;
1415
1416 }
1417 public XmlRpcResponse landBuy_func(XmlRpcRequest request)
1418 {
1419 XmlRpcResponse ret = new XmlRpcResponse();
1420 Hashtable retparam = new Hashtable();
1421 Hashtable requestData = (Hashtable)request.Params[0];
1422
1423 LLUUID agentId = LLUUID.Zero;
1424 int amount = 0;
1425 if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
1426 {
1427 Helpers.TryParse((string)requestData["agentId"], out agentId);
1428 try
1429 {
1430 amount = (Int32)requestData["currencyBuy"];
1431 }
1432 catch (InvalidCastException)
1433 {
1434
1435 }
1436 if (agentId != LLUUID.Zero)
1437 {
1438 lock (m_KnownClientFunds)
1439 {
1440 if (m_KnownClientFunds.ContainsKey(agentId))
1441 {
1442 m_KnownClientFunds[agentId] += amount;
1443 }
1444 else
1445 {
1446 m_KnownClientFunds.Add(agentId, amount);
1447 }
1448 }
1449 IClientAPI client = LocateClientObject(agentId);
1450 if (client != null)
1451 {
1452 SendMoneyBalance(client, agentId, client.SessionId, LLUUID.Zero);
1453 }
1454 }
1455 }
1456 retparam.Add("success", true);
1457 ret.Value = retparam;
1458
1459 return ret;
1460
1461 }
1462 #endregion
1463
1464 public void PostInitialise()
1465 {
1466 }
1467
1468 public void Close()
1469 {
1470 }
1471
1472 public string Name
1473 {
1474 get { return "BetaGridLikeMoneyModule"; }
1475 }
1476
1477 public bool IsSharedModule
1478 {
1479 get { return true; }
1480 }
1481 }
1482
1483 public enum TransactionType : int
1484 {
1485 SystemGenerated=0,
1486 RegionMoneyRequest=1,
1487 Gift=2,
1488 Purchase=3
1489
1490 }
1491} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs
new file mode 100644
index 0000000..3b0cc4c
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs
@@ -0,0 +1,504 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using libsecondlife;
31using libsecondlife.Packets;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenSim.Framework;
36using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Region.Environment.Scenes;
38
39namespace OpenSim.Region.Environment.Modules.Avatar.Friends
40{
41 public class FriendsModule : IRegionModule
42 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 private List<Scene> m_scene = new List<Scene>();
46
47 Dictionary<LLUUID, ulong> m_rootAgents = new Dictionary<LLUUID, ulong>();
48
49 Dictionary<LLUUID, LLUUID> m_pendingFriendRequests = new Dictionary<LLUUID, LLUUID>();
50
51 Dictionary<LLUUID, List<FriendListItem>> FriendLists = new Dictionary<LLUUID, List<FriendListItem>>();
52
53 public void Initialise(Scene scene, IConfigSource config)
54 {
55 lock (m_scene)
56 {
57 if (m_scene.Count == 0)
58 {
59 scene.AddXmlRPCHandler("presence_update", processPresenceUpdate);
60 }
61
62 if (!m_scene.Contains(scene))
63 m_scene.Add(scene);
64 }
65 scene.EventManager.OnNewClient += OnNewClient;
66 scene.EventManager.OnGridInstantMessageToFriendsModule += OnGridInstantMessage;
67 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
68 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
69 scene.EventManager.OnClientClosed += ClientLoggedOut;
70 }
71 public XmlRpcResponse processPresenceUpdate(XmlRpcRequest req)
72 {
73 m_log.Info("[FRIENDS]: Got Notification about a user! OMG");
74 return new XmlRpcResponse();
75 }
76 private void OnNewClient(IClientAPI client)
77 {
78 // All friends establishment protocol goes over instant message
79 // There's no way to send a message from the sim
80 // to a user to 'add a friend' without causing dialog box spam
81 //
82 // The base set of friends are added when the user signs on in their XMLRPC response
83 // Generated by LoginService. The friends are retreived from the database by the UserManager
84
85 // Subscribe to instant messages
86
87 client.OnInstantMessage += OnInstantMessage;
88 client.OnApproveFriendRequest += OnApprovedFriendRequest;
89 client.OnDenyFriendRequest += OnDenyFriendRequest;
90 client.OnTerminateFriendship += OnTerminateFriendship;
91
92 List<FriendListItem> fl = new List<FriendListItem>();
93
94 //bool addFLback = false;
95
96 lock (FriendLists)
97 {
98 if (FriendLists.ContainsKey(client.AgentId))
99 {
100 fl = FriendLists[client.AgentId];
101 }
102 else
103 {
104 fl = m_scene[0].GetFriendList(client.AgentId);
105
106 //lock (FriendLists)
107 //{
108 if (!FriendLists.ContainsKey(client.AgentId))
109 FriendLists.Add(client.AgentId, fl);
110 //}
111 }
112 }
113
114 List<LLUUID> UpdateUsers = new List<LLUUID>();
115
116 foreach (FriendListItem f in fl)
117 {
118 if (m_rootAgents.ContainsKey(f.Friend))
119 {
120 if (f.onlinestatus == false)
121 {
122 UpdateUsers.Add(f.Friend);
123 f.onlinestatus = true;
124 }
125 }
126 }
127 foreach (LLUUID user in UpdateUsers)
128 {
129 ScenePresence av = GetPresenceFromAgentID(user);
130 if (av != null)
131 {
132 List<FriendListItem> usrfl = new List<FriendListItem>();
133
134 lock (FriendLists)
135 {
136 usrfl = FriendLists[user];
137 }
138
139 lock (usrfl)
140 {
141 foreach (FriendListItem fli in usrfl)
142 {
143 if (fli.Friend == client.AgentId)
144 {
145 fli.onlinestatus = true;
146 OnlineNotificationPacket onp = new OnlineNotificationPacket();
147 OnlineNotificationPacket.AgentBlockBlock[] onpb = new OnlineNotificationPacket.AgentBlockBlock[1];
148 OnlineNotificationPacket.AgentBlockBlock onpbl = new OnlineNotificationPacket.AgentBlockBlock();
149 onpbl.AgentID = client.AgentId;
150 onpb[0] = onpbl;
151 onp.AgentBlock = onpb;
152 av.ControllingClient.OutPacket(onp, ThrottleOutPacketType.Task);
153 }
154 }
155 }
156 }
157 }
158
159 if (UpdateUsers.Count > 0)
160 {
161 OnlineNotificationPacket onp = new OnlineNotificationPacket();
162 OnlineNotificationPacket.AgentBlockBlock[] onpb = new OnlineNotificationPacket.AgentBlockBlock[UpdateUsers.Count];
163 for (int i = 0; i < UpdateUsers.Count; i++)
164 {
165 OnlineNotificationPacket.AgentBlockBlock onpbl = new OnlineNotificationPacket.AgentBlockBlock();
166 onpbl.AgentID = UpdateUsers[i];
167 onpb[i] = onpbl;
168 }
169 onp.AgentBlock = onpb;
170 client.OutPacket(onp, ThrottleOutPacketType.Task);
171 }
172
173
174
175
176 }
177
178 private void ClientLoggedOut(LLUUID AgentId)
179 {
180 lock (m_rootAgents)
181 {
182 if (m_rootAgents.ContainsKey(AgentId))
183 {
184 m_rootAgents.Remove(AgentId);
185 m_log.Info("[FRIEND]: Removing " + AgentId + ". Agent logged out.");
186 }
187 }
188 List<FriendListItem> lfli = new List<FriendListItem>();
189 lock (FriendLists)
190 {
191 if (FriendLists.ContainsKey(AgentId))
192 {
193 lfli = FriendLists[AgentId];
194 }
195 }
196 List<LLUUID> updateUsers = new List<LLUUID>();
197 foreach (FriendListItem fli in lfli)
198 {
199 if (fli.onlinestatus == true)
200 {
201 updateUsers.Add(fli.Friend);
202 }
203 }
204 lock (updateUsers)
205 {
206 for (int i = 0; i < updateUsers.Count; i++)
207 {
208 List<FriendListItem> flfli = new List<FriendListItem>();
209 try
210 {
211
212 lock (FriendLists)
213 {
214 if (FriendLists.ContainsKey(updateUsers[i]))
215 flfli = FriendLists[updateUsers[i]];
216 }
217 }
218 catch (IndexOutOfRangeException)
219 {
220 // Ignore the index out of range exception.
221 // This causes friend lists to get out of sync slightly.. however
222 // prevents a sim crash.
223 m_log.Info("[FRIEND]: Unable to enumerate last friendlist user. User logged off");
224 }
225
226 for (int j = 0; j < flfli.Count; j++)
227 {
228 try
229 {
230 if (flfli[i].Friend == AgentId)
231 {
232 flfli[i].onlinestatus = false;
233 }
234
235 }
236
237 catch (IndexOutOfRangeException)
238 {
239 // Ignore the index out of range exception.
240 // This causes friend lists to get out of sync slightly.. however
241 // prevents a sim crash.
242 m_log.Info("[FRIEND]: Unable to enumerate last friendlist user. User logged off");
243 }
244 }
245
246 }
247
248 for (int i = 0; i < updateUsers.Count; i++)
249 {
250 ScenePresence av = GetPresenceFromAgentID(updateUsers[i]);
251 if (av != null)
252 {
253
254 OfflineNotificationPacket onp = new OfflineNotificationPacket();
255 OfflineNotificationPacket.AgentBlockBlock[] onpb = new OfflineNotificationPacket.AgentBlockBlock[1];
256 OfflineNotificationPacket.AgentBlockBlock onpbl = new OfflineNotificationPacket.AgentBlockBlock();
257 onpbl.AgentID = AgentId;
258 onpb[0] = onpbl;
259 onp.AgentBlock = onpb;
260 av.ControllingClient.OutPacket(onp, ThrottleOutPacketType.Task);
261 }
262 }
263 }
264 lock (FriendLists)
265 {
266 FriendLists.Remove(AgentId);
267 }
268
269 }
270
271 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
272 {
273 lock (m_rootAgents)
274 {
275 if (m_rootAgents.ContainsKey(avatar.UUID))
276 {
277 if (avatar.RegionHandle != m_rootAgents[avatar.UUID])
278 {
279 m_rootAgents[avatar.UUID] = avatar.RegionHandle;
280 m_log.Info("[FRIEND]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
281 if (avatar.JID.Length > 0)
282 {
283 JId avatarID = new JId(avatar.JID);
284 // REST Post XMPP Stanzas!
285
286 }
287 // Claim User! my user! Mine mine mine!
288 }
289 }
290 else
291 {
292 m_rootAgents.Add(avatar.UUID, avatar.RegionHandle);
293 m_log.Info("[FRIEND]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
294 }
295 }
296 //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString());
297 }
298 private void MakeChildAgent(ScenePresence avatar)
299 {
300
301 lock (m_rootAgents)
302 {
303 if (m_rootAgents.ContainsKey(avatar.UUID))
304 {
305 if (m_rootAgents[avatar.UUID] == avatar.RegionHandle)
306 {
307 m_rootAgents.Remove(avatar.UUID);
308 m_log.Info("[FRIEND]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent");
309 }
310
311 }
312 }
313
314 }
315 #region FriendRequestHandling
316 private void OnInstantMessage(IClientAPI client,LLUUID fromAgentID,
317 LLUUID fromAgentSession, LLUUID toAgentID,
318 LLUUID imSessionID, uint timestamp, string fromAgentName,
319 string message, byte dialog, bool fromGroup, byte offline,
320 uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
321 byte[] binaryBucket)
322 {
323 // Friend Requests go by Instant Message.. using the dialog param
324 // https://wiki.secondlife.com/wiki/ImprovedInstantMessage
325
326 // 38 == Offer friendship
327 if (dialog == (byte)38)
328 {
329 LLUUID friendTransactionID = LLUUID.Random();
330
331 m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
332
333 m_log.Info("[FRIEND]: 38 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
334 GridInstantMessage msg = new GridInstantMessage();
335 msg.fromAgentID = fromAgentID.UUID;
336 msg.fromAgentSession = fromAgentSession.UUID;
337 msg.toAgentID = toAgentID.UUID;
338 msg.imSessionID = friendTransactionID.UUID; // This is the item we're mucking with here
339 m_log.Info("[FRIEND]: Filling Session: " + msg.imSessionID.ToString());
340 msg.timestamp = timestamp;
341 if (client != null)
342 {
343 msg.fromAgentName = client.FirstName + " " + client.LastName;// fromAgentName;
344 }
345 else
346 {
347 msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
348 }
349 msg.message = message;
350 msg.dialog = dialog;
351 msg.fromGroup = fromGroup;
352 msg.offline = offline;
353 msg.ParentEstateID = ParentEstateID;
354 msg.Position = new sLLVector3(Position);
355 msg.RegionID = RegionID.UUID;
356 msg.binaryBucket = binaryBucket;
357 // We don't really care which scene we pipe it through.
358 m_scene[0].TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
359 }
360
361 // 39 == Accept Friendship
362 if (dialog == (byte)39)
363 {
364 m_log.Info("[FRIEND]: 39 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
365 }
366
367 // 40 == Decline Friendship
368 if (dialog == (byte)40)
369 {
370 m_log.Info("[FRIEND]: 40 - From:" + fromAgentID.ToString() + " To: " + toAgentID.ToString() + " Session:" + imSessionID.ToString() + " Message:" + message);
371 }
372 }
373
374 private void OnApprovedFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List<LLUUID> callingCardFolders)
375 {
376 if (m_pendingFriendRequests.ContainsKey(transactionID))
377 {
378 // Found Pending Friend Request with that Transaction..
379 Scene SceneAgentIn = m_scene[0];
380
381 // Found Pending Friend Request with that Transaction..
382 ScenePresence agentpresence = GetPresenceFromAgentID(agentID);
383 if (agentpresence != null)
384 {
385 SceneAgentIn = agentpresence.Scene;
386 }
387
388 // Compose response to other agent.
389 GridInstantMessage msg = new GridInstantMessage();
390 msg.toAgentID = m_pendingFriendRequests[transactionID].UUID;
391 msg.fromAgentID = agentID.UUID;
392 msg.fromAgentName = client.FirstName + " " + client.LastName;
393 msg.fromAgentSession = client.SessionId.UUID;
394 msg.fromGroup = false;
395 msg.imSessionID = transactionID.UUID;
396 msg.message = agentID.UUID.ToString();
397 msg.ParentEstateID = 0;
398 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
399 msg.RegionID = SceneAgentIn.RegionInfo.RegionID.UUID;
400 msg.dialog = (byte)39;// Approved friend request
401 msg.Position = new sLLVector3();
402 msg.offline = (byte)0;
403 msg.binaryBucket = new byte[0];
404 // We don't really care which scene we pipe it through, it goes to the shared IM Module and/or the database
405
406 SceneAgentIn.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
407 SceneAgentIn.StoreAddFriendship(m_pendingFriendRequests[transactionID], agentID, (uint)1);
408 m_pendingFriendRequests.Remove(transactionID);
409
410 // TODO: Inform agent that the friend is online
411 }
412 }
413
414 private void OnDenyFriendRequest(IClientAPI client, LLUUID agentID, LLUUID transactionID, List<LLUUID> callingCardFolders)
415 {
416 if (m_pendingFriendRequests.ContainsKey(transactionID))
417 {
418 Scene SceneAgentIn = m_scene[0];
419
420 // Found Pending Friend Request with that Transaction..
421 ScenePresence agentpresence = GetPresenceFromAgentID(agentID);
422 if (agentpresence != null)
423 {
424 SceneAgentIn = agentpresence.Scene;
425 }
426 // Compose response to other agent.
427 GridInstantMessage msg = new GridInstantMessage();
428 msg.toAgentID = m_pendingFriendRequests[transactionID].UUID;
429 msg.fromAgentID = agentID.UUID;
430 msg.fromAgentName = client.FirstName + " " + client.LastName;
431 msg.fromAgentSession = client.SessionId.UUID;
432 msg.fromGroup = false;
433 msg.imSessionID = transactionID.UUID;
434 msg.message = agentID.UUID.ToString();
435 msg.ParentEstateID = 0;
436 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
437 msg.RegionID = SceneAgentIn.RegionInfo.RegionID.UUID;
438 msg.dialog = (byte)40;// Deny friend request
439 msg.Position = new sLLVector3();
440 msg.offline = (byte)0;
441 msg.binaryBucket = new byte[0];
442 SceneAgentIn.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
443 m_pendingFriendRequests.Remove(transactionID);
444 }
445 }
446
447 private void OnTerminateFriendship(IClientAPI client, LLUUID agent, LLUUID exfriendID)
448 {
449 m_scene[0].StoreRemoveFriendship(agent, exfriendID);
450 // TODO: Inform the client that the ExFriend is offline
451 }
452
453 private void OnGridInstantMessage(GridInstantMessage msg)
454 {
455 // Trigger the above event handler
456 OnInstantMessage(null,new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession),
457 new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName,
458 msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID,
459 new LLVector3(msg.Position.x, msg.Position.y, msg.Position.z), new LLUUID(msg.RegionID),
460 msg.binaryBucket);
461 }
462 #endregion
463 private ScenePresence GetPresenceFromAgentID(LLUUID AgentID)
464 {
465 ScenePresence returnAgent = null;
466 lock (m_scene)
467 {
468 ScenePresence queryagent = null;
469 for (int i = 0; i < m_scene.Count; i++)
470 {
471 queryagent = m_scene[i].GetScenePresence(AgentID);
472 if (queryagent != null)
473 {
474 if (!queryagent.IsChildAgent)
475 {
476 returnAgent = queryagent;
477 break;
478 }
479 }
480 }
481 }
482 return returnAgent;
483
484 }
485
486 public void PostInitialise()
487 {
488 }
489
490 public void Close()
491 {
492 }
493
494 public string Name
495 {
496 get { return "FriendsModule"; }
497 }
498
499 public bool IsSharedModule
500 {
501 get { return true; }
502 }
503 }
504} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs
new file mode 100644
index 0000000..4b28ad7
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs
@@ -0,0 +1,278 @@
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.Generic;
30using System.Reflection;
31using libsecondlife;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Environment.Interfaces;
36using OpenSim.Region.Environment.Scenes;
37
38namespace OpenSim.Region.Environment.Modules.Avatar.Groups
39{
40 public class GroupsModule : IRegionModule
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private List<Scene> m_scene = new List<Scene>();
45 private Dictionary<LLUUID, IClientAPI> m_iclientmap = new Dictionary<LLUUID, IClientAPI>();
46 private Dictionary<LLUUID, GroupData> m_groupmap = new Dictionary<LLUUID, GroupData>();
47 private Dictionary<LLUUID, GroupList> m_grouplistmap = new Dictionary<LLUUID, GroupList>();
48
49 public void Initialise(Scene scene, IConfigSource config)
50 {
51 lock (m_scene)
52 {
53 m_scene.Add(scene);
54 }
55 scene.EventManager.OnNewClient += OnNewClient;
56 scene.EventManager.OnClientClosed += OnClientClosed;
57 scene.EventManager.OnGridInstantMessageToGroupsModule += OnGridInstantMessage;
58 //scene.EventManager.
59 }
60
61 private void OnNewClient(IClientAPI client)
62 {
63 // All friends establishment protocol goes over instant message
64 // There's no way to send a message from the sim
65 // to a user to 'add a friend' without causing dialog box spam
66 //
67 // The base set of friends are added when the user signs on in their XMLRPC response
68 // Generated by LoginService. The friends are retreived from the database by the UserManager
69
70 // Subscribe to instant messages
71 client.OnInstantMessage += OnInstantMessage;
72 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
73 lock (m_iclientmap)
74 {
75 if (!m_iclientmap.ContainsKey(client.AgentId))
76 {
77 m_iclientmap.Add(client.AgentId, client);
78 }
79 }
80 GroupData OpenSimulatorGroup = new GroupData();
81 OpenSimulatorGroup.ActiveGroupTitle = "OpenSimulator Tester";
82 OpenSimulatorGroup.GroupID = new LLUUID("00000000-68f9-1111-024e-222222111120");
83 OpenSimulatorGroup.GroupMembers.Add(client.AgentId);
84 OpenSimulatorGroup.groupName = "OpenSimulator Testing";
85 OpenSimulatorGroup.ActiveGroupPowers = GroupPowers.LandAllowSetHome;
86 OpenSimulatorGroup.GroupTitles.Add("OpenSimulator Tester");
87 lock (m_groupmap)
88 {
89 if (!m_groupmap.ContainsKey(client.AgentId))
90 {
91 m_groupmap.Add(client.AgentId, OpenSimulatorGroup);
92 }
93 }
94 GroupList testGroupList = new GroupList();
95 testGroupList.m_GroupList.Add(new LLUUID("00000000-68f9-1111-024e-222222111120"));
96
97 lock (m_grouplistmap)
98 {
99 if (!m_grouplistmap.ContainsKey(client.AgentId))
100 {
101 m_grouplistmap.Add(client.AgentId, testGroupList);
102 }
103 }
104 m_log.Info("[GROUP]: Adding " + client.FirstName + " " + client.LastName + " to OpenSimulator Tester group");
105 }
106
107 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, LLUUID AgentID, LLUUID SessionID)
108 {
109 string firstname = remoteClient.FirstName;
110 string lastname = remoteClient.LastName;
111
112 LLUUID ActiveGroupID = LLUUID.Zero;
113 uint ActiveGroupPowers = 0;
114 string ActiveGroupName = "";
115 string ActiveGroupTitle = "";
116
117 bool foundUser = false;
118
119 lock (m_iclientmap)
120 {
121 if (m_iclientmap.ContainsKey(remoteClient.AgentId))
122 {
123 foundUser = true;
124 }
125 }
126 if (foundUser)
127 {
128 lock (m_groupmap)
129 {
130 if (m_groupmap.ContainsKey(remoteClient.AgentId))
131 {
132 GroupData grp = m_groupmap[remoteClient.AgentId];
133 if (grp != null)
134 {
135 ActiveGroupID = grp.GroupID;
136 ActiveGroupName = grp.groupName;
137 ActiveGroupPowers = grp.groupPowers;
138 ActiveGroupTitle = grp.ActiveGroupTitle;
139 }
140
141 //remoteClient.SendAgentDataUpdate(AgentID, ActiveGroupID, firstname, lastname, ActiveGroupPowers, ActiveGroupName, ActiveGroupTitle);
142
143 }
144 }
145 }
146
147 }
148
149 private void OnInstantMessage(IClientAPI client, LLUUID fromAgentID,
150 LLUUID fromAgentSession, LLUUID toAgentID,
151 LLUUID imSessionID, uint timestamp, string fromAgentName,
152 string message, byte dialog, bool fromGroup, byte offline,
153 uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
154 byte[] binaryBucket)
155 {
156 }
157
158 private void OnGridInstantMessage(GridInstantMessage msg)
159 {
160 // Trigger the above event handler
161 OnInstantMessage(null, new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession),
162 new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName,
163 msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID,
164 new LLVector3(msg.Position.x, msg.Position.y, msg.Position.z), new LLUUID(msg.RegionID),
165 msg.binaryBucket);
166 }
167
168 private void OnClientClosed(LLUUID agentID)
169 {
170 lock (m_iclientmap)
171 {
172 if (m_iclientmap.ContainsKey(agentID))
173 {
174 IClientAPI cli = m_iclientmap[agentID];
175 if (cli != null)
176 {
177 m_log.Info("[GROUP]: Removing all reference to groups for " + cli.FirstName + " " + cli.LastName);
178 }
179 else
180 {
181 m_log.Info("[GROUP]: Removing all reference to groups for " + agentID.ToString());
182 }
183 m_iclientmap.Remove(agentID);
184 }
185 }
186
187 lock (m_groupmap)
188 {
189 if (m_groupmap.ContainsKey(agentID))
190 {
191 m_groupmap.Remove(agentID);
192 }
193 }
194
195 lock (m_grouplistmap)
196 {
197 if (m_grouplistmap.ContainsKey(agentID))
198 {
199 m_grouplistmap.Remove(agentID);
200 }
201 }
202 GC.Collect();
203 }
204
205 public void PostInitialise()
206 {
207 }
208
209 public void Close()
210 {
211 m_log.Info("[GROUP]: Shutting down group module.");
212 lock (m_iclientmap)
213 {
214 m_iclientmap.Clear();
215 }
216
217 lock (m_groupmap)
218 {
219 m_groupmap.Clear();
220 }
221
222 lock (m_grouplistmap)
223 {
224 m_grouplistmap.Clear();
225 }
226 GC.Collect();
227 }
228
229 public string Name
230 {
231 get { return "GroupsModule"; }
232 }
233
234 public bool IsSharedModule
235 {
236 get { return true; }
237 }
238
239 }
240
241 public class GroupData
242 {
243 public LLUUID GroupID;
244 public string groupName;
245 public string ActiveGroupTitle;
246 public List<string> GroupTitles;
247 public List<LLUUID> GroupMembers;
248 public uint groupPowers = (uint)(GroupPowers.LandAllowLandmark | GroupPowers.LandAllowSetHome);
249
250 public GroupPowers ActiveGroupPowers
251 {
252 set
253 {
254 groupPowers = (uint) value;
255 }
256 get
257 {
258 return (GroupPowers)groupPowers;
259 }
260 }
261
262 public GroupData()
263 {
264 GroupTitles = new List<string>();
265 GroupMembers = new List<LLUUID>();
266 }
267
268 }
269
270 public class GroupList
271 {
272 public List<LLUUID> m_GroupList;
273 public GroupList()
274 {
275 m_GroupList = new List<LLUUID>();
276 }
277 }
278} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs
new file mode 100644
index 0000000..1b82837
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs
@@ -0,0 +1,157 @@
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.Collections.Generic;
29using libsecondlife;
30using Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Region.Environment.Interfaces;
33using OpenSim.Region.Environment.Scenes;
34
35namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage
36{
37 public class InstantMessageModule : IRegionModule
38 {
39 private readonly List<Scene> m_scenes = new List<Scene>();
40
41 public void Initialise(Scene scene, IConfigSource config)
42 {
43 lock (m_scenes)
44 {
45 if (m_scenes.Count == 0)
46 {
47 //scene.AddXmlRPCHandler("avatar_location_update", processPresenceUpdate);
48 }
49
50 if (!m_scenes.Contains(scene))
51 {
52 m_scenes.Add(scene);
53 scene.EventManager.OnNewClient += OnNewClient;
54 scene.EventManager.OnGridInstantMessageToIMModule += OnGridInstantMessage;
55 }
56 }
57 }
58
59 private void OnNewClient(IClientAPI client)
60 {
61 client.OnInstantMessage += OnInstantMessage;
62 }
63
64 private void OnInstantMessage(IClientAPI client,LLUUID fromAgentID,
65 LLUUID fromAgentSession, LLUUID toAgentID,
66 LLUUID imSessionID, uint timestamp, string fromAgentName,
67 string message, byte dialog, bool fromGroup, byte offline,
68 uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
69 byte[] binaryBucket)
70 {
71 bool dialogHandledElsewhere
72 = ((dialog == 38) || (dialog == 39) || (dialog == 40)
73 || dialog == (byte)InstantMessageDialog.InventoryOffered
74 || dialog == (byte)InstantMessageDialog.InventoryAccepted
75 || dialog == (byte)InstantMessageDialog.InventoryDeclined);
76
77 // IM dialogs need to be pre-processed and have their sessionID filled by the server
78 // so the sim can match the transaction on the return packet.
79
80 // Don't send a Friend Dialog IM with a LLUUID.Zero session.
81 if (!(dialogHandledElsewhere && imSessionID == LLUUID.Zero))
82 {
83 // Try root avatar only first
84 foreach (Scene scene in m_scenes)
85 {
86 if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence)
87 {
88 // Local message
89 ScenePresence user = (ScenePresence)scene.Entities[toAgentID];
90 if (!user.IsChildAgent)
91 {
92 user.ControllingClient.SendInstantMessage(fromAgentID, fromAgentSession, message,
93 toAgentID, imSessionID, fromAgentName, dialog,
94 timestamp);
95 // Message sent
96 return;
97 }
98 }
99 }
100
101 // try child avatar second
102 foreach (Scene scene in m_scenes)
103 {
104 if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence)
105 {
106 // Local message
107 ScenePresence user = (ScenePresence)scene.Entities[toAgentID];
108
109 user.ControllingClient.SendInstantMessage(fromAgentID, fromAgentSession, message,
110 toAgentID, imSessionID, fromAgentName, dialog,
111 timestamp);
112 // Message sent
113 return;
114
115 }
116 }
117
118 }
119
120
121 // Still here, try send via Grid
122 // TODO
123 }
124
125 // Trusty OSG1 called method. This method also gets called from the FriendsModule
126 // Turns out the sim has to send an instant message to the user to get it to show an accepted friend.
127
128 private void OnGridInstantMessage(GridInstantMessage msg)
129 {
130 // Trigger the above event handler
131 OnInstantMessage(null,new LLUUID(msg.fromAgentID), new LLUUID(msg.fromAgentSession),
132 new LLUUID(msg.toAgentID), new LLUUID(msg.imSessionID), msg.timestamp, msg.fromAgentName,
133 msg.message, msg.dialog, msg.fromGroup, msg.offline, msg.ParentEstateID,
134 new LLVector3(msg.Position.x,msg.Position.y,msg.Position.z), new LLUUID(msg.RegionID),
135 msg.binaryBucket);
136
137 }
138
139 public void PostInitialise()
140 {
141 }
142
143 public void Close()
144 {
145 }
146
147 public string Name
148 {
149 get { return "InstantMessageModule"; }
150 }
151
152 public bool IsSharedModule
153 {
154 get { return true; }
155 }
156 }
157} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Inventory/InventoryModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Inventory/InventoryModule.cs
new file mode 100644
index 0000000..42c6238
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Inventory/InventoryModule.cs
@@ -0,0 +1,216 @@
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.Collections.Generic;
29using System.Reflection;
30using libsecondlife;
31using log4net;
32using Nini.Config;
33using OpenSim.Framework;
34using OpenSim.Region.Environment.Interfaces;
35using OpenSim.Region.Environment.Scenes;
36
37namespace OpenSim.Region.Environment.Modules.Avatar.Inventory
38{
39 public class InventoryModule : IRegionModule
40 {
41 private static readonly ILog m_log
42 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private Scene m_scene;
45
46 /// <summary>
47 /// We need to keep track of the pending item offers between clients since the itemId offered only
48 /// occurs in the initial offer message, not the accept message. So this dictionary links
49 /// IM Session Ids to ItemIds
50 /// </summary>
51 private IDictionary<LLUUID, LLUUID> m_pendingOffers = new Dictionary<LLUUID, LLUUID>();
52
53 public void Initialise(Scene scene, IConfigSource config)
54 {
55 m_scene = scene;
56 scene.EventManager.OnNewClient += OnNewClient;
57 }
58
59 public void PostInitialise()
60 {
61 }
62
63 public void Close()
64 {
65 }
66
67 public string Name
68 {
69 get { return "InventoryModule"; }
70 }
71
72 public bool IsSharedModule
73 {
74 get { return false; }
75 }
76
77 private void OnNewClient(IClientAPI client)
78 {
79 // Inventory giving is conducted via instant message
80 client.OnInstantMessage += OnInstantMessage;
81 }
82
83 private void OnInstantMessage(IClientAPI client, LLUUID fromAgentID,
84 LLUUID fromAgentSession, LLUUID toAgentID,
85 LLUUID imSessionID, uint timestamp, string fromAgentName,
86 string message, byte dialog, bool fromGroup, byte offline,
87 uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
88 byte[] binaryBucket)
89 {
90 if (dialog == (byte)InstantMessageDialog.InventoryOffered)
91 {
92 m_log.DebugFormat(
93 "[AGENT INVENTORY]: Routing inventory offering message from {0}, {1} to {2}",
94 client.AgentId, client.Name, toAgentID);
95
96 if (m_scene.Entities.ContainsKey(toAgentID) && m_scene.Entities[toAgentID] is ScenePresence)
97 {
98 ScenePresence user = (ScenePresence)m_scene.Entities[toAgentID];
99
100 if (!user.IsChildAgent)
101 {
102 //byte[] rawId = new byte[16];
103
104 // First byte of the array is probably the item type
105 // Next 16 bytes are the UUID
106 //Array.Copy(binaryBucket, 1, rawId, 0, 16);
107
108 //LLUUID itemId = new LLUUID(new Guid(rawId));
109 LLUUID itemId = new LLUUID(binaryBucket, 1);
110
111 m_log.DebugFormat(
112 "[AGENT INVENTORY]: ItemId for giving is {0}", itemId);
113
114 m_pendingOffers[imSessionID] = itemId;
115
116 user.ControllingClient.SendInstantMessage(
117 fromAgentID, fromAgentSession, message, toAgentID, imSessionID, fromAgentName,
118 dialog, timestamp, binaryBucket);
119
120 return;
121 }
122 else
123 {
124 m_log.WarnFormat(
125 "[AGENT INVENTORY]: Agent {0} targeted for inventory give by {1}, {2} of {3} was a child agent!",
126 toAgentID, client.AgentId, client.Name, message);
127 }
128 }
129 else
130 {
131 m_log.WarnFormat(
132 "[AGENT INVENTORY]: Could not find agent {0} for user {1}, {2} to give {3}",
133 toAgentID, client.AgentId, client.Name, message);
134 }
135 }
136 else if (dialog == (byte)InstantMessageDialog.InventoryAccepted)
137 {
138 m_log.DebugFormat(
139 "[AGENT INVENTORY]: Routing inventory accepted message from {0}, {1} to {2}",
140 client.AgentId, client.Name, toAgentID);
141
142 if (m_scene.Entities.ContainsKey(toAgentID) && m_scene.Entities[toAgentID] is ScenePresence)
143 {
144 ScenePresence user = (ScenePresence)m_scene.Entities[toAgentID];
145
146 if (!user.IsChildAgent)
147 {
148 user.ControllingClient.SendInstantMessage(
149 fromAgentID, fromAgentSession, message, toAgentID, imSessionID, fromAgentName,
150 dialog, timestamp, binaryBucket);
151
152 if (m_pendingOffers.ContainsKey(imSessionID))
153 {
154 m_log.DebugFormat(
155 "[AGENT INVENTORY]: Accepted item id {0}", m_pendingOffers[imSessionID]);
156
157 // Since the message originates from the accepting client, the toAgentID is
158 // the agent giving the item.
159 m_scene.GiveInventoryItem(client, toAgentID, m_pendingOffers[imSessionID]);
160
161 m_pendingOffers.Remove(imSessionID);
162 }
163 else
164 {
165 m_log.ErrorFormat(
166 "[AGENT INVENTORY]: Could not find an item associated with session id {0} to accept",
167 imSessionID);
168 }
169
170 return;
171 }
172 else
173 {
174 m_log.WarnFormat(
175 "[AGENT INVENTORY]: Agent {0} targeted for inventory give by {1}, {2} of {3} was a child agent!",
176 toAgentID, client.AgentId, client.Name, message);
177 }
178 }
179 else
180 {
181 m_log.WarnFormat(
182 "[AGENT INVENTORY]: Could not find agent {0} for user {1}, {2} to give {3}",
183 toAgentID, client.AgentId, client.Name, message);
184 }
185 }
186 else if (dialog == (byte)InstantMessageDialog.InventoryDeclined)
187 {
188 if (m_scene.Entities.ContainsKey(toAgentID) && m_scene.Entities[toAgentID] is ScenePresence)
189 {
190 ScenePresence user = (ScenePresence)m_scene.Entities[toAgentID];
191
192 if (!user.IsChildAgent)
193 {
194 user.ControllingClient.SendInstantMessage(
195 fromAgentID, fromAgentSession, message, toAgentID, imSessionID, fromAgentName,
196 dialog, timestamp, binaryBucket);
197
198 if (m_pendingOffers.ContainsKey(imSessionID))
199 {
200 m_log.DebugFormat(
201 "[AGENT INVENTORY]: Declined item id {0}", m_pendingOffers[imSessionID]);
202
203 m_pendingOffers.Remove(imSessionID);
204 }
205 else
206 {
207 m_log.ErrorFormat(
208 "[AGENT INVENTORY]: Could not find an item associated with session id {0} to decline",
209 imSessionID);
210 }
211 }
212 }
213 }
214 }
215 }
216} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs
new file mode 100644
index 0000000..f8b14d3
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs
@@ -0,0 +1,129 @@
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.Reflection;
30using libsecondlife;
31using log4net;
32using Nini.Config;
33using OpenSim.Framework;
34using OpenSim.Region.Environment.Interfaces;
35using OpenSim.Region.Environment.Scenes;
36
37namespace OpenSim.Region.Environment.Modules.Avatar.Profiles
38{
39 public class AvatarProfilesModule : IRegionModule
40 {
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 private Scene m_scene;
43
44 public AvatarProfilesModule()
45 {
46 }
47
48 public void Initialise(Scene scene, IConfigSource config)
49 {
50 m_scene = scene;
51 m_scene.EventManager.OnNewClient += NewClient;
52 }
53
54 public void PostInitialise()
55 {
56 }
57
58 public void Close()
59 {
60 }
61
62 public string Name
63 {
64 get { return "AvatarProfilesModule"; }
65 }
66
67 public bool IsSharedModule
68 {
69 get { return false; }
70 }
71
72 public void NewClient(IClientAPI client)
73 {
74 client.OnRequestAvatarProperties += RequestAvatarProperty;
75 client.OnUpdateAvatarProperties += UpdateAvatarProperties;
76 }
77
78 public void RemoveClient(IClientAPI client)
79 {
80 client.OnRequestAvatarProperties -= RequestAvatarProperty;
81 client.OnUpdateAvatarProperties -= UpdateAvatarProperties;
82 }
83
84 /// <summary>
85 ///
86 /// </summary>
87 /// <param name="remoteClient"></param>
88 /// <param name="avatarID"></param>
89 public void RequestAvatarProperty(IClientAPI remoteClient, LLUUID avatarID)
90 {
91 // FIXME: finish adding fields such as url, masking, etc.
92 LLUUID partner = new LLUUID("11111111-1111-0000-0000-000100bba000");
93 UserProfileData profile = m_scene.CommsManager.UserService.GetUserProfile(avatarID);
94 if (null != profile)
95 {
96 remoteClient.SendAvatarProperties(profile.ID, profile.AboutText,
97 Util.ToDateTime(profile.Created).ToString(),
98 String.Empty, profile.FirstLifeAboutText, profile.CanDoMask,
99 profile.FirstLifeImage, profile.Image, String.Empty, partner);
100 }
101 else
102 {
103 m_log.Debug("[AvatarProfilesModule]: Got null for profile for " + avatarID.ToString());
104 }
105 }
106
107 public void UpdateAvatarProperties(IClientAPI remoteClient, UserProfileData newProfile)
108 {
109 UserProfileData Profile = m_scene.CommsManager.UserService.GetUserProfile(newProfile.ID);
110
111 // if it's the profile of the user requesting the update, then we change only a few things.
112 if (remoteClient.AgentId.CompareTo(Profile.ID) == 0)
113 {
114 Profile.Image = newProfile.Image;
115 Profile.FirstLifeImage = newProfile.FirstLifeImage;
116 Profile.AboutText = newProfile.AboutText;
117 Profile.FirstLifeAboutText = newProfile.FirstLifeAboutText;
118 }
119 else
120 {
121 return;
122 }
123 if (m_scene.CommsManager.UserService.UpdateUserProfileProperties(Profile))
124 {
125 RequestAvatarProperty(remoteClient, newProfile.ID);
126 }
127 }
128 }
129} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
new file mode 100644
index 0000000..0d7de78
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
@@ -0,0 +1,285 @@
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.Reflection;
31using libsecondlife;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications.Cache;
37using OpenSim.Framework.Servers;
38using OpenSim.Region.Capabilities;
39using OpenSim.Region.Environment.Interfaces;
40using OpenSim.Region.Environment.Scenes;
41using Caps=OpenSim.Region.Capabilities.Caps;
42
43namespace OpenSim.Region.Environment.Modules.Avatar.Voice.AsterixVoice
44{
45 public class AsteriskVoiceModule : IRegionModule
46 {
47 private static readonly ILog m_log =
48 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private Scene m_scene;
51 private IConfig m_config;
52 private string m_asterisk;
53 private string m_asterisk_password;
54 private string m_asterisk_salt;
55 private int m_asterisk_timeout;
56 private string m_sipDomain;
57 private string m_confDomain;
58
59 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
60 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
61
62 public void Initialise(Scene scene, IConfigSource config)
63 {
64 m_scene = scene;
65 m_config = config.Configs["AsteriskVoice"];
66
67 if (null == m_config)
68 {
69 m_log.Info("[ASTERISKVOICE] no config found, plugin disabled");
70 return;
71 }
72
73 if (!m_config.GetBoolean("enabled", false))
74 {
75 m_log.Info("[ASTERISKVOICE] plugin disabled by configuration");
76 return;
77 }
78 m_log.Info("[ASTERISKVOICE] plugin enabled");
79
80 try {
81 m_sipDomain = m_config.GetString("sip_domain", String.Empty);
82 m_log.InfoFormat("[ASTERISKVOICE] using SIP domain {0}", m_sipDomain);
83
84 m_confDomain = m_config.GetString("conf_domain", String.Empty);
85 m_log.InfoFormat("[ASTERISKVOICE] using conf domain {0}", m_confDomain);
86
87 m_asterisk = m_config.GetString("asterisk_frontend", String.Empty);
88 m_asterisk_password = m_config.GetString("asterisk_password", String.Empty);
89 m_asterisk_timeout = m_config.GetInt("asterisk_timeout", 3000);
90 m_asterisk_salt = m_config.GetString("asterisk_salt", "Wuffwuff");
91 if (String.IsNullOrEmpty(m_asterisk)) throw new Exception("missing asterisk_frontend config parameter");
92 if (String.IsNullOrEmpty(m_asterisk_password)) throw new Exception("missing asterisk_password config parameter");
93 m_log.InfoFormat("[ASTERISKVOICE] using asterisk front end {0}", m_asterisk);
94
95 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
96 }
97 catch (Exception e)
98 {
99 m_log.ErrorFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.Message);
100 m_log.DebugFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.ToString());
101 return;
102 }
103 }
104
105 public void PostInitialise()
106 {
107 }
108
109 public void Close()
110 {
111 }
112
113 public string Name
114 {
115 get { return "AsteriskVoiceModule"; }
116 }
117
118 public bool IsSharedModule
119 {
120 get { return false; }
121 }
122
123 public void OnRegisterCaps(LLUUID agentID, Caps caps)
124 {
125 m_log.DebugFormat("[ASTERISKVOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
126 string capsBase = "/CAPS/" + caps.CapsObjectPath;
127 caps.RegisterHandler("ParcelVoiceInfoRequest",
128 new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath,
129 delegate(string request, string path, string param)
130 {
131 return ParcelVoiceInfoRequest(request, path, param,
132 agentID, caps);
133 }));
134 caps.RegisterHandler("ProvisionVoiceAccountRequest",
135 new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath,
136 delegate(string request, string path, string param)
137 {
138 return ProvisionVoiceAccountRequest(request, path, param,
139 agentID, caps);
140 }));
141 }
142
143 /// <summary>
144 /// Callback for a client request for ParcelVoiceInfo
145 /// </summary>
146 /// <param name="request"></param>
147 /// <param name="path"></param>
148 /// <param name="param"></param>
149 /// <param name="agentID"></param>
150 /// <param name="caps"></param>
151 /// <returns></returns>
152 public string ParcelVoiceInfoRequest(string request, string path, string param,
153 LLUUID agentID, Caps caps)
154 {
155 // we need to do:
156 // - send channel_uri: as "sip:regionID@m_sipDomain"
157 try
158 {
159 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}",
160 request, path, param);
161
162
163 // setup response to client
164 Hashtable creds = new Hashtable();
165 creds["channel_uri"] = String.Format("sip:{0}@{1}",
166 m_scene.RegionInfo.RegionID, m_sipDomain);
167
168 string regionName = m_scene.RegionInfo.RegionName;
169 ScenePresence avatar = m_scene.GetScenePresence(agentID);
170 if (null == m_scene.LandChannel) throw new Exception("land data not yet available");
171 LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
172
173 LLSDParcelVoiceInfoResponse parcelVoiceInfo =
174 new LLSDParcelVoiceInfoResponse(regionName, land.localID, creds);
175
176 string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
177
178
179 // update region on asterisk-opensim frontend
180 Hashtable requestData = new Hashtable();
181 requestData["admin_password"] = m_asterisk_password;
182 requestData["region"] = m_scene.RegionInfo.RegionID.ToString();
183 if (!String.IsNullOrEmpty(m_confDomain))
184 {
185 requestData["region"] += String.Format("@{0}", m_confDomain);
186 }
187
188 ArrayList SendParams = new ArrayList();
189 SendParams.Add(requestData);
190 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("region_update", SendParams);
191 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
192 Hashtable responseData = (Hashtable)updateAccountResponse.Value;
193
194 if (!responseData.ContainsKey("success")) throw new Exception("region_update call failed");
195
196 bool success = Convert.ToBoolean((string)responseData["success"]);
197 if (!success) throw new Exception("region_update failed");
198
199
200 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: {0}", r);
201 return r;
202 }
203 catch (Exception e)
204 {
205 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0}, retry later", e.Message);
206 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0} failed", e.ToString());
207
208 return "<llsd>undef</llsd>";
209 }
210 }
211
212 /// <summary>
213 /// Callback for a client request for Voice Account Details
214 /// </summary>
215 /// <param name="request"></param>
216 /// <param name="path"></param>
217 /// <param name="param"></param>
218 /// <param name="agentID"></param>
219 /// <param name="caps"></param>
220 /// <returns></returns>
221 public string ProvisionVoiceAccountRequest(string request, string path, string param,
222 LLUUID agentID, Caps caps)
223 {
224 // we need to
225 // - get user data from UserProfileCacheService
226 // - generate nonce for user voice account password
227 // - issue XmlRpc request to asterisk opensim front end:
228 // + user: base 64 encoded user name (otherwise SL
229 // client is unhappy)
230 // + password: nonce
231 // - the XmlRpc call to asteris-opensim was successful:
232 // send account details back to client
233 try
234 {
235 m_log.DebugFormat("[ASTERISKVOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
236 request, path, param);
237
238 // get user data & prepare voice account response
239 string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes());
240 voiceUser = voiceUser.Replace('+', '-').Replace('/', '_');
241
242 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
243 if (null == userInfo) throw new Exception("cannot get user details");
244
245 // we generate a nonce everytime
246 string voicePassword = "$1$" + Util.Md5Hash(DateTime.UtcNow.ToLongTimeString() + m_asterisk_salt);
247 LLSDVoiceAccountResponse voiceAccountResponse =
248 new LLSDVoiceAccountResponse(voiceUser, voicePassword);
249 string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
250 m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r);
251
252
253 // update user account on asterisk frontend
254 Hashtable requestData = new Hashtable();
255 requestData["admin_password"] = m_asterisk_password;
256 requestData["username"] = voiceUser;
257 if (!String.IsNullOrEmpty(m_sipDomain))
258 {
259 requestData["username"] += String.Format("@{0}", m_sipDomain);
260 }
261 requestData["password"] = voicePassword;
262
263 ArrayList SendParams = new ArrayList();
264 SendParams.Add(requestData);
265 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("account_update", SendParams);
266 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
267 Hashtable responseData = (Hashtable)updateAccountResponse.Value;
268
269 if (!responseData.ContainsKey("success")) throw new Exception("account_update call failed");
270
271 bool success = Convert.ToBoolean((string)responseData["success"]);
272 if (!success) throw new Exception("account_update failed");
273
274 return r;
275 }
276 catch (Exception e)
277 {
278 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0}, retry later", e.Message);
279 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0} failed", e.ToString());
280
281 return "<llsd>undef</llsd>";
282 }
283 }
284 }
285} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs
new file mode 100644
index 0000000..8b7c3d0
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs
@@ -0,0 +1,197 @@
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.Reflection;
31using libsecondlife;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Framework.Servers;
37using OpenSim.Region.Capabilities;
38using OpenSim.Region.Environment.Interfaces;
39using OpenSim.Region.Environment.Scenes;
40using Caps=OpenSim.Region.Capabilities.Caps;
41
42namespace OpenSim.Region.Environment.Modules.Avatar.Voice.SIPVoice
43{
44 public class SIPVoiceModule : IRegionModule
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private Scene m_scene;
50 private IConfig m_config;
51 private string m_sipDomain;
52
53 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
54 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
55
56 public void Initialise(Scene scene, IConfigSource config)
57 {
58 m_scene = scene;
59 m_config = config.Configs["Voice"];
60
61 if (null == m_config || !m_config.GetBoolean("enabled", false))
62 {
63 m_log.Info("[VOICE] plugin disabled");
64 return;
65 }
66 m_log.Info("[VOICE] plugin enabled");
67
68 m_sipDomain = m_config.GetString("sip_domain", String.Empty);
69 if (String.IsNullOrEmpty(m_sipDomain))
70 {
71 m_log.Error("[VOICE] plugin mis-configured: missing sip_domain configuration");
72 m_log.Info("[VOICE] plugin disabled");
73 return;
74 }
75 m_log.InfoFormat("[VOICE] using SIP domain {0}", m_sipDomain);
76
77 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
78 }
79
80 public void PostInitialise()
81 {
82 }
83
84 public void Close()
85 {
86 }
87
88 public string Name
89 {
90 get { return "VoiceModule"; }
91 }
92
93 public bool IsSharedModule
94 {
95 get { return false; }
96 }
97
98 public void OnRegisterCaps(LLUUID agentID, Caps caps)
99 {
100 m_log.DebugFormat("[VOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
101 string capsBase = "/CAPS/" + caps.CapsObjectPath;
102 caps.RegisterHandler("ParcelVoiceInfoRequest",
103 new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath,
104 delegate(string request, string path, string param)
105 {
106 return ParcelVoiceInfoRequest(request, path, param,
107 agentID, caps);
108 }));
109 caps.RegisterHandler("ProvisionVoiceAccountRequest",
110 new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath,
111 delegate(string request, string path, string param)
112 {
113 return ProvisionVoiceAccountRequest(request, path, param,
114 agentID, caps);
115 }));
116 }
117
118 /// <summary>
119 /// Callback for a client request for ParcelVoiceInfo
120 /// </summary>
121 /// <param name="request"></param>
122 /// <param name="path"></param>
123 /// <param name="param"></param>
124 /// <param name="agentID"></param>
125 /// <param name="caps"></param>
126 /// <returns></returns>
127 public string ParcelVoiceInfoRequest(string request, string path, string param,
128 LLUUID agentID, Caps caps)
129 {
130 try
131 {
132 m_log.DebugFormat("[VOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}", request, path, param);
133
134 // FIXME: get the creds from region file or from config
135 Hashtable creds = new Hashtable();
136
137 creds["channel_uri"] = String.Format("sip:{0}@{1}", agentID, m_sipDomain);
138
139 string regionName = m_scene.RegionInfo.RegionName;
140 ScenePresence avatar = m_scene.GetScenePresence(agentID);
141 if (null == m_scene.LandChannel) throw new Exception("land data not yet available");
142 LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
143
144 LLSDParcelVoiceInfoResponse parcelVoiceInfo =
145 new LLSDParcelVoiceInfoResponse(regionName, land.localID, creds);
146
147 string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
148 m_log.DebugFormat("[VOICE][PARCELVOICE]: {0}", r);
149
150 return r;
151 }
152 catch (Exception e)
153 {
154 m_log.ErrorFormat("[CAPS]: {0}, try again later", e.ToString());
155 }
156
157 return null;
158 }
159
160 /// <summary>
161 /// Callback for a client request for Voice Account Details
162 /// </summary>
163 /// <param name="request"></param>
164 /// <param name="path"></param>
165 /// <param name="param"></param>
166 /// <param name="agentID"></param>
167 /// <param name="caps"></param>
168 /// <returns></returns>
169 public string ProvisionVoiceAccountRequest(string request, string path, string param,
170 LLUUID agentID, Caps caps)
171 {
172 try
173 {
174 m_log.DebugFormat("[VOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
175 request, path, param);
176
177 string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes());
178 voiceUser = voiceUser.Replace('+', '-').Replace('/', '_');
179
180 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
181 if (null == userInfo) throw new Exception("cannot get user details");
182
183 LLSDVoiceAccountResponse voiceAccountResponse =
184 new LLSDVoiceAccountResponse(voiceUser, "$1$" + userInfo.UserProfile.PasswordHash);
185 string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
186 m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r);
187 return r;
188 }
189 catch (Exception e)
190 {
191 m_log.ErrorFormat("[CAPS][PROVISIONVOICE]: {0}, retry later", e.Message);
192 }
193
194 return null;
195 }
196 }
197} \ No newline at end of file