aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar
diff options
context:
space:
mode:
authorDr Scofield2009-02-10 13:10:57 +0000
committerDr Scofield2009-02-10 13:10:57 +0000
commit180be7de07014aa33bc6066f12a0819b731c1c9d (patch)
tree3aa13af3cda4b808fa9453655875327699b61311 /OpenSim/Region/CoreModules/Avatar
parentStopgap measure: To use gridlaunch, or GUI, start opensim with (diff)
downloadopensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.zip
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.gz
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.bz2
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.xz
this is step 2 of 2 of the OpenSim.Region.Environment refactor.
NOTHING has been deleted or moved off to forge at this point. what has happened is that OpenSim.Region.Environment.Modules has been split in two: - OpenSim.Region.CoreModules: all those modules that are either directly or indirectly referenced from other OpenSim packages, or that provide functionality that the OpenSim developer community considers core functionality: CoreModules/Agent/AssetTransaction CoreModules/Agent/Capabilities CoreModules/Agent/TextureDownload CoreModules/Agent/TextureSender CoreModules/Agent/TextureSender/Tests CoreModules/Agent/Xfer CoreModules/Avatar/AvatarFactory CoreModules/Avatar/Chat/ChatModule CoreModules/Avatar/Combat CoreModules/Avatar/Currency/SampleMoney CoreModules/Avatar/Dialog CoreModules/Avatar/Friends CoreModules/Avatar/Gestures CoreModules/Avatar/Groups CoreModules/Avatar/InstantMessage CoreModules/Avatar/Inventory CoreModules/Avatar/Inventory/Archiver CoreModules/Avatar/Inventory/Transfer CoreModules/Avatar/Lure CoreModules/Avatar/ObjectCaps CoreModules/Avatar/Profiles CoreModules/Communications/Local CoreModules/Communications/REST CoreModules/Framework/EventQueue CoreModules/Framework/InterfaceCommander CoreModules/Hypergrid CoreModules/InterGrid CoreModules/Scripting/DynamicTexture CoreModules/Scripting/EMailModules CoreModules/Scripting/HttpRequest CoreModules/Scripting/LoadImageURL CoreModules/Scripting/VectorRender CoreModules/Scripting/WorldComm CoreModules/Scripting/XMLRPC CoreModules/World/Archiver CoreModules/World/Archiver/Tests CoreModules/World/Estate CoreModules/World/Land CoreModules/World/Permissions CoreModules/World/Serialiser CoreModules/World/Sound CoreModules/World/Sun CoreModules/World/Terrain CoreModules/World/Terrain/DefaultEffects CoreModules/World/Terrain/DefaultEffects/bin CoreModules/World/Terrain/DefaultEffects/bin/Debug CoreModules/World/Terrain/Effects CoreModules/World/Terrain/FileLoaders CoreModules/World/Terrain/FloodBrushes CoreModules/World/Terrain/PaintBrushes CoreModules/World/Terrain/Tests CoreModules/World/Vegetation CoreModules/World/Wind CoreModules/World/WorldMap - OpenSim.Region.OptionalModules: all those modules that are not core modules: OptionalModules/Avatar/Chat/IRC-stuff OptionalModules/Avatar/Concierge OptionalModules/Avatar/Voice/AsterixVoice OptionalModules/Avatar/Voice/SIPVoice OptionalModules/ContentManagementSystem OptionalModules/Grid/Interregion OptionalModules/Python OptionalModules/SvnSerialiser OptionalModules/World/NPC OptionalModules/World/TreePopulator
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs232
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs287
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs154
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs1605
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs143
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs1003
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs104
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs223
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs170
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs655
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs426
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs279
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs247
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs389
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs176
-rw-r--r--OpenSim/Region/CoreModules/Avatar/ObjectCaps/ObjectAdd.cs368
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Profiles/AvatarProfilesModule.cs145
17 files changed, 6606 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
new file mode 100644
index 0000000..d084dbd
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -0,0 +1,232 @@
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;
31
32using System.Threading;
33using OpenMetaverse;
34using log4net;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Framework.Communications.Cache;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40
41namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
42{
43 public class AvatarFactoryModule : IAvatarFactory, IRegionModule
44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 private Scene m_scene = null;
47 private static readonly AvatarAppearance def = new AvatarAppearance();
48
49 public bool TryGetAvatarAppearance(UUID avatarId, out AvatarAppearance appearance)
50 {
51 CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(avatarId);
52 //if ((profile != null) && (profile.RootFolder != null))
53 if (profile != null)
54 {
55 appearance = m_scene.CommsManager.AvatarService.GetUserAppearance(avatarId);
56 if (appearance != null)
57 {
58 //SetAppearanceAssets(profile, ref appearance);
59 //m_log.DebugFormat("[APPEARANCE]: Found : {0}", appearance.ToString());
60 return true;
61 }
62 }
63
64 appearance = CreateDefault(avatarId);
65 m_log.ErrorFormat("[APPEARANCE]: Appearance not found for {0}, creating default", avatarId);
66 return false;
67 }
68
69 private AvatarAppearance CreateDefault(UUID avatarId)
70 {
71 AvatarAppearance appearance = null;
72 AvatarWearable[] wearables;
73 byte[] visualParams;
74 GetDefaultAvatarAppearance(out wearables, out visualParams);
75 appearance = new AvatarAppearance(avatarId, wearables, visualParams);
76
77 return appearance;
78 }
79
80 public void Initialise(Scene scene, IConfigSource source)
81 {
82 scene.RegisterModuleInterface<IAvatarFactory>(this);
83 scene.EventManager.OnNewClient += NewClient;
84
85 if (m_scene == null)
86 {
87 m_scene = scene;
88 }
89
90 }
91
92 public void PostInitialise()
93 {
94 }
95
96 public void Close()
97 {
98 }
99
100 public string Name
101 {
102 get { return "Default Avatar Factory"; }
103 }
104
105 public bool IsSharedModule
106 {
107 get { return false; }
108 }
109
110 public void NewClient(IClientAPI client)
111 {
112 client.OnAvatarNowWearing += AvatarIsWearing;
113 }
114
115 public void RemoveClient(IClientAPI client)
116 {
117 // client.OnAvatarNowWearing -= AvatarIsWearing;
118 }
119
120
121 public void SetAppearanceAssets(CachedUserInfo profile, ref AvatarAppearance appearance)
122 {
123 if (profile.RootFolder != null)
124 {
125 for (int i = 0; i < 13; i++)
126 {
127 if (appearance.Wearables[i].ItemID == UUID.Zero)
128 {
129 appearance.Wearables[i].AssetID = UUID.Zero;
130 }
131 else
132 {
133 InventoryItemBase baseItem = profile.RootFolder.FindItem(appearance.Wearables[i].ItemID);
134
135 if (baseItem != null)
136 {
137 appearance.Wearables[i].AssetID = baseItem.AssetID;
138 }
139 else
140 {
141 m_log.ErrorFormat("[APPEARANCE]: Can't find inventory item {0}, setting to default", appearance.Wearables[i].ItemID);
142 appearance.Wearables[i].AssetID = def.Wearables[i].AssetID;
143 }
144 }
145 }
146 }
147 else
148 {
149 m_log.Error("[APPEARANCE]: you have no inventory, appearance stuff isn't going to work");
150 }
151 }
152
153 /// <summary>
154 /// Update what the avatar is wearing using an item from their inventory.
155 /// </summary>
156 /// <param name="sender"></param>
157 /// <param name="e"></param>
158 public void AvatarIsWearing(Object sender, AvatarWearingArgs e)
159 {
160 IClientAPI clientView = (IClientAPI)sender;
161 ScenePresence avatar = m_scene.GetScenePresence(clientView.AgentId);
162
163 if (avatar == null)
164 {
165 m_log.Error("[APPEARANCE]: Avatar is child agent, ignoring AvatarIsWearing event");
166 return;
167 }
168
169 CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(clientView.AgentId);
170
171 AvatarAppearance avatAppearance = null;
172 if (!TryGetAvatarAppearance(clientView.AgentId, out avatAppearance))
173 {
174 m_log.Warn("[APPEARANCE]: We didn't seem to find the appearance, falling back to ScenePresence");
175 avatAppearance = avatar.Appearance;
176 }
177
178 //m_log.DebugFormat("[APPEARANCE]: Received wearables for {0}", clientView.Name);
179
180 if (profile != null)
181 {
182 if (profile.RootFolder != null)
183 {
184 foreach (AvatarWearingArgs.Wearable wear in e.NowWearing)
185 {
186 if (wear.Type < 13)
187 {
188 avatAppearance.Wearables[wear.Type].ItemID = wear.ItemID;
189 }
190 }
191
192 SetAppearanceAssets(profile, ref avatAppearance);
193
194 m_scene.CommsManager.AvatarService.UpdateUserAppearance(clientView.AgentId, avatAppearance);
195 avatar.Appearance = avatAppearance;
196 }
197 else
198 {
199 m_log.WarnFormat(
200 "[APPEARANCE]: Inventory has not yet been received for {0}, cannot set wearables",
201 clientView.Name);
202 }
203 }
204 else
205 {
206 m_log.WarnFormat("[APPEARANCE]: Cannot set wearables for {0}, no user profile found", clientView.Name);
207 }
208 }
209
210 public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams)
211 {
212 visualParams = GetDefaultVisualParams();
213 wearables = AvatarWearable.DefaultWearables;
214 }
215
216 public void UpdateDatabase(UUID user, AvatarAppearance appearance)
217 {
218 m_scene.CommsManager.AvatarService.UpdateUserAppearance(user, appearance);
219 }
220
221 private static byte[] GetDefaultVisualParams()
222 {
223 byte[] visualParams;
224 visualParams = new byte[218];
225 for (int i = 0; i < 218; i++)
226 {
227 visualParams[i] = 100;
228 }
229 return visualParams;
230 }
231 }
232}
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
new file mode 100644
index 0000000..f036faf
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -0,0 +1,287 @@
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 OpenMetaverse;
36using log4net;
37using Nini.Config;
38using OpenSim.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Avatar.Chat
43{
44 public class ChatModule : IRegionModule
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private const int DEBUG_CHANNEL = 2147483647;
50
51 private bool m_enabled = true;
52 private int m_saydistance = 30;
53 private int m_shoutdistance = 100;
54 private int m_whisperdistance = 10;
55 private List<Scene> m_scenes = new List<Scene>();
56
57 internal object m_syncInit = new object();
58
59 #region IRegionModule Members
60 public virtual void Initialise(Scene scene, IConfigSource config)
61 {
62 // wrap this in a try block so that defaults will work if
63 // the config file doesn't specify otherwise.
64 try
65 {
66 m_enabled = config.Configs["Chat"].GetBoolean("enabled", m_enabled);
67 if (!m_enabled) return;
68
69 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
70 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance);
71 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance);
72 }
73 catch (Exception)
74 {
75 }
76
77 lock (m_syncInit)
78 {
79 if (!m_scenes.Contains(scene))
80 {
81 m_scenes.Add(scene);
82 scene.EventManager.OnNewClient += OnNewClient;
83 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
84 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
85 }
86 }
87
88 m_log.InfoFormat("[CHAT] initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName,
89 m_whisperdistance, m_saydistance, m_shoutdistance);
90 }
91 public virtual void PostInitialise()
92 {
93 }
94
95 public virtual void Close()
96 {
97 }
98
99 public virtual string Name
100 {
101 get { return "ChatModule"; }
102 }
103
104 public virtual bool IsSharedModule
105 {
106 get { return true; }
107 }
108
109 #endregion
110
111
112 public virtual void OnNewClient(IClientAPI client)
113 {
114 client.OnChatFromClient += OnChatFromClient;
115 }
116
117 protected OSChatMessage FixPositionOfChatMessage(OSChatMessage c)
118 {
119 ScenePresence avatar;
120 Scene scene = (Scene)c.Scene;
121 if ((avatar = scene.GetScenePresence(c.Sender.AgentId)) != null)
122 c.Position = avatar.AbsolutePosition;
123
124 return c;
125 }
126
127 public virtual void OnChatFromClient(Object sender, OSChatMessage c)
128 {
129 c = FixPositionOfChatMessage(c);
130
131 // redistribute to interested subscribers
132 Scene scene = (Scene)c.Scene;
133 scene.EventManager.TriggerOnChatFromClient(sender, c);
134
135 // early return if not on public or debug channel
136 if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL) return;
137
138 // sanity check:
139 if (c.Sender == null)
140 {
141 m_log.ErrorFormat("[CHAT] OnChatFromClient from {0} has empty Sender field!", sender);
142 return;
143 }
144
145 DeliverChatToAvatars(ChatSourceType.Agent, c);
146 }
147
148 public virtual void OnChatFromWorld(Object sender, OSChatMessage c)
149 {
150 // early return if not on public or debug channel
151 if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL) return;
152
153 DeliverChatToAvatars(ChatSourceType.Object, c);
154 }
155
156 protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c)
157 {
158 string fromName = c.From;
159 UUID fromID = UUID.Zero;
160 string message = c.Message;
161 IScene scene = c.Scene;
162 Vector3 fromPos = c.Position;
163 Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize,
164 scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
165
166 if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel;
167
168 switch (sourceType)
169 {
170 case ChatSourceType.Agent:
171 if (!(scene is Scene))
172 {
173 m_log.WarnFormat("[CHAT]: scene {0} is not a Scene object, cannot obtain scene presence for {1}",
174 scene.RegionInfo.RegionName, c.Sender.AgentId);
175 return;
176 }
177 ScenePresence avatar = (scene as Scene).GetScenePresence(c.Sender.AgentId);
178 fromPos = avatar.AbsolutePosition;
179 fromName = avatar.Name;
180 fromID = c.Sender.AgentId;
181
182 break;
183
184 case ChatSourceType.Object:
185 fromID = c.SenderUUID;
186
187 break;
188 }
189
190 // TODO: iterate over message
191 if (message.Length >= 1000) // libomv limit
192 message = message.Substring(0, 1000);
193
194 // m_log.DebugFormat("[CHAT]: DCTA: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, c.Type, sourceType);
195
196 foreach (Scene s in m_scenes)
197 {
198 s.ForEachScenePresence(delegate(ScenePresence presence)
199 {
200 TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName,
201 c.Type, message, sourceType);
202 });
203 }
204 }
205
206
207 static private Vector3 CenterOfRegion = new Vector3(128, 128, 30);
208 public virtual void OnChatBroadcast(Object sender, OSChatMessage c)
209 {
210 // unless the chat to be broadcast is of type Region, we
211 // drop it if its channel is neither 0 nor DEBUG_CHANNEL
212 if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL && c.Type != ChatTypeEnum.Region) return;
213
214 ChatTypeEnum cType = c.Type;
215 if (c.Channel == DEBUG_CHANNEL)
216 cType = ChatTypeEnum.DebugChannel;
217
218 if (cType == ChatTypeEnum.Region)
219 cType = ChatTypeEnum.Say;
220
221 if (c.Message.Length > 1100)
222 c.Message = c.Message.Substring(0, 1000);
223
224 // broadcast chat works by redistributing every incoming chat
225 // message to each avatar in the scene.
226 string fromName = c.From;
227
228 UUID fromID = UUID.Zero;
229 ChatSourceType sourceType = ChatSourceType.Object;
230 if (null != c.Sender)
231 {
232 ScenePresence avatar = (c.Scene as Scene).GetScenePresence(c.Sender.AgentId);
233 fromID = c.Sender.AgentId;
234 fromName = avatar.Name;
235 sourceType = ChatSourceType.Agent;
236 }
237
238 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType);
239
240 ((Scene)c.Scene).ForEachScenePresence(
241 delegate(ScenePresence presence)
242 {
243 // ignore chat from child agents
244 if (presence.IsChildAgent) return;
245
246 IClientAPI client = presence.ControllingClient;
247
248 // don't forward SayOwner chat from objects to
249 // non-owner agents
250 if ((c.Type == ChatTypeEnum.Owner) &&
251 (null != c.SenderObject) &&
252 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
253 return;
254
255 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID,
256 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
257 });
258 }
259
260
261 protected virtual void TrySendChatMessage(ScenePresence presence, Vector3 fromPos, Vector3 regionPos,
262 UUID fromAgentID, string fromName, ChatTypeEnum type,
263 string message, ChatSourceType src)
264 {
265 // don't send stuff to child agents
266 if (presence.IsChildAgent) return;
267
268 Vector3 fromRegionPos = fromPos + regionPos;
269 Vector3 toRegionPos = presence.AbsolutePosition +
270 new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize,
271 presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
272
273 int dis = Math.Abs((int) Util.GetDistanceTo(toRegionPos, fromRegionPos));
274
275 if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance ||
276 type == ChatTypeEnum.Say && dis > m_saydistance ||
277 type == ChatTypeEnum.Shout && dis > m_shoutdistance)
278 {
279 return;
280 }
281
282 // TODO: should change so the message is sent through the avatar rather than direct to the ClientView
283 presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName,
284 fromAgentID,(byte)src,(byte)ChatAudibleLevel.Fully);
285 }
286 }
287}
diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
new file mode 100644
index 0000000..1ed608a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
@@ -0,0 +1,154 @@
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 OpenMetaverse;
36using log4net;
37using Nini.Config;
38using Nwc.XmlRpc;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Framework.Communications.Cache;
43
44namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule
45{
46 public class CombatModule : IRegionModule
47 {
48 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 /// <summary>
51 /// Region UUIDS indexed by AgentID
52 /// </summary>
53 //private Dictionary<UUID, UUID> m_rootAgents = new Dictionary<UUID, UUID>();
54
55 /// <summary>
56 /// Scenes by Region Handle
57 /// </summary>
58 private Dictionary<ulong, Scene> m_scenel = new Dictionary<ulong, Scene>();
59
60 /// <summary>
61 /// Startup
62 /// </summary>
63 /// <param name="scene"></param>
64 /// <param name="config"></param>
65 public void Initialise(Scene scene, IConfigSource config)
66 {
67 lock (m_scenel)
68 {
69 if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle))
70 {
71 m_scenel[scene.RegionInfo.RegionHandle] = scene;
72 }
73 else
74 {
75 m_scenel.Add(scene.RegionInfo.RegionHandle, scene);
76 }
77 }
78
79 scene.EventManager.OnAvatarKilled += KillAvatar;
80 }
81
82 public void PostInitialise()
83 {
84 }
85
86 public void Close()
87 {
88 }
89
90 public string Name
91 {
92 get { return "CombatModule"; }
93 }
94
95 public bool IsSharedModule
96 {
97 get { return true; }
98 }
99
100 private void KillAvatar(uint killerObjectLocalID, ScenePresence DeadAvatar)
101 {
102 if (killerObjectLocalID == 0)
103 DeadAvatar.ControllingClient.SendAgentAlertMessage("You committed suicide!", true);
104 else
105 {
106 bool foundResult = false;
107 string resultstring = "";
108 List<ScenePresence> allav = DeadAvatar.Scene.GetScenePresences();
109 try
110 {
111 foreach (ScenePresence av in allav)
112 {
113 if (av.LocalId == killerObjectLocalID)
114 {
115 av.ControllingClient.SendAlertMessage("You fragged " + DeadAvatar.Firstname + " " + DeadAvatar.Lastname);
116 resultstring = av.Firstname + " " + av.Lastname;
117 foundResult = true;
118 }
119 }
120 } catch (System.InvalidOperationException)
121 {
122
123 }
124
125 if (!foundResult)
126 {
127 SceneObjectPart part = DeadAvatar.Scene.GetSceneObjectPart(killerObjectLocalID);
128 if (part != null)
129 {
130 ScenePresence av = DeadAvatar.Scene.GetScenePresence(part.OwnerID);
131 if (av != null)
132 {
133 av.ControllingClient.SendAlertMessage("You fragged " + DeadAvatar.Firstname + " " + DeadAvatar.Lastname);
134 resultstring = av.Firstname + " " + av.Lastname;
135 DeadAvatar.ControllingClient.SendAgentAlertMessage("You got killed by " + resultstring + "!", true);
136 }
137 else
138 {
139 string killer = DeadAvatar.Scene.CommsManager.UUIDNameRequestString(part.OwnerID);
140 DeadAvatar.ControllingClient.SendAgentAlertMessage("You impaled yourself on " + part.Name + " owned by " + killer +"!", true);
141 }
142 //DeadAvatar.Scene. part.ObjectOwner
143 }
144 else
145 {
146 DeadAvatar.ControllingClient.SendAgentAlertMessage("You died!", true);
147 }
148 }
149 }
150 DeadAvatar.Health = 100;
151 DeadAvatar.Scene.TeleportClientHome(DeadAvatar.UUID, DeadAvatar.ControllingClient);
152 }
153 }
154}
diff --git a/OpenSim/Region/CoreModules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs b/OpenSim/Region/CoreModules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs
new file mode 100644
index 0000000..0a1de44
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs
@@ -0,0 +1,1605 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Net.Sockets;
33using System.Reflection;
34using System.Xml;
35using log4net;
36using Nini.Config;
37using Nwc.XmlRpc;
38using OpenMetaverse;
39using OpenSim.Framework;
40using OpenSim.Framework.Communications.Cache;
41using OpenSim.Framework.Servers;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44
45namespace OpenSim.Region.CoreModules.Avatar.Currency.SampleMoney
46{
47 /// <summary>
48 /// Demo Economy/Money Module. This is not a production quality money/economy module!
49 /// This is a demo for you to use when making one that works for you.
50 /// // To use the following you need to add:
51 /// -helperuri <ADDRESS TO HERE OR grid MONEY SERVER>
52 /// to the command line parameters you use to start up your client
53 /// This commonly looks like -helperuri http://127.0.0.1:9000/
54 ///
55 /// Centralized grid structure example using OpenSimWi Redux revision 9+
56 /// svn co https://opensimwiredux.svn.sourceforge.net/svnroot/opensimwiredux
57 /// </summary>
58 public class SampleMoneyModule : IMoneyModule, IRegionModule
59 {
60 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61
62 /// <summary>
63 /// Where Stipends come from and Fees go to.
64 /// </summary>
65 // private UUID EconomyBaseAccount = UUID.Zero;
66
67 private float EnergyEfficiency = 0f;
68 private bool gridmode = false;
69 // private ObjectPaid handerOnObjectPaid;
70 private bool m_enabled = true;
71
72 private IConfigSource m_gConfig;
73
74 private bool m_keepMoneyAcrossLogins = true;
75 private Dictionary<UUID, int> m_KnownClientFunds = new Dictionary<UUID, int>();
76 // private string m_LandAddress = String.Empty;
77
78 private int m_minFundsBeforeRefresh = 100;
79 private string m_MoneyAddress = String.Empty;
80
81 /// <summary>
82 /// Region UUIDS indexed by AgentID
83 /// </summary>
84 private Dictionary<UUID, UUID> m_rootAgents = new Dictionary<UUID, UUID>();
85
86 /// <summary>
87 /// Scenes by Region Handle
88 /// </summary>
89 private Dictionary<ulong, Scene> m_scenel = new Dictionary<ulong, Scene>();
90
91 private int m_stipend = 1000;
92
93 private int ObjectCapacity = 45000;
94 private int ObjectCount = 0;
95 private int PriceEnergyUnit = 0;
96 private int PriceGroupCreate = 0;
97 private int PriceObjectClaim = 0;
98 private float PriceObjectRent = 0f;
99 private float PriceObjectScaleFactor = 0f;
100 private int PriceParcelClaim = 0;
101 private float PriceParcelClaimFactor = 0f;
102 private int PriceParcelRent = 0;
103 private int PricePublicObjectDecay = 0;
104 private int PricePublicObjectDelete = 0;
105 private int PriceRentLight = 0;
106 private int PriceUpload = 0;
107 private int TeleportMinPrice = 0;
108
109 private float TeleportPriceExponent = 0f;
110 // private int UserLevelPaysFees = 2;
111 // private Scene XMLRPCHandler;
112
113 #region IMoneyModule Members
114
115 public event ObjectPaid OnObjectPaid;
116
117 /// <summary>
118 /// Startup
119 /// </summary>
120 /// <param name="scene"></param>
121 /// <param name="config"></param>
122 public void Initialise(Scene scene, IConfigSource config)
123 {
124 m_gConfig = config;
125
126 IConfig startupConfig = m_gConfig.Configs["Startup"];
127 IConfig economyConfig = m_gConfig.Configs["Economy"];
128
129
130 ReadConfigAndPopulate(scene, startupConfig, "Startup");
131 ReadConfigAndPopulate(scene, economyConfig, "Economy");
132
133 if (m_enabled)
134 {
135 scene.RegisterModuleInterface<IMoneyModule>(this);
136 BaseHttpServer httpServer = scene.CommsManager.HttpServer;
137
138 lock (m_scenel)
139 {
140 if (m_scenel.Count == 0)
141 {
142 // XMLRPCHandler = scene;
143
144 // To use the following you need to add:
145 // -helperuri <ADDRESS TO HERE OR grid MONEY SERVER>
146 // to the command line parameters you use to start up your client
147 // This commonly looks like -helperuri http://127.0.0.1:9000/
148
149 if (m_MoneyAddress.Length > 0)
150 {
151 // Centralized grid structure using OpenSimWi Redux revision 9+
152 // https://opensimwiredux.svn.sourceforge.net/svnroot/opensimwiredux
153 httpServer.AddXmlRPCHandler("balanceUpdateRequest", GridMoneyUpdate);
154 httpServer.AddXmlRPCHandler("userAlert", UserAlert);
155 }
156 else
157 {
158 // Local Server.. enables functionality only.
159 httpServer.AddXmlRPCHandler("getCurrencyQuote", quote_func);
160 httpServer.AddXmlRPCHandler("buyCurrency", buy_func);
161 httpServer.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func);
162 httpServer.AddXmlRPCHandler("buyLandPrep", landBuy_func);
163 }
164 }
165
166 if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle))
167 {
168 m_scenel[scene.RegionInfo.RegionHandle] = scene;
169 }
170 else
171 {
172 m_scenel.Add(scene.RegionInfo.RegionHandle, scene);
173 }
174 }
175
176 scene.EventManager.OnNewClient += OnNewClient;
177 scene.EventManager.OnMoneyTransfer += MoneyTransferAction;
178 scene.EventManager.OnClientClosed += ClientClosed;
179 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
180 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
181 scene.EventManager.OnClientClosed += ClientLoggedOut;
182 scene.EventManager.OnValidateLandBuy += ValidateLandBuy;
183 scene.EventManager.OnLandBuy += processLandBuy;
184 }
185 }
186
187 // Please do not refactor these to be just one method
188 // Existing implementations need the distinction
189 //
190 public void ApplyUploadCharge(UUID agentID)
191 {
192 }
193
194 public void ApplyGroupCreationCharge(UUID agentID)
195 {
196 }
197
198 public void ApplyCharge(UUID agentID, int amount, string text)
199 {
200 }
201
202 public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount)
203 {
204 string description = String.Format("Object {0} pays {1}", resolveObjectName(objectID), resolveAgentName(toID));
205
206 bool give_result = doMoneyTransfer(fromID, toID, amount, 2, description);
207
208 if (m_MoneyAddress.Length == 0)
209 BalanceUpdate(fromID, toID, give_result, description);
210
211 return give_result;
212 }
213
214 public void PostInitialise()
215 {
216 }
217
218 public void Close()
219 {
220 }
221
222 public string Name
223 {
224 get { return "BetaGridLikeMoneyModule"; }
225 }
226
227 public bool IsSharedModule
228 {
229 get { return true; }
230 }
231
232 #endregion
233
234 /// <summary>
235 /// Parse Configuration
236 /// </summary>
237 /// <param name="scene"></param>
238 /// <param name="startupConfig"></param>
239 /// <param name="config"></param>
240 private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string config)
241 {
242 if (config == "Startup" && startupConfig != null)
243 {
244 gridmode = startupConfig.GetBoolean("gridmode", false);
245 m_enabled = (startupConfig.GetString("economymodule", "BetaGridLikeMoneyModule") == "BetaGridLikeMoneyModule");
246 }
247
248 if (config == "Economy" && startupConfig != null)
249 {
250 ObjectCapacity = startupConfig.GetInt("ObjectCapacity", 45000);
251 PriceEnergyUnit = startupConfig.GetInt("PriceEnergyUnit", 100);
252 PriceObjectClaim = startupConfig.GetInt("PriceObjectClaim", 10);
253 PricePublicObjectDecay = startupConfig.GetInt("PricePublicObjectDecay", 4);
254 PricePublicObjectDelete = startupConfig.GetInt("PricePublicObjectDelete", 4);
255 PriceParcelClaim = startupConfig.GetInt("PriceParcelClaim", 1);
256 PriceParcelClaimFactor = startupConfig.GetFloat("PriceParcelClaimFactor", 1f);
257 PriceUpload = startupConfig.GetInt("PriceUpload", 0);
258 PriceRentLight = startupConfig.GetInt("PriceRentLight", 5);
259 TeleportMinPrice = startupConfig.GetInt("TeleportMinPrice", 2);
260 TeleportPriceExponent = startupConfig.GetFloat("TeleportPriceExponent", 2f);
261 EnergyEfficiency = startupConfig.GetFloat("EnergyEfficiency", 1);
262 PriceObjectRent = startupConfig.GetFloat("PriceObjectRent", 1);
263 PriceObjectScaleFactor = startupConfig.GetFloat("PriceObjectScaleFactor", 10);
264 PriceParcelRent = startupConfig.GetInt("PriceParcelRent", 1);
265 PriceGroupCreate = startupConfig.GetInt("PriceGroupCreate", -1);
266 // string EBA = startupConfig.GetString("EconomyBaseAccount", UUID.Zero.ToString());
267 // Helpers.TryParse(EBA, out EconomyBaseAccount);
268
269 // UserLevelPaysFees = startupConfig.GetInt("UserLevelPaysFees", -1);
270 m_stipend = startupConfig.GetInt("UserStipend", 500);
271 m_minFundsBeforeRefresh = startupConfig.GetInt("IssueStipendWhenClientIsBelowAmount", 10);
272 m_keepMoneyAcrossLogins = startupConfig.GetBoolean("KeepMoneyAcrossLogins", true);
273 m_MoneyAddress = startupConfig.GetString("CurrencyServer", String.Empty);
274 // m_LandAddress = startupConfig.GetString("LandServer", String.Empty);
275 }
276
277 // Send ObjectCapacity to Scene.. Which sends it to the SimStatsReporter.
278 scene.SetObjectCapacity(ObjectCapacity);
279 }
280
281 public EconomyData GetEconomyData()
282 {
283 EconomyData edata = new EconomyData();
284 edata.ObjectCapacity = ObjectCapacity;
285 edata.ObjectCount = ObjectCount;
286 edata.PriceEnergyUnit = PriceEnergyUnit;
287 edata.PriceGroupCreate = PriceGroupCreate;
288 edata.PriceObjectClaim = PriceObjectClaim;
289 edata.PriceObjectRent = PriceObjectRent;
290 edata.PriceObjectScaleFactor = PriceObjectScaleFactor;
291 edata.PriceParcelClaim = PriceParcelClaim;
292 edata.PriceParcelClaimFactor = PriceParcelClaimFactor;
293 edata.PriceParcelRent = PriceParcelRent;
294 edata.PricePublicObjectDecay = PricePublicObjectDecay;
295 edata.PricePublicObjectDelete = PricePublicObjectDelete;
296 edata.PriceRentLight = PriceRentLight;
297 edata.PriceUpload = PriceUpload;
298 edata.TeleportMinPrice = TeleportMinPrice;
299 return edata;
300 }
301
302 private void GetClientFunds(IClientAPI client)
303 {
304 // Here we check if we're in grid mode
305 // I imagine that the 'check balance'
306 // function for the client should be here or shortly after
307
308 if (gridmode)
309 {
310 if (m_MoneyAddress.Length == 0)
311 {
312 CheckExistAndRefreshFunds(client.AgentId);
313 }
314 else
315 {
316 bool childYN = true;
317 ScenePresence agent = null;
318 //client.SecureSessionId;
319 Scene s = LocateSceneClientIn(client.AgentId);
320 if (s != null)
321 {
322 agent = s.GetScenePresence(client.AgentId);
323 if (agent != null)
324 childYN = agent.IsChildAgent;
325 }
326 if (s != null && agent != null && childYN == false)
327 {
328 //s.RegionInfo.RegionHandle;
329 UUID agentID = UUID.Zero;
330 int funds = 0;
331
332 Hashtable hbinfo =
333 GetBalanceForUserFromMoneyServer(client.AgentId, client.SecureSessionId, s.RegionInfo.originRegionID,
334 s.RegionInfo.regionSecret);
335 if ((bool) hbinfo["success"] == true)
336 {
337 UUID.TryParse((string)hbinfo["agentId"], out agentID);
338 try
339 {
340 funds = (Int32) hbinfo["funds"];
341 }
342 catch (ArgumentException)
343 {
344 }
345 catch (FormatException)
346 {
347 }
348 catch (OverflowException)
349 {
350 m_log.ErrorFormat("[MONEY]: While getting the Currency for user {0}, the return funds overflowed.", agentID);
351 client.SendAlertMessage("Unable to get your money balance, money operations will be unavailable");
352 }
353 catch (InvalidCastException)
354 {
355 funds = 0;
356 }
357
358 m_KnownClientFunds[agentID] = funds;
359 }
360 else
361 {
362 m_log.WarnFormat("[MONEY]: Getting Money for user {0} failed with the following message:{1}", agentID,
363 (string) hbinfo["errorMessage"]);
364 client.SendAlertMessage((string) hbinfo["errorMessage"]);
365 }
366 SendMoneyBalance(client, agentID, client.SessionId, UUID.Zero);
367 }
368 }
369 }
370 else
371 {
372 CheckExistAndRefreshFunds(client.AgentId);
373 }
374
375 }
376
377 /// <summary>
378 /// New Client Event Handler
379 /// </summary>
380 /// <param name="client"></param>
381 private void OnNewClient(IClientAPI client)
382 {
383 GetClientFunds(client);
384
385 // Subscribe to Money messages
386 client.OnEconomyDataRequest += EconomyDataRequestHandler;
387 client.OnMoneyBalanceRequest += SendMoneyBalance;
388 client.OnRequestPayPrice += requestPayPrice;
389 client.OnObjectBuy += ObjectBuy;
390 client.OnLogout += ClientClosed;
391 }
392
393 /// <summary>
394 /// Transfer money
395 /// </summary>
396 /// <param name="Sender"></param>
397 /// <param name="Receiver"></param>
398 /// <param name="amount"></param>
399 /// <returns></returns>
400 private bool doMoneyTransfer(UUID Sender, UUID Receiver, int amount, int transactiontype, string description)
401 {
402 bool result = false;
403 if (amount >= 0)
404 {
405 lock (m_KnownClientFunds)
406 {
407 // If we don't know about the sender, then the sender can't
408 // actually be here and therefore this is likely fraud or outdated.
409 if (m_MoneyAddress.Length == 0)
410 {
411 if (m_KnownClientFunds.ContainsKey(Sender))
412 {
413 // Does the sender have enough funds to give?
414 if (m_KnownClientFunds[Sender] >= amount)
415 {
416 // Subtract the funds from the senders account
417 m_KnownClientFunds[Sender] -= amount;
418
419 // do we know about the receiver?
420 if (!m_KnownClientFunds.ContainsKey(Receiver))
421 {
422 // Make a record for them so they get the updated balance when they login
423 CheckExistAndRefreshFunds(Receiver);
424 }
425 if (m_enabled)
426 {
427 //Add the amount to the Receiver's funds
428 m_KnownClientFunds[Receiver] += amount;
429 result = true;
430 }
431 }
432 else
433 {
434 // These below are redundant to make this clearer to read
435 result = false;
436 }
437 }
438 else
439 {
440 result = false;
441 }
442 }
443 else
444 {
445 result = TransferMoneyonMoneyServer(Sender, Receiver, amount, transactiontype, description);
446 }
447 }
448 }
449 return result;
450 }
451
452
453 /// <summary>
454 /// Sends the the stored money balance to the client
455 /// </summary>
456 /// <param name="client"></param>
457 /// <param name="agentID"></param>
458 /// <param name="SessionID"></param>
459 /// <param name="TransactionID"></param>
460 public void SendMoneyBalance(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID)
461 {
462 if (client.AgentId == agentID && client.SessionId == SessionID)
463 {
464 int returnfunds = 0;
465
466 try
467 {
468 returnfunds = GetFundsForAgentID(agentID);
469 }
470 catch (Exception e)
471 {
472 client.SendAlertMessage(e.Message + " ");
473 }
474
475 client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds);
476 }
477 else
478 {
479 client.SendAlertMessage("Unable to send your money balance to you!");
480 }
481 }
482
483 /// <summary>
484 /// Gets the current balance for the user from the Grid Money Server
485 /// </summary>
486 /// <param name="agentId"></param>
487 /// <param name="secureSessionID"></param>
488 /// <param name="regionId"></param>
489 /// <param name="regionSecret"></param>
490 /// <returns></returns>
491 public Hashtable GetBalanceForUserFromMoneyServer(UUID agentId, UUID secureSessionID, UUID regionId, string regionSecret)
492 {
493 Hashtable MoneyBalanceRequestParams = new Hashtable();
494 MoneyBalanceRequestParams["agentId"] = agentId.ToString();
495 MoneyBalanceRequestParams["secureSessionId"] = secureSessionID.ToString();
496 MoneyBalanceRequestParams["regionId"] = regionId.ToString();
497 MoneyBalanceRequestParams["secret"] = regionSecret;
498 MoneyBalanceRequestParams["currencySecret"] = ""; // per - region/user currency secret gotten from the money system
499
500 Hashtable MoneyRespData = genericCurrencyXMLRPCRequest(MoneyBalanceRequestParams, "simulatorUserBalanceRequest");
501
502 return MoneyRespData;
503 }
504
505
506 /// <summary>
507 /// Generic XMLRPC client abstraction
508 /// </summary>
509 /// <param name="ReqParams">Hashtable containing parameters to the method</param>
510 /// <param name="method">Method to invoke</param>
511 /// <returns>Hashtable with success=>bool and other values</returns>
512 public Hashtable genericCurrencyXMLRPCRequest(Hashtable ReqParams, string method)
513 {
514 ArrayList SendParams = new ArrayList();
515 SendParams.Add(ReqParams);
516 // Send Request
517 XmlRpcResponse MoneyResp;
518 try
519 {
520 XmlRpcRequest BalanceRequestReq = new XmlRpcRequest(method, SendParams);
521 MoneyResp = BalanceRequestReq.Send(m_MoneyAddress, 30000);
522 }
523 catch (WebException ex)
524 {
525 m_log.ErrorFormat(
526 "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
527 m_MoneyAddress, ex);
528
529 Hashtable ErrorHash = new Hashtable();
530 ErrorHash["success"] = false;
531 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
532 ErrorHash["errorURI"] = "";
533
534 return ErrorHash;
535 //throw (ex);
536 }
537 catch (SocketException ex)
538 {
539 m_log.ErrorFormat(
540 "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
541 m_MoneyAddress, ex);
542
543 Hashtable ErrorHash = new Hashtable();
544 ErrorHash["success"] = false;
545 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
546 ErrorHash["errorURI"] = "";
547
548 return ErrorHash;
549 //throw (ex);
550 }
551 catch (XmlException ex)
552 {
553 m_log.ErrorFormat(
554 "[MONEY]: Unable to connect to Money Server {0}. Exception {1}",
555 m_MoneyAddress, ex);
556
557 Hashtable ErrorHash = new Hashtable();
558 ErrorHash["success"] = false;
559 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
560 ErrorHash["errorURI"] = "";
561
562 return ErrorHash;
563 }
564 if (MoneyResp.IsFault)
565 {
566 Hashtable ErrorHash = new Hashtable();
567 ErrorHash["success"] = false;
568 ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
569 ErrorHash["errorURI"] = "";
570
571 return ErrorHash;
572 }
573 Hashtable MoneyRespData = (Hashtable) MoneyResp.Value;
574
575 return MoneyRespData;
576 }
577
578 /// <summary>
579 /// This informs the Money Grid Server that the avatar is in this simulator
580 /// </summary>
581 /// <param name="agentId"></param>
582 /// <param name="secureSessionID"></param>
583 /// <param name="regionId"></param>
584 /// <param name="regionSecret"></param>
585 /// <returns></returns>
586 public Hashtable claim_user(UUID agentId, UUID secureSessionID, UUID regionId, string regionSecret)
587 {
588 Hashtable MoneyBalanceRequestParams = new Hashtable();
589 MoneyBalanceRequestParams["agentId"] = agentId.ToString();
590 MoneyBalanceRequestParams["secureSessionId"] = secureSessionID.ToString();
591 MoneyBalanceRequestParams["regionId"] = regionId.ToString();
592 MoneyBalanceRequestParams["secret"] = regionSecret;
593
594 Hashtable MoneyRespData = genericCurrencyXMLRPCRequest(MoneyBalanceRequestParams, "simulatorClaimUserRequest");
595 IClientAPI sendMoneyBal = LocateClientObject(agentId);
596 if (sendMoneyBal != null)
597 {
598 SendMoneyBalance(sendMoneyBal, agentId, sendMoneyBal.SessionId, UUID.Zero);
599 }
600 return MoneyRespData;
601 }
602
603 private SceneObjectPart findPrim(UUID objectID)
604 {
605 lock (m_scenel)
606 {
607 foreach (Scene s in m_scenel.Values)
608 {
609 SceneObjectPart part = s.GetSceneObjectPart(objectID);
610 if (part != null)
611 {
612 return part;
613 }
614 }
615 }
616 return null;
617 }
618
619 private string resolveObjectName(UUID objectID)
620 {
621 SceneObjectPart part = findPrim(objectID);
622 if (part != null)
623 {
624 return part.Name;
625 }
626 return String.Empty;
627 }
628
629 private string resolveAgentName(UUID agentID)
630 {
631 // try avatar username surname
632 Scene scene = GetRandomScene();
633 CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
634 if (profile != null && profile.UserProfile != null)
635 {
636 string avatarname = profile.UserProfile.FirstName + " " + profile.UserProfile.SurName;
637 return avatarname;
638 }
639 else
640 {
641 m_log.ErrorFormat(
642 "[MONEY]: Could not resolve user {0}",
643 agentID);
644 }
645
646 return String.Empty;
647 }
648
649 private void BalanceUpdate(UUID senderID, UUID receiverID, bool transactionresult, string description)
650 {
651 IClientAPI sender = LocateClientObject(senderID);
652 IClientAPI receiver = LocateClientObject(receiverID);
653
654 if (senderID != receiverID)
655 {
656 if (sender != null)
657 {
658 sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID));
659 }
660
661 if (receiver != null)
662 {
663 receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID));
664 }
665 }
666 }
667
668 /// <summary>
669 /// Informs the Money Grid Server of a transfer.
670 /// </summary>
671 /// <param name="sourceId"></param>
672 /// <param name="destId"></param>
673 /// <param name="amount"></param>
674 /// <returns></returns>
675 public bool TransferMoneyonMoneyServer(UUID sourceId, UUID destId, int amount, int transactiontype, string description)
676 {
677 int aggregatePermInventory = 0;
678 int aggregatePermNextOwner = 0;
679 int flags = 0;
680 bool rvalue = false;
681
682 IClientAPI cli = LocateClientObject(sourceId);
683 if (cli != null)
684 {
685 Scene userScene = null;
686 lock (m_rootAgents)
687 {
688 userScene = GetSceneByUUID(m_rootAgents[sourceId]);
689 }
690 if (userScene != null)
691 {
692 Hashtable ht = new Hashtable();
693 ht["agentId"] = sourceId.ToString();
694 ht["secureSessionId"] = cli.SecureSessionId.ToString();
695 ht["regionId"] = userScene.RegionInfo.originRegionID.ToString();
696 ht["secret"] = userScene.RegionInfo.regionSecret;
697 ht["currencySecret"] = " ";
698 ht["destId"] = destId.ToString();
699 ht["cash"] = amount;
700 ht["aggregatePermInventory"] = aggregatePermInventory;
701 ht["aggregatePermNextOwner"] = aggregatePermNextOwner;
702 ht["flags"] = flags;
703 ht["transactionType"] = transactiontype;
704 ht["description"] = description;
705
706 Hashtable hresult = genericCurrencyXMLRPCRequest(ht, "regionMoveMoney");
707
708 if ((bool) hresult["success"] == true)
709 {
710 int funds1 = 0;
711 int funds2 = 0;
712 try
713 {
714 funds1 = (Int32) hresult["funds"];
715 }
716 catch (InvalidCastException)
717 {
718 funds1 = 0;
719 }
720 SetLocalFundsForAgentID(sourceId, funds1);
721 if (m_KnownClientFunds.ContainsKey(destId))
722 {
723 try
724 {
725 funds2 = (Int32) hresult["funds2"];
726 }
727 catch (InvalidCastException)
728 {
729 funds2 = 0;
730 }
731 SetLocalFundsForAgentID(destId, funds2);
732 }
733
734
735 rvalue = true;
736 }
737 else
738 {
739 cli.SendAgentAlertMessage((string) hresult["errorMessage"], true);
740 }
741 }
742 }
743 else
744 {
745 m_log.ErrorFormat("[MONEY]: Client {0} not found", sourceId.ToString());
746 }
747
748 return rvalue;
749 }
750
751 public int GetRemoteBalance(UUID agentId)
752 {
753 int funds = 0;
754
755 IClientAPI aClient = LocateClientObject(agentId);
756 if (aClient != null)
757 {
758 Scene s = LocateSceneClientIn(agentId);
759 if (s != null)
760 {
761 if (m_MoneyAddress.Length > 0)
762 {
763 Hashtable hbinfo =
764 GetBalanceForUserFromMoneyServer(aClient.AgentId, aClient.SecureSessionId, s.RegionInfo.originRegionID,
765 s.RegionInfo.regionSecret);
766 if ((bool) hbinfo["success"] == true)
767 {
768 try
769 {
770 funds = (Int32) hbinfo["funds"];
771 }
772 catch (ArgumentException)
773 {
774 }
775 catch (FormatException)
776 {
777 }
778 catch (OverflowException)
779 {
780 m_log.ErrorFormat("[MONEY]: While getting the Currency for user {0}, the return funds overflowed.", agentId);
781 aClient.SendAlertMessage("Unable to get your money balance, money operations will be unavailable");
782 }
783 catch (InvalidCastException)
784 {
785 funds = 0;
786 }
787 }
788 else
789 {
790 m_log.WarnFormat("[MONEY]: Getting Money for user {0} failed with the following message:{1}", agentId,
791 (string) hbinfo["errorMessage"]);
792 aClient.SendAlertMessage((string) hbinfo["errorMessage"]);
793 }
794 }
795
796 SetLocalFundsForAgentID(agentId, funds);
797 SendMoneyBalance(aClient, agentId, aClient.SessionId, UUID.Zero);
798 }
799 else
800 {
801 m_log.Debug("[MONEY]: Got balance request update for agent that is here, but couldn't find which scene.");
802 }
803 }
804 else
805 {
806 m_log.Debug("[MONEY]: Got balance request update for agent that isn't here.");
807 }
808 return funds;
809 }
810
811 public XmlRpcResponse GridMoneyUpdate(XmlRpcRequest request)
812 {
813 m_log.Debug("[MONEY]: Dynamic balance update called.");
814 Hashtable requestData = (Hashtable) request.Params[0];
815
816 if (requestData.ContainsKey("agentId"))
817 {
818 UUID agentId = UUID.Zero;
819
820 UUID.TryParse((string) requestData["agentId"], out agentId);
821 if (agentId != UUID.Zero)
822 {
823 GetRemoteBalance(agentId);
824 }
825 else
826 {
827 m_log.Debug("[MONEY]: invalid agentId specified, dropping.");
828 }
829 }
830 else
831 {
832 m_log.Debug("[MONEY]: no agentId specified, dropping.");
833 }
834 XmlRpcResponse r = new XmlRpcResponse();
835 Hashtable rparms = new Hashtable();
836 rparms["success"] = true;
837
838 r.Value = rparms;
839 return r;
840 }
841
842 /// <summary>
843 /// XMLRPC handler to send alert message and sound to client
844 /// </summary>
845 public XmlRpcResponse UserAlert(XmlRpcRequest request)
846 {
847 XmlRpcResponse ret = new XmlRpcResponse();
848 Hashtable retparam = new Hashtable();
849 Hashtable requestData = (Hashtable) request.Params[0];
850
851 UUID agentId;
852 UUID soundId;
853 UUID regionId;
854
855 UUID.TryParse((string) requestData["agentId"], out agentId);
856 UUID.TryParse((string) requestData["soundId"], out soundId);
857 UUID.TryParse((string) requestData["regionId"], out regionId);
858 string text = (string) requestData["text"];
859 string secret = (string) requestData["secret"];
860
861 Scene userScene = GetSceneByUUID(regionId);
862 if (userScene != null)
863 {
864 if (userScene.RegionInfo.regionSecret == secret)
865 {
866
867 IClientAPI client = LocateClientObject(agentId);
868 if (client != null)
869 {
870
871 if (soundId != UUID.Zero)
872 client.SendPlayAttachedSound(soundId, UUID.Zero, UUID.Zero, 1.0f, 0);
873
874 client.SendBlueBoxMessage(UUID.Zero, "", text);
875
876 retparam.Add("success", true);
877 }
878 else
879 {
880 retparam.Add("success", false);
881 }
882 }
883 else
884 {
885 retparam.Add("success", false);
886 }
887 }
888
889 ret.Value = retparam;
890 return ret;
891 }
892
893 # region Standalone box enablers only
894
895 public XmlRpcResponse quote_func(XmlRpcRequest request)
896 {
897 Hashtable requestData = (Hashtable) request.Params[0];
898 UUID agentId = UUID.Zero;
899 int amount = 0;
900 Hashtable quoteResponse = new Hashtable();
901 XmlRpcResponse returnval = new XmlRpcResponse();
902
903 if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
904 {
905 UUID.TryParse((string) requestData["agentId"], out agentId);
906 try
907 {
908 amount = (Int32) requestData["currencyBuy"];
909 }
910 catch (InvalidCastException)
911 {
912 }
913 Hashtable currencyResponse = new Hashtable();
914 currencyResponse.Add("estimatedCost", 0);
915 currencyResponse.Add("currencyBuy", amount);
916
917 quoteResponse.Add("success", true);
918 quoteResponse.Add("currency", currencyResponse);
919 quoteResponse.Add("confirm", "asdfad9fj39ma9fj");
920
921 returnval.Value = quoteResponse;
922 return returnval;
923 }
924
925
926 quoteResponse.Add("success", false);
927 quoteResponse.Add("errorMessage", "Invalid parameters passed to the quote box");
928 quoteResponse.Add("errorURI", "http://www.opensimulator.org/wiki");
929 returnval.Value = quoteResponse;
930 return returnval;
931 }
932
933 public XmlRpcResponse buy_func(XmlRpcRequest request)
934 {
935 Hashtable requestData = (Hashtable) request.Params[0];
936 UUID agentId = UUID.Zero;
937 int amount = 0;
938 if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
939 {
940 UUID.TryParse((string) requestData["agentId"], out agentId);
941 try
942 {
943 amount = (Int32) requestData["currencyBuy"];
944 }
945 catch (InvalidCastException)
946 {
947 }
948 if (agentId != UUID.Zero)
949 {
950 lock (m_KnownClientFunds)
951 {
952 if (m_KnownClientFunds.ContainsKey(agentId))
953 {
954 m_KnownClientFunds[agentId] += amount;
955 }
956 else
957 {
958 m_KnownClientFunds.Add(agentId, amount);
959 }
960 }
961 IClientAPI client = LocateClientObject(agentId);
962 if (client != null)
963 {
964 SendMoneyBalance(client, agentId, client.SessionId, UUID.Zero);
965 }
966 }
967 }
968 XmlRpcResponse returnval = new XmlRpcResponse();
969 Hashtable returnresp = new Hashtable();
970 returnresp.Add("success", true);
971 returnval.Value = returnresp;
972 return returnval;
973 }
974
975 public XmlRpcResponse preflightBuyLandPrep_func(XmlRpcRequest request)
976 {
977 XmlRpcResponse ret = new XmlRpcResponse();
978 Hashtable retparam = new Hashtable();
979 Hashtable membershiplevels = new Hashtable();
980 ArrayList levels = new ArrayList();
981 Hashtable level = new Hashtable();
982 level.Add("id", "00000000-0000-0000-0000-000000000000");
983 level.Add("description", "some level");
984 levels.Add(level);
985 //membershiplevels.Add("levels",levels);
986
987 Hashtable landuse = new Hashtable();
988 landuse.Add("upgrade", false);
989 landuse.Add("action", "http://invaliddomaininvalid.com/");
990
991 Hashtable currency = new Hashtable();
992 currency.Add("estimatedCost", 0);
993
994 Hashtable membership = new Hashtable();
995 membershiplevels.Add("upgrade", false);
996 membershiplevels.Add("action", "http://invaliddomaininvalid.com/");
997 membershiplevels.Add("levels", membershiplevels);
998
999 retparam.Add("success", true);
1000 retparam.Add("currency", currency);
1001 retparam.Add("membership", membership);
1002 retparam.Add("landuse", landuse);
1003 retparam.Add("confirm", "asdfajsdkfjasdkfjalsdfjasdf");
1004
1005 ret.Value = retparam;
1006
1007 return ret;
1008 }
1009
1010 public XmlRpcResponse landBuy_func(XmlRpcRequest request)
1011 {
1012 XmlRpcResponse ret = new XmlRpcResponse();
1013 Hashtable retparam = new Hashtable();
1014 Hashtable requestData = (Hashtable) request.Params[0];
1015
1016 UUID agentId = UUID.Zero;
1017 int amount = 0;
1018 if (requestData.ContainsKey("agentId") && requestData.ContainsKey("currencyBuy"))
1019 {
1020 UUID.TryParse((string) requestData["agentId"], out agentId);
1021 try
1022 {
1023 amount = (Int32) requestData["currencyBuy"];
1024 }
1025 catch (InvalidCastException)
1026 {
1027 }
1028 if (agentId != UUID.Zero)
1029 {
1030 lock (m_KnownClientFunds)
1031 {
1032 if (m_KnownClientFunds.ContainsKey(agentId))
1033 {
1034 m_KnownClientFunds[agentId] += amount;
1035 }
1036 else
1037 {
1038 m_KnownClientFunds.Add(agentId, amount);
1039 }
1040 }
1041 IClientAPI client = LocateClientObject(agentId);
1042 if (client != null)
1043 {
1044 SendMoneyBalance(client, agentId, client.SessionId, UUID.Zero);
1045 }
1046 }
1047 }
1048 retparam.Add("success", true);
1049 ret.Value = retparam;
1050
1051 return ret;
1052 }
1053
1054 #endregion
1055
1056 #region local Fund Management
1057
1058 /// <summary>
1059 /// Ensures that the agent accounting data is set up in this instance.
1060 /// </summary>
1061 /// <param name="agentID"></param>
1062 private void CheckExistAndRefreshFunds(UUID agentID)
1063 {
1064 lock (m_KnownClientFunds)
1065 {
1066 if (!m_KnownClientFunds.ContainsKey(agentID))
1067 {
1068 m_KnownClientFunds.Add(agentID, m_stipend);
1069 }
1070 else
1071 {
1072 if (m_KnownClientFunds[agentID] <= m_minFundsBeforeRefresh)
1073 {
1074 m_KnownClientFunds[agentID] = m_stipend;
1075 }
1076 }
1077 }
1078 }
1079
1080 /// <summary>
1081 /// Gets the amount of Funds for an agent
1082 /// </summary>
1083 /// <param name="AgentID"></param>
1084 /// <returns></returns>
1085 private int GetFundsForAgentID(UUID AgentID)
1086 {
1087 int returnfunds = 0;
1088 lock (m_KnownClientFunds)
1089 {
1090 if (m_KnownClientFunds.ContainsKey(AgentID))
1091 {
1092 returnfunds = m_KnownClientFunds[AgentID];
1093 }
1094 else
1095 {
1096 //throw new Exception("Unable to get funds.");
1097 }
1098 }
1099 return returnfunds;
1100 }
1101
1102 private void SetLocalFundsForAgentID(UUID AgentID, int amount)
1103 {
1104 lock (m_KnownClientFunds)
1105 {
1106 if (m_KnownClientFunds.ContainsKey(AgentID))
1107 {
1108 m_KnownClientFunds[AgentID] = amount;
1109 }
1110 else
1111 {
1112 m_KnownClientFunds.Add(AgentID, amount);
1113 }
1114 }
1115 }
1116
1117 #endregion
1118
1119 #region Utility Helpers
1120
1121 /// <summary>
1122 /// Locates a IClientAPI for the client specified
1123 /// </summary>
1124 /// <param name="AgentID"></param>
1125 /// <returns></returns>
1126 private IClientAPI LocateClientObject(UUID AgentID)
1127 {
1128 ScenePresence tPresence = null;
1129 IClientAPI rclient = null;
1130
1131 lock (m_scenel)
1132 {
1133 foreach (Scene _scene in m_scenel.Values)
1134 {
1135 tPresence = _scene.GetScenePresence(AgentID);
1136 if (tPresence != null)
1137 {
1138 if (!tPresence.IsChildAgent)
1139 {
1140 rclient = tPresence.ControllingClient;
1141 }
1142 }
1143 if (rclient != null)
1144 {
1145 return rclient;
1146 }
1147 }
1148 }
1149 return null;
1150 }
1151
1152 private Scene LocateSceneClientIn(UUID AgentId)
1153 {
1154 lock (m_scenel)
1155 {
1156 foreach (Scene _scene in m_scenel.Values)
1157 {
1158 ScenePresence tPresence = _scene.GetScenePresence(AgentId);
1159 if (tPresence != null)
1160 {
1161 if (!tPresence.IsChildAgent)
1162 {
1163 return _scene;
1164 }
1165 }
1166 }
1167 }
1168 return null;
1169 }
1170
1171 /// <summary>
1172 /// Utility function Gets a Random scene in the instance. For when which scene exactly you're doing something with doesn't matter
1173 /// </summary>
1174 /// <returns></returns>
1175 public Scene GetRandomScene()
1176 {
1177 lock (m_scenel)
1178 {
1179 foreach (Scene rs in m_scenel.Values)
1180 return rs;
1181 }
1182 return null;
1183 }
1184
1185 /// <summary>
1186 /// Utility function to get a Scene by RegionID in a module
1187 /// </summary>
1188 /// <param name="RegionID"></param>
1189 /// <returns></returns>
1190 public Scene GetSceneByUUID(UUID RegionID)
1191 {
1192 lock (m_scenel)
1193 {
1194 foreach (Scene rs in m_scenel.Values)
1195 {
1196 if (rs.RegionInfo.originRegionID == RegionID)
1197 {
1198 return rs;
1199 }
1200 }
1201 }
1202 return null;
1203 }
1204
1205 #endregion
1206
1207 #region event Handlers
1208
1209 public void requestPayPrice(IClientAPI client, UUID objectID)
1210 {
1211 Scene scene = LocateSceneClientIn(client.AgentId);
1212 if (scene == null)
1213 return;
1214
1215 SceneObjectPart task = scene.GetSceneObjectPart(objectID);
1216 if (task == null)
1217 return;
1218 SceneObjectGroup group = task.ParentGroup;
1219 SceneObjectPart root = group.RootPart;
1220
1221 client.SendPayPrice(objectID, root.PayPrice);
1222 }
1223
1224 /// <summary>
1225 /// When the client closes the connection we remove their accounting info from memory to free up resources.
1226 /// </summary>
1227 /// <param name="AgentID"></param>
1228 public void ClientClosed(UUID AgentID)
1229 {
1230 lock (m_KnownClientFunds)
1231 {
1232 if (m_keepMoneyAcrossLogins && m_MoneyAddress.Length == 0)
1233 {
1234 }
1235 else
1236 {
1237 m_KnownClientFunds.Remove(AgentID);
1238 }
1239 }
1240 }
1241
1242 /// <summary>
1243 /// Event called Economy Data Request handler.
1244 /// </summary>
1245 /// <param name="agentId"></param>
1246 public void EconomyDataRequestHandler(UUID agentId)
1247 {
1248 IClientAPI user = LocateClientObject(agentId);
1249
1250 if (user != null)
1251 {
1252 user.SendEconomyData(EnergyEfficiency, ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
1253 PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
1254 PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
1255 TeleportMinPrice, TeleportPriceExponent);
1256 }
1257 }
1258
1259 private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e)
1260 {
1261 if (m_MoneyAddress.Length == 0)
1262 {
1263 lock (m_KnownClientFunds)
1264 {
1265 if (m_KnownClientFunds.ContainsKey(e.agentId))
1266 {
1267 // Does the sender have enough funds to give?
1268 if (m_KnownClientFunds[e.agentId] >= e.parcelPrice)
1269 {
1270 lock (e)
1271 {
1272 e.economyValidated = true;
1273 }
1274 }
1275 }
1276 }
1277 }
1278 else
1279 {
1280 if (GetRemoteBalance(e.agentId) >= e.parcelPrice)
1281 {
1282 lock (e)
1283 {
1284 e.economyValidated = true;
1285 }
1286 }
1287 }
1288 }
1289
1290 private void processLandBuy(Object osender, EventManager.LandBuyArgs e)
1291 {
1292 lock (e)
1293 {
1294 if (e.economyValidated == true && e.transactionID == 0)
1295 {
1296 e.transactionID = Util.UnixTimeSinceEpoch();
1297
1298 if (doMoneyTransfer(e.agentId, e.parcelOwnerID, e.parcelPrice, 0, "Land purchase"))
1299 {
1300 lock (e)
1301 {
1302 e.amountDebited = e.parcelPrice;
1303 }
1304 }
1305 }
1306 }
1307 }
1308
1309 /// <summary>
1310 /// THis method gets called when someone pays someone else as a gift.
1311 /// </summary>
1312 /// <param name="osender"></param>
1313 /// <param name="e"></param>
1314 private void MoneyTransferAction(Object osender, EventManager.MoneyTransferArgs e)
1315 {
1316 IClientAPI sender = null;
1317 IClientAPI receiver = null;
1318
1319 if (m_MoneyAddress.Length > 0) // Handled on server
1320 e.description = String.Empty;
1321
1322 if (e.transactiontype == 5008) // Object gets paid
1323 {
1324 sender = LocateClientObject(e.sender);
1325 if (sender != null)
1326 {
1327 SceneObjectPart part = findPrim(e.receiver);
1328 if (part == null)
1329 return;
1330
1331 string name = resolveAgentName(part.OwnerID);
1332 if (name == String.Empty)
1333 name = "(hippos)";
1334
1335 receiver = LocateClientObject(part.OwnerID);
1336
1337 string description = String.Format("Paid {0} via object {1}", name, e.description);
1338 bool transactionresult = doMoneyTransfer(e.sender, part.OwnerID, e.amount, e.transactiontype, description);
1339
1340 if (transactionresult)
1341 {
1342 ObjectPaid handlerOnObjectPaid = OnObjectPaid;
1343 if (handlerOnObjectPaid != null)
1344 {
1345 handlerOnObjectPaid(e.receiver, e.sender, e.amount);
1346 }
1347 }
1348
1349 if (e.sender != e.receiver)
1350 {
1351 sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(e.sender));
1352 }
1353 if (receiver != null)
1354 {
1355 receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(part.OwnerID));
1356 }
1357 }
1358 return;
1359 }
1360
1361 sender = LocateClientObject(e.sender);
1362 if (sender != null)
1363 {
1364 receiver = LocateClientObject(e.receiver);
1365
1366 bool transactionresult = doMoneyTransfer(e.sender, e.receiver, e.amount, e.transactiontype, e.description);
1367
1368 if (e.sender != e.receiver)
1369 {
1370 if (sender != null)
1371 {
1372 sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(e.sender));
1373 }
1374 }
1375
1376 if (receiver != null)
1377 {
1378 receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(e.description), GetFundsForAgentID(e.receiver));
1379 }
1380 }
1381 else
1382 {
1383 m_log.Warn("[MONEY]: Potential Fraud Warning, got money transfer request for avatar that isn't in this simulator - Details; Sender:" +
1384 e.sender.ToString() + " Receiver: " + e.receiver.ToString() + " Amount: " + e.amount.ToString());
1385 }
1386 }
1387
1388 /// <summary>
1389 /// Event Handler for when a root agent becomes a child agent
1390 /// </summary>
1391 /// <param name="avatar"></param>
1392 private void MakeChildAgent(ScenePresence avatar)
1393 {
1394 lock (m_rootAgents)
1395 {
1396 if (m_rootAgents.ContainsKey(avatar.UUID))
1397 {
1398 if (m_rootAgents[avatar.UUID] == avatar.Scene.RegionInfo.originRegionID)
1399 {
1400 m_rootAgents.Remove(avatar.UUID);
1401// m_log.Debug("[MONEY]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent");
1402 }
1403 }
1404 }
1405 }
1406
1407 /// <summary>
1408 /// Event Handler for when the client logs out.
1409 /// </summary>
1410 /// <param name="AgentId"></param>
1411 private void ClientLoggedOut(UUID AgentId)
1412 {
1413 lock (m_rootAgents)
1414 {
1415 if (m_rootAgents.ContainsKey(AgentId))
1416 {
1417 m_rootAgents.Remove(AgentId);
1418 //m_log.Info("[MONEY]: Removing " + AgentId + ". Agent logged out.");
1419 }
1420 }
1421 }
1422
1423 /// <summary>
1424 /// Call this when the client disconnects.
1425 /// </summary>
1426 /// <param name="client"></param>
1427 public void ClientClosed(IClientAPI client)
1428 {
1429 ClientClosed(client.AgentId);
1430 }
1431
1432 /// <summary>
1433 /// Event Handler for when an Avatar enters one of the parcels in the simulator.
1434 /// </summary>
1435 /// <param name="avatar"></param>
1436 /// <param name="localLandID"></param>
1437 /// <param name="regionID"></param>
1438 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
1439 {
1440 lock (m_rootAgents)
1441 {
1442 if (m_rootAgents.ContainsKey(avatar.UUID))
1443 {
1444 if (avatar.Scene.RegionInfo.originRegionID != m_rootAgents[avatar.UUID])
1445 {
1446 m_rootAgents[avatar.UUID] = avatar.Scene.RegionInfo.originRegionID;
1447
1448
1449 //m_log.Info("[MONEY]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
1450 // Claim User! my user! Mine mine mine!
1451 if (m_MoneyAddress.Length > 0)
1452 {
1453 Scene RegionItem = GetSceneByUUID(regionID);
1454 if (RegionItem != null)
1455 {
1456 Hashtable hresult =
1457 claim_user(avatar.UUID, avatar.ControllingClient.SecureSessionId, regionID, RegionItem.RegionInfo.regionSecret);
1458 if ((bool)hresult["success"] == true)
1459 {
1460 int funds = 0;
1461 try
1462 {
1463 funds = (Int32)hresult["funds"];
1464 }
1465 catch (InvalidCastException)
1466 {
1467 }
1468 SetLocalFundsForAgentID(avatar.UUID, funds);
1469 }
1470 else
1471 {
1472 avatar.ControllingClient.SendAgentAlertMessage((string)hresult["errorMessage"], true);
1473 }
1474 }
1475 }
1476 }
1477 else
1478 {
1479 ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
1480 if ((obj.landData.Flags & (uint)Parcel.ParcelFlags.AllowDamage) != 0)
1481 {
1482 avatar.Invulnerable = false;
1483 }
1484 else
1485 {
1486 avatar.Invulnerable = true;
1487 }
1488 }
1489 }
1490 else
1491 {
1492 lock (m_rootAgents)
1493 {
1494 m_rootAgents.Add(avatar.UUID, avatar.Scene.RegionInfo.originRegionID);
1495 }
1496 if (m_MoneyAddress.Length > 0)
1497 {
1498 Scene RegionItem = GetSceneByUUID(regionID);
1499 if (RegionItem != null)
1500 {
1501 Hashtable hresult = claim_user(avatar.UUID, avatar.ControllingClient.SecureSessionId, regionID, RegionItem.RegionInfo.regionSecret);
1502 if ((bool) hresult["success"] == true)
1503 {
1504 int funds = 0;
1505 try
1506 {
1507 funds = (Int32) hresult["funds"];
1508 }
1509 catch (InvalidCastException)
1510 {
1511 }
1512 SetLocalFundsForAgentID(avatar.UUID, funds);
1513 }
1514 else
1515 {
1516 avatar.ControllingClient.SendAgentAlertMessage((string) hresult["errorMessage"], true);
1517 }
1518 }
1519 }
1520
1521 //m_log.Info("[MONEY]: Claiming " + avatar.Firstname + " " + avatar.Lastname + " in region:" + avatar.RegionHandle + ".");
1522 }
1523 }
1524 //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString());
1525 }
1526
1527 public int GetBalance(IClientAPI client)
1528 {
1529 GetClientFunds(client);
1530
1531 lock (m_KnownClientFunds)
1532 {
1533 if (!m_KnownClientFunds.ContainsKey(client.AgentId))
1534 return 0;
1535
1536 return m_KnownClientFunds[client.AgentId];
1537 }
1538 }
1539
1540 // Please do not refactor these to be just one method
1541 // Existing implementations need the distinction
1542 //
1543 public bool UploadCovered(IClientAPI client)
1544 {
1545 return AmountCovered(client, PriceUpload);
1546 }
1547
1548 public bool GroupCreationCovered(IClientAPI client)
1549 {
1550 return AmountCovered(client, PriceGroupCreate);
1551 }
1552
1553 public bool AmountCovered(IClientAPI client, int amount)
1554 {
1555 if (GetBalance(client) < amount)
1556 return false;
1557 return true;
1558 }
1559
1560 #endregion
1561
1562 public void ObjectBuy(IClientAPI remoteClient, UUID agentID,
1563 UUID sessionID, UUID groupID, UUID categoryID,
1564 uint localID, byte saleType, int salePrice)
1565 {
1566 GetClientFunds(remoteClient);
1567
1568 if (!m_KnownClientFunds.ContainsKey(remoteClient.AgentId))
1569 {
1570 remoteClient.SendAgentAlertMessage("Unable to buy now. Your account balance was not found.", false);
1571 return;
1572 }
1573
1574 int funds = m_KnownClientFunds[remoteClient.AgentId];
1575
1576 if (salePrice != 0 && funds < salePrice)
1577 {
1578 remoteClient.SendAgentAlertMessage("Unable to buy now. You don't have sufficient funds.", false);
1579 return;
1580 }
1581
1582 Scene s = LocateSceneClientIn(remoteClient.AgentId);
1583
1584 SceneObjectPart part = s.GetSceneObjectPart(localID);
1585 if (part == null)
1586 {
1587 remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found.", false);
1588 return;
1589 }
1590
1591 if (s.PerformObjectBuy(remoteClient, categoryID, localID, saleType))
1592 doMoneyTransfer(remoteClient.AgentId, part.OwnerID, salePrice, 5000, "Object buy");
1593 }
1594 }
1595
1596 public enum TransactionType : int
1597 {
1598 SystemGenerated = 0,
1599 RegionMoneyRequest = 1,
1600 Gift = 2,
1601 Purchase = 3
1602 }
1603
1604
1605}
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
new file mode 100644
index 0000000..7326373
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -0,0 +1,143 @@
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 log4net;
31using Nini.Config;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36
37namespace OpenSim.Region.CoreModules.Avatar.Dialog
38{
39 public class DialogModule : IRegionModule, IDialogModule
40 {
41 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 protected Scene m_scene;
44
45 public void Initialise(Scene scene, IConfigSource source)
46 {
47 m_scene = scene;
48 m_scene.RegisterModuleInterface<IDialogModule>(this);
49 }
50
51 public void PostInitialise() {}
52 public void Close() {}
53 public string Name { get { return "Dialog Module"; } }
54 public bool IsSharedModule { get { return false; } }
55
56 public void SendAlertToUser(IClientAPI client, string message)
57 {
58 SendAlertToUser(client, message, false);
59 }
60
61 public void SendAlertToUser(IClientAPI client, string message, bool modal)
62 {
63 client.SendAgentAlertMessage(message, modal);
64 }
65
66 public void SendAlertToUser(UUID agentID, string message)
67 {
68 SendAlertToUser(agentID, message, false);
69 }
70
71 public void SendAlertToUser(UUID agentID, string message, bool modal)
72 {
73 ScenePresence sp = m_scene.GetScenePresence(agentID);
74
75 if (sp != null)
76 sp.ControllingClient.SendAgentAlertMessage(message, modal);
77 }
78
79 public void SendAlertToUser(string firstName, string lastName, string message, bool modal)
80 {
81 List<ScenePresence> presenceList = m_scene.GetScenePresences();
82
83 foreach (ScenePresence presence in presenceList)
84 {
85 if (presence.Firstname == firstName && presence.Lastname == lastName)
86 {
87 presence.ControllingClient.SendAgentAlertMessage(message, modal);
88 break;
89 }
90 }
91 }
92
93 public void SendGeneralAlert(string message)
94 {
95 List<ScenePresence> presenceList = m_scene.GetScenePresences();
96
97 foreach (ScenePresence presence in presenceList)
98 {
99 if (!presence.IsChildAgent)
100 presence.ControllingClient.SendAlertMessage(message);
101 }
102 }
103
104 public void SendDialogToUser(
105 UUID avatarID, string objectName, UUID objectID, UUID ownerID,
106 string message, UUID textureID, int ch, string[] buttonlabels)
107 {
108 ScenePresence sp = m_scene.GetScenePresence(avatarID);
109
110 if (sp != null)
111 sp.ControllingClient.SendDialog(objectName, objectID, ownerID, message, textureID, ch, buttonlabels);
112 }
113
114 public void SendUrlToUser(
115 UUID avatarID, string objectName, UUID objectID, UUID ownerID, bool groupOwned, string message, string url)
116 {
117 ScenePresence sp = m_scene.GetScenePresence(avatarID);
118
119 if (sp != null)
120 sp.ControllingClient.SendLoadURL(objectName, objectID, ownerID, groupOwned, message, url);
121 }
122
123 public void SendNotificationToUsersInEstate(
124 UUID fromAvatarID, string fromAvatarName, string message)
125 {
126 // TODO: This does not yet do what it says on the tin - it only sends the message to users in the same
127 // region as the sending avatar.
128 SendNotificationToUsersInRegion(fromAvatarID, fromAvatarName, message);
129 }
130
131 public void SendNotificationToUsersInRegion(
132 UUID fromAvatarID, string fromAvatarName, string message)
133 {
134 List<ScenePresence> presenceList = m_scene.GetScenePresences();
135
136 foreach (ScenePresence presence in presenceList)
137 {
138 if (!presence.IsChildAgent)
139 presence.ControllingClient.SendBlueBoxMessage(fromAvatarID, fromAvatarName, message);
140 }
141 }
142 }
143}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
new file mode 100644
index 0000000..fb4d08a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -0,0 +1,1003 @@
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.Reflection;
32using OpenMetaverse;
33using log4net;
34using Nini.Config;
35using Nwc.XmlRpc;
36using OpenSim.Framework;
37using OpenSim.Framework.Communications.Cache;
38using OpenSim.Framework.Servers;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Avatar.Friends
43{
44 /*
45 This module handles adding/removing friends, and the the presence
46 notification process for login/logoff of friends.
47
48 The presence notification works as follows:
49 - After the user initially connects to a region (so we now have a UDP
50 connection to work with), this module fetches the friends of user
51 (those are cached), their on-/offline status, and info about the
52 region they are in from the MessageServer.
53 - (*) It then informs the user about the on-/offline status of her friends.
54 - It then informs all online friends currently on this region-server about
55 user's new online status (this will save some network traffic, as local
56 messages don't have to be transferred inter-region, and it will be all
57 that has to be done in Standalone Mode).
58 - For the rest of the online friends (those not on this region-server),
59 this module uses the provided region-information to map users to
60 regions, and sends one notification to every region containing the
61 friends to inform on that server.
62 - The region-server will handle that in the following way:
63 - If it finds the friend, it informs her about the user being online.
64 - If it doesn't find the friend (maybe she TPed away in the meantime),
65 it stores that information.
66 - After it processed all friends, it returns the list of friends it
67 couldn't find.
68 - If this list isn't empty, the FriendsModule re-requests information
69 about those online friends that have been missed and starts at (*)
70 again until all friends have been found, or until it tried 3 times
71 (to prevent endless loops due to some uncaught error).
72
73 NOTE: Online/Offline notifications don't need to be sent on region change.
74
75 We implement two XMLRpc handlers here, handling all the inter-region things
76 we have to handle:
77 - On-/Offline-Notifications (bulk)
78 - Terminate Friendship messages (single)
79 */
80
81 public class FriendsModule : IRegionModule, IFriendsModule
82 {
83 private class Transaction
84 {
85 public UUID agentID;
86 public string agentName;
87 public uint count;
88
89 public Transaction(UUID agentID, string agentName)
90 {
91 this.agentID = agentID;
92 this.agentName = agentName;
93 this.count = 1;
94 }
95 }
96
97 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
98
99 private Cache m_friendLists = new Cache(CacheFlags.AllowUpdate);
100
101 private Dictionary<UUID, ulong> m_rootAgents = new Dictionary<UUID, ulong>();
102
103 private Dictionary<UUID, UUID> m_pendingCallingcardRequests = new Dictionary<UUID,UUID>();
104
105 private Scene m_initialScene; // saves a lookup if we don't have a specific scene
106 private Dictionary<ulong, Scene> m_scenes = new Dictionary<ulong,Scene>();
107 private IMessageTransferModule m_TransferModule = null;
108
109 #region IRegionModule Members
110
111 public void Initialise(Scene scene, IConfigSource config)
112 {
113 lock (m_scenes)
114 {
115 if (m_scenes.Count == 0)
116 {
117 scene.CommsManager.HttpServer.AddXmlRPCHandler("presence_update_bulk", processPresenceUpdateBulk);
118 scene.CommsManager.HttpServer.AddXmlRPCHandler("terminate_friend", processTerminateFriend);
119 m_friendLists.DefaultTTL = new TimeSpan(1, 0, 0); // store entries for one hour max
120 m_initialScene = scene;
121 }
122
123 if (!m_scenes.ContainsKey(scene.RegionInfo.RegionHandle))
124 m_scenes[scene.RegionInfo.RegionHandle] = scene;
125 }
126
127 scene.RegisterModuleInterface<IFriendsModule>(this);
128
129 scene.EventManager.OnNewClient += OnNewClient;
130 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
131 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
132 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
133 scene.EventManager.OnClientClosed += ClientClosed;
134 }
135
136 public void PostInitialise()
137 {
138 if (m_scenes.Count > 0)
139 {
140 m_TransferModule = m_initialScene.RequestModuleInterface<IMessageTransferModule>();
141 }
142 if (m_TransferModule == null)
143 m_log.Error("[FRIENDS]: Unable to find a message transfer module, friendship offers will not work");
144 }
145
146 public void Close()
147 {
148 }
149
150 public string Name
151 {
152 get { return "FriendsModule"; }
153 }
154
155 public bool IsSharedModule
156 {
157 get { return true; }
158 }
159
160 #endregion
161
162 /// <summary>
163 /// Receive presence information changes about clients in other regions.
164 /// </summary>
165 /// <param name="req"></param>
166 /// <returns></returns>
167 public XmlRpcResponse processPresenceUpdateBulk(XmlRpcRequest req)
168 {
169 Hashtable requestData = (Hashtable)req.Params[0];
170
171 List<UUID> friendsNotHere = new List<UUID>();
172
173 // this is called with the expectation that all the friends in the request are on this region-server.
174 // But as some time passed since we checked (on the other region-server, via the MessagingServer),
175 // some of the friends might have teleported away.
176 // Actually, even now, between this line and the sending below, some people could TP away. So,
177 // we'll have to lock the m_rootAgents list for the duration to prevent/delay that.
178 lock (m_rootAgents)
179 {
180 List<ScenePresence> friendsHere = new List<ScenePresence>();
181
182 try
183 {
184 UUID agentID = new UUID((string)requestData["agentID"]);
185 bool agentOnline = (bool)requestData["agentOnline"];
186 int count = (int)requestData["friendCount"];
187 for (int i = 0; i < count; ++i)
188 {
189 UUID uuid;
190 if (UUID.TryParse((string)requestData["friendID_" + i], out uuid))
191 {
192 if (m_rootAgents.ContainsKey(uuid)) friendsHere.Add(GetRootPresenceFromAgentID(uuid));
193 else friendsNotHere.Add(uuid);
194 }
195 }
196
197 // now send, as long as they are still here...
198 UUID[] agentUUID = new UUID[] { agentID };
199 if (agentOnline)
200 {
201 foreach (ScenePresence agent in friendsHere)
202 {
203 agent.ControllingClient.SendAgentOnline(agentUUID);
204 }
205 }
206 else
207 {
208 foreach (ScenePresence agent in friendsHere)
209 {
210 agent.ControllingClient.SendAgentOffline(agentUUID);
211 }
212 }
213 }
214 catch(Exception e)
215 {
216 m_log.Warn("[FRIENDS]: Got exception while parsing presence_update_bulk request:", e);
217 }
218 }
219
220 // no need to lock anymore; if TPs happen now, worst case is that we have an additional agent in this region,
221 // which should be caught on the next iteration...
222 Hashtable result = new Hashtable();
223 int idx = 0;
224 foreach (UUID uuid in friendsNotHere)
225 {
226 result["friendID_" + idx++] = uuid.ToString();
227 }
228 result["friendCount"] = idx;
229
230 XmlRpcResponse response = new XmlRpcResponse();
231 response.Value = result;
232
233 return response;
234 }
235
236 public XmlRpcResponse processTerminateFriend(XmlRpcRequest req)
237 {
238 Hashtable requestData = (Hashtable)req.Params[0];
239
240 bool success = false;
241
242 UUID agentID;
243 UUID friendID;
244 if (requestData.ContainsKey("agentID") && UUID.TryParse((string)requestData["agentID"], out agentID) &&
245 requestData.ContainsKey("friendID") && UUID.TryParse((string)requestData["friendID"], out friendID))
246 {
247 // try to find it and if it is there, prevent it to vanish before we sent the message
248 lock (m_rootAgents)
249 {
250 if (m_rootAgents.ContainsKey(agentID))
251 {
252 m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", friendID, agentID);
253 GetRootPresenceFromAgentID(agentID).ControllingClient.SendTerminateFriend(friendID);
254 success = true;
255 }
256 }
257 }
258
259 // return whether we were successful
260 Hashtable result = new Hashtable();
261 result["success"] = success;
262
263 XmlRpcResponse response = new XmlRpcResponse();
264 response.Value = result;
265 return response;
266 }
267
268 private void OnNewClient(IClientAPI client)
269 {
270 // All friends establishment protocol goes over instant message
271 // There's no way to send a message from the sim
272 // to a user to 'add a friend' without causing dialog box spam
273
274 // Subscribe to instant messages
275 client.OnInstantMessage += OnInstantMessage;
276
277 // Friend list management
278 client.OnApproveFriendRequest += OnApproveFriendRequest;
279 client.OnDenyFriendRequest += OnDenyFriendRequest;
280 client.OnTerminateFriendship += OnTerminateFriendship;
281
282 // ... calling card handling...
283 client.OnOfferCallingCard += OnOfferCallingCard;
284 client.OnAcceptCallingCard += OnAcceptCallingCard;
285 client.OnDeclineCallingCard += OnDeclineCallingCard;
286
287 // we need this one exactly once per agent session (see comments in the handler below)
288 client.OnEconomyDataRequest += OnEconomyDataRequest;
289
290 // if it leaves, we want to know, too
291 client.OnLogout += OnLogout;
292 }
293
294 private void ClientClosed(UUID AgentId)
295 {
296 // agent's client was closed. As we handle logout in OnLogout, this here has only to handle
297 // TPing away (root agent is closed) or TPing/crossing in a region far enough away (client
298 // agent is closed).
299 // NOTE: In general, this doesn't mean that the agent logged out, just that it isn't around
300 // in one of the regions here anymore.
301 lock (m_rootAgents)
302 {
303 if (m_rootAgents.ContainsKey(AgentId))
304 {
305 m_rootAgents.Remove(AgentId);
306 }
307 }
308 }
309
310 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
311 {
312 lock (m_rootAgents)
313 {
314 m_rootAgents[avatar.UUID] = avatar.RegionHandle;
315 // Claim User! my user! Mine mine mine!
316 }
317 }
318
319 private void MakeChildAgent(ScenePresence avatar)
320 {
321 lock (m_rootAgents)
322 {
323 if (m_rootAgents.ContainsKey(avatar.UUID))
324 {
325 // only delete if the region matches. As this is a shared module, the avatar could be
326 // root agent in another region on this server.
327 if (m_rootAgents[avatar.UUID] == avatar.RegionHandle)
328 {
329 m_rootAgents.Remove(avatar.UUID);
330// m_log.Debug("[FRIEND]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent");
331 }
332 }
333 }
334 }
335
336 private ScenePresence GetRootPresenceFromAgentID(UUID AgentID)
337 {
338 ScenePresence returnAgent = null;
339 lock (m_scenes)
340 {
341 ScenePresence queryagent = null;
342 foreach (Scene scene in m_scenes.Values)
343 {
344 queryagent = scene.GetScenePresence(AgentID);
345 if (queryagent != null)
346 {
347 if (!queryagent.IsChildAgent)
348 {
349 returnAgent = queryagent;
350 break;
351 }
352 }
353 }
354 }
355 return returnAgent;
356 }
357
358 private ScenePresence GetAnyPresenceFromAgentID(UUID AgentID)
359 {
360 ScenePresence returnAgent = null;
361 lock (m_scenes)
362 {
363 ScenePresence queryagent = null;
364 foreach (Scene scene in m_scenes.Values)
365 {
366 queryagent = scene.GetScenePresence(AgentID);
367 if (queryagent != null)
368 {
369 returnAgent = queryagent;
370 break;
371 }
372 }
373 }
374 return returnAgent;
375 }
376
377 public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, string offerMessage)
378 {
379 CachedUserInfo userInfo = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(fromUserId);
380
381 if (userInfo != null)
382 {
383 GridInstantMessage msg = new GridInstantMessage(
384 toUserClient.Scene, fromUserId, userInfo.UserProfile.Name, toUserClient.AgentId,
385 (byte)InstantMessageDialog.FriendshipOffered, offerMessage, false, Vector3.Zero);
386
387 FriendshipOffered(msg);
388 }
389 else
390 {
391 m_log.ErrorFormat("[FRIENDS]: No user found for id {0} in OfferFriendship()", fromUserId);
392 }
393 }
394
395 #region FriendRequestHandling
396
397 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
398 {
399 // Friend Requests go by Instant Message.. using the dialog param
400 // https://wiki.secondlife.com/wiki/ImprovedInstantMessage
401
402 if (im.dialog == (byte)InstantMessageDialog.FriendshipOffered) // 38
403 {
404 // fromAgentName is the *destination* name (the friend we offer friendship to)
405 ScenePresence initiator = GetAnyPresenceFromAgentID(new UUID(im.fromAgentID));
406 im.fromAgentName = initiator != null ? initiator.Name : "(hippo)";
407
408 FriendshipOffered(im);
409 }
410 else if (im.dialog == (byte)InstantMessageDialog.FriendshipAccepted) // 39
411 {
412 FriendshipAccepted(client, im);
413 }
414 else if (im.dialog == (byte)InstantMessageDialog.FriendshipDeclined) // 40
415 {
416 FriendshipDeclined(client, im);
417 }
418 }
419
420 /// <summary>
421 /// Invoked when a user offers a friendship.
422 /// </summary>
423 ///
424 /// <param name="im"></param>
425 /// <param name="client"></param>
426 private void FriendshipOffered(GridInstantMessage im)
427 {
428 // this is triggered by the initiating agent:
429 // A local agent offers friendship to some possibly remote friend.
430 // A IM is triggered, processed here and sent to the friend (possibly in a remote region).
431
432 m_log.DebugFormat("[FRIEND]: Offer(38) - From: {0}, FromName: {1} To: {2}, Session: {3}, Message: {4}, Offline {5}",
433 im.fromAgentID, im.fromAgentName, im.toAgentID, im.imSessionID, im.message, im.offline);
434
435 // 1.20 protocol sends an UUID in the message field, instead of the friendship offer text.
436 // For interoperability, we have to clear that
437 if (Util.isUUID(im.message)) im.message = "";
438
439 // be sneeky and use the initiator-UUID as transactionID. This means we can be stateless.
440 // we have to look up the agent name on friendship-approval, though.
441 im.imSessionID = im.fromAgentID;
442
443 if (m_TransferModule != null)
444 {
445 // Send it to whoever is the destination.
446 // If new friend is local, it will send an IM to the viewer.
447 // If new friend is remote, it will cause a OnGridInstantMessage on the remote server
448 m_TransferModule.SendInstantMessage(
449 im,
450 delegate(bool success)
451 {
452 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
453 }
454 );
455 }
456 }
457
458 /// <summary>
459 /// Invoked when a user accepts a friendship offer.
460 /// </summary>
461 /// <param name="im"></param>
462 /// <param name="client"></param>
463 private void FriendshipAccepted(IClientAPI client, GridInstantMessage im)
464 {
465 m_log.DebugFormat("[FRIEND]: 39 - from client {0}, agent {2} {3}, imsession {4} to {5}: {6} (dialog {7})",
466 client.AgentId, im.fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog);
467 }
468
469 /// <summary>
470 /// Invoked when a user declines a friendship offer.
471 /// </summary>
472 /// May not currently be used - see OnDenyFriendRequest() instead
473 /// <param name="im"></param>
474 /// <param name="client"></param>
475 private void FriendshipDeclined(IClientAPI client, GridInstantMessage im)
476 {
477 UUID fromAgentID = new UUID(im.fromAgentID);
478 UUID toAgentID = new UUID(im.toAgentID);
479
480 // declining the friendship offer causes a type 40 IM being sent to the (possibly remote) initiator
481 // toAgentID is initiator, fromAgentID declined friendship
482 m_log.DebugFormat("[FRIEND]: 40 - from client {0}, agent {1} {2}, imsession {3} to {4}: {5} (dialog {6})",
483 client != null ? client.AgentId.ToString() : "<null>",
484 fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog);
485
486 // Send the decline to whoever is the destination.
487 GridInstantMessage msg
488 = new GridInstantMessage(
489 client.Scene, fromAgentID, client.Name, toAgentID,
490 im.dialog, im.message, im.offline != 0, im.Position);
491
492 // If new friend is local, it will send an IM to the viewer.
493 // If new friend is remote, it will cause a OnGridInstantMessage on the remote server
494 m_TransferModule.SendInstantMessage(msg,
495 delegate(bool success) {
496 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
497 }
498 );
499 }
500
501 private void OnGridInstantMessage(GridInstantMessage msg)
502 {
503 // This event won't be raised unless we have that agent,
504 // so we can depend on the above not trying to send
505 // via grid again
506 m_log.DebugFormat("[FRIEND]: Got GridIM from {0}, to {1}, imSession {2}, message {3}, dialog {4}",
507 msg.fromAgentID, msg.toAgentID, msg.imSessionID, msg.message, msg.dialog);
508
509 if (msg.dialog == (byte)InstantMessageDialog.FriendshipOffered ||
510 msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted ||
511 msg.dialog == (byte)InstantMessageDialog.FriendshipDeclined)
512 {
513 // this should succeed as we *know* the root agent is here.
514 m_TransferModule.SendInstantMessage(msg,
515 delegate(bool success) {
516 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
517 }
518 );
519 }
520
521 if (msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted)
522 {
523 // for accept friendship, we have to do a bit more
524 ApproveFriendship(new UUID(msg.fromAgentID), new UUID(msg.toAgentID), msg.fromAgentName);
525 }
526 }
527
528 private void ApproveFriendship(UUID fromAgentID, UUID toAgentID, string fromName)
529 {
530 m_log.DebugFormat("[FRIEND]: Approve friendship from {0} (ID: {1}) to {2}",
531 fromAgentID, fromName, toAgentID);
532
533 // a new friend was added in the initiator's and friend's data, so the cache entries are wrong now.
534 lock (m_friendLists)
535 {
536 m_friendLists.Invalidate(fromAgentID);
537 m_friendLists.Invalidate(toAgentID);
538 }
539
540 // now send presence update and add a calling card for the new friend
541
542 ScenePresence initiator = GetAnyPresenceFromAgentID(toAgentID);
543 if (initiator == null)
544 {
545 // quite wrong. Shouldn't happen.
546 m_log.WarnFormat("[FRIEND]: Coudn't find initiator of friend request {0}", toAgentID);
547 return;
548 }
549
550 m_log.DebugFormat("[FRIEND]: Tell {0} that {1} is online",
551 initiator.Name, fromName);
552 // tell initiator that friend is online
553 initiator.ControllingClient.SendAgentOnline(new UUID[] { fromAgentID });
554
555 // find the folder for the friend...
556 InventoryFolderImpl folder =
557 initiator.Scene.CommsManager.UserProfileCacheService.GetUserDetails(toAgentID).FindFolderForType((int)InventoryType.CallingCard);
558 if (folder != null)
559 {
560 // ... and add the calling card
561 CreateCallingCard(initiator.ControllingClient, fromAgentID, folder.ID, fromName);
562 }
563 }
564
565 private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
566 {
567 m_log.DebugFormat("[FRIEND]: Got approve friendship from {0} {1}, agentID {2}, tid {3}",
568 client.Name, client.AgentId, agentID, friendID);
569
570 // store the new friend persistently for both avatars
571 m_initialScene.StoreAddFriendship(friendID, agentID, (uint) FriendRights.CanSeeOnline);
572
573 // The cache entries aren't valid anymore either, as we just added a friend to both sides.
574 lock (m_friendLists)
575 {
576 m_friendLists.Invalidate(agentID);
577 m_friendLists.Invalidate(friendID);
578 }
579
580 // if it's a local friend, we don't have to do the lookup
581 ScenePresence friendPresence = GetAnyPresenceFromAgentID(friendID);
582
583 if (friendPresence != null)
584 {
585 m_log.Debug("[FRIEND]: Local agent detected.");
586
587 // create calling card
588 CreateCallingCard(client, friendID, callingCardFolders[0], friendPresence.Name);
589
590 // local message means OnGridInstantMessage won't be triggered, so do the work here.
591 friendPresence.ControllingClient.SendInstantMessage(agentID, agentID.ToString(), friendID, client.Name,
592 (byte)InstantMessageDialog.FriendshipAccepted,
593 (uint)Util.UnixTimeSinceEpoch());
594 ApproveFriendship(agentID, friendID, client.Name);
595 }
596 else
597 {
598 m_log.Debug("[FRIEND]: Remote agent detected.");
599
600 // fetch the friend's name for the calling card.
601 CachedUserInfo info = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(friendID);
602
603 // create calling card
604 CreateCallingCard(client, friendID, callingCardFolders[0],
605 info.UserProfile.FirstName + " " + info.UserProfile.SurName);
606
607 // Compose (remote) response to friend.
608 GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID,
609 (byte)InstantMessageDialog.FriendshipAccepted,
610 agentID.ToString(), false, Vector3.Zero);
611 if (m_TransferModule != null)
612 {
613 m_TransferModule.SendInstantMessage(msg,
614 delegate(bool success) {
615 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
616 }
617 );
618 }
619 }
620
621 // tell client that new friend is online
622 client.SendAgentOnline(new UUID[] { friendID });
623 }
624
625 private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
626 {
627 m_log.DebugFormat("[FRIEND]: Got deny friendship from {0} {1}, agentID {2}, tid {3}",
628 client.Name, client.AgentId, agentID, friendID);
629
630 // Compose response to other agent.
631 GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID,
632 (byte)InstantMessageDialog.FriendshipDeclined,
633 agentID.ToString(), false, Vector3.Zero);
634 // send decline to initiator
635 if (m_TransferModule != null)
636 {
637 m_TransferModule.SendInstantMessage(msg,
638 delegate(bool success) {
639 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
640 }
641 );
642 }
643 }
644
645 private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID)
646 {
647 // client.AgentId == agentID!
648
649 // this removes the friends from the stored friendlists. After the next login, they will be gone...
650 m_initialScene.StoreRemoveFriendship(agentID, exfriendID);
651
652 // ... now tell the two involved clients that they aren't friends anymore.
653
654 // I don't know why we have to tell <agent>, as this was caused by her, but that's how it works in SL...
655 client.SendTerminateFriend(exfriendID);
656
657 // now send the friend, if online
658 ScenePresence presence = GetAnyPresenceFromAgentID(exfriendID);
659 if (presence != null)
660 {
661 m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", agentID, exfriendID);
662 presence.ControllingClient.SendTerminateFriend(agentID);
663 }
664 else
665 {
666 // retry 3 times, in case the agent TPed from the last known region...
667 for (int retry = 0; retry < 3; ++retry)
668 {
669 // wasn't sent, so ex-friend wasn't around on this region-server. Fetch info and try to send
670 UserAgentData data = m_initialScene.CommsManager.UserService.GetAgentByUUID(exfriendID);
671
672 if (null == data)
673 break;
674
675 if (!data.AgentOnline)
676 {
677 m_log.DebugFormat("[FRIEND]: {0} is offline, so not sending TerminateFriend", exfriendID);
678 break; // if ex-friend isn't online, we don't need to send
679 }
680
681 m_log.DebugFormat("[FRIEND]: Sending remote terminate friend {0} to agent {1}@{2}",
682 agentID, exfriendID, data.Handle);
683
684 // try to send to foreign region, retry if it fails (friend TPed away, for example)
685 if (m_initialScene.TriggerTerminateFriend(data.Handle, exfriendID, agentID)) break;
686 }
687 }
688
689 // clean up cache: FriendList is wrong now...
690 lock (m_friendLists)
691 {
692 m_friendLists.Invalidate(agentID);
693 m_friendLists.Invalidate(exfriendID);
694 }
695 }
696
697 #endregion
698
699 #region CallingCards
700
701 private void OnOfferCallingCard(IClientAPI client, UUID destID, UUID transactionID)
702 {
703 m_log.DebugFormat("[CALLING CARD]: got offer from {0} for {1}, transaction {2}",
704 client.AgentId, destID, transactionID);
705 // This might be slightly wrong. On a multi-region server, we might get the child-agent instead of the root-agent
706 // (or the root instead of the child)
707 ScenePresence destAgent = GetAnyPresenceFromAgentID(destID);
708 if (destAgent == null)
709 {
710 client.SendAlertMessage("The person you have offered a card to can't be found anymore.");
711 return;
712 }
713
714 lock (m_pendingCallingcardRequests)
715 {
716 m_pendingCallingcardRequests[transactionID] = client.AgentId;
717 }
718 // inform the destination agent about the offer
719 destAgent.ControllingClient.SendOfferCallingCard(client.AgentId, transactionID);
720 }
721
722 private void CreateCallingCard(IClientAPI client, UUID creator, UUID folder, string name)
723 {
724 InventoryItemBase item = new InventoryItemBase();
725 item.AssetID = UUID.Zero;
726 item.AssetType = (int)AssetType.CallingCard;
727 item.BasePermissions = (uint)PermissionMask.Copy;
728 item.CreationDate = Util.UnixTimeSinceEpoch();
729 item.Creator = creator;
730 item.CurrentPermissions = item.BasePermissions;
731 item.Description = "";
732 item.EveryOnePermissions = (uint)PermissionMask.None;
733 item.Flags = 0;
734 item.Folder = folder;
735 item.GroupID = UUID.Zero;
736 item.GroupOwned = false;
737 item.ID = UUID.Random();
738 item.InvType = (int)InventoryType.CallingCard;
739 item.Name = name;
740 item.NextPermissions = item.EveryOnePermissions;
741 item.Owner = client.AgentId;
742 item.SalePrice = 10;
743 item.SaleType = (byte)SaleType.Not;
744 ((Scene)client.Scene).AddInventoryItem(client, item);
745 }
746
747 private void OnAcceptCallingCard(IClientAPI client, UUID transactionID, UUID folderID)
748 {
749 m_log.DebugFormat("[CALLING CARD]: User {0} ({1} {2}) accepted tid {3}, folder {4}",
750 client.AgentId,
751 client.FirstName, client.LastName,
752 transactionID, folderID);
753 UUID destID;
754 lock (m_pendingCallingcardRequests)
755 {
756 if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID))
757 {
758 m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.",
759 client.Name);
760 return;
761 }
762 // else found pending calling card request with that transaction.
763 m_pendingCallingcardRequests.Remove(transactionID);
764 }
765
766
767 ScenePresence destAgent = GetAnyPresenceFromAgentID(destID);
768 // inform sender of the card that destination declined the offer
769 if (destAgent != null) destAgent.ControllingClient.SendAcceptCallingCard(transactionID);
770
771 // put a calling card into the inventory of receiver
772 CreateCallingCard(client, destID, folderID, destAgent.Name);
773 }
774
775 private void OnDeclineCallingCard(IClientAPI client, UUID transactionID)
776 {
777 m_log.DebugFormat("[CALLING CARD]: User {0} (ID:{1}) declined card, tid {2}",
778 client.Name, client.AgentId, transactionID);
779 UUID destID;
780 lock (m_pendingCallingcardRequests)
781 {
782 if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID))
783 {
784 m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.",
785 client.Name);
786 return;
787 }
788 // else found pending calling card request with that transaction.
789 m_pendingCallingcardRequests.Remove(transactionID);
790 }
791
792 ScenePresence destAgent = GetAnyPresenceFromAgentID(destID);
793 // inform sender of the card that destination declined the offer
794 if (destAgent != null) destAgent.ControllingClient.SendDeclineCallingCard(transactionID);
795 }
796
797 /// <summary>
798 /// Send presence information about a client to other clients in both this region and others.
799 /// </summary>
800 /// <param name="client"></param>
801 /// <param name="friendList"></param>
802 /// <param name="iAmOnline"></param>
803 private void SendPresenceState(IClientAPI client, List<FriendListItem> friendList, bool iAmOnline)
804 {
805 //m_log.DebugFormat("[FRIEND]: {0} logged {1}; sending presence updates", client.Name, iAmOnline ? "in" : "out");
806
807 if (friendList == null || friendList.Count == 0)
808 {
809 //m_log.DebugFormat("[FRIEND]: {0} doesn't have friends.", client.Name);
810 return; // nothing we can do if she doesn't have friends...
811 }
812
813 // collect sets of friendIDs; to send to (online and offline), and to receive from
814 // TODO: If we ever switch to .NET >= 3, replace those Lists with HashSets.
815 // I can't believe that we have Dictionaries, but no Sets, considering Java introduced them years ago...
816 List<UUID> friendIDsToSendTo = new List<UUID>();
817 List<UUID> candidateFriendIDsToReceive = new List<UUID>();
818
819 foreach (FriendListItem item in friendList)
820 {
821 if (((item.FriendListOwnerPerms | item.FriendPerms) & (uint)FriendRights.CanSeeOnline) != 0)
822 {
823 // friend is allowed to see my presence => add
824 if ((item.FriendListOwnerPerms & (uint)FriendRights.CanSeeOnline) != 0)
825 friendIDsToSendTo.Add(item.Friend);
826
827 if ((item.FriendPerms & (uint)FriendRights.CanSeeOnline) != 0)
828 candidateFriendIDsToReceive.Add(item.Friend);
829 }
830 }
831
832 // we now have a list of "interesting" friends (which we have to find out on-/offline state for),
833 // friends we want to send our online state to (if *they* are online, too), and
834 // friends we want to receive online state for (currently unknown whether online or not)
835
836 // as this processing might take some time and friends might TP away, we try up to three times to
837 // reach them. Most of the time, we *will* reach them, and this loop won't loop
838 int retry = 0;
839 do
840 {
841 // build a list of friends to look up region-information and on-/offline-state for
842 List<UUID> friendIDsToLookup = new List<UUID>(friendIDsToSendTo);
843 foreach (UUID uuid in candidateFriendIDsToReceive)
844 {
845 if (!friendIDsToLookup.Contains(uuid)) friendIDsToLookup.Add(uuid);
846 }
847
848 m_log.DebugFormat(
849 "[FRIEND]: {0} to lookup, {1} to send to, {2} candidates to receive from for agent {3}",
850 friendIDsToLookup.Count, friendIDsToSendTo.Count, candidateFriendIDsToReceive.Count, client.Name);
851
852 // we have to fetch FriendRegionInfos, as the (cached) FriendListItems don't
853 // necessarily contain the correct online state...
854 Dictionary<UUID, FriendRegionInfo> friendRegions = m_initialScene.GetFriendRegionInfos(friendIDsToLookup);
855 m_log.DebugFormat(
856 "[FRIEND]: Found {0} regionInfos for {1} friends of {2}",
857 friendRegions.Count, friendIDsToLookup.Count, client.Name);
858
859 // argument for SendAgentOn/Offline; we shouldn't generate that repeatedly within loops.
860 UUID[] agentArr = new UUID[] { client.AgentId };
861
862 // first, send to friend presence state to me, if I'm online...
863 if (iAmOnline)
864 {
865 List<UUID> friendIDsToReceive = new List<UUID>();
866
867 for (int i = candidateFriendIDsToReceive.Count - 1; i >= 0; --i)
868 {
869 UUID uuid = candidateFriendIDsToReceive[i];
870 FriendRegionInfo info;
871 if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline)
872 {
873 friendIDsToReceive.Add(uuid);
874 }
875 }
876
877 m_log.DebugFormat(
878 "[FRIEND]: Sending {0} online friends to {1}", friendIDsToReceive.Count, client.Name);
879
880 if (friendIDsToReceive.Count > 0)
881 client.SendAgentOnline(friendIDsToReceive.ToArray());
882
883 // clear them for a possible second iteration; we don't have to repeat this
884 candidateFriendIDsToReceive.Clear();
885 }
886
887 // now, send my presence state to my friends
888 for (int i = friendIDsToSendTo.Count - 1; i >= 0; --i)
889 {
890 UUID uuid = friendIDsToSendTo[i];
891 FriendRegionInfo info;
892 if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline)
893 {
894 // any client is good enough, root or child...
895 ScenePresence agent = GetAnyPresenceFromAgentID(uuid);
896 if (agent != null)
897 {
898 m_log.DebugFormat("[FRIEND]: Found local agent {0}", agent.Name);
899
900 // friend is online and on this server...
901 if (iAmOnline) agent.ControllingClient.SendAgentOnline(agentArr);
902 else agent.ControllingClient.SendAgentOffline(agentArr);
903
904 // done, remove it
905 friendIDsToSendTo.RemoveAt(i);
906 }
907 }
908 else
909 {
910 m_log.DebugFormat("[FRIEND]: Friend {0} ({1}) is offline; not sending.", uuid, i);
911
912 // friend is offline => no need to try sending
913 friendIDsToSendTo.RemoveAt(i);
914 }
915 }
916
917 m_log.DebugFormat("[FRIEND]: Have {0} friends to contact via inter-region comms.", friendIDsToSendTo.Count);
918
919 // we now have all the friends left that are online (we think), but not on this region-server
920 if (friendIDsToSendTo.Count > 0)
921 {
922 // sort them into regions
923 Dictionary<ulong, List<UUID>> friendsInRegion = new Dictionary<ulong,List<UUID>>();
924 foreach (UUID uuid in friendIDsToSendTo)
925 {
926 ulong handle = friendRegions[uuid].regionHandle; // this can't fail as we filtered above already
927 List<UUID> friends;
928 if (!friendsInRegion.TryGetValue(handle, out friends))
929 {
930 friends = new List<UUID>();
931 friendsInRegion[handle] = friends;
932 }
933 friends.Add(uuid);
934 }
935 m_log.DebugFormat("[FRIEND]: Found {0} regions to send to.", friendRegions.Count);
936
937 // clear uuids list and collect missed friends in it for the next retry
938 friendIDsToSendTo.Clear();
939
940 // send bulk updates to the region
941 foreach (KeyValuePair<ulong, List<UUID>> pair in friendsInRegion)
942 {
943 m_log.DebugFormat("[FRIEND]: Inform {0} friends in region {1} that user {2} is {3}line",
944 pair.Value.Count, pair.Key, client.Name, iAmOnline ? "on" : "off");
945
946 friendIDsToSendTo.AddRange(m_initialScene.InformFriendsInOtherRegion(client.AgentId, pair.Key, pair.Value, iAmOnline));
947 }
948 }
949 // now we have in friendIDsToSendTo only the agents left that TPed away while we tried to contact them.
950 // In most cases, it will be empty, and it won't loop here. But sometimes, we have to work harder and try again...
951 }
952 while (++retry < 3 && friendIDsToSendTo.Count > 0);
953 }
954
955 private void OnEconomyDataRequest(UUID agentID)
956 {
957 // KLUDGE: This is the only way I found to get a message (only) after login was completed and the
958 // client is connected enough to receive UDP packets).
959 // This packet seems to be sent only once, just after connection was established to the first
960 // region after login.
961 // We use it here to trigger a presence update; the old update-on-login was never be heard by
962 // the freshly logged in viewer, as it wasn't connected to the region at that time.
963 // TODO: Feel free to replace this by a better solution if you find one.
964
965 // get the agent. This should work every time, as we just got a packet from it
966 //ScenePresence agent = GetRootPresenceFromAgentID(agentID);
967 // KLUDGE 2: As this is sent quite early, the avatar isn't here as root agent yet. So, we have to cheat a bit
968 ScenePresence agent = GetAnyPresenceFromAgentID(agentID);
969
970 // just to be paranoid...
971 if (agent == null)
972 {
973 m_log.ErrorFormat("[FRIEND]: Got a packet from agent {0} who can't be found anymore!?", agentID);
974 return;
975 }
976
977 List<FriendListItem> fl;
978 lock (m_friendLists)
979 {
980 fl = (List<FriendListItem>)m_friendLists.Get(agent.ControllingClient.AgentId,
981 m_initialScene.GetFriendList);
982 }
983
984 // tell everyone that we are online
985 SendPresenceState(agent.ControllingClient, fl, true);
986 }
987
988 private void OnLogout(IClientAPI remoteClient)
989 {
990 List<FriendListItem> fl;
991 lock (m_friendLists)
992 {
993 fl = (List<FriendListItem>)m_friendLists.Get(remoteClient.AgentId,
994 m_initialScene.GetFriendList);
995 }
996
997 // tell everyone that we are offline
998 SendPresenceState(remoteClient, fl, false);
999 }
1000 }
1001
1002 #endregion
1003}
diff --git a/OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs b/OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs
new file mode 100644
index 0000000..a3a642f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs
@@ -0,0 +1,104 @@
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 log4net;
29using Nini.Config;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Framework.Communications;
33using OpenSim.Framework.Communications.Cache;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36using System.Reflection;
37
38namespace OpenSim.Region.CoreModules.Avatar.Gestures
39{
40 public class GesturesModule : IRegionModule
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 protected Scene m_scene;
45
46 public void Initialise(Scene scene, IConfigSource source)
47 {
48 m_scene = scene;
49
50 m_scene.EventManager.OnNewClient += OnNewClient;
51 }
52
53 public void PostInitialise() {}
54 public void Close() {}
55 public string Name { get { return "Gestures Module"; } }
56 public bool IsSharedModule { get { return false; } }
57
58 private void OnNewClient(IClientAPI client)
59 {
60 client.OnActivateGesture += ActivateGesture;
61 client.OnDeactivateGesture += DeactivateGesture;
62 }
63
64 public virtual void ActivateGesture(IClientAPI client, UUID assetId, UUID gestureId)
65 {
66 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(client.AgentId);
67
68 if (userInfo != null)
69 {
70 InventoryItemBase item = userInfo.RootFolder.FindItem(gestureId);
71 if (item != null)
72 {
73 item.Flags = 1;
74 userInfo.UpdateItem(item);
75 }
76 else
77 m_log.ErrorFormat(
78 "[GESTURES]: Unable to find gesture to activate {0} for {1}", gestureId, client.Name);
79 }
80 else
81 m_log.ErrorFormat("[GESTURES]: Unable to find user {0}", client.Name);
82 }
83
84 public virtual void DeactivateGesture(IClientAPI client, UUID gestureId)
85 {
86 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(client.AgentId);
87
88 if (userInfo != null)
89 {
90 InventoryItemBase item = userInfo.RootFolder.FindItem(gestureId);
91 if (item != null)
92 {
93 item.Flags = 0;
94 userInfo.UpdateItem(item);
95 }
96 else
97 m_log.ErrorFormat(
98 "[GESTURES]: Unable to find gesture to deactivate {0} for {1}", gestureId, client.Name);
99 }
100 else
101 m_log.ErrorFormat("[GESTURES]: Unable to find user {0}", client.Name);
102 }
103 }
104} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
new file mode 100644
index 0000000..92d0fdd
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
@@ -0,0 +1,223 @@
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 OpenMetaverse;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.CoreModules.Avatar.Groups
39{
40 public class GroupsModule : IRegionModule
41 {
42 private static readonly ILog m_log =
43 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 private Dictionary<UUID, GroupMembershipData> m_GroupMap =
46 new Dictionary<UUID, GroupMembershipData>();
47
48 private Dictionary<UUID, IClientAPI> m_ClientMap =
49 new Dictionary<UUID, IClientAPI>();
50
51 private UUID opensimulatorGroupID =
52 new UUID("00000000-68f9-1111-024e-222222111123");
53
54 private List<Scene> m_SceneList = new List<Scene>();
55
56 private static GroupMembershipData osGroup =
57 new GroupMembershipData();
58
59 #region IRegionModule Members
60
61 public void Initialise(Scene scene, IConfigSource config)
62 {
63 IConfig groupsConfig = config.Configs["Groups"];
64
65 if (groupsConfig == null)
66 {
67 m_log.Info("[GROUPS]: No configuration found. Using defaults");
68 }
69 else
70 {
71 if (!groupsConfig.GetBoolean("Enabled", false))
72 {
73 m_log.Info("[GROUPS]: Groups disabled in configuration");
74 return;
75 }
76
77 if (groupsConfig.GetString("Module", "Default") != "Default")
78 return;
79 }
80
81 lock (m_SceneList)
82 {
83 if (!m_SceneList.Contains(scene))
84 {
85 if (m_SceneList.Count == 0)
86 {
87 osGroup.GroupID = opensimulatorGroupID;
88 osGroup.GroupName = "OpenSimulator Testing";
89 osGroup.GroupPowers =
90 (uint)(GroupPowers.AllowLandmark |
91 GroupPowers.AllowSetHome);
92 m_GroupMap[opensimulatorGroupID] = osGroup;
93 }
94 m_SceneList.Add(scene);
95 }
96 }
97
98 scene.EventManager.OnNewClient += OnNewClient;
99 scene.EventManager.OnClientClosed += OnClientClosed;
100 scene.EventManager.OnIncomingInstantMessage +=
101 OnGridInstantMessage;
102 }
103
104 public void PostInitialise()
105 {
106 }
107
108 public void Close()
109 {
110// m_log.Debug("[GROUPS]: Shutting down group module.");
111
112 lock (m_ClientMap)
113 {
114 m_ClientMap.Clear();
115 }
116
117 lock (m_GroupMap)
118 {
119 m_GroupMap.Clear();
120 }
121 }
122
123 public string Name
124 {
125 get { return "GroupsModule"; }
126 }
127
128 public bool IsSharedModule
129 {
130 get { return true; }
131 }
132
133 #endregion
134
135 private void OnNewClient(IClientAPI client)
136 {
137 // Subscribe to instant messages
138 client.OnInstantMessage += OnInstantMessage;
139 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
140 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
141 lock (m_ClientMap)
142 {
143 if (!m_ClientMap.ContainsKey(client.AgentId))
144 {
145 m_ClientMap.Add(client.AgentId, client);
146 }
147 }
148
149 GroupMembershipData[] updateGroups = new GroupMembershipData[1];
150 updateGroups[0] = osGroup;
151
152 client.SendGroupMembership(updateGroups);
153 }
154
155 private void OnAgentDataUpdateRequest(IClientAPI remoteClient,
156 UUID AgentID, UUID SessionID)
157 {
158 UUID ActiveGroupID;
159 string ActiveGroupName;
160 ulong ActiveGroupPowers;
161
162 string firstname = remoteClient.FirstName;
163 string lastname = remoteClient.LastName;
164
165 string ActiveGroupTitle = "I IZ N0T";
166
167 ActiveGroupID = osGroup.GroupID;
168 ActiveGroupName = osGroup.GroupName;
169 ActiveGroupPowers = osGroup.GroupPowers;
170
171 remoteClient.SendAgentDataUpdate(AgentID, ActiveGroupID, firstname,
172 lastname, ActiveGroupPowers, ActiveGroupName,
173 ActiveGroupTitle);
174 }
175
176 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
177 {
178 }
179
180 private void OnGridInstantMessage(GridInstantMessage msg)
181 {
182 // Trigger the above event handler
183 OnInstantMessage(null, msg);
184 }
185
186 private void HandleUUIDGroupNameRequest(UUID id,IClientAPI remote_client)
187 {
188 string groupnamereply = "Unknown";
189 UUID groupUUID = UUID.Zero;
190
191 lock (m_GroupMap)
192 {
193 if (m_GroupMap.ContainsKey(id))
194 {
195 GroupMembershipData grp = m_GroupMap[id];
196 groupnamereply = grp.GroupName;
197 groupUUID = grp.GroupID;
198 }
199 }
200 remote_client.SendGroupNameReply(groupUUID, groupnamereply);
201 }
202
203 private void OnClientClosed(UUID agentID)
204 {
205 lock (m_ClientMap)
206 {
207 if (m_ClientMap.ContainsKey(agentID))
208 {
209// IClientAPI cli = m_ClientMap[agentID];
210// if (cli != null)
211// {
212// //m_log.Info("[GROUPS]: Removing all reference to groups for " + cli.Name);
213// }
214// else
215// {
216// //m_log.Info("[GROUPS]: Removing all reference to groups for " + agentID.ToString());
217// }
218 m_ClientMap.Remove(agentID);
219 }
220 }
221 }
222 }
223}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
new file mode 100644
index 0000000..3ad2c91
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
@@ -0,0 +1,170 @@
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;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Net;
32using System.Threading;
33using OpenMetaverse;
34using log4net;
35using Nini.Config;
36using Nwc.XmlRpc;
37using OpenSim.Framework;
38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
43{
44 public class InstantMessageModule : IRegionModule
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 /// <value>
49 /// Is this module enabled?
50 /// </value>
51 private bool m_enabled = false;
52
53 private readonly List<Scene> m_scenes = new List<Scene>();
54
55 #region IRegionModule Members
56
57 private IMessageTransferModule m_TransferModule = null;
58
59 public void Initialise(Scene scene, IConfigSource config)
60 {
61 if (config.Configs["Messaging"] != null)
62 {
63 if (config.Configs["Messaging"].GetString(
64 "InstantMessageModule", "InstantMessageModule") !=
65 "InstantMessageModule")
66 return;
67 }
68
69 m_enabled = true;
70
71 lock (m_scenes)
72 {
73 if (!m_scenes.Contains(scene))
74 {
75 m_scenes.Add(scene);
76 scene.EventManager.OnClientConnect += OnClientConnect;
77 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
78 }
79 }
80 }
81
82 void OnClientConnect(IClientCore client)
83 {
84 IClientIM clientIM;
85 if (client.TryGet(out clientIM))
86 {
87 clientIM.OnInstantMessage += OnInstantMessage;
88 }
89 }
90
91 public void PostInitialise()
92 {
93 if (!m_enabled)
94 return;
95
96 m_TransferModule =
97 m_scenes[0].RequestModuleInterface<IMessageTransferModule>();
98
99 if (m_TransferModule == null)
100 m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+
101 "IM will not work!");
102 }
103
104 public void Close()
105 {
106 }
107
108 public string Name
109 {
110 get { return "InstantMessageModule"; }
111 }
112
113 public bool IsSharedModule
114 {
115 get { return true; }
116 }
117
118 #endregion
119
120 public void OnInstantMessage(IClientAPI client, GridInstantMessage im)
121 {
122 byte dialog = im.dialog;
123
124 if ( dialog != (byte)InstantMessageDialog.MessageFromAgent
125 && dialog != (byte)InstantMessageDialog.StartTyping
126 && dialog != (byte)InstantMessageDialog.StopTyping)
127 {
128 return;
129 }
130
131 if (m_TransferModule != null)
132 {
133 m_TransferModule.SendInstantMessage(im,
134 delegate(bool success)
135 {
136 if (dialog == (uint)InstantMessageDialog.StartTyping ||
137 dialog == (uint)InstantMessageDialog.StopTyping)
138 {
139 return;
140 }
141
142 if ((client != null) && !success)
143 {
144 client.SendInstantMessage(new UUID(im.toAgentID),
145 "Unable to send instant message. "+
146 "User is not logged in.",
147 new UUID(im.fromAgentID), "System",
148 (byte)InstantMessageDialog.BusyAutoResponse,
149 (uint)Util.UnixTimeSinceEpoch());
150 }
151 }
152 );
153 }
154 }
155
156 /// <summary>
157 ///
158 /// </summary>
159 /// <param name="msg"></param>
160 private void OnGridInstantMessage(GridInstantMessage msg)
161 {
162 // Just call the Text IM handler above
163 // This event won't be raised unless we have that agent,
164 // so we can depend on the above not trying to send
165 // via grid again
166 //
167 OnInstantMessage(null, msg);
168 }
169 }
170}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
new file mode 100644
index 0000000..91c22eb
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -0,0 +1,655 @@
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;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Net;
32using System.Threading;
33using OpenMetaverse;
34using log4net;
35using Nini.Config;
36using Nwc.XmlRpc;
37using OpenSim.Framework;
38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
43{
44 public class MessageTransferModule : IRegionModule, IMessageTransferModule
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 // private bool m_Enabled = false;
49 private bool m_Gridmode = false;
50 private List<Scene> m_Scenes = new List<Scene>();
51 private Dictionary<UUID, ulong> m_UserRegionMap = new Dictionary<UUID, ulong>();
52
53 public void Initialise(Scene scene, IConfigSource config)
54 {
55 IConfig cnf = config.Configs["Messaging"];
56 if (cnf != null && cnf.GetString(
57 "MessageTransferModule", "MessageTransferModule") !=
58 "MessageTransferModule")
59 return;
60
61 cnf = config.Configs["Startup"];
62 if (cnf != null)
63 m_Gridmode = cnf.GetBoolean("gridmode", false);
64
65 // m_Enabled = true;
66
67 lock (m_Scenes)
68 {
69 if (m_Scenes.Count == 0)
70 {
71 scene.CommsManager.HttpServer.AddXmlRPCHandler(
72 "grid_instant_message", processXMLRPCGridInstantMessage);
73 }
74
75 scene.RegisterModuleInterface<IMessageTransferModule>(this);
76 m_Scenes.Add(scene);
77 }
78 }
79
80 public void PostInitialise()
81 {
82 }
83
84 public void Close()
85 {
86 }
87
88 public string Name
89 {
90 get { return "MessageTransferModule"; }
91 }
92
93 public bool IsSharedModule
94 {
95 get { return true; }
96 }
97
98 public void SendInstantMessage(GridInstantMessage im, MessageResultNotification result)
99 {
100 UUID toAgentID = new UUID(im.toAgentID);
101
102 m_log.DebugFormat("[INSTANT MESSAGE]: Attempting delivery of IM from {0} to {1}", im.fromAgentName, toAgentID.ToString());
103
104 // Try root avatar only first
105 foreach (Scene scene in m_Scenes)
106 {
107 if (scene.Entities.ContainsKey(toAgentID) &&
108 scene.Entities[toAgentID] is ScenePresence)
109 {
110 m_log.DebugFormat("[INSTANT MESSAGE]: Looking for {0} in {1}", toAgentID.ToString(), scene.RegionInfo.RegionName);
111 // Local message
112 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
113 if (!user.IsChildAgent)
114 {
115 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
116 user.ControllingClient.SendInstantMessage(
117 new UUID(im.fromAgentID),
118 im.message,
119 new UUID(im.toAgentID),
120 im.fromAgentName,
121 im.dialog,
122 im.timestamp,
123 new UUID(im.imSessionID),
124 im.fromGroup,
125 im.binaryBucket);
126 // Message sent
127 result(true);
128 return;
129 }
130 }
131 }
132
133 // try child avatar second
134 foreach (Scene scene in m_Scenes)
135 {
136// m_log.DebugFormat(
137// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
138
139 if (scene.Entities.ContainsKey(toAgentID) &&
140 scene.Entities[toAgentID] is ScenePresence)
141 {
142 // Local message
143 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
144
145 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
146 user.ControllingClient.SendInstantMessage(
147 new UUID(im.fromAgentID),
148 im.message,
149 new UUID(im.toAgentID),
150 im.fromAgentName,
151 im.dialog,
152 im.timestamp,
153 new UUID(im.imSessionID),
154 im.fromGroup,
155 im.binaryBucket);
156 // Message sent
157 result(true);
158 return;
159 }
160 }
161
162 if (m_Gridmode)
163 {
164 //m_log.DebugFormat("[INSTANT MESSAGE]: Delivering via grid");
165 // Still here, try send via Grid
166 SendGridInstantMessageViaXMLRPC(im, result);
167 return;
168 }
169
170 //m_log.DebugFormat("[INSTANT MESSAGE]: Undeliverable");
171 result(false);
172 return;
173 }
174
175 /// <summary>
176 /// Process a XMLRPC Grid Instant Message
177 /// </summary>
178 /// <param name="request">XMLRPC parameters
179 /// </param>
180 /// <returns>Nothing much</returns>
181 protected virtual XmlRpcResponse processXMLRPCGridInstantMessage(XmlRpcRequest request)
182 {
183 bool successful = false;
184
185 // TODO: For now, as IMs seem to be a bit unreliable on OSGrid, catch all exception that
186 // happen here and aren't caught and log them.
187 try
188 {
189 // various rational defaults
190 UUID fromAgentID = UUID.Zero;
191 UUID toAgentID = UUID.Zero;
192 UUID imSessionID = UUID.Zero;
193 uint timestamp = 0;
194 string fromAgentName = "";
195 string message = "";
196 byte dialog = (byte)0;
197 bool fromGroup = false;
198 byte offline = (byte)0;
199 uint ParentEstateID=0;
200 Vector3 Position = Vector3.Zero;
201 UUID RegionID = UUID.Zero ;
202 byte[] binaryBucket = new byte[0];
203
204 float pos_x = 0;
205 float pos_y = 0;
206 float pos_z = 0;
207 //m_log.Info("Processing IM");
208
209
210 Hashtable requestData = (Hashtable)request.Params[0];
211 // Check if it's got all the data
212 if (requestData.ContainsKey("from_agent_id")
213 && requestData.ContainsKey("to_agent_id") && requestData.ContainsKey("im_session_id")
214 && requestData.ContainsKey("timestamp") && requestData.ContainsKey("from_agent_name")
215 && requestData.ContainsKey("message") && requestData.ContainsKey("dialog")
216 && requestData.ContainsKey("from_group")
217 && requestData.ContainsKey("offline") && requestData.ContainsKey("parent_estate_id")
218 && requestData.ContainsKey("position_x") && requestData.ContainsKey("position_y")
219 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
220 && requestData.ContainsKey("binary_bucket"))
221 {
222 // Do the easy way of validating the UUIDs
223 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
224 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
225 UUID.TryParse((string)requestData["im_session_id"], out imSessionID);
226 UUID.TryParse((string)requestData["region_id"], out RegionID);
227
228 try
229 {
230 timestamp = (uint)Convert.ToInt32((string)requestData["timestamp"]);
231 }
232 catch (ArgumentException)
233 {
234 }
235 catch (FormatException)
236 {
237 }
238 catch (OverflowException)
239 {
240 }
241
242 fromAgentName = (string)requestData["from_agent_name"];
243 message = (string)requestData["message"];
244
245 // Bytes don't transfer well over XMLRPC, so, we Base64 Encode them.
246 string requestData1 = (string)requestData["dialog"];
247 if (string.IsNullOrEmpty(requestData1))
248 {
249 dialog = 0;
250 }
251 else
252 {
253 byte[] dialogdata = Convert.FromBase64String(requestData1);
254 dialog = dialogdata[0];
255 }
256
257 if ((string)requestData["from_group"] == "TRUE")
258 fromGroup = true;
259
260 string requestData2 = (string)requestData["offline"];
261 if (String.IsNullOrEmpty(requestData2))
262 {
263 offline = 0;
264 }
265 else
266 {
267 byte[] offlinedata = Convert.FromBase64String(requestData2);
268 offline = offlinedata[0];
269 }
270
271 try
272 {
273 ParentEstateID = (uint)Convert.ToInt32((string)requestData["parent_estate_id"]);
274 }
275 catch (ArgumentException)
276 {
277 }
278 catch (FormatException)
279 {
280 }
281 catch (OverflowException)
282 {
283 }
284
285 try
286 {
287 pos_x = (uint)Convert.ToInt32((string)requestData["position_x"]);
288 }
289 catch (ArgumentException)
290 {
291 }
292 catch (FormatException)
293 {
294 }
295 catch (OverflowException)
296 {
297 }
298 try
299 {
300 pos_y = (uint)Convert.ToInt32((string)requestData["position_y"]);
301 }
302 catch (ArgumentException)
303 {
304 }
305 catch (FormatException)
306 {
307 }
308 catch (OverflowException)
309 {
310 }
311 try
312 {
313 pos_z = (uint)Convert.ToInt32((string)requestData["position_z"]);
314 }
315 catch (ArgumentException)
316 {
317 }
318 catch (FormatException)
319 {
320 }
321 catch (OverflowException)
322 {
323 }
324
325 Position = new Vector3(pos_x, pos_y, pos_z);
326
327 string requestData3 = (string)requestData["binary_bucket"];
328 if (string.IsNullOrEmpty(requestData3))
329 {
330 binaryBucket = new byte[0];
331 }
332 else
333 {
334 binaryBucket = Convert.FromBase64String(requestData3);
335 }
336
337 // Create a New GridInstantMessageObject the the data
338 GridInstantMessage gim = new GridInstantMessage();
339 gim.fromAgentID = fromAgentID.Guid;
340 gim.fromAgentName = fromAgentName;
341 gim.fromGroup = fromGroup;
342 gim.imSessionID = imSessionID.Guid;
343 gim.RegionID = RegionID.Guid;
344 gim.timestamp = timestamp;
345 gim.toAgentID = toAgentID.Guid;
346 gim.message = message;
347 gim.dialog = dialog;
348 gim.offline = offline;
349 gim.ParentEstateID = ParentEstateID;
350 gim.Position = Position;
351 gim.binaryBucket = binaryBucket;
352
353
354 // Trigger the Instant message in the scene.
355 foreach (Scene scene in m_Scenes)
356 {
357 if (scene.Entities.ContainsKey(toAgentID) &&
358 scene.Entities[toAgentID] is ScenePresence)
359 {
360 ScenePresence user =
361 (ScenePresence)scene.Entities[toAgentID];
362
363 if (!user.IsChildAgent)
364 {
365 scene.EventManager.TriggerIncomingInstantMessage(gim);
366 successful = true;
367 }
368 }
369 }
370 if (!successful)
371 {
372 // If the message can't be delivered to an agent, it
373 // is likely to be a group IM. On a group IM, the
374 // imSessionID = toAgentID = group id. Raise the
375 // unhandled IM event to give the groups module
376 // a chance to pick it up. We raise that in a random
377 // scene, since the groups module is shared.
378 //
379 m_Scenes[0].EventManager.TriggerUnhandledInstantMessage(gim);
380 }
381 }
382 }
383 catch (Exception e)
384 {
385 m_log.Error("[INSTANT MESSAGE]: Caught unexpected exception:", e);
386 successful = false;
387 }
388
389 //Send response back to region calling if it was successful
390 // calling region uses this to know when to look up a user's location again.
391 XmlRpcResponse resp = new XmlRpcResponse();
392 Hashtable respdata = new Hashtable();
393 if (successful)
394 respdata["success"] = "TRUE";
395 else
396 respdata["success"] = "FALSE";
397 resp.Value = respdata;
398
399 return resp;
400 }
401
402 /// <summary>
403 /// delegate for sending a grid instant message asynchronously
404 /// </summary>
405 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, ulong prevRegionHandle);
406
407 private void GridInstantMessageCompleted(IAsyncResult iar)
408 {
409 GridInstantMessageDelegate icon =
410 (GridInstantMessageDelegate)iar.AsyncState;
411 icon.EndInvoke(iar);
412 }
413
414
415 protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result)
416 {
417 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync;
418
419 d.BeginInvoke(im, result, 0, GridInstantMessageCompleted, d);
420 }
421
422 /// <summary>
423 /// Recursive SendGridInstantMessage over XMLRPC method.
424 /// This is called from within a dedicated thread.
425 /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from
426 /// itself, prevRegionHandle will be the last region handle that we tried to send.
427 /// If the handles are the same, we look up the user's location using the grid.
428 /// If the handles are still the same, we end. The send failed.
429 /// </summary>
430 /// <param name="prevRegionHandle">
431 /// Pass in 0 the first time this method is called. It will be called recursively with the last
432 /// regionhandle tried
433 /// </param>
434 protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, ulong prevRegionHandle)
435 {
436 UUID toAgentID = new UUID(im.toAgentID);
437
438 UserAgentData upd = null;
439
440 bool lookupAgent = false;
441
442 lock (m_UserRegionMap)
443 {
444 if (m_UserRegionMap.ContainsKey(toAgentID))
445 {
446 upd = new UserAgentData();
447 upd.AgentOnline = true;
448 upd.Handle = m_UserRegionMap[toAgentID];
449
450 // We need to compare the current regionhandle with the previous region handle
451 // or the recursive loop will never end because it will never try to lookup the agent again
452 if (prevRegionHandle == upd.Handle)
453 {
454 lookupAgent = true;
455 }
456 }
457 else
458 {
459 lookupAgent = true;
460 }
461 }
462
463
464 // Are we needing to look-up an agent?
465 if (lookupAgent)
466 {
467 // Non-cached user agent lookup.
468 upd = m_Scenes[0].CommsManager.UserService.GetAgentByUUID(toAgentID);
469
470 if (upd != null)
471 {
472 // check if we've tried this before..
473 // This is one way to end the recursive loop
474 //
475 if (upd.Handle == prevRegionHandle)
476 {
477 m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
478 result(false);
479 return;
480 }
481 }
482 else
483 {
484 m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
485 result(false);
486 return;
487 }
488 }
489
490 if (upd != null)
491 {
492 if (upd.AgentOnline)
493 {
494 RegionInfo reginfo = m_Scenes[0].SceneGridService.RequestNeighbouringRegionInfo(upd.Handle);
495 if (reginfo != null)
496 {
497 Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
498 // Not actually used anymore, left in for compatibility
499 // Remove at next interface change
500 //
501 msgdata["region_handle"] = 0;
502 bool imresult = doIMSending(reginfo, msgdata);
503 if (imresult)
504 {
505 // IM delivery successful, so store the Agent's location in our local cache.
506 lock (m_UserRegionMap)
507 {
508 if (m_UserRegionMap.ContainsKey(toAgentID))
509 {
510 m_UserRegionMap[toAgentID] = upd.Handle;
511 }
512 else
513 {
514 m_UserRegionMap.Add(toAgentID, upd.Handle);
515 }
516 }
517 result(true);
518 }
519 else
520 {
521 // try again, but lookup user this time.
522 // Warning, this must call the Async version
523 // of this method or we'll be making thousands of threads
524 // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
525 // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
526
527 // This is recursive!!!!!
528 SendGridInstantMessageViaXMLRPCAsync(im, result,
529 upd.Handle);
530 }
531
532 }
533 else
534 {
535 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.Handle);
536 result(false);
537 }
538 }
539 else
540 {
541 result(false);
542 }
543 }
544 else
545 {
546 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find user {0}", toAgentID);
547 result(false);
548 }
549
550 }
551
552 /// <summary>
553 /// This actually does the XMLRPC Request
554 /// </summary>
555 /// <param name="reginfo">RegionInfo we pull the data out of to send the request to</param>
556 /// <param name="xmlrpcdata">The Instant Message data Hashtable</param>
557 /// <returns>Bool if the message was successfully delivered at the other side.</returns>
558 private bool doIMSending(RegionInfo reginfo, Hashtable xmlrpcdata)
559 {
560
561 ArrayList SendParams = new ArrayList();
562 SendParams.Add(xmlrpcdata);
563 XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams);
564 try
565 {
566
567 XmlRpcResponse GridResp = GridReq.Send("http://" + reginfo.ExternalHostName + ":" + reginfo.HttpPort, 3000);
568
569 Hashtable responseData = (Hashtable)GridResp.Value;
570
571 if (responseData.ContainsKey("success"))
572 {
573 if ((string)responseData["success"] == "TRUE")
574 {
575 return true;
576 }
577 else
578 {
579 return false;
580 }
581 }
582 else
583 {
584 return false;
585 }
586 }
587 catch (WebException e)
588 {
589 m_log.ErrorFormat("[GRID INSTANT MESSAGE]: Error sending message to http://{0}:{1} the host didn't respond ({2})",
590 reginfo.ExternalHostName, reginfo.HttpPort, e.Message);
591 }
592
593 return false;
594 }
595
596 /// <summary>
597 /// Get ulong region handle for region by it's Region UUID.
598 /// We use region handles over grid comms because there's all sorts of free and cool caching.
599 /// </summary>
600 /// <param name="regionID">UUID of region to get the region handle for</param>
601 /// <returns></returns>
602// private ulong getLocalRegionHandleFromUUID(UUID regionID)
603// {
604// ulong returnhandle = 0;
605//
606// lock (m_Scenes)
607// {
608// foreach (Scene sn in m_Scenes)
609// {
610// if (sn.RegionInfo.RegionID == regionID)
611// {
612// returnhandle = sn.RegionInfo.RegionHandle;
613// break;
614// }
615// }
616// }
617// return returnhandle;
618// }
619
620 /// <summary>
621 /// Takes a GridInstantMessage and converts it into a Hashtable for XMLRPC
622 /// </summary>
623 /// <param name="msg">The GridInstantMessage object</param>
624 /// <returns>Hashtable containing the XMLRPC request</returns>
625 private Hashtable ConvertGridInstantMessageToXMLRPC(GridInstantMessage msg)
626 {
627 Hashtable gim = new Hashtable();
628 gim["from_agent_id"] = msg.fromAgentID.ToString();
629 // Kept for compatibility
630 gim["from_agent_session"] = UUID.Zero.ToString();
631 gim["to_agent_id"] = msg.toAgentID.ToString();
632 gim["im_session_id"] = msg.imSessionID.ToString();
633 gim["timestamp"] = msg.timestamp.ToString();
634 gim["from_agent_name"] = msg.fromAgentName;
635 gim["message"] = msg.message;
636 byte[] dialogdata = new byte[1];dialogdata[0] = msg.dialog;
637 gim["dialog"] = Convert.ToBase64String(dialogdata,Base64FormattingOptions.None);
638
639 if (msg.fromGroup)
640 gim["from_group"] = "TRUE";
641 else
642 gim["from_group"] = "FALSE";
643 byte[] offlinedata = new byte[1]; offlinedata[0] = msg.offline;
644 gim["offline"] = Convert.ToBase64String(offlinedata, Base64FormattingOptions.None);
645 gim["parent_estate_id"] = msg.ParentEstateID.ToString();
646 gim["position_x"] = msg.Position.X.ToString();
647 gim["position_y"] = msg.Position.Y.ToString();
648 gim["position_z"] = msg.Position.Z.ToString();
649 gim["region_id"] = msg.RegionID.ToString();
650 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
651 return gim;
652 }
653
654 }
655}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
new file mode 100644
index 0000000..49fd70a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
@@ -0,0 +1,426 @@
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;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Net;
32using System.Threading;
33using OpenMetaverse;
34using log4net;
35using Nini.Config;
36using Nwc.XmlRpc;
37using OpenSim.Framework;
38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
43{
44 public class PresenceModule : IRegionModule, IPresenceModule
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private bool m_Enabled = false;
49 private bool m_Gridmode = false;
50
51 // some default scene for doing things that aren't connected to a specific scene. Avoids locking.
52 private Scene m_initialScene;
53
54 private List<Scene> m_Scenes = new List<Scene>();
55
56 // we currently are only interested in root-agents. If the root isn't here, we don't know the region the
57 // user is in, so we have to ask the messaging server anyway.
58 private Dictionary<UUID, Scene> m_RootAgents =
59 new Dictionary<UUID, Scene>();
60
61 public event PresenceChange OnPresenceChange;
62 public event BulkPresenceData OnBulkPresenceData;
63
64 public void Initialise(Scene scene, IConfigSource config)
65 {
66 lock (m_Scenes)
67 {
68 // This is a shared module; Initialise will be called for every region on this server.
69 // Only check config once for the first region.
70 if (m_Scenes.Count == 0)
71 {
72 IConfig cnf = config.Configs["Messaging"];
73 if (cnf != null && cnf.GetString(
74 "PresenceModule", "PresenceModule") !=
75 "PresenceModule")
76 return;
77
78 cnf = config.Configs["Startup"];
79 if (cnf != null)
80 m_Gridmode = cnf.GetBoolean("gridmode", false);
81
82 m_Enabled = true;
83
84 m_initialScene = scene;
85 }
86
87 if (m_Gridmode)
88 NotifyMessageServerOfStartup(scene);
89
90 m_Scenes.Add(scene);
91 }
92
93 scene.RegisterModuleInterface<IPresenceModule>(this);
94
95 scene.EventManager.OnNewClient += OnNewClient;
96 scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
97 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
98 }
99
100 public void PostInitialise()
101 {
102 }
103
104 public void Close()
105 {
106 if (!m_Gridmode || !m_Enabled)
107 return;
108
109 if (OnPresenceChange != null)
110 {
111 lock (m_RootAgents)
112 {
113 // on shutdown, users are kicked, too
114 foreach (KeyValuePair<UUID, Scene> pair in m_RootAgents)
115 {
116 OnPresenceChange(new PresenceInfo(pair.Key, UUID.Zero));
117 }
118 }
119 }
120
121 lock (m_Scenes)
122 {
123 foreach (Scene scene in m_Scenes)
124 NotifyMessageServerOfShutdown(scene);
125 }
126 }
127
128 public string Name
129 {
130 get { return "PresenceModule"; }
131 }
132
133 public bool IsSharedModule
134 {
135 get { return true; }
136 }
137
138 public void RequestBulkPresenceData(UUID[] users)
139 {
140 if (OnBulkPresenceData != null)
141 {
142 PresenceInfo[] result = new PresenceInfo[users.Length];
143 if (m_Gridmode)
144 {
145 // first check the local information
146 List<UUID> uuids = new List<UUID>(); // the uuids to check remotely
147 List<int> indices = new List<int>(); // just for performance.
148 lock (m_RootAgents)
149 {
150 for (int i = 0; i < uuids.Count; ++i)
151 {
152 Scene scene;
153 if (m_RootAgents.TryGetValue(users[i], out scene))
154 {
155 result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID);
156 }
157 else
158 {
159 uuids.Add(users[i]);
160 indices.Add(i);
161 }
162 }
163 }
164
165 // now we have filtered out all the local root agents. The rest we have to request info about
166 Dictionary<UUID, FriendRegionInfo> infos = m_initialScene.GetFriendRegionInfos(uuids);
167 for (int i = 0; i < uuids.Count; ++i)
168 {
169 FriendRegionInfo info;
170 if (infos.TryGetValue(uuids[i], out info) && info.isOnline)
171 {
172 UUID regionID = info.regionID;
173 if (regionID == UUID.Zero)
174 {
175 // TODO this is the old messaging-server protocol; only the regionHandle is available.
176 // Fetch region-info to get the id
177 RegionInfo regionInfo = m_initialScene.RequestNeighbouringRegionInfo(info.regionHandle);
178 regionID = regionInfo.RegionID;
179 }
180 result[indices[i]] = new PresenceInfo(uuids[i], regionID);
181 }
182 else result[indices[i]] = new PresenceInfo(uuids[i], UUID.Zero);
183 }
184 }
185 else
186 {
187 // in standalone mode, we have all the info locally available.
188 lock (m_RootAgents)
189 {
190 for (int i = 0; i < users.Length; ++i)
191 {
192 Scene scene;
193 if (m_RootAgents.TryGetValue(users[i], out scene))
194 {
195 result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID);
196 }
197 else
198 {
199 result[i] = new PresenceInfo(users[i], UUID.Zero);
200 }
201 }
202 }
203 }
204
205 // tell everyone
206 OnBulkPresenceData(result);
207 }
208 }
209
210 // new client doesn't mean necessarily that user logged in, it just means it entered one of the
211 // the regions on this server
212 public void OnNewClient(IClientAPI client)
213 {
214 client.OnConnectionClosed += OnConnectionClosed;
215 client.OnLogout += OnLogout;
216
217 // KLUDGE: See handler for details.
218 client.OnEconomyDataRequest += OnEconomyDataRequest;
219 }
220
221 // connection closed just means *one* client connection has been closed. It doesn't mean that the
222 // user has logged off; it might have just TPed away.
223 public void OnConnectionClosed(IClientAPI client)
224 {
225 // TODO: Have to think what we have to do here...
226 // Should we just remove the root from the list (if scene matches)?
227 if (!(client.Scene is Scene))
228 return;
229 Scene scene = (Scene)client.Scene;
230
231 lock (m_RootAgents)
232 {
233 Scene rootScene;
234 if (!(m_RootAgents.TryGetValue(client.AgentId, out rootScene)) || scene != rootScene)
235 return;
236
237 m_RootAgents.Remove(client.AgentId);
238 }
239
240 // Should it have logged off, we'll do the logout part in OnLogout, even if no root is stored
241 // anymore. It logged off, after all...
242 }
243
244 // Triggered when the user logs off.
245 public void OnLogout(IClientAPI client)
246 {
247 if (!(client.Scene is Scene))
248 return;
249 Scene scene = (Scene)client.Scene;
250
251 // On logout, we really remove the client from rootAgents, even if the scene doesn't match
252 lock (m_RootAgents)
253 {
254 if (m_RootAgents.ContainsKey(client.AgentId)) m_RootAgents.Remove(client.AgentId);
255 }
256
257 // now inform the messaging server and anyone who is interested
258 NotifyMessageServerOfAgentLeaving(client.AgentId, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle);
259 if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(client.AgentId, UUID.Zero));
260 }
261
262 public void OnSetRootAgentScene(UUID agentID, Scene scene)
263 {
264 // OnSetRootAgentScene can be called from several threads at once (with different agentID).
265 // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without
266 // correct locking).
267 lock (m_RootAgents)
268 {
269 Scene rootScene;
270 if (m_RootAgents.TryGetValue(agentID, out rootScene) && scene == rootScene)
271 {
272 return;
273 }
274 m_RootAgents[agentID] = scene;
275 }
276 // inform messaging server that agent changed the region
277 NotifyMessageServerOfAgentLocation(agentID, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle);
278 }
279
280 private void OnEconomyDataRequest(UUID agentID)
281 {
282 // KLUDGE: This is the only way I found to get a message (only) after login was completed and the
283 // client is connected enough to receive UDP packets.
284 // This packet seems to be sent only once, just after connection was established to the first
285 // region after login.
286 // We use it here to trigger a presence update; the old update-on-login was never be heard by
287 // the freshly logged in viewer, as it wasn't connected to the region at that time.
288 // TODO: Feel free to replace this by a better solution if you find one.
289
290 // get the agent. This should work every time, as we just got a packet from it
291 ScenePresence agent = null;
292 lock (m_Scenes)
293 {
294 foreach (Scene scene in m_Scenes)
295 {
296 agent = scene.GetScenePresence(agentID);
297 if (agent != null) break;
298 }
299 }
300
301 // just to be paranoid...
302 if (agent == null)
303 {
304 m_log.ErrorFormat("[PRESENCE]: Got a packet from agent {0} who can't be found anymore!?", agentID);
305 return;
306 }
307
308 // we are a bit premature here, but the next packet will switch this child agent to root.
309 if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(agentID, agent.Scene.RegionInfo.RegionID));
310 }
311
312 public void OnMakeChildAgent(ScenePresence agent)
313 {
314 // OnMakeChildAgent can be called from several threads at once (with different agent).
315 // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without
316 // correct locking).
317 lock (m_RootAgents)
318 {
319 Scene rootScene;
320 if (m_RootAgents.TryGetValue(agent.UUID, out rootScene) && agent.Scene == rootScene)
321 {
322 m_RootAgents.Remove(agent.UUID);
323 }
324 }
325 // don't notify the messaging-server; either this agent just had been downgraded and another one will be upgraded
326 // to root momentarily (which will notify the messaging-server), or possibly it will be closed in a moment,
327 // which will update the messaging-server, too.
328 }
329
330 private void NotifyMessageServerOfStartup(Scene scene)
331 {
332 Hashtable xmlrpcdata = new Hashtable();
333 xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString();
334 ArrayList SendParams = new ArrayList();
335 SendParams.Add(xmlrpcdata);
336 try
337 {
338 XmlRpcRequest UpRequest = new XmlRpcRequest("region_startup", SendParams);
339 XmlRpcResponse resp = UpRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000);
340
341 Hashtable responseData = (Hashtable)resp.Value;
342 if (responseData == null || (!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE")
343 {
344 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName);
345 }
346 }
347 catch (System.Net.WebException)
348 {
349 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName);
350 }
351 }
352
353 private void NotifyMessageServerOfShutdown(Scene scene)
354 {
355 Hashtable xmlrpcdata = new Hashtable();
356 xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString();
357 ArrayList SendParams = new ArrayList();
358 SendParams.Add(xmlrpcdata);
359 try
360 {
361 XmlRpcRequest DownRequest = new XmlRpcRequest("region_shutdown", SendParams);
362 XmlRpcResponse resp = DownRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000);
363
364 Hashtable responseData = (Hashtable)resp.Value;
365 if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE")
366 {
367 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName);
368 }
369 }
370 catch (System.Net.WebException)
371 {
372 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName);
373 }
374 }
375
376 private void NotifyMessageServerOfAgentLocation(UUID agentID, UUID region, ulong regionHandle)
377 {
378 Hashtable xmlrpcdata = new Hashtable();
379 xmlrpcdata["AgentID"] = agentID.ToString();
380 xmlrpcdata["RegionUUID"] = region.ToString();
381 xmlrpcdata["RegionHandle"] = regionHandle.ToString();
382 ArrayList SendParams = new ArrayList();
383 SendParams.Add(xmlrpcdata);
384 try
385 {
386 XmlRpcRequest LocationRequest = new XmlRpcRequest("agent_location", SendParams);
387 XmlRpcResponse resp = LocationRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000);
388
389 Hashtable responseData = (Hashtable)resp.Value;
390 if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE")
391 {
392 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString());
393 }
394 }
395 catch (System.Net.WebException)
396 {
397 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString());
398 }
399 }
400
401 private void NotifyMessageServerOfAgentLeaving(UUID agentID, UUID region, ulong regionHandle)
402 {
403 Hashtable xmlrpcdata = new Hashtable();
404 xmlrpcdata["AgentID"] = agentID.ToString();
405 xmlrpcdata["RegionUUID"] = region.ToString();
406 xmlrpcdata["RegionHandle"] = regionHandle.ToString();
407 ArrayList SendParams = new ArrayList();
408 SendParams.Add(xmlrpcdata);
409 try
410 {
411 XmlRpcRequest LeavingRequest = new XmlRpcRequest("agent_leaving", SendParams);
412 XmlRpcResponse resp = LeavingRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000);
413
414 Hashtable responseData = (Hashtable)resp.Value;
415 if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE")
416 {
417 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString());
418 }
419 }
420 catch (System.Net.WebException)
421 {
422 m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString());
423 }
424 }
425 }
426}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
new file mode 100644
index 0000000..49006a2
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -0,0 +1,279 @@
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.IO.Compression;
32using System.Reflection;
33using System.Xml;
34using OpenMetaverse;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.CoreModules.World.Archiver;
37using OpenSim.Region.CoreModules.World.Serialiser;
38using OpenSim.Framework;
39using OpenSim.Framework.Communications;
40using OpenSim.Framework.Communications.Cache;
41using log4net;
42
43
44namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
45{
46 public class InventoryArchiveReadRequest
47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 protected Scene scene;
51 protected TarArchiveReader archive;
52 private static System.Text.ASCIIEncoding m_asciiEncoding = new System.Text.ASCIIEncoding();
53
54 CommunicationsManager commsManager;
55
56 public InventoryArchiveReadRequest(Scene currentScene, CommunicationsManager commsManager)
57 {
58 //List<string> serialisedObjects = new List<string>();
59 scene = currentScene;
60 this.commsManager = commsManager;
61 }
62
63 protected InventoryItemBase loadInvItem(string path, string contents)
64 {
65 InventoryItemBase item = new InventoryItemBase();
66 StringReader sr = new StringReader(contents);
67 XmlTextReader reader = new XmlTextReader(sr);
68
69 if (contents.Equals("")) return null;
70
71 reader.ReadStartElement("InventoryObject");
72 reader.ReadStartElement("Name");
73 item.Name = reader.ReadString();
74 reader.ReadEndElement();
75 reader.ReadStartElement("ID");
76 item.ID = UUID.Parse(reader.ReadString());
77 reader.ReadEndElement();
78 reader.ReadStartElement("InvType");
79 item.InvType = System.Convert.ToInt32(reader.ReadString());
80 reader.ReadEndElement();
81 reader.ReadStartElement("CreatorUUID");
82 item.Creator = UUID.Parse(reader.ReadString());
83 reader.ReadEndElement();
84 reader.ReadStartElement("CreationDate");
85 item.CreationDate = System.Convert.ToInt32(reader.ReadString());
86 reader.ReadEndElement();
87 reader.ReadStartElement("Owner");
88 item.Owner = UUID.Parse(reader.ReadString());
89 reader.ReadEndElement();
90 //No description would kill it
91 if (reader.IsEmptyElement)
92 {
93 reader.ReadStartElement("Description");
94 }
95 else
96 {
97 reader.ReadStartElement("Description");
98 item.Description = reader.ReadString();
99 reader.ReadEndElement();
100 }
101 reader.ReadStartElement("AssetType");
102 item.AssetType = System.Convert.ToInt32(reader.ReadString());
103 reader.ReadEndElement();
104 reader.ReadStartElement("AssetID");
105 item.AssetID = UUID.Parse(reader.ReadString());
106 reader.ReadEndElement();
107 reader.ReadStartElement("SaleType");
108 item.SaleType = System.Convert.ToByte(reader.ReadString());
109 reader.ReadEndElement();
110 reader.ReadStartElement("SalePrice");
111 item.SalePrice = System.Convert.ToInt32(reader.ReadString());
112 reader.ReadEndElement();
113 reader.ReadStartElement("BasePermissions");
114 item.BasePermissions = System.Convert.ToUInt32(reader.ReadString());
115 reader.ReadEndElement();
116 reader.ReadStartElement("CurrentPermissions");
117 item.CurrentPermissions = System.Convert.ToUInt32(reader.ReadString());
118 reader.ReadEndElement();
119 reader.ReadStartElement("EveryOnePermssions");
120 item.EveryOnePermissions = System.Convert.ToUInt32(reader.ReadString());
121 reader.ReadEndElement();
122 reader.ReadStartElement("NextPermissions");
123 item.NextPermissions = System.Convert.ToUInt32(reader.ReadString());
124 reader.ReadEndElement();
125 reader.ReadStartElement("Flags");
126 item.Flags = System.Convert.ToUInt32(reader.ReadString());
127 reader.ReadEndElement();
128 reader.ReadStartElement("GroupID");
129 item.GroupID = UUID.Parse(reader.ReadString());
130 reader.ReadEndElement();
131 reader.ReadStartElement("GroupOwned");
132 item.GroupOwned = System.Convert.ToBoolean(reader.ReadString());
133 reader.ReadEndElement();
134 //reader.ReadStartElement("ParentFolderID");
135 //item.Folder = UUID.Parse(reader.ReadString());
136 //reader.ReadEndElement();
137 //reader.ReadEndElement();
138
139 return item;
140 }
141
142 public void execute(string firstName, string lastName, string invPath, string loadPath)
143 {
144 string filePath = "ERROR";
145 int successfulAssetRestores = 0;
146 int failedAssetRestores = 0;
147 int successfulItemRestores = 0;
148
149 UserProfileData userProfile = commsManager.UserService.GetUserProfile(firstName, lastName);
150 if (null == userProfile)
151 {
152 m_log.ErrorFormat("[CONSOLE]: Failed to find user {0} {1}", firstName, lastName);
153 return;
154 }
155
156 CachedUserInfo userInfo = commsManager.UserProfileCacheService.GetUserDetails(userProfile.ID);
157 if (null == userInfo)
158 {
159 m_log.ErrorFormat(
160 "[CONSOLE]: Failed to find user info for {0} {1} {2}",
161 firstName, lastName, userProfile.ID);
162
163 return;
164 }
165
166 if (!userInfo.HasReceivedInventory)
167 {
168 m_log.ErrorFormat(
169 "[CONSOLE]: Have not yet received inventory info for user {0} {1} {2}",
170 firstName, lastName, userProfile.ID);
171
172 return;
173 }
174
175 InventoryFolderImpl inventoryFolder = userInfo.RootFolder.FindFolderByPath(invPath);
176
177 if (null == inventoryFolder)
178 {
179 // TODO: Later on, automatically create this folder if it does not exist
180 m_log.ErrorFormat("[ARCHIVER]: Inventory path {0} does not exist", invPath);
181
182 return;
183 }
184
185 archive
186 = new TarArchiveReader(new GZipStream(
187 new FileStream(loadPath, FileMode.Open), CompressionMode.Decompress));
188
189 byte[] data;
190 TarArchiveReader.TarEntryType entryType;
191 while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
192 {
193 if (entryType == TarArchiveReader.TarEntryType.TYPE_DIRECTORY) {
194 m_log.WarnFormat("[ARCHIVER]: Ignoring directory entry {0}", filePath);
195 } else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
196 {
197 if (LoadAsset(filePath, data))
198 successfulAssetRestores++;
199 else
200 failedAssetRestores++;
201 }
202 else
203 {
204 InventoryItemBase item = loadInvItem(filePath, m_asciiEncoding.GetString(data));
205
206 if (item != null)
207 {
208 item.Creator = userProfile.ID;
209 item.Owner = userProfile.ID;
210
211 // Reset folder ID to the one in which we want to load it
212 // TODO: Properly restore entire folder structure. At the moment all items are dumped in this
213 // single folder no matter where in the saved folder structure they are.
214 item.Folder = inventoryFolder.ID;
215
216 userInfo.AddItem(item);
217 successfulItemRestores++;
218 }
219 }
220 }
221
222 archive.Close();
223
224 m_log.DebugFormat("[ARCHIVER]: Restored {0} assets", successfulAssetRestores);
225 m_log.InfoFormat("[ARCHIVER]: Restored {0} items", successfulItemRestores);
226 }
227
228 /// <summary>
229 /// Load an asset
230 /// </summary>
231 /// <param name="assetFilename"></param>
232 /// <param name="data"></param>
233 /// <returns>true if asset was successfully loaded, false otherwise</returns>
234 private bool LoadAsset(string assetPath, byte[] data)
235 {
236 //IRegionSerialiser serialiser = scene.RequestModuleInterface<IRegionSerialiser>();
237 // Right now we're nastily obtaining the UUID from the filename
238 string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
239 int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR);
240
241 if (i == -1)
242 {
243 m_log.ErrorFormat(
244 "[ARCHIVER]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping",
245 assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR);
246
247 return false;
248 }
249
250 string extension = filename.Substring(i);
251 string uuid = filename.Remove(filename.Length - extension.Length);
252
253 if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension))
254 {
255 sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension];
256
257 m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType);
258
259 AssetBase asset = new AssetBase(new UUID(uuid), "RandomName");
260
261 asset.Metadata.Type = assetType;
262 asset.Data = data;
263
264 scene.AssetCache.AddAsset(asset);
265
266
267 return true;
268 }
269 else
270 {
271 m_log.ErrorFormat(
272 "[ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}",
273 assetPath, extension);
274
275 return false;
276 }
277 }
278 }
279}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
new file mode 100644
index 0000000..f548296
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
@@ -0,0 +1,247 @@
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.IO.Compression;
32using System.Reflection;
33using System.Xml;
34using OpenMetaverse;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.CoreModules.World.Archiver;
37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Communications.Cache;
40using log4net;
41
42
43namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
44{
45 public class InventoryArchiveWriteRequest
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 protected Scene scene;
50 protected TarArchiveWriter archive;
51 protected CommunicationsManager commsManager;
52 Dictionary<UUID, int> assetUuids;
53
54 /// <value>
55 /// The path to which the inventory archive will be saved.
56 /// </value>
57 private string m_savePath;
58
59 public InventoryArchiveWriteRequest(Scene currentScene, CommunicationsManager commsManager)
60 {
61 scene = currentScene;
62 archive = new TarArchiveWriter();
63 this.commsManager = commsManager;
64 assetUuids = new Dictionary<UUID, int>();
65 }
66
67 protected void ReceivedAllAssets(IDictionary<UUID, AssetBase> assetsFound, ICollection<UUID> assetsNotFoundUuids)
68 {
69 AssetsArchiver assetsArchiver = new AssetsArchiver(assetsFound);
70 assetsArchiver.Archive(archive);
71 archive.WriteTar(new GZipStream(new FileStream(m_savePath, FileMode.Create), CompressionMode.Compress));
72 }
73
74 protected void saveInvItem(InventoryItemBase inventoryItem, string path)
75 {
76 string filename
77 = string.Format("{0}{1}_{2}.xml",
78 path, inventoryItem.Name, inventoryItem.ID);
79 StringWriter sw = new StringWriter();
80 XmlTextWriter writer = new XmlTextWriter(sw);
81 writer.WriteStartElement("InventoryObject");
82 writer.WriteStartElement("Name");
83 writer.WriteString(inventoryItem.Name);
84 writer.WriteEndElement();
85 writer.WriteStartElement("ID");
86 writer.WriteString(inventoryItem.ID.ToString());
87 writer.WriteEndElement();
88 writer.WriteStartElement("InvType");
89 writer.WriteString(inventoryItem.InvType.ToString());
90 writer.WriteEndElement();
91 writer.WriteStartElement("CreatorUUID");
92 writer.WriteString(inventoryItem.Creator.ToString());
93 writer.WriteEndElement();
94 writer.WriteStartElement("CreationDate");
95 writer.WriteString(inventoryItem.CreationDate.ToString());
96 writer.WriteEndElement();
97 writer.WriteStartElement("Owner");
98 writer.WriteString(inventoryItem.Owner.ToString());
99 writer.WriteEndElement();
100 writer.WriteStartElement("Description");
101 if (inventoryItem.Description.Length > 0)
102 writer.WriteString(inventoryItem.Description);
103 else writer.WriteString("No Description");
104 writer.WriteEndElement();
105 writer.WriteStartElement("AssetType");
106 writer.WriteString(inventoryItem.AssetType.ToString());
107 writer.WriteEndElement();
108 writer.WriteStartElement("AssetID");
109 writer.WriteString(inventoryItem.AssetID.ToString());
110 writer.WriteEndElement();
111 writer.WriteStartElement("SaleType");
112 writer.WriteString(inventoryItem.SaleType.ToString());
113 writer.WriteEndElement();
114 writer.WriteStartElement("SalePrice");
115 writer.WriteString(inventoryItem.SalePrice.ToString());
116 writer.WriteEndElement();
117 writer.WriteStartElement("BasePermissions");
118 writer.WriteString(inventoryItem.BasePermissions.ToString());
119 writer.WriteEndElement();
120 writer.WriteStartElement("CurrentPermissions");
121 writer.WriteString(inventoryItem.CurrentPermissions.ToString());
122 writer.WriteEndElement();
123 writer.WriteStartElement("EveryOnePermssions");
124 writer.WriteString(inventoryItem.EveryOnePermissions.ToString());
125 writer.WriteEndElement();
126 writer.WriteStartElement("NextPermissions");
127 writer.WriteString(inventoryItem.NextPermissions.ToString());
128 writer.WriteEndElement();
129 writer.WriteStartElement("Flags");
130 writer.WriteString(inventoryItem.Flags.ToString());
131 writer.WriteEndElement();
132 writer.WriteStartElement("GroupID");
133 writer.WriteString(inventoryItem.GroupID.ToString());
134 writer.WriteEndElement();
135 writer.WriteStartElement("GroupOwned");
136 writer.WriteString(inventoryItem.GroupOwned.ToString());
137 writer.WriteEndElement();
138 writer.WriteStartElement("ParentFolderID");
139 writer.WriteString(inventoryItem.Folder.ToString());
140 writer.WriteEndElement();
141 writer.WriteEndElement();
142
143 archive.AddFile(filename, sw.ToString());
144
145 assetUuids[inventoryItem.AssetID] = 1;
146 }
147
148 protected void saveInvDir(InventoryFolderImpl inventoryFolder, string path)
149 {
150 List<InventoryFolderImpl> inventories = inventoryFolder.RequestListOfFolderImpls();
151 List<InventoryItemBase> items = inventoryFolder.RequestListOfItems();
152 string newPath = path + inventoryFolder.Name + InventoryFolderImpl.PATH_DELIMITER;
153 archive.AddDir(newPath);
154 foreach (InventoryFolderImpl folder in inventories)
155 {
156 saveInvDir(folder, newPath);
157 }
158 foreach (InventoryItemBase item in items)
159 {
160 saveInvItem(item, newPath);
161 }
162 }
163
164 public void execute(string firstName, string lastName, string invPath, string savePath)
165 {
166 m_savePath = savePath;
167
168 UserProfileData userProfile = commsManager.UserService.GetUserProfile(firstName, lastName);
169 if (null == userProfile)
170 {
171 m_log.ErrorFormat("[CONSOLE]: Failed to find user {0} {1}", firstName, lastName);
172 return;
173 }
174
175 CachedUserInfo userInfo = commsManager.UserProfileCacheService.GetUserDetails(userProfile.ID);
176 if (null == userInfo)
177 {
178 m_log.ErrorFormat("[CONSOLE]: Failed to find user info for {0} {1} {2}", firstName, lastName, userProfile.ID);
179 return;
180 }
181
182 InventoryFolderImpl inventoryFolder = null;
183 InventoryItemBase inventoryItem = null;
184
185 if (userInfo.HasReceivedInventory)
186 {
187 // Eliminate double slashes and any leading / on the path. This might be better done within InventoryFolderImpl
188 // itself (possibly at a small loss in efficiency).
189 string[] components
190 = invPath.Split(new string[] { InventoryFolderImpl.PATH_DELIMITER }, StringSplitOptions.RemoveEmptyEntries);
191 invPath = String.Empty;
192 foreach (string c in components)
193 {
194 invPath += c + InventoryFolderImpl.PATH_DELIMITER;
195 }
196
197 // Annoyingly Split actually returns the original string if the input string consists only of delimiters
198 // Therefore if we still start with a / after the split, then we need the root folder
199 if (invPath.Length == 0)
200 {
201 inventoryFolder = userInfo.RootFolder;
202 }
203 else
204 {
205 invPath = invPath.Remove(invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER));
206 inventoryFolder = userInfo.RootFolder.FindFolderByPath(invPath);
207 }
208
209 // The path may point to an item instead
210 if (inventoryFolder == null)
211 {
212 inventoryItem = userInfo.RootFolder.FindItemByPath(invPath);
213 }
214 }
215 else
216 {
217 m_log.ErrorFormat("[CONSOLE]: Have not yet received inventory info for user {0} {1} {2}", firstName, lastName, userProfile.ID);
218 return;
219 }
220
221 if (null == inventoryFolder)
222 {
223 if (null == inventoryItem)
224 {
225 m_log.ErrorFormat("[CONSOLE]: Could not find inventory entry at path {0}", invPath);
226 return;
227 }
228 else
229 {
230 m_log.InfoFormat("[CONSOLE]: Found item {0} {1} at {2}", inventoryItem.Name, inventoryItem.ID,
231 invPath);
232 //get and export item info
233 saveInvItem(inventoryItem, invPath);
234 }
235 }
236 else
237 {
238 m_log.InfoFormat("[CONSOLE]: Found folder {0} {1} at {2}", inventoryFolder.Name, inventoryFolder.ID,
239 invPath);
240 //recurse through all dirs getting dirs and files
241 saveInvDir(inventoryFolder, "");
242 }
243
244 new AssetsRequest(assetUuids.Keys, scene.AssetCache, ReceivedAllAssets).Execute();
245 }
246 }
247}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
new file mode 100644
index 0000000..d2cf6c9
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -0,0 +1,389 @@
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.Reflection;
32using OpenMetaverse;
33using log4net;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Framework.Communications.Cache;
39
40namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
41{
42 public class InventoryTransferModule : IInventoryTransferModule, IRegionModule
43 {
44 private static readonly ILog m_log
45 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 /// <summary>
48 private List<Scene> m_Scenelist = new List<Scene>();
49 private Dictionary<UUID, Scene> m_AgentRegions =
50 new Dictionary<UUID, Scene>();
51
52 private IMessageTransferModule m_TransferModule = null;
53
54 #region IRegionModule Members
55
56 public void Initialise(Scene scene, IConfigSource config)
57 {
58 if (config.Configs["Messaging"] != null)
59 {
60 // Allow disabling this module in config
61 //
62 if (config.Configs["Messaging"].GetString(
63 "InventoryTransferModule", "InventoryTransferModule") !=
64 "InventoryTransferModule")
65 return;
66 }
67
68 if (!m_Scenelist.Contains(scene))
69 {
70 if (m_Scenelist.Count == 0)
71 {
72 m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
73 if (m_TransferModule == null)
74 m_log.Error("[INVENTORY TRANSFER] No Message transfer module found, transfers will be local only");
75 }
76
77 m_Scenelist.Add(scene);
78
79 scene.RegisterModuleInterface<IInventoryTransferModule>(this);
80
81 scene.EventManager.OnNewClient += OnNewClient;
82 scene.EventManager.OnClientClosed += ClientLoggedOut;
83 }
84 }
85
86 public void PostInitialise()
87 {
88 }
89
90 public void Close()
91 {
92 }
93
94 public string Name
95 {
96 get { return "InventoryModule"; }
97 }
98
99 public bool IsSharedModule
100 {
101 get { return true; }
102 }
103
104 #endregion
105
106 private void OnNewClient(IClientAPI client)
107 {
108 // Inventory giving is conducted via instant message
109 client.OnInstantMessage += OnInstantMessage;
110 }
111
112 private Scene FindClientScene(UUID agentId)
113 {
114 lock (m_Scenelist)
115 {
116 foreach (Scene scene in m_Scenelist)
117 {
118 ScenePresence presence = scene.GetScenePresence(agentId);
119 if (presence != null)
120 {
121 if (!presence.IsChildAgent)
122 return scene;
123 }
124 }
125 }
126 return null;
127 }
128
129 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
130 {
131 Scene scene = FindClientScene(client.AgentId);
132
133 if (scene == null) // Something seriously wrong here.
134 return;
135
136 if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
137 {
138 //m_log.DebugFormat("Asset type {0}", ((AssetType)im.binaryBucket[0]));
139
140 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
141 UUID copyID;
142
143 // First byte is the asset type
144 AssetType assetType = (AssetType)im.binaryBucket[0];
145
146 if (AssetType.Folder == assetType)
147 {
148 UUID folderID = new UUID(im.binaryBucket, 1);
149
150 m_log.DebugFormat("[AGENT INVENTORY]: Inserting original folder {0} "+
151 "into agent {1}'s inventory",
152 folderID, new UUID(im.toAgentID));
153
154 InventoryFolderImpl folderCopy
155 = scene.GiveInventoryFolder(new UUID(im.toAgentID), client.AgentId, folderID, UUID.Zero);
156
157 if (folderCopy == null)
158 {
159 client.SendAgentAlertMessage("Can't find folder to give. Nothing given.", false);
160 return;
161 }
162
163 // The outgoing binary bucket should contain only the byte which signals an asset folder is
164 // being copied and the following bytes for the copied folder's UUID
165 copyID = folderCopy.ID;
166 byte[] copyIDBytes = copyID.GetBytes();
167 im.binaryBucket = new byte[1 + copyIDBytes.Length];
168 im.binaryBucket[0] = (byte)AssetType.Folder;
169 Array.Copy(copyIDBytes, 0, im.binaryBucket, 1, copyIDBytes.Length);
170
171 if (user != null && !user.IsChildAgent)
172 {
173 user.ControllingClient.SendBulkUpdateInventory(folderCopy);
174 }
175 }
176 else
177 {
178 // First byte of the array is probably the item type
179 // Next 16 bytes are the UUID
180
181 UUID itemID = new UUID(im.binaryBucket, 1);
182
183 m_log.DebugFormat("[AGENT INVENTORY]: Inserting item {0} "+
184 "into agent {1}'s inventory",
185 itemID, new UUID(im.toAgentID));
186
187 InventoryItemBase itemCopy = scene.GiveInventoryItem(
188 new UUID(im.toAgentID),
189 client.AgentId, itemID);
190
191 if (itemCopy == null)
192 {
193 client.SendAgentAlertMessage("Can't find item to give. Nothing given.", false);
194 return;
195 }
196
197 copyID = itemCopy.ID;
198 Array.Copy(copyID.GetBytes(), 0, im.binaryBucket, 1, 16);
199
200 if (user != null && !user.IsChildAgent)
201 {
202 user.ControllingClient.SendBulkUpdateInventory(itemCopy);
203 }
204 }
205
206 // Send the IM to the recipient. The item is already
207 // in their inventory, so it will not be lost if
208 // they are offline.
209 //
210 if (user != null && !user.IsChildAgent)
211 {
212 // And notify. Transaction ID is the item ID. We get that
213 // same ID back on the reply so we know what to act on
214 //
215 user.ControllingClient.SendInstantMessage(
216 new UUID(im.fromAgentID), im.message,
217 new UUID(im.toAgentID),
218 im.fromAgentName, im.dialog, im.timestamp,
219 copyID, false, im.binaryBucket);
220
221 return;
222 }
223 else
224 {
225 if (m_TransferModule != null)
226 m_TransferModule.SendInstantMessage(im, delegate(bool success) {} );
227 }
228 }
229 else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
230 {
231 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
232
233 if (user != null) // Local
234 {
235 user.ControllingClient.SendInstantMessage(
236 new UUID(im.fromAgentID), im.message,
237 new UUID(im.toAgentID),
238 im.fromAgentName, im.dialog, im.timestamp,
239 UUID.Zero, false, im.binaryBucket);
240 }
241 else
242 {
243 if (m_TransferModule != null)
244 m_TransferModule.SendInstantMessage(im, delegate(bool success) {} );
245 }
246 }
247 else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
248 {
249 // Here, the recipient is local and we can assume that the
250 // inventory is loaded. Courtesy of the above bulk update,
251 // It will have been pushed to the client, too
252 //
253
254 CachedUserInfo userInfo =
255 scene.CommsManager.UserProfileCacheService.
256 GetUserDetails(client.AgentId);
257
258 if (userInfo != null)
259 {
260 InventoryFolderImpl trashFolder =
261 userInfo.FindFolderForType((int)AssetType.TrashFolder);
262
263 UUID inventoryEntityID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
264
265 InventoryItemBase item = userInfo.RootFolder.FindItem(inventoryEntityID);
266 InventoryFolderBase folder = null;
267
268 if (item != null && trashFolder != null)
269 {
270 item.Folder = trashFolder.ID;
271
272 userInfo.DeleteItem(inventoryEntityID);
273
274 scene.AddInventoryItem(client, item);
275 }
276 else
277 {
278 folder = userInfo.RootFolder.FindFolder(inventoryEntityID);
279
280 if (folder != null & trashFolder != null)
281 {
282 userInfo.MoveFolder(inventoryEntityID, trashFolder.ID);
283 }
284 }
285
286 if ((null == item && null == folder) | null == trashFolder)
287 {
288 string reason = String.Empty;
289
290 if (trashFolder == null)
291 reason += " Trash folder not found.";
292 if (item == null)
293 reason += " Item not found.";
294 if (folder == null)
295 reason += " Folder not found.";
296
297 client.SendAgentAlertMessage("Unable to delete "+
298 "received inventory" + reason, false);
299 }
300 }
301
302 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
303
304 if (user != null) // Local
305 {
306 user.ControllingClient.SendInstantMessage(
307 new UUID(im.fromAgentID), im.message,
308 new UUID(im.toAgentID),
309 im.fromAgentName, im.dialog, im.timestamp,
310 UUID.Zero, false, im.binaryBucket);
311 }
312 else
313 {
314 if (m_TransferModule != null)
315 m_TransferModule.SendInstantMessage(im, delegate(bool success) {} );
316 }
317 }
318 }
319
320 public void SetRootAgentScene(UUID agentID, Scene scene)
321 {
322 m_AgentRegions[agentID] = scene;
323 }
324
325 public bool NeedSceneCacheClear(UUID agentID, Scene scene)
326 {
327 if (!m_AgentRegions.ContainsKey(agentID))
328 {
329 // Since we can get here two ways, we need to scan
330 // the scenes here. This is somewhat more expensive
331 // but helps avoid a nasty bug
332 //
333
334 foreach (Scene s in m_Scenelist)
335 {
336 ScenePresence presence;
337
338 if (s.TryGetAvatar(agentID, out presence))
339 {
340 // If the agent is in this scene, then we
341 // are being called twice in a single
342 // teleport. This is wasteful of cycles
343 // but harmless due to this 2nd level check
344 //
345 // If the agent is found in another scene
346 // then the list wasn't current
347 //
348 // If the agent is totally unknown, then what
349 // are we even doing here??
350 //
351 if (s == scene)
352 {
353 //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
354 return true;
355 }
356 else
357 {
358 //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
359 return false;
360 }
361 }
362 }
363 //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
364 return true;
365 }
366
367 // The agent is left in current Scene, so we must be
368 // going to another instance
369 //
370 if (m_AgentRegions[agentID] == scene)
371 {
372 //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
373 m_AgentRegions.Remove(agentID);
374 return true;
375 }
376
377 // Another region has claimed the agent
378 //
379 //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
380 return false;
381 }
382
383 public void ClientLoggedOut(UUID agentID)
384 {
385 if (m_AgentRegions.ContainsKey(agentID))
386 m_AgentRegions.Remove(agentID);
387 }
388 }
389}
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
new file mode 100644
index 0000000..ebf4f0a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -0,0 +1,176 @@
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.Reflection;
32using System.Net;
33using System.Threading;
34using OpenMetaverse;
35using log4net;
36using Nini.Config;
37using Nwc.XmlRpc;
38using OpenSim.Framework;
39using OpenSim.Framework.Client;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.CoreModules.Avatar.Lure
44{
45 public class LureModule : IRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private readonly List<Scene> m_scenes = new List<Scene>();
50
51 private IMessageTransferModule m_TransferModule = null;
52
53 public void Initialise(Scene scene, IConfigSource config)
54 {
55 if (config.Configs["Messaging"] != null)
56 {
57 if (config.Configs["Messaging"].GetString(
58 "LureModule", "LureModule") !=
59 "LureModule")
60 return;
61 }
62
63 lock (m_scenes)
64 {
65 if (!m_scenes.Contains(scene))
66 {
67 m_scenes.Add(scene);
68 scene.EventManager.OnNewClient += OnNewClient;
69 scene.EventManager.OnIncomingInstantMessage +=
70 OnGridInstantMessage;
71 }
72 }
73 }
74
75 void OnNewClient(IClientAPI client)
76 {
77 client.OnInstantMessage += OnInstantMessage;
78 client.OnStartLure += OnStartLure;
79 client.OnTeleportLureRequest += OnTeleportLureRequest;
80 }
81
82 public void PostInitialise()
83 {
84 m_TransferModule =
85 m_scenes[0].RequestModuleInterface<IMessageTransferModule>();
86
87 if (m_TransferModule == null)
88 m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+
89 "lures will not work!");
90 }
91
92 public void Close()
93 {
94 }
95
96 public string Name
97 {
98 get { return "LureModule"; }
99 }
100
101 public bool IsSharedModule
102 {
103 get { return true; }
104 }
105
106 public void OnInstantMessage(IClientAPI client, GridInstantMessage im)
107 {
108 }
109
110 public void OnStartLure(byte lureType, string message, UUID targetid, IClientAPI client)
111 {
112 if (!(client.Scene is Scene))
113 return;
114
115 Scene scene = (Scene)(client.Scene);
116 ScenePresence presence = scene.GetScenePresence(client.AgentId);
117
118 UUID dest = Util.BuildFakeParcelID(
119 scene.RegionInfo.RegionHandle,
120 (uint)presence.AbsolutePosition.X,
121 (uint)presence.AbsolutePosition.Y,
122 (uint)presence.AbsolutePosition.Z);
123
124 m_log.DebugFormat("TP invite with message {0}", message);
125
126 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId,
127 client.FirstName+" "+client.LastName, targetid,
128 (byte)InstantMessageDialog.RequestTeleport, false,
129 message, dest, false, presence.AbsolutePosition,
130 new Byte[0]);
131
132 if (m_TransferModule != null)
133 {
134 m_TransferModule.SendInstantMessage(m,
135 delegate(bool success) { });
136 }
137 }
138
139 public void OnTeleportLureRequest(UUID lureID, uint teleportFlags, IClientAPI client)
140 {
141 if (!(client.Scene is Scene))
142 return;
143
144 Scene scene = (Scene)(client.Scene);
145
146 ulong handle = 0;
147 uint x = 128;
148 uint y = 128;
149 uint z = 70;
150
151 Util.ParseFakeParcelID(lureID, out handle, out x, out y, out z);
152
153 Vector3 position = new Vector3();
154 position.X = (float)x;
155 position.Y = (float)y;
156 position.Z = (float)z;
157
158 scene.RequestTeleportLocation(client, handle, position,
159 Vector3.Zero, teleportFlags);
160 }
161
162 private void OnGridInstantMessage(GridInstantMessage msg)
163 {
164 // Forward remote teleport requests
165 //
166 if (msg.dialog != 22)
167 return;
168
169 if (m_TransferModule != null)
170 {
171 m_TransferModule.SendInstantMessage(msg,
172 delegate(bool success) { });
173 }
174 }
175 }
176}
diff --git a/OpenSim/Region/CoreModules/Avatar/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/CoreModules/Avatar/ObjectCaps/ObjectAdd.cs
new file mode 100644
index 0000000..193307d
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/ObjectCaps/ObjectAdd.cs
@@ -0,0 +1,368 @@
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 log4net;
32using Nini.Config;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim.Framework;
36using OpenSim.Framework.Servers;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
40
41namespace OpenSim.Region.CoreModules.Avatar.ObjectCaps
42{
43 public class ObjectAdd : IRegionModule
44 {
45 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 private Scene m_scene;
48 #region IRegionModule Members
49
50 public void Initialise(Scene pScene, IConfigSource pSource)
51 {
52 m_scene = pScene;
53 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
54 }
55
56 public void PostInitialise()
57 {
58
59 }
60
61 public void RegisterCaps(UUID agentID, Caps caps)
62 {
63 UUID capuuid = UUID.Random();
64
65 m_log.InfoFormat("[OBJECTADD]: {0}", "/CAPS/OA/" + capuuid + "/");
66
67 caps.RegisterHandler("ObjectAdd",
68 new RestHTTPHandler("POST", "/CAPS/OA/" + capuuid + "/",
69 delegate(Hashtable m_dhttpMethod)
70 {
71 return ProcessAdd(m_dhttpMethod, agentID, caps);
72 }));
73 }
74
75 public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap)
76 {
77 Hashtable responsedata = new Hashtable();
78 responsedata["int_response_code"] = 400; //501; //410; //404;
79 responsedata["content_type"] = "text/plain";
80 responsedata["keepalive"] = false;
81 responsedata["str_response_string"] = "Request wasn't what was expected";
82 ScenePresence avatar;
83
84 if (!m_scene.TryGetAvatar(AgentId, out avatar))
85 return responsedata;
86
87
88 OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]);
89 //UUID session_id = UUID.Zero;
90 bool bypass_raycast = false;
91 uint everyone_mask = 0;
92 uint group_mask = 0;
93 uint next_owner_mask = 0;
94 uint flags = 0;
95 UUID group_id = UUID.Zero;
96 int hollow = 0;
97 int material = 0;
98 int p_code = 0;
99 int path_begin = 0;
100 int path_curve = 0;
101 int path_end = 0;
102 int path_radius_offset = 0;
103 int path_revolutions = 0;
104 int path_scale_x = 0;
105 int path_scale_y = 0;
106 int path_shear_x = 0;
107 int path_shear_y = 0;
108 int path_skew = 0;
109 int path_taper_x = 0;
110 int path_taper_y = 0;
111 int path_twist = 0;
112 int path_twist_begin = 0;
113 int profile_begin = 0;
114 int profile_curve = 0;
115 int profile_end = 0;
116 Vector3 ray_end = Vector3.Zero;
117 bool ray_end_is_intersection = false;
118 Vector3 ray_start = Vector3.Zero;
119 UUID ray_target_id = UUID.Zero;
120 Quaternion rotation = Quaternion.Identity;
121 Vector3 scale = Vector3.Zero;
122 int state = 0;
123
124 if (r.Type != OSDType.Map) // not a proper req
125 return responsedata;
126
127 OSDMap rm = (OSDMap)r;
128
129 if (rm.ContainsKey("ObjectData")) //v2
130 {
131 if (rm["ObjectData"].Type != OSDType.Map)
132 {
133 responsedata["str_response_string"] = "Has ObjectData key, but data not in expected format";
134 return responsedata;
135 }
136
137 OSDMap ObjMap = (OSDMap) rm["ObjectData"];
138
139 bypass_raycast = ObjMap["BypassRaycast"].AsBoolean();
140 everyone_mask = readuintval(ObjMap["EveryoneMask"]);
141 flags = readuintval(ObjMap["Flags"]);
142 group_mask = readuintval(ObjMap["GroupMask"]);
143 material = ObjMap["Material"].AsInteger();
144 next_owner_mask = readuintval(ObjMap["NextOwnerMask"]);
145 p_code = ObjMap["PCode"].AsInteger();
146
147 if (ObjMap.ContainsKey("Path"))
148 {
149 if (ObjMap["Path"].Type != OSDType.Map)
150 {
151 responsedata["str_response_string"] = "Has Path key, but data not in expected format";
152 return responsedata;
153 }
154
155 OSDMap PathMap = (OSDMap)ObjMap["Path"];
156 path_begin = PathMap["Begin"].AsInteger();
157 path_curve = PathMap["Curve"].AsInteger();
158 path_end = PathMap["End"].AsInteger();
159 path_radius_offset = PathMap["RadiusOffset"].AsInteger();
160 path_revolutions = PathMap["Revolutions"].AsInteger();
161 path_scale_x = PathMap["ScaleX"].AsInteger();
162 path_scale_y = PathMap["ScaleY"].AsInteger();
163 path_shear_x = PathMap["ShearX"].AsInteger();
164 path_shear_y = PathMap["ShearY"].AsInteger();
165 path_skew = PathMap["Skew"].AsInteger();
166 path_taper_x = PathMap["TaperX"].AsInteger();
167 path_taper_y = PathMap["TaperY"].AsInteger();
168 path_twist = PathMap["Twist"].AsInteger();
169 path_twist_begin = PathMap["TwistBegin"].AsInteger();
170
171 }
172
173 if (ObjMap.ContainsKey("Profile"))
174 {
175 if (ObjMap["Profile"].Type != OSDType.Map)
176 {
177 responsedata["str_response_string"] = "Has Profile key, but data not in expected format";
178 return responsedata;
179 }
180
181 OSDMap ProfileMap = (OSDMap)ObjMap["Profile"];
182
183 profile_begin = ProfileMap["Begin"].AsInteger();
184 profile_curve = ProfileMap["Curve"].AsInteger();
185 profile_end = ProfileMap["End"].AsInteger();
186 hollow = ProfileMap["Hollow"].AsInteger();
187 }
188 ray_end_is_intersection = ObjMap["RayEndIsIntersection"].AsBoolean();
189
190 ray_target_id = ObjMap["RayTargetId"].AsUUID();
191 state = ObjMap["State"].AsInteger();
192 try
193 {
194 ray_end = ((OSDArray) ObjMap["RayEnd"]).AsVector3();
195 ray_start = ((OSDArray) ObjMap["RayStart"]).AsVector3();
196 scale = ((OSDArray) ObjMap["Scale"]).AsVector3();
197 rotation = ((OSDArray)ObjMap["Rotation"]).AsQuaternion();
198 }
199 catch (Exception)
200 {
201 responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format";
202 return responsedata;
203 }
204
205 if (rm.ContainsKey("AgentData"))
206 {
207 if (rm["AgentData"].Type != OSDType.Map)
208 {
209 responsedata["str_response_string"] = "Has AgentData key, but data not in expected format";
210 return responsedata;
211 }
212
213 OSDMap AgentDataMap = (OSDMap) rm["AgentData"];
214
215 //session_id = AgentDataMap["SessionId"].AsUUID();
216 group_id = AgentDataMap["GroupId"].AsUUID();
217 }
218
219 }
220 else
221 { //v1
222 bypass_raycast = rm["bypass_raycast"].AsBoolean();
223
224 everyone_mask = readuintval(rm["everyone_mask"]);
225 flags = readuintval(rm["flags"]);
226 group_id = rm["group_id"].AsUUID();
227 group_mask = readuintval(rm["group_mask"]);
228 hollow = rm["hollow"].AsInteger();
229 material = rm["material"].AsInteger();
230 next_owner_mask = readuintval(rm["next_owner_mask"]);
231 hollow = rm["hollow"].AsInteger();
232 p_code = rm["p_code"].AsInteger();
233 path_begin = rm["path_begin"].AsInteger();
234 path_curve = rm["path_curve"].AsInteger();
235 path_end = rm["path_end"].AsInteger();
236 path_radius_offset = rm["path_radius_offset"].AsInteger();
237 path_revolutions = rm["path_revolutions"].AsInteger();
238 path_scale_x = rm["path_scale_x"].AsInteger();
239 path_scale_y = rm["path_scale_y"].AsInteger();
240 path_shear_x = rm["path_shear_x"].AsInteger();
241 path_shear_y = rm["path_shear_y"].AsInteger();
242 path_skew = rm["path_skew"].AsInteger();
243 path_taper_x = rm["path_taper_x"].AsInteger();
244 path_taper_y = rm["path_taper_y"].AsInteger();
245 path_twist = rm["path_twist"].AsInteger();
246 path_twist_begin = rm["path_twist_begin"].AsInteger();
247 profile_begin = rm["profile_begin"].AsInteger();
248 profile_curve = rm["profile_curve"].AsInteger();
249 profile_end = rm["profile_end"].AsInteger();
250
251 ray_end_is_intersection = rm["ray_end_is_intersection"].AsBoolean();
252
253 ray_target_id = rm["ray_target_id"].AsUUID();
254
255
256 //session_id = rm["session_id"].AsUUID();
257 state = rm["state"].AsInteger();
258 try
259 {
260 ray_end = ((OSDArray)rm["ray_end"]).AsVector3();
261 ray_start = ((OSDArray)rm["ray_start"]).AsVector3();
262 rotation = ((OSDArray)rm["rotation"]).AsQuaternion();
263 scale = ((OSDArray)rm["scale"]).AsVector3();
264 }
265 catch (Exception)
266 {
267 responsedata["str_response_string"] = "RayEnd, RayStart, Scale or Rotation wasn't in the expected format";
268 return responsedata;
269 }
270 }
271
272
273
274 Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false);
275
276 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
277
278 pbs.PathBegin = (ushort)path_begin;
279 pbs.PathCurve = (byte)path_curve;
280 pbs.PathEnd = (ushort)path_end;
281 pbs.PathRadiusOffset = (sbyte)path_radius_offset;
282 pbs.PathRevolutions = (byte)path_revolutions;
283 pbs.PathScaleX = (byte)path_scale_x;
284 pbs.PathScaleY = (byte)path_scale_y;
285 pbs.PathShearX = (byte) path_shear_x;
286 pbs.PathShearY = (byte)path_shear_y;
287 pbs.PathSkew = (sbyte)path_skew;
288 pbs.PathTaperX = (sbyte)path_taper_x;
289 pbs.PathTaperY = (sbyte)path_taper_y;
290 pbs.PathTwist = (sbyte)path_twist;
291 pbs.PathTwistBegin = (sbyte)path_twist_begin;
292 pbs.HollowShape = (HollowShape) hollow;
293 pbs.PCode = (byte)p_code;
294 pbs.ProfileBegin = (ushort) profile_begin;
295 pbs.ProfileCurve = (byte) profile_curve;
296 pbs.ProfileEnd = (ushort)profile_end;
297 pbs.Scale = scale;
298 pbs.State = (byte)state;
299
300 SceneObjectGroup obj = null; ;
301
302 if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos))
303 {
304 // rez ON the ground, not IN the ground
305 pos.Z += 0.25F;
306
307 obj = m_scene.AddNewPrim(avatar.UUID, group_id, pos, rotation, pbs);
308 }
309
310
311 if (obj == null)
312 return responsedata;
313
314 SceneObjectPart rootpart = obj.RootPart;
315 rootpart.Shape = pbs;
316 rootpart.Flags |= (PrimFlags)flags;
317 rootpart.EveryoneMask = everyone_mask;
318 rootpart.GroupID = group_id;
319 rootpart.GroupMask = group_mask;
320 rootpart.NextOwnerMask = next_owner_mask;
321 rootpart.Material = (byte)material;
322
323
324
325 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
326
327 responsedata["int_response_code"] = 200; //501; //410; //404;
328 responsedata["content_type"] = "text/plain";
329 responsedata["keepalive"] = false;
330 responsedata["str_response_string"] = String.Format("<llsd><map><key>local_id</key>{0}</map></llsd>",ConvertUintToBytes(obj.LocalId));
331
332 return responsedata;
333 }
334
335 private uint readuintval(OSD obj)
336 {
337 byte[] tmp = obj.AsBinary();
338 if (BitConverter.IsLittleEndian)
339 Array.Reverse(tmp);
340 return Utils.BytesToUInt(tmp);
341
342 }
343 private string ConvertUintToBytes(uint val)
344 {
345 byte[] resultbytes = Utils.UIntToBytes(val);
346 if (BitConverter.IsLittleEndian)
347 Array.Reverse(resultbytes);
348 return String.Format("<binary encoding=\"base64\">{0}</binary>",Convert.ToBase64String(resultbytes));
349 }
350
351 public void Close()
352 {
353
354 }
355
356 public string Name
357 {
358 get { return "ObjectAddModule"; }
359 }
360
361 public bool IsSharedModule
362 {
363 get { return false; }
364 }
365
366 #endregion
367 }
368}
diff --git a/OpenSim/Region/CoreModules/Avatar/Profiles/AvatarProfilesModule.cs b/OpenSim/Region/CoreModules/Avatar/Profiles/AvatarProfilesModule.cs
new file mode 100644
index 0000000..6ea5b56
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Profiles/AvatarProfilesModule.cs
@@ -0,0 +1,145 @@
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.Globalization;
30using System.Reflection;
31using OpenMetaverse;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.CoreModules.Avatar.Profiles
39{
40 public class AvatarProfilesModule : IRegionModule
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private Scene m_scene;
44
45 public AvatarProfilesModule()
46 {
47 }
48
49 #region IRegionModule Members
50
51 public void Initialise(Scene scene, IConfigSource config)
52 {
53 m_scene = scene;
54 m_scene.EventManager.OnNewClient += NewClient;
55 }
56
57 public void PostInitialise()
58 {
59 }
60
61 public void Close()
62 {
63 }
64
65 public string Name
66 {
67 get { return "AvatarProfilesModule"; }
68 }
69
70 public bool IsSharedModule
71 {
72 get { return false; }
73 }
74
75 #endregion
76
77 public void NewClient(IClientAPI client)
78 {
79 client.OnRequestAvatarProperties += RequestAvatarProperty;
80 client.OnUpdateAvatarProperties += UpdateAvatarProperties;
81 }
82
83 public void RemoveClient(IClientAPI client)
84 {
85 client.OnRequestAvatarProperties -= RequestAvatarProperty;
86 client.OnUpdateAvatarProperties -= UpdateAvatarProperties;
87 }
88
89 /// <summary>
90 ///
91 /// </summary>
92 /// <param name="remoteClient"></param>
93 /// <param name="avatarID"></param>
94 public void RequestAvatarProperty(IClientAPI remoteClient, UUID avatarID)
95 {
96 // FIXME: finish adding fields such as url, masking, etc.
97 UserProfileData profile = m_scene.CommsManager.UserService.GetUserProfile(avatarID);
98 if (null != profile)
99 {
100 Byte[] charterMember;
101 if (profile.CustomType == "")
102 {
103 charterMember = new Byte[1];
104 charterMember[0] = (Byte)((profile.UserFlags & 0xf00) >> 8);
105 }
106 else
107 {
108 charterMember = Utils.StringToBytes(profile.CustomType);
109 }
110
111 remoteClient.SendAvatarProperties(profile.ID, profile.AboutText,
112 Util.ToDateTime(profile.Created).ToString("M/d/yyyy", CultureInfo.InvariantCulture),
113 charterMember, profile.FirstLifeAboutText, (uint)(profile.UserFlags & 0xff),
114 profile.FirstLifeImage, profile.Image, String.Empty, profile.Partner);
115 }
116 else
117 {
118 m_log.Debug("[AvatarProfilesModule]: Got null for profile for " + avatarID.ToString());
119 }
120 }
121
122 public void UpdateAvatarProperties(IClientAPI remoteClient, UserProfileData newProfile)
123 {
124 UserProfileData Profile = m_scene.CommsManager.UserService.GetUserProfile(newProfile.ID);
125
126 // if it's the profile of the user requesting the update, then we change only a few things.
127 if (remoteClient.AgentId.CompareTo(Profile.ID) == 0)
128 {
129 Profile.Image = newProfile.Image;
130 Profile.FirstLifeImage = newProfile.FirstLifeImage;
131 Profile.AboutText = newProfile.AboutText;
132 Profile.FirstLifeAboutText = newProfile.FirstLifeAboutText;
133 }
134 else
135 {
136 return;
137 }
138
139 if (m_scene.CommsManager.UserService.UpdateUserProfile(Profile))
140 {
141 RequestAvatarProperty(remoteClient, newProfile.ID);
142 }
143 }
144 }
145}