aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/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/Environment/Modules/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/Environment/Modules/Avatar')
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs232
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs628
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs287
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs219
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs887
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Chat/RegionState.cs424
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Combat/CombatModule.cs154
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs604
-rwxr-xr-xOpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeServer.py130
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs1605
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Dialog/DialogModule.cs143
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs1003
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Gestures/GesturesModule.cs104
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs223
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs170
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs655
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/InstantMessage/PresenceModule.cs426
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs279
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs247
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Inventory/Transfer/InventoryTransferModule.cs389
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Lure/LureModule.cs176
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/ObjectCaps/ObjectAdd.cs368
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs145
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs292
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs202
25 files changed, 0 insertions, 9992 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs
deleted file mode 100644
index 1ac0807..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ /dev/null
@@ -1,232 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Chat/ChannelState.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs
deleted file mode 100644
index dfa1caa..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChannelState.cs
+++ /dev/null
@@ -1,628 +0,0 @@
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 System.Text.RegularExpressions;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.Environment.Modules.Avatar.Chat
39{
40
41 // An instance of this class exists for each unique combination of
42 // IRC chat interface characteristics, as determined by the supplied
43 // configuration file.
44
45 internal class ChannelState
46 {
47
48 private static readonly ILog m_log =
49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private static Regex arg = new Regex(@"\[[^\[\]]*\]");
52 private static int _idk_ = 0;
53 private static int DEBUG_CHANNEL = 2147483647;
54
55 // These are the IRC Connector configurable parameters with hard-wired
56 // default values (retained for compatability).
57
58 internal string Server = null;
59 internal string Password = null;
60 internal string IrcChannel = null;
61 internal string BaseNickname = "OSimBot";
62 internal uint Port = 6667;
63 internal string User = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
64
65 internal bool ClientReporting = true;
66 internal bool RelayChat = true;
67 internal bool RelayPrivateChannels = false;
68 internal int RelayChannel = 1;
69 internal List<int> ValidInWorldChannels = new List<int>();
70
71 // Connector agnostic parameters. These values are NOT shared with the
72 // connector and do not differentiate at an IRC level
73
74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}";
75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
76 internal int RelayChannelOut = -1;
77 internal bool RandomizeNickname = true;
78 internal bool CommandsEnabled = false;
79 internal int CommandChannel = -1;
80 internal int ConnectDelay = 10;
81 internal int PingDelay = 15;
82 internal string DefaultZone = "Sim";
83
84 internal string _accessPassword = String.Empty;
85 internal Regex AccessPasswordRegex = null;
86 internal string AccessPassword
87 {
88 get { return _accessPassword; }
89 set
90 {
91 _accessPassword = value;
92 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
93 RegexOptions.Compiled);
94 }
95 }
96
97
98
99 // IRC connector reference
100
101 internal IRCConnector irc = null;
102
103 internal int idn = _idk_++;
104
105 // List of regions dependent upon this connection
106
107 internal List<RegionState> clientregions = new List<RegionState>();
108
109 // Needed by OpenChannel
110
111 internal ChannelState()
112 {
113 }
114
115 // This constructor is used by the Update* methods. A copy of the
116 // existing channel state is created, and distinguishing characteristics
117 // are copied across.
118
119 internal ChannelState(ChannelState model)
120 {
121 Server = model.Server;
122 Password = model.Password;
123 IrcChannel = model.IrcChannel;
124 Port = model.Port;
125 BaseNickname = model.BaseNickname;
126 RandomizeNickname = model.RandomizeNickname;
127 User = model.User;
128 CommandsEnabled = model.CommandsEnabled;
129 CommandChannel = model.CommandChannel;
130 RelayChat = model.RelayChat;
131 RelayPrivateChannels = model.RelayPrivateChannels;
132 RelayChannelOut = model.RelayChannelOut;
133 RelayChannel = model.RelayChannel;
134 ValidInWorldChannels = model.ValidInWorldChannels;
135 PrivateMessageFormat = model.PrivateMessageFormat;
136 NoticeMessageFormat = model.NoticeMessageFormat;
137 ClientReporting = model.ClientReporting;
138 AccessPassword = model.AccessPassword;
139 DefaultZone = model.DefaultZone;
140 ConnectDelay = model.ConnectDelay;
141 PingDelay = model.PingDelay;
142 }
143
144 // Read the configuration file, performing variable substitution and any
145 // necessary aliasing. See accompanying documentation for how this works.
146 // If you don't need variables, then this works exactly as before.
147 // If either channel or server are not specified, the request fails.
148
149 internal static void OpenChannel(RegionState rs, IConfig config)
150 {
151
152 // Create a new instance of a channel. This may not actually
153 // get used if an equivalent channel already exists.
154
155 ChannelState cs = new ChannelState();
156
157 // Read in the configuration file and filter everything for variable
158 // subsititution.
159
160 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);
161
162 cs.Server = Substitute(rs, config.GetString("server", null));
163 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
164 cs.Password = Substitute(rs, config.GetString("password", null));
165 // probably not a good idea to put a password in the log file
166 cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
167 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
168 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
169 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
170 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
171 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
172 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
173 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
176 cs.User = Substitute(rs, config.GetString("username", cs.User));
177 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
178 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
179 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
180 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
181 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
184 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
185 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat);
186 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
187 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
190 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
191 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
192 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
196 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
197 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
198 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
199 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
200 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0;
201 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
202 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
204 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
205 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
206 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
207 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
208 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
209 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
210 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
211 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
212
213
214 // Fail if fundamental information is still missing
215
216 if (cs.Server == null || cs.IrcChannel == null || cs.BaseNickname == null || cs.User == null)
217 throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}", cs.idn, rs.Region));
218
219 m_log.InfoFormat("[IRC-Channel-{0}] Configuration for Region {1} is valid", cs.idn, rs.Region);
220 m_log.InfoFormat("[IRC-Channel-{0}] Server = {1}", cs.idn, cs.Server);
221 m_log.InfoFormat("[IRC-Channel-{0}] Channel = {1}", cs.idn, cs.IrcChannel);
222 m_log.InfoFormat("[IRC-Channel-{0}] Port = {1}", cs.idn, cs.Port);
223 m_log.InfoFormat("[IRC-Channel-{0}] Nickname = {1}", cs.idn, cs.BaseNickname);
224 m_log.InfoFormat("[IRC-Channel-{0}] User = {1}", cs.idn, cs.User);
225
226 // Set the channel state for this region
227
228 if (cs.RelayChat)
229 {
230 cs.ValidInWorldChannels.Add(0);
231 cs.ValidInWorldChannels.Add(DEBUG_CHANNEL);
232 }
233
234 if (cs.RelayPrivateChannels)
235 cs.ValidInWorldChannels.Add(cs.RelayChannelOut);
236
237 rs.cs = Integrate(rs, cs);
238
239 }
240
241 // An initialized channel state instance is passed in. If an identical
242 // channel state instance already exists, then the existing instance
243 // is used to replace the supplied value.
244 // If the instance matches with respect to IRC, then the underlying
245 // IRCConnector is assigned to the supplied channel state and the
246 // updated value is returned.
247 // If there is no match, then the supplied instance is completed by
248 // creating and assigning an instance of an IRC connector.
249
250 private static ChannelState Integrate(RegionState rs, ChannelState p_cs)
251 {
252
253 ChannelState cs = p_cs;
254
255 // Check to see if we have an existing server/channel setup that can be used
256 // In the absence of variable substitution this will always resolve to the
257 // same ChannelState instance, and the table will only contains a single
258 // entry, so the performance considerations for the existing behavior are
259 // zero. Only the IRC connector is shared, the ChannelState still contains
260 // values that, while independent of the IRC connetion, do still distinguish
261 // this region's behavior.
262
263 lock (IRCBridgeModule.m_channels)
264 {
265
266 foreach (ChannelState xcs in IRCBridgeModule.m_channels)
267 {
268 if (cs.IsAPerfectMatchFor(xcs))
269 {
270 m_log.DebugFormat("[IRC-Channel-{0}] Channel state matched", cs.idn);
271 cs = xcs;
272 break;
273 }
274 if (cs.IsAConnectionMatchFor(xcs))
275 {
276 m_log.DebugFormat("[IRC-Channel-{0}] Channel matched", cs.idn);
277 cs.irc = xcs.irc;
278 break;
279 }
280 }
281
282 }
283
284 // No entry was found, so this is going to be a new entry.
285
286 if (cs.irc == null)
287 {
288
289 m_log.DebugFormat("[IRC-Channel-{0}] New channel required", cs.idn);
290
291 if ((cs.irc = new IRCConnector(cs)) != null)
292 {
293
294 IRCBridgeModule.m_channels.Add(cs);
295
296 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
297 cs.idn, rs.Region, cs.DefaultZone,
298 cs.CommandsEnabled ? "enabled" : "not enabled",
299 cs.RelayPrivateChannels ? "relayed" : "not relayed");
300 }
301 else
302 {
303 string txt = String.Format("[IRC-Channel-{0}] Region {1} failed to connect to channel {2} on server {3}:{4}",
304 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
305 m_log.Error(txt);
306 throw new Exception(txt);
307 }
308 }
309 else
310 {
311 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} reusing existing connection to channel {2} on server {3}:{4}",
312 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
313 }
314
315 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} associated with channel {2} on server {3}:{4}",
316 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
317
318 // We're finally ready to commit ourselves
319
320
321 return cs;
322
323 }
324
325 // These routines allow differentiating changes to
326 // the underlying channel state. If necessary, a
327 // new channel state will be created.
328
329 internal ChannelState UpdateServer(RegionState rs, string server)
330 {
331 RemoveRegion(rs);
332 ChannelState cs = new ChannelState(this);
333 cs.Server = server;
334 cs = Integrate(rs, cs);
335 cs.AddRegion(rs);
336 return cs;
337 }
338
339 internal ChannelState UpdatePort(RegionState rs, string port)
340 {
341 RemoveRegion(rs);
342 ChannelState cs = new ChannelState(this);
343 cs.Port = Convert.ToUInt32(port);
344 cs = Integrate(rs, cs);
345 cs.AddRegion(rs);
346 return cs;
347 }
348
349 internal ChannelState UpdateChannel(RegionState rs, string channel)
350 {
351 RemoveRegion(rs);
352 ChannelState cs = new ChannelState(this);
353 cs.IrcChannel = channel;
354 cs = Integrate(rs, cs);
355 cs.AddRegion(rs);
356 return cs;
357 }
358
359 internal ChannelState UpdateNickname(RegionState rs, string nickname)
360 {
361 RemoveRegion(rs);
362 ChannelState cs = new ChannelState(this);
363 cs.BaseNickname = nickname;
364 cs = Integrate(rs, cs);
365 cs.AddRegion(rs);
366 return cs;
367 }
368
369 internal ChannelState UpdateClientReporting(RegionState rs, string cr)
370 {
371 RemoveRegion(rs);
372 ChannelState cs = new ChannelState(this);
373 cs.ClientReporting = Convert.ToBoolean(cr);
374 cs = Integrate(rs, cs);
375 cs.AddRegion(rs);
376 return cs;
377 }
378
379 internal ChannelState UpdateRelayIn(RegionState rs, string channel)
380 {
381 RemoveRegion(rs);
382 ChannelState cs = new ChannelState(this);
383 cs.RelayChannel = Convert.ToInt32(channel);
384 cs = Integrate(rs, cs);
385 cs.AddRegion(rs);
386 return cs;
387 }
388
389 internal ChannelState UpdateRelayOut(RegionState rs, string channel)
390 {
391 RemoveRegion(rs);
392 ChannelState cs = new ChannelState(this);
393 cs.RelayChannelOut = Convert.ToInt32(channel);
394 cs = Integrate(rs, cs);
395 cs.AddRegion(rs);
396 return cs;
397 }
398
399 // Determine whether or not this is a 'new' channel. Only those
400 // attributes that uniquely distinguish an IRC connection should
401 // be included here (and only those attributes should really be
402 // in the ChannelState structure)
403
404 private bool IsAConnectionMatchFor(ChannelState cs)
405 {
406 return (
407 Server == cs.Server &&
408 IrcChannel == cs.IrcChannel &&
409 Port == cs.Port &&
410 BaseNickname == cs.BaseNickname &&
411 User == cs.User
412 );
413 }
414
415 // This level of obsessive matching allows us to produce
416 // a minimal overhead int he case of a server which does
417 // need to differentiate IRC at a region level.
418
419 private bool IsAPerfectMatchFor(ChannelState cs)
420 {
421 return ( IsAConnectionMatchFor(cs) &&
422 RelayChannelOut == cs.RelayChannelOut &&
423 PrivateMessageFormat == cs.PrivateMessageFormat &&
424 NoticeMessageFormat == cs.NoticeMessageFormat &&
425 RandomizeNickname == cs.RandomizeNickname &&
426 AccessPassword == cs.AccessPassword &&
427 CommandsEnabled == cs.CommandsEnabled &&
428 CommandChannel == cs.CommandChannel &&
429 DefaultZone == cs.DefaultZone &&
430 RelayPrivateChannels == cs.RelayPrivateChannels &&
431 RelayChannel == cs.RelayChannel &&
432 RelayChat == cs.RelayChat &&
433 ClientReporting == cs.ClientReporting
434 );
435 }
436
437 // This function implements the variable substitution mechanism
438 // for the configuration values. Each string read from the
439 // configuration file is scanned for '[...]' enclosures. Each
440 // one that is found is replaced by either a runtime variable
441 // (%xxx) or an existing configuration key. When no further
442 // substitution is possible, the remaining string is returned
443 // to the caller. This allows for arbitrarily nested
444 // enclosures.
445
446 private static string Substitute(RegionState rs, string instr)
447 {
448
449 string result = instr;
450
451 if (result == null || result.Length == 0)
452 return result;
453
454 // Repeatedly scan the string until all possible
455 // substitutions have been performed.
456
457 // m_log.DebugFormat("[IRC-Channel] Parse[1]: {0}", result);
458
459 while (arg.IsMatch(result))
460 {
461
462 string vvar = arg.Match(result).ToString();
463 string var = vvar.Substring(1,vvar.Length-2).Trim();
464
465 switch (var.ToLower())
466 {
467 case "%region" :
468 result = result.Replace(vvar, rs.Region);
469 break;
470 case "%host" :
471 result = result.Replace(vvar, rs.Host);
472 break;
473 case "%master1" :
474 result = result.Replace(vvar, rs.MA1);
475 break;
476 case "%master2" :
477 result = result.Replace(vvar, rs.MA2);
478 break;
479 case "%locx" :
480 result = result.Replace(vvar, rs.LocX);
481 break;
482 case "%locy" :
483 result = result.Replace(vvar, rs.LocY);
484 break;
485 case "%k" :
486 result = result.Replace(vvar, rs.IDK);
487 break;
488 default :
489 result = result.Replace(vvar, rs.config.GetString(var,var));
490 break;
491 }
492 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
493 }
494
495 // m_log.DebugFormat("[IRC-Channel] Parse[3]: {0}", result);
496 return result;
497
498 }
499
500 public void Close()
501 {
502 m_log.InfoFormat("[IRC-Channel-{0}] Closing channel <{1}> to server <{2}:{3}>",
503 idn, IrcChannel, Server, Port);
504 m_log.InfoFormat("[IRC-Channel-{0}] There are {1} active clients",
505 idn, clientregions.Count);
506 irc.Close();
507 }
508
509 public void Open()
510 {
511 m_log.InfoFormat("[IRC-Channel-{0}] Opening channel <{1}> to server <{2}:{3}>",
512 idn, IrcChannel, Server, Port);
513
514 irc.Open();
515
516 }
517
518 // These are called by each region that attaches to this channel. The call affects
519 // only the relationship of the region with the channel. Not the channel to IRC
520 // relationship (unless it is closed and we want it open).
521
522 public void Open(RegionState rs)
523 {
524 AddRegion(rs);
525 Open();
526 }
527
528 // Close is called to ensure that the IRC session is terminated if this is the
529 // only client.
530
531 public void Close(RegionState rs)
532 {
533 RemoveRegion(rs);
534 lock (IRCBridgeModule.m_channels)
535 {
536 if (clientregions.Count == 0)
537 {
538 Close();
539 IRCBridgeModule.m_channels.Remove(this);
540 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} is last user of channel <{2}> to server <{3}:{4}>",
541 idn, rs.Region, IrcChannel, Server, Port);
542 m_log.InfoFormat("[IRC-Channel-{0}] Removed", idn);
543 }
544 }
545 }
546
547 // Add a client region to this channel if it is not already known
548
549 public void AddRegion(RegionState rs)
550 {
551 m_log.InfoFormat("[IRC-Channel-{0}] Adding region {1} to channel <{2}> to server <{3}:{4}>",
552 idn, rs.Region, IrcChannel, Server, Port);
553 if (!clientregions.Contains(rs))
554 {
555 clientregions.Add(rs);
556 lock (irc) irc.depends++;
557 }
558 }
559
560 // Remove a client region from the channel. If this is the last
561 // region, then clean up the channel. The connector will clean itself
562 // up if it finds itself about to be GC'd.
563
564 public void RemoveRegion(RegionState rs)
565 {
566
567 m_log.InfoFormat("[IRC-Channel-{0}] Removing region {1} from channel <{2} to server <{3}:{4}>",
568 idn, rs.Region, IrcChannel, Server, Port);
569
570 if (clientregions.Contains(rs))
571 {
572 clientregions.Remove(rs);
573 lock (irc) irc.depends--;
574 }
575
576 }
577
578 // This function is lifted from the IRCConnector because it
579 // contains information that is not differentiating from an
580 // IRC point-of-view.
581
582 public static void OSChat(IRCConnector p_irc, OSChatMessage c, bool cmsg)
583 {
584
585 // m_log.DebugFormat("[IRC-OSCHAT] from {0}:{1}", p_irc.Server, p_irc.IrcChannel);
586
587 try
588 {
589
590 // Scan through the set of unique channel configuration for those
591 // that belong to this connector. And then forward the message to
592 // all regions known to those channels.
593 // Note that this code is responsible for completing some of the
594 // settings for the inbound OSChatMessage
595
596 lock (IRCBridgeModule.m_channels)
597 {
598 foreach (ChannelState cs in IRCBridgeModule.m_channels)
599 {
600 if ( p_irc == cs.irc)
601 {
602
603 // This non-IRC differentiator moved to here
604
605 if (cmsg && !cs.ClientReporting)
606 continue;
607
608 // This non-IRC differentiator moved to here
609
610 c.Channel = (cs.RelayPrivateChannels ? cs.RelayChannel : 0);
611
612 foreach (RegionState region in cs.clientregions)
613 {
614 region.OSChat(cs.irc, c);
615 }
616
617 }
618 }
619 }
620 }
621 catch (Exception ex)
622 {
623 m_log.ErrorFormat("[IRC-OSCHAT]: BroadcastSim Exception: {0}", ex.Message);
624 m_log.Debug(ex);
625 }
626 }
627 }
628}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
deleted file mode 100644
index f234b75..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/ChatModule.cs
+++ /dev/null
@@ -1,287 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
deleted file mode 100644
index ccd81c7..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCBridgeModule.cs
+++ /dev/null
@@ -1,219 +0,0 @@
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 log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.Environment.Modules.Avatar.Chat
40{
41 public class IRCBridgeModule : IRegionModule
42 {
43 private static readonly ILog m_log =
44 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 internal static bool configured = false;
47 internal static bool enabled = false;
48 internal static IConfig m_config = null;
49
50 internal static List<ChannelState> m_channels = new List<ChannelState>();
51 internal static List<RegionState> m_regions = new List<RegionState>();
52
53 internal static string password = String.Empty;
54
55 internal RegionState region = null;
56
57 #region IRegionModule Members
58
59 public string Name
60 {
61 get { return "IRCBridgeModule"; }
62 }
63
64 public bool IsSharedModule
65 {
66 get { return false; }
67 }
68
69 public void Initialise(Scene scene, IConfigSource config)
70 {
71 // Do a once-only scan of the configuration file to make
72 // sure it's basically intact.
73
74 if (!configured)
75 {
76 configured = true;
77
78 try
79 {
80 if ((m_config = config.Configs["IRC"]) == null)
81 {
82 m_log.InfoFormat("[IRC-Bridge] module not configured");
83 return;
84 }
85
86 if (!m_config.GetBoolean("enabled", false))
87 {
88 m_log.InfoFormat("[IRC-Bridge] module disabled in configuration");
89 return;
90 }
91 }
92 catch (Exception e)
93 {
94 m_log.ErrorFormat("[IRC-Bridge] configuration failed : {0}", e.Message);
95 return;
96 }
97
98 enabled = true;
99
100 if (config.Configs["RemoteAdmin"] != null)
101 {
102 password = config.Configs["RemoteAdmin"].GetString("access_password", password);
103 scene.CommsManager.HttpServer.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false);
104 }
105 }
106
107 // Iff the IRC bridge is enabled, then each new region may be
108 // connected to IRC. But it should NOT be obligatory (and it
109 // is not).
110 // We have to do ALL of the startup here because PostInitialize
111 // is not called when a region gets created in-flight from the
112 // command line.
113
114 if (enabled)
115 {
116 try
117 {
118 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName);
119 region = new RegionState(scene, m_config);
120 lock (m_regions) m_regions.Add(region);
121 region.Open();
122 }
123 catch (Exception e)
124 {
125 m_log.WarnFormat("[IRC-Bridge] Region {0} not connected to IRC : {1}", scene.RegionInfo.RegionName, e.Message);
126 m_log.Debug(e);
127 }
128 }
129 else
130 {
131 m_log.WarnFormat("[IRC-Bridge] Not enabled. Connect for region {0} ignored", scene.RegionInfo.RegionName);
132 }
133 }
134
135 // This module can be called in-flight in which case PostInitialize
136 // is not called following Initialize. So no use is made of this
137 // call.
138
139 public void PostInitialise()
140 {
141 }
142
143 // Called immediately before the region module is unloaded. Cleanup
144 // the region.
145
146 public void Close()
147 {
148 if (!enabled)
149 return;
150
151 region.Close();
152 lock (m_regions) m_regions.Remove(region);
153 }
154
155 #endregion
156
157 public static XmlRpcResponse XmlRpcAdminMethod(XmlRpcRequest request)
158 {
159 m_log.Info("[IRC-Bridge]: XML RPC Admin Entry");
160
161 XmlRpcResponse response = new XmlRpcResponse();
162 Hashtable responseData = new Hashtable();
163
164 try
165 {
166 Hashtable requestData = (Hashtable)request.Params[0];
167 bool found = false;
168 string region = String.Empty;
169
170 if (password != String.Empty)
171 {
172 if (!requestData.ContainsKey("password"))
173 throw new Exception("Invalid request");
174 if ((string)requestData["password"] != password)
175 throw new Exception("Invalid request");
176 }
177
178 if (!requestData.ContainsKey("region"))
179 throw new Exception("No region name specified");
180 region = (string)requestData["region"];
181
182 foreach (RegionState rs in m_regions)
183 {
184 if (rs.Region == region)
185 {
186 responseData["server"] = rs.cs.Server;
187 responseData["port"] = (int)rs.cs.Port;
188 responseData["user"] = rs.cs.User;
189 responseData["channel"] = rs.cs.IrcChannel;
190 responseData["enabled"] = rs.cs.irc.Enabled;
191 responseData["connected"] = rs.cs.irc.Connected;
192 responseData["nickname"] = rs.cs.irc.Nick;
193 found = true;
194 break;
195 }
196 }
197
198 if (!found) throw new Exception(String.Format("Region <{0}> not found", region));
199
200 responseData["success"] = true;
201 }
202 catch (Exception e)
203 {
204 m_log.InfoFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message);
205
206 responseData["success"] = "false";
207 responseData["error"] = e.Message;
208 }
209 finally
210 {
211 response.Value = responseData;
212 }
213
214 m_log.Debug("[IRC-Bridge]: XML RPC Admin Exit");
215
216 return response;
217 }
218 }
219}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
deleted file mode 100644
index c3cafb0..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/IRCConnector.cs
+++ /dev/null
@@ -1,887 +0,0 @@
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.Timers;
30using System.Collections.Generic;
31using System.IO;
32using System.Net.Sockets;
33using System.Reflection;
34using System.Text.RegularExpressions;
35using System.Threading;
36using OpenMetaverse;
37using log4net;
38using Nini.Config;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.Environment.Modules.Avatar.Chat
44{
45 public class IRCConnector
46 {
47
48 #region Global (static) state
49
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 // Local constants
53
54 private static readonly Vector3 CenterOfRegion = new Vector3(128, 128, 20);
55 private static readonly char[] CS_SPACE = { ' ' };
56
57 private const int WD_INTERVAL = 1000; // base watchdog interval
58 private static int PING_PERIOD = 15; // WD intervals per PING
59 private static int ICCD_PERIOD = 10; // WD intervals between Connects
60 private static int L_TIMEOUT = 25; // Login time out interval
61
62 private static int _idk_ = 0; // core connector identifier
63 private static int _pdk_ = 0; // ping interval counter
64 private static int _icc_ = 0; // IRC connect counter
65
66 // List of configured connectors
67
68 private static List<IRCConnector> m_connectors = new List<IRCConnector>();
69
70 // Watchdog state
71
72 private static System.Timers.Timer m_watchdog = null;
73
74 static IRCConnector()
75 {
76 m_log.DebugFormat("[IRC-Connector]: Static initialization started");
77 m_watchdog = new System.Timers.Timer(WD_INTERVAL);
78 m_watchdog.Elapsed += new ElapsedEventHandler(WatchdogHandler);
79 m_watchdog.AutoReset = true;
80 m_watchdog.Start();
81 m_log.DebugFormat("[IRC-Connector]: Static initialization complete");
82 }
83
84 #endregion
85
86 #region Instance state
87
88 // Connector identity
89
90 internal int idn = _idk_++;
91
92 // How many regions depend upon this connection
93 // This count is updated by the ChannelState object and reflects the sum
94 // of the region clients associated with the set of associated channel
95 // state instances. That's why it cannot be managed here.
96
97 internal int depends = 0;
98
99 // Working threads
100
101 private Thread m_listener = null;
102
103 private Object msyncConnect = new Object();
104
105 internal bool m_randomizeNick = true; // add random suffix
106 internal string m_baseNick = null; // base name for randomizing
107 internal string m_nick = null; // effective nickname
108
109 public string Nick // Public property
110 {
111 get { return m_nick; }
112 set { m_nick = value; }
113 }
114
115 private bool m_enabled = false; // connector enablement
116 public bool Enabled
117 {
118 get { return m_enabled; }
119 }
120
121 private bool m_connected = false; // connection status
122 private bool m_pending = false; // login disposition
123 private int m_timeout = L_TIMEOUT; // login timeout counter
124 public bool Connected
125 {
126 get { return m_connected; }
127 }
128
129 private string m_ircChannel; // associated channel id
130 public string IrcChannel
131 {
132 get { return m_ircChannel; }
133 set { m_ircChannel = value; }
134 }
135
136 private uint m_port = 6667; // session port
137 public uint Port
138 {
139 get { return m_port; }
140 set { m_port = value; }
141 }
142
143 private string m_server = null; // IRC server name
144 public string Server
145 {
146 get { return m_server; }
147 set { m_server = value; }
148 }
149 private string m_password = null;
150 public string Password
151 {
152 get { return m_password; }
153 set { m_password = value; }
154 }
155
156 private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
157 public string User
158 {
159 get { return m_user; }
160 }
161
162 // Network interface
163
164 private TcpClient m_tcp;
165 private NetworkStream m_stream = null;
166 private StreamReader m_reader;
167 private StreamWriter m_writer;
168
169 // Channel characteristic info (if available)
170
171 internal string usermod = String.Empty;
172 internal string chanmod = String.Empty;
173 internal string version = String.Empty;
174 internal bool motd = false;
175
176 #endregion
177
178 #region connector instance management
179
180 internal IRCConnector(ChannelState cs)
181 {
182
183 // Prepare network interface
184
185 m_tcp = null;
186 m_writer = null;
187 m_reader = null;
188
189 // Setup IRC session parameters
190
191 m_server = cs.Server;
192 m_password = cs.Password;
193 m_baseNick = cs.BaseNickname;
194 m_randomizeNick = cs.RandomizeNickname;
195 m_ircChannel = cs.IrcChannel;
196 m_port = cs.Port;
197 m_user = cs.User;
198
199 if (m_watchdog == null)
200 {
201 // Non-differentiating
202
203 ICCD_PERIOD = cs.ConnectDelay;
204 PING_PERIOD = cs.PingDelay;
205
206 // Smaller values are not reasonable
207
208 if (ICCD_PERIOD < 5)
209 ICCD_PERIOD = 5;
210
211 if (PING_PERIOD < 5)
212 PING_PERIOD = 5;
213
214 _icc_ = ICCD_PERIOD; // get started right away!
215
216 }
217
218 // The last line of defense
219
220 if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null)
221 throw new Exception("Invalid connector configuration");
222
223 // Generate an initial nickname if randomizing is enabled
224
225 if (m_randomizeNick)
226 {
227 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
228 }
229
230 // Add the newly created connector to the known connectors list
231
232 m_connectors.Add(this);
233
234 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
235
236 }
237
238 ~IRCConnector()
239 {
240 m_watchdog.Stop();
241 Close();
242 }
243
244 // Mark the connector as connectable. Harmless if already enabled.
245
246 public void Open()
247 {
248 if (!m_enabled)
249 {
250
251 m_connectors.Add(this);
252 m_enabled = true;
253
254 if (!Connected)
255 {
256 Connect();
257 }
258
259 }
260 }
261
262 // Only close the connector if the dependency count is zero.
263
264 public void Close()
265 {
266
267 m_log.InfoFormat("[IRC-Connector-{0}] Closing", idn);
268
269 lock (msyncConnect)
270 {
271
272 if ((depends == 0) && Enabled)
273 {
274
275 m_enabled = false;
276
277 if (Connected)
278 {
279 m_log.DebugFormat("[IRC-Connector-{0}] Closing interface", idn);
280
281 // Cleanup the IRC session
282
283 try
284 {
285 m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole to {2} closing",
286 m_nick, m_ircChannel, m_server));
287 m_writer.Flush();
288 }
289 catch (Exception) {}
290
291
292 m_connected = false;
293
294 try { m_writer.Close(); } catch (Exception) {}
295 try { m_reader.Close(); } catch (Exception) {}
296 try { m_stream.Close(); } catch (Exception) {}
297 try { m_tcp.Close(); } catch (Exception) {}
298
299 }
300
301 m_connectors.Remove(this);
302
303 }
304 }
305
306 m_log.InfoFormat("[IRC-Connector-{0}] Closed", idn);
307
308 }
309
310 #endregion
311
312 #region session management
313
314 // Connect to the IRC server. A connector should always be connected, once enabled
315
316 public void Connect()
317 {
318
319 if (!m_enabled)
320 return;
321
322 // Delay until next WD cycle if this is too close to the last start attempt
323
324 while (_icc_ < ICCD_PERIOD)
325 return;
326
327 m_log.DebugFormat("[IRC-Connector-{0}]: Connection request for {1} on {2}:{3}", idn, m_nick, m_server, m_ircChannel);
328
329 lock (msyncConnect)
330 {
331
332 _icc_ = 0;
333
334 try
335 {
336 if (m_connected) return;
337
338 m_connected = true;
339 m_pending = true;
340 m_timeout = L_TIMEOUT;
341
342 m_tcp = new TcpClient(m_server, (int)m_port);
343 m_stream = m_tcp.GetStream();
344 m_reader = new StreamReader(m_stream);
345 m_writer = new StreamWriter(m_stream);
346
347 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port);
348
349 m_listener = new Thread(new ThreadStart(ListenerRun));
350 m_listener.Name = "IRCConnectorListenerThread";
351 m_listener.IsBackground = true;
352 m_listener.Start();
353 ThreadTracker.Add(m_listener);
354
355 // This is the message order recommended by RFC 2812
356 if (m_password != null)
357 m_writer.WriteLine(String.Format("PASS {0}", m_password));
358 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
359 m_writer.Flush();
360 m_writer.WriteLine(m_user);
361 m_writer.Flush();
362 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
363 m_writer.Flush();
364
365 m_log.InfoFormat("[IRC-Connector-{0}]: {1} has asked to join {2}", idn, m_nick, m_ircChannel);
366
367 }
368 catch (Exception e)
369 {
370 m_log.ErrorFormat("[IRC-Connector-{0}] cannot connect {1} to {2}:{3}: {4}",
371 idn, m_nick, m_server, m_port, e.Message);
372 m_connected = false;
373 m_pending = false;
374 }
375
376 }
377
378 return;
379
380 }
381
382 // Reconnect is used to force a re-cycle of the IRC connection. Should generally
383 // be a transparent event
384
385 public void Reconnect()
386 {
387 m_log.DebugFormat("[IRC-Connector-{0}]: Reconnect request for {1} on {2}:{3}", idn, m_nick, m_server, m_ircChannel);
388
389 // Don't do this if a Connect is in progress...
390
391 lock (msyncConnect)
392 {
393
394 if (m_connected)
395 {
396 m_log.InfoFormat("[IRC-Connector-{0}] Resetting connector", idn);
397
398 // Mark as disconnected. This will allow the listener thread
399 // to exit if still in-flight.
400
401
402 // The listener thread is not aborted - it *might* actually be
403 // the thread that is running the Reconnect! Instead just close
404 // the socket and it will disappear of its own accord, once this
405 // processing is completed.
406
407 try { m_writer.Close(); } catch (Exception) {}
408 try { m_reader.Close(); } catch (Exception) {}
409 try { m_tcp.Close(); } catch (Exception) {}
410
411 m_connected = false;
412 m_pending = false;
413
414 }
415
416 }
417
418 Connect();
419
420 }
421
422 #endregion
423
424 #region Outbound (to-IRC) message handlers
425
426 public void PrivMsg(string pattern, string from, string region, string msg)
427 {
428
429 m_log.DebugFormat("[IRC-Connector-{0}] PrivMsg to IRC from {1}: <{2}>", idn, from,
430 String.Format(pattern, m_ircChannel, from, region, msg));
431
432 // One message to the IRC server
433
434 try
435 {
436 m_writer.WriteLine(pattern, m_ircChannel, from, region, msg);
437 m_writer.Flush();
438 m_log.DebugFormat("[IRC-Connector-{0}]: PrivMsg from {1} in {2}: {3}", idn, from, region, msg);
439 }
440 catch (IOException)
441 {
442 m_log.ErrorFormat("[IRC-Connector-{0}]: PrivMsg I/O Error: disconnected from IRC server", idn);
443 Reconnect();
444 }
445 catch (Exception ex)
446 {
447 m_log.ErrorFormat("[IRC-Connector-{0}]: PrivMsg exception : {1}", idn, ex.Message);
448 m_log.Debug(ex);
449 }
450
451 }
452
453 public void Send(string msg)
454 {
455
456 m_log.DebugFormat("[IRC-Connector-{0}] Send to IRC : <{1}>", idn, msg);
457
458 try
459 {
460 m_writer.WriteLine(msg);
461 m_writer.Flush();
462 m_log.DebugFormat("[IRC-Connector-{0}] Sent command string: {1}", idn, msg);
463 }
464 catch (IOException)
465 {
466 m_log.ErrorFormat("[IRC-Connector-{0}] Disconnected from IRC server.(Send)", idn);
467 Reconnect();
468 }
469 catch (Exception ex)
470 {
471 m_log.ErrorFormat("[IRC-Connector-{0}] Send exception trap: {0}", idn, ex.Message);
472 m_log.Debug(ex);
473 }
474
475 }
476
477 #endregion
478
479 public void ListenerRun()
480 {
481 string inputLine;
482
483 try
484 {
485 while (m_enabled && m_connected)
486 {
487
488 if ((inputLine = m_reader.ReadLine()) == null)
489 throw new Exception("Listener input socket closed");
490
491 // m_log.Info("[IRCConnector]: " + inputLine);
492
493 if (inputLine.Contains("PRIVMSG"))
494 {
495
496 Dictionary<string, string> data = ExtractMsg(inputLine);
497
498 // Any chat ???
499 if (data != null)
500 {
501
502 OSChatMessage c = new OSChatMessage();
503 c.Message = data["msg"];
504 c.Type = ChatTypeEnum.Region;
505 c.Position = CenterOfRegion;
506 c.From = data["nick"];
507 c.Sender = null;
508 c.SenderUUID = UUID.Zero;
509
510 // Is message "\001ACTION foo bar\001"?
511 // Then change to: "/me foo bar"
512
513 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
514 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
515
516 ChannelState.OSChat(this, c, false);
517
518 }
519
520 }
521 else
522 {
523 ProcessIRCCommand(inputLine);
524 }
525 }
526 }
527 catch (Exception /*e*/)
528 {
529 // m_log.ErrorFormat("[IRC-Connector-{0}]: ListenerRun exception trap: {1}", idn, e.Message);
530 // m_log.Debug(e);
531 }
532
533 // This is potentially circular, but harmless if so.
534 // The connection is marked as not connected the first time
535 // through reconnect.
536
537 if (m_enabled) Reconnect();
538
539 }
540
541 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
542 RegexOptions.Multiline);
543
544 private Dictionary<string, string> ExtractMsg(string input)
545 {
546 //examines IRC commands and extracts any private messages
547 // which will then be reboadcast in the Sim
548
549 // m_log.InfoFormat("[IRC-Connector-{0}]: ExtractMsg: {1}", idn, input);
550
551 Dictionary<string, string> result = null;
552 MatchCollection matches = RE.Matches(input);
553
554 // Get some direct matches $1 $4 is a
555 if ((matches.Count == 0) || (matches.Count != 1) || (matches[0].Groups.Count != 5))
556 {
557 // m_log.Info("[IRCConnector]: Number of matches: " + matches.Count);
558 // if (matches.Count > 0)
559 // {
560 // m_log.Info("[IRCConnector]: Number of groups: " + matches[0].Groups.Count);
561 // }
562 return null;
563 }
564
565 result = new Dictionary<string, string>();
566 result.Add("nick", matches[0].Groups[1].Value);
567 result.Add("user", matches[0].Groups[2].Value);
568 result.Add("channel", matches[0].Groups[3].Value);
569 result.Add("msg", matches[0].Groups[4].Value);
570
571 return result;
572 }
573
574 public void BroadcastSim(string sender, string format, params string[] args)
575 {
576 try
577 {
578 OSChatMessage c = new OSChatMessage();
579 c.From = sender;
580 c.Message = String.Format(format, args);
581 c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say;
582 c.Position = CenterOfRegion;
583 c.Sender = null;
584 c.SenderUUID = UUID.Zero;
585
586 ChannelState.OSChat(this, c, true);
587
588 }
589 catch (Exception ex) // IRC gate should not crash Sim
590 {
591 m_log.ErrorFormat("[IRC-Connector-{0}]: BroadcastSim Exception Trap: {1}\n{2}", idn, ex.Message, ex.StackTrace);
592 }
593 }
594
595 #region IRC Command Handlers
596
597 public void ProcessIRCCommand(string command)
598 {
599
600 string[] commArgs;
601 string c_server = m_server;
602
603 string pfx = String.Empty;
604 string cmd = String.Empty;
605 string parms = String.Empty;
606
607 // ":" indicates that a prefix is present
608 // There are NEVER more than 17 real
609 // fields. A parameter that starts with
610 // ":" indicates that the remainder of the
611 // line is a single parameter value.
612
613 commArgs = command.Split(CS_SPACE,2);
614
615 if (commArgs[0].StartsWith(":"))
616 {
617 pfx = commArgs[0].Substring(1);
618 commArgs = commArgs[1].Split(CS_SPACE,2);
619 }
620
621 cmd = commArgs[0];
622 parms = commArgs[1];
623
624 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd);
625
626 switch (cmd)
627 {
628
629 // Messages 001-004 are always sent
630 // following signon.
631
632 case "001" : // Welcome ...
633 case "002" : // Server information
634 case "003" : // Welcome ...
635 break;
636 case "004" : // Server information
637 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
638 commArgs = parms.Split(CS_SPACE);
639 c_server = commArgs[1];
640 m_server = c_server;
641 version = commArgs[2];
642 usermod = commArgs[3];
643 chanmod = commArgs[4];
644 break;
645 case "005" : // Server information
646 break;
647 case "042" :
648 case "250" :
649 case "251" :
650 case "252" :
651 case "254" :
652 case "255" :
653 case "265" :
654 case "266" :
655 case "332" : // Subject
656 case "333" : // Subject owner (?)
657 case "353" : // Name list
658 case "366" : // End-of-Name list marker
659 case "372" : // MOTD body
660 case "375" : // MOTD start
661 m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
662 break;
663 case "376" : // MOTD end
664 m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
665 motd = true;
666 break;
667 case "451" : // Not registered
668 break;
669 case "433" : // Nickname in use
670 // Gen a new name
671 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
672 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick);
673 // Retry
674 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
675 m_writer.Flush();
676 m_writer.WriteLine(m_user);
677 m_writer.Flush();
678 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
679 m_writer.Flush();
680 break;
681 case "479" : // Bad channel name, etc. This will never work, so disable the connection
682 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
683 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd);
684 m_enabled = false;
685 m_connected = false;
686 m_pending = false;
687 break;
688 case "NOTICE" :
689 m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
690 break;
691 case "ERROR" :
692 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
693 if (parms.Contains("reconnect too fast"))
694 ICCD_PERIOD++;
695 m_pending = false;
696 Reconnect();
697 break;
698 case "PING" :
699 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
700 m_writer.WriteLine(String.Format("PONG {0}", parms));
701 m_writer.Flush();
702 break;
703 case "PONG" :
704 break;
705 case "JOIN":
706 if (m_pending)
707 {
708 m_log.InfoFormat("[IRC-Connector-{0}] [{1}] Connected", idn, cmd);
709 m_pending = false;
710 }
711 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
712 eventIrcJoin(pfx, cmd, parms);
713 break;
714 case "PART":
715 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
716 eventIrcPart(pfx, cmd, parms);
717 break;
718 case "MODE":
719 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
720 eventIrcMode(pfx, cmd, parms);
721 break;
722 case "NICK":
723 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
724 eventIrcNickChange(pfx, cmd, parms);
725 break;
726 case "KICK":
727 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
728 eventIrcKick(pfx, cmd, parms);
729 break;
730 case "QUIT":
731 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
732 eventIrcQuit(pfx, cmd, parms);
733 break;
734 default :
735 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms);
736 break;
737 }
738
739 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd);
740
741 }
742
743 public void eventIrcJoin(string prefix, string command, string parms)
744 {
745 string[] args = parms.Split(CS_SPACE,2);
746 string IrcUser = prefix.Split('!')[0];
747 string IrcChannel = args[0];
748
749 if (IrcChannel.StartsWith(":"))
750 IrcChannel = IrcChannel.Substring(1);
751
752 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCJoin {1}:{2}", idn, m_server, m_ircChannel);
753 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel);
754 }
755
756 public void eventIrcPart(string prefix, string command, string parms)
757 {
758 string[] args = parms.Split(CS_SPACE,2);
759 string IrcUser = prefix.Split('!')[0];
760 string IrcChannel = args[0];
761
762 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel);
763 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel);
764 }
765
766 public void eventIrcMode(string prefix, string command, string parms)
767 {
768 string[] args = parms.Split(CS_SPACE,2);
769 string UserMode = args[1];
770
771 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel);
772 if (UserMode.Substring(0, 1) == ":")
773 {
774 UserMode = UserMode.Remove(0, 1);
775 }
776 }
777
778 public void eventIrcNickChange(string prefix, string command, string parms)
779 {
780 string[] args = parms.Split(CS_SPACE,2);
781 string UserOldNick = prefix.Split('!')[0];
782 string UserNewNick = args[0].Remove(0, 1);
783
784 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCNickChange {1}:{2}", idn, m_server, m_ircChannel);
785 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick);
786 }
787
788 public void eventIrcKick(string prefix, string command, string parms)
789 {
790 string[] args = parms.Split(CS_SPACE,3);
791 string UserKicker = prefix.Split('!')[0];
792 string IrcChannel = args[0];
793 string UserKicked = args[1];
794 string KickMessage = args[2];
795
796 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel);
797 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
798
799 if (UserKicked == m_nick)
800 {
801 BroadcastSim(m_nick, "Hey, that was me!!!");
802 }
803
804 }
805
806 public void eventIrcQuit(string prefix, string command, string parms)
807 {
808 string IrcUser = prefix.Split('!')[0];
809 string QuitMessage = parms;
810
811 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel);
812 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage);
813 }
814
815 #endregion
816
817 #region Connector Watch Dog
818
819 // A single watch dog monitors extant connectors and makes sure that they
820 // are re-connected as necessary. If a connector IS connected, then it is
821 // pinged, but only if a PING period has elapsed.
822
823 protected static void WatchdogHandler(Object source, ElapsedEventArgs args)
824 {
825
826 // m_log.InfoFormat("[IRC-Watchdog] Status scan");
827
828 _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger
829 _icc_++; // increment the inter-consecutive-connect-delay counter
830
831 foreach (IRCConnector connector in m_connectors)
832 {
833 if (connector.Enabled)
834 {
835 if (!connector.Connected)
836 {
837 try
838 {
839 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel);
840 connector.Connect();
841 }
842 catch (Exception e)
843 {
844 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
845 }
846 }
847 else
848 {
849
850 if (connector.m_pending)
851 {
852 if (connector.m_timeout == 0)
853 {
854 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn);
855 connector.Reconnect();
856 }
857 else
858 connector.m_timeout--;
859 }
860
861 if (_pdk_ == 0)
862 {
863 try
864 {
865 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
866 connector.m_writer.Flush();
867 }
868 catch (Exception /*e*/)
869 {
870 // m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message);
871 // m_log.Debug(e);
872 connector.Reconnect();
873 }
874 }
875
876 }
877 }
878 }
879
880 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed");
881
882 }
883
884 #endregion
885
886 }
887}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Chat/RegionState.cs b/OpenSim/Region/Environment/Modules/Avatar/Chat/RegionState.cs
deleted file mode 100644
index 78f4265..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Chat/RegionState.cs
+++ /dev/null
@@ -1,424 +0,0 @@
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 System.Text.RegularExpressions;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.Environment.Modules.Avatar.Chat
39{
40 // An instance of this class exists for every active region
41
42 internal class RegionState
43 {
44
45 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(128, 128, 20);
49 private const int DEBUG_CHANNEL = 2147483647;
50
51 private static int _idk_ = 0;
52
53 // Runtime variables; these values are assigned when the
54 // IrcState is created and remain constant thereafter.
55
56 internal string Region = String.Empty;
57 internal string Host = String.Empty;
58 internal string LocX = String.Empty;
59 internal string LocY = String.Empty;
60 internal string MA1 = String.Empty;
61 internal string MA2 = String.Empty;
62 internal string IDK = String.Empty;
63
64 // System values - used only be the IRC classes themselves
65
66 internal ChannelState cs = null; // associated IRC configuration
67 internal Scene scene = null; // associated scene
68 internal IConfig config = null; // configuration file reference
69 internal bool enabled = true;
70
71 // This list is used to keep track of who is here, and by
72 // implication, who is not.
73
74 internal List<IClientAPI> clients = new List<IClientAPI>();
75
76 // Setup runtime variable values
77
78 public RegionState(Scene p_scene, IConfig p_config)
79 {
80
81 scene = p_scene;
82 config = p_config;
83
84 Region = scene.RegionInfo.RegionName;
85 Host = scene.RegionInfo.ExternalHostName;
86 LocX = Convert.ToString(scene.RegionInfo.RegionLocX);
87 LocY = Convert.ToString(scene.RegionInfo.RegionLocY);
88 MA1 = scene.RegionInfo.MasterAvatarFirstName;
89 MA2 = scene.RegionInfo.MasterAvatarLastName;
90 IDK = Convert.ToString(_idk_++);
91
92 // OpenChannel conditionally establishes a connection to the
93 // IRC server. The request will either succeed, or it will
94 // throw an exception.
95
96 ChannelState.OpenChannel(this, config);
97
98 // Connect channel to world events
99
100 scene.EventManager.OnChatFromWorld += OnSimChat;
101 scene.EventManager.OnChatFromClient += OnSimChat;
102 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
103 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
104
105 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region);
106
107 }
108
109 // Auto cleanup when abandoned
110
111 ~RegionState()
112 {
113 if (cs != null)
114 cs.RemoveRegion(this);
115 }
116
117 // Called by PostInitialize after all regions have been created
118
119 public void Open()
120 {
121 cs.Open(this);
122 enabled = true;
123 }
124
125 // Called by IRCBridgeModule.Close immediately prior to unload
126 // of the module for this region. This happens when the region
127 // is being removed or the server is terminating. The IRC
128 // BridgeModule will remove the region from the region list
129 // when control returns.
130
131 public void Close()
132 {
133 enabled = false;
134 cs.Close(this);
135 }
136
137 // The agent has disconnected, cleanup associated resources
138
139 private void OnClientLoggedOut(IClientAPI client)
140 {
141 try
142 {
143 if (clients.Contains(client))
144 {
145 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
146 {
147 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name);
148 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name));
149 }
150 client.OnLogout -= OnClientLoggedOut;
151 client.OnConnectionClosed -= OnClientLoggedOut;
152 clients.Remove(client);
153 }
154 }
155 catch (Exception ex)
156 {
157 m_log.ErrorFormat("[IRC-Region {0}]: ClientLoggedOut exception: {1}", Region, ex.Message);
158 m_log.Debug(ex);
159 }
160 }
161
162 // This event indicates that the agent has left the building. We should treat that the same
163 // as if the agent has logged out (we don't want cross-region noise - or do we?)
164
165 private void OnMakeChildAgent(ScenePresence presence)
166 {
167
168 IClientAPI client = presence.ControllingClient;
169
170 try
171 {
172 if (clients.Contains(client))
173 {
174 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
175 {
176 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
177 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName);
178 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName));
179 }
180 client.OnLogout -= OnClientLoggedOut;
181 client.OnConnectionClosed -= OnClientLoggedOut;
182 clients.Remove(client);
183 }
184 }
185 catch (Exception ex)
186 {
187 m_log.ErrorFormat("[IRC-Region {0}]: MakeChildAgent exception: {1}", Region, ex.Message);
188 m_log.Debug(ex);
189 }
190
191 }
192
193 // An agent has entered the region (from another region). Add the client to the locally
194 // known clients list
195
196 private void OnMakeRootAgent(ScenePresence presence)
197 {
198
199 IClientAPI client = presence.ControllingClient;
200
201 try
202 {
203 if (!clients.Contains(client))
204 {
205 client.OnLogout += OnClientLoggedOut;
206 client.OnConnectionClosed += OnClientLoggedOut;
207 clients.Add(client);
208 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
209 {
210 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
211 m_log.DebugFormat("[IRC-Region {0}] {1} has arrived", Region, clientName);
212 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has arrived", clientName));
213 }
214 }
215 }
216 catch (Exception ex)
217 {
218 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message);
219 m_log.Debug(ex);
220 }
221
222 }
223
224 // This handler detects chat events int he virtual world.
225
226 public void OnSimChat(Object sender, OSChatMessage msg)
227 {
228
229 // early return if this comes from the IRC forwarder
230
231 if (cs.irc.Equals(sender)) return;
232
233 // early return if nothing to forward
234
235 if (msg.Message.Length == 0) return;
236
237 // check for commands coming from avatars or in-world
238 // object (if commands are enabled)
239
240 if (cs.CommandsEnabled && msg.Channel == cs.CommandChannel)
241 {
242
243 m_log.DebugFormat("[IRC-Region {0}] command on channel {1}: {2}", Region, msg.Channel, msg.Message);
244
245 string[] messages = msg.Message.Split(' ');
246 string command = messages[0].ToLower();
247
248 try
249 {
250 switch (command)
251 {
252
253 // These commands potentially require a change in the
254 // underlying ChannelState.
255
256 case "server":
257 cs.Close(this);
258 cs = cs.UpdateServer(this, messages[1]);
259 cs.Open(this);
260 break;
261 case "port":
262 cs.Close(this);
263 cs = cs.UpdatePort(this, messages[1]);
264 cs.Open(this);
265 break;
266 case "channel":
267 cs.Close(this);
268 cs = cs.UpdateChannel(this, messages[1]);
269 cs.Open(this);
270 break;
271 case "nick":
272 cs.Close(this);
273 cs = cs.UpdateNickname(this, messages[1]);
274 cs.Open(this);
275 break;
276
277 // These may also (but are less likely) to require a
278 // change in ChannelState.
279
280 case "client-reporting":
281 cs = cs.UpdateClientReporting(this, messages[1]);
282 break;
283 case "in-channel":
284 cs = cs.UpdateRelayIn(this, messages[1]);
285 break;
286 case "out-channel":
287 cs = cs.UpdateRelayOut(this, messages[1]);
288 break;
289
290 // These are all taken to be temporary changes in state
291 // so the underlying connector remains intact. But note
292 // that with regions sharing a connector, there could
293 // be interference.
294
295 case "close":
296 enabled = false;
297 cs.Close(this);
298 break;
299
300 case "connect":
301 enabled = true;
302 cs.Open(this);
303 break;
304
305 case "reconnect":
306 enabled = true;
307 cs.Close(this);
308 cs.Open(this);
309 break;
310
311 // This one is harmless as far as we can judge from here.
312 // If it is not, then the complaints will eventually make
313 // that evident.
314
315 default:
316 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}",
317 Region, msg.Message);
318 cs.irc.Send(msg.Message);
319 break;
320 }
321 }
322 catch (Exception ex)
323 {
324 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
325 Region, ex.Message);
326 m_log.Debug(ex);
327 }
328
329 return;
330
331 }
332
333 // The command channel remains enabled, even if we have otherwise disabled the IRC
334 // interface.
335
336 if (!enabled)
337 return;
338
339 // drop messages unless they are on a valid in-world
340 // channel as configured in the ChannelState
341
342 if (!cs.ValidInWorldChannels.Contains(msg.Channel))
343 {
344 m_log.DebugFormat("[IRC-Region {0}] dropping message {1} on channel {2}", Region, msg, msg.Channel);
345 return;
346 }
347
348 ScenePresence avatar = null;
349 string fromName = msg.From;
350
351 if (msg.Sender != null)
352 {
353 avatar = scene.GetScenePresence(msg.Sender.AgentId);
354 if (avatar != null) fromName = avatar.Name;
355 }
356
357 if (!cs.irc.Connected)
358 {
359 m_log.WarnFormat("[IRC-Region {0}] IRCConnector not connected: dropping message from {1}", Region, fromName);
360 return;
361 }
362
363 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
364
365 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
366 {
367 string txt = msg.Message;
368 if (txt.StartsWith("/me "))
369 txt = String.Format("{0} {1}", fromName, msg.Message.Substring(4));
370
371 cs.irc.PrivMsg(cs.PrivateMessageFormat, fromName, Region, txt);
372 return;
373 }
374
375 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
376 msg.Channel == cs.RelayChannelOut)
377 {
378 Match m = cs.AccessPasswordRegex.Match(msg.Message);
379 if (null != m)
380 {
381 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
382 m.Groups["message"].ToString());
383 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
384 scene.RegionInfo.RegionName, m.Groups["message"].ToString());
385 }
386 }
387 }
388
389 // This method gives the region an opportunity to interfere with
390 // message delivery. For now we just enforce the enable/disable
391 // flag.
392
393 internal void OSChat(Object irc, OSChatMessage msg)
394 {
395 if (enabled)
396 {
397 // m_log.DebugFormat("[IRC-OSCHAT] Region {0} being sent message", region.Region);
398 msg.Scene = scene;
399 scene.EventManager.TriggerOnChatBroadcast(irc, msg);
400 }
401 }
402
403 // This supports any local message traffic that might be needed in
404 // support of command processing. At present there is none.
405
406 internal void LocalChat(string msg)
407 {
408 if (enabled)
409 {
410 OSChatMessage osm = new OSChatMessage();
411 osm.From = "IRC Agent";
412 osm.Message = msg;
413 osm.Type = ChatTypeEnum.Region;
414 osm.Position = CenterOfRegion;
415 osm.Sender = null;
416 osm.SenderUUID = OpenMetaverse.UUID.Zero; // Hmph! Still?
417 osm.Channel = 0;
418 OSChat(this, osm);
419 }
420 }
421
422 }
423
424}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Combat/CombatModule.cs
deleted file mode 100644
index f032319..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Combat/CombatModule.cs
+++ /dev/null
@@ -1,154 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
deleted file mode 100644
index 5ac5dbe..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
+++ /dev/null
@@ -1,604 +0,0 @@
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.IO;
32using System.Net;
33using System.Net.Sockets;
34using System.Reflection;
35using System.Text;
36using System.Text.RegularExpressions;
37using System.Threading;
38using log4net;
39using Nini.Config;
40using Nwc.XmlRpc;
41using OpenMetaverse;
42using OpenSim.Framework;
43using OpenSim.Framework.Servers;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.Environment.Modules.Avatar.Chat;
47
48namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
49{
50 public class ConciergeModule : ChatModule, IRegionModule
51 {
52 private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private const int DEBUG_CHANNEL = 2147483647;
55
56 private List<IScene> _scenes = new List<IScene>();
57 private List<IScene> _conciergedScenes = new List<IScene>();
58 private Dictionary<IScene, List<UUID>> _sceneAttendees =
59 new Dictionary<IScene, List<UUID>>();
60 private Dictionary<UUID, string> _attendeeNames =
61 new Dictionary<UUID, string>();
62
63 private bool _replacingChatModule = false;
64
65 private IConfig _config;
66
67 private string _whoami = "conferencier";
68 private Regex _regions = null;
69 private string _welcomes = null;
70 private int _conciergeChannel = 42;
71 private string _announceEntering = "{0} enters {1} (now {2} visitors in this region)";
72 private string _announceLeaving = "{0} leaves {1} (back to {2} visitors in this region)";
73 private string _xmlRpcPassword = String.Empty;
74 private string _brokerURI = String.Empty;
75
76 internal object _syncy = new object();
77
78 #region IRegionModule Members
79 public override void Initialise(Scene scene, IConfigSource config)
80 {
81 try
82 {
83 if ((_config = config.Configs["Concierge"]) == null)
84 {
85 //_log.InfoFormat("[Concierge]: no configuration section [Concierge] in OpenSim.ini: module not configured");
86 return;
87 }
88
89 if (!_config.GetBoolean("enabled", false))
90 {
91 //_log.InfoFormat("[Concierge]: module disabled by OpenSim.ini configuration");
92 return;
93 }
94 }
95 catch (Exception)
96 {
97 _log.Info("[Concierge]: module not configured");
98 return;
99 }
100
101 // check whether ChatModule has been disabled: if yes,
102 // then we'll "stand in"
103 try
104 {
105 if (config.Configs["Chat"] == null)
106 {
107 _replacingChatModule = false;
108 }
109 else
110 {
111 _replacingChatModule = !config.Configs["Chat"].GetBoolean("enabled", true);
112 }
113 }
114 catch (Exception)
115 {
116 _replacingChatModule = false;
117 }
118 _log.InfoFormat("[Concierge] {0} ChatModule", _replacingChatModule ? "replacing" : "not replacing");
119
120
121 // take note of concierge channel and of identity
122 _conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", _conciergeChannel);
123 _whoami = _config.GetString("whoami", "conferencier");
124 _welcomes = _config.GetString("welcomes", _welcomes);
125 _announceEntering = _config.GetString("announce_entering", _announceEntering);
126 _announceLeaving = _config.GetString("announce_leaving", _announceLeaving);
127 _xmlRpcPassword = _config.GetString("password", _xmlRpcPassword);
128 _brokerURI = _config.GetString("broker", _brokerURI);
129
130 _log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", _whoami);
131
132 // calculate regions Regex
133 if (_regions == null)
134 {
135 string regions = _config.GetString("regions", String.Empty);
136 if (!String.IsNullOrEmpty(regions))
137 {
138 _regions = new Regex(@regions, RegexOptions.Compiled | RegexOptions.IgnoreCase);
139 }
140 }
141
142 scene.CommsManager.HttpServer.AddXmlRPCHandler("concierge_update_welcome", XmlRpcUpdateWelcomeMethod, false);
143
144 lock (_syncy)
145 {
146 if (!_scenes.Contains(scene))
147 {
148 _scenes.Add(scene);
149
150 if (_regions == null || _regions.IsMatch(scene.RegionInfo.RegionName))
151 _conciergedScenes.Add(scene);
152
153 // subscribe to NewClient events
154 scene.EventManager.OnNewClient += OnNewClient;
155
156 // subscribe to *Chat events
157 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
158 if (!_replacingChatModule)
159 scene.EventManager.OnChatFromClient += OnChatFromClient;
160 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
161
162 // subscribe to agent change events
163 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
164 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
165 }
166 }
167 _log.InfoFormat("[Concierge]: initialized for {0}", scene.RegionInfo.RegionName);
168 }
169
170 public override void PostInitialise()
171 {
172 }
173
174 public override void Close()
175 {
176 }
177
178 public override string Name
179 {
180 get { return "ConciergeModule"; }
181 }
182
183 public override bool IsSharedModule
184 {
185 get { return true; }
186 }
187
188 #endregion
189
190 #region ISimChat Members
191 public override void OnChatBroadcast(Object sender, OSChatMessage c)
192 {
193 if (_replacingChatModule)
194 {
195 // distribute chat message to each and every avatar in
196 // the region
197 base.OnChatBroadcast(sender, c);
198 }
199
200 // TODO: capture logic
201 return;
202 }
203
204 public override void OnChatFromClient(Object sender, OSChatMessage c)
205 {
206 if (_replacingChatModule)
207 {
208 // replacing ChatModule: need to redistribute
209 // ChatFromClient to interested subscribers
210 c = FixPositionOfChatMessage(c);
211
212 Scene scene = (Scene)c.Scene;
213 scene.EventManager.TriggerOnChatFromClient(sender, c);
214
215 if (_conciergedScenes.Contains(c.Scene))
216 {
217 // when we are replacing ChatModule, we treat
218 // OnChatFromClient like OnChatBroadcast for
219 // concierged regions, effectively extending the
220 // range of chat to cover the whole
221 // region. however, we don't do this for whisper
222 // (got to have some privacy)
223 if (c.Type != ChatTypeEnum.Whisper)
224 {
225 base.OnChatBroadcast(sender, c);
226 return;
227 }
228 }
229
230 // redistribution will be done by base class
231 base.OnChatFromClient(sender, c);
232 }
233
234 // TODO: capture chat
235 return;
236 }
237
238 public override void OnChatFromWorld(Object sender, OSChatMessage c)
239 {
240 if (_replacingChatModule)
241 {
242 if (_conciergedScenes.Contains(c.Scene))
243 {
244 // when we are replacing ChatModule, we treat
245 // OnChatFromClient like OnChatBroadcast for
246 // concierged regions, effectively extending the
247 // range of chat to cover the whole
248 // region. however, we don't do this for whisper
249 // (got to have some privacy)
250 if (c.Type != ChatTypeEnum.Whisper)
251 {
252 base.OnChatBroadcast(sender, c);
253 return;
254 }
255 }
256
257 base.OnChatFromWorld(sender, c);
258 }
259 return;
260 }
261 #endregion
262
263
264 public override void OnNewClient(IClientAPI client)
265 {
266 client.OnLogout += OnClientLoggedOut;
267
268 if (_replacingChatModule)
269 client.OnChatFromClient += OnChatFromClient;
270 }
271
272
273
274 public void OnClientLoggedOut(IClientAPI client)
275 {
276 client.OnLogout -= OnClientLoggedOut;
277 client.OnConnectionClosed -= OnClientLoggedOut;
278
279 if (_conciergedScenes.Contains(client.Scene))
280 {
281 _log.DebugFormat("[Concierge]: {0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName);
282 RemoveFromAttendeeList(client.AgentId, client.Name, client.Scene);
283 AnnounceToAgentsRegion(client.Scene, String.Format(_announceLeaving, client.Name, client.Scene.RegionInfo.RegionName,
284 _sceneAttendees[client.Scene].Count));
285 UpdateBroker(client.Scene);
286 }
287 }
288
289
290 public void OnMakeRootAgent(ScenePresence agent)
291 {
292 if (_conciergedScenes.Contains(agent.Scene))
293 {
294 _log.DebugFormat("[Concierge]: {0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
295 AddToAttendeeList(agent.UUID, agent.Name, agent.Scene);
296 WelcomeAvatar(agent, agent.Scene);
297 AnnounceToAgentsRegion(agent.Scene, String.Format(_announceEntering, agent.Name, agent.Scene.RegionInfo.RegionName,
298 _sceneAttendees[agent.Scene].Count));
299 UpdateBroker(agent.Scene);
300 }
301 }
302
303
304 public void OnMakeChildAgent(ScenePresence agent)
305 {
306 if (_conciergedScenes.Contains(agent.Scene))
307 {
308 _log.DebugFormat("[Concierge]: {0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
309 RemoveFromAttendeeList(agent.UUID, agent.Name, agent.Scene);
310 AnnounceToAgentsRegion(agent.Scene, String.Format(_announceLeaving, agent.Name, agent.Scene.RegionInfo.RegionName,
311 _sceneAttendees[agent.Scene].Count));
312 UpdateBroker(agent.Scene);
313 }
314 }
315
316 protected void AddToAttendeeList(UUID agentID, string name, Scene scene)
317 {
318 lock (_sceneAttendees)
319 {
320 if (!_sceneAttendees.ContainsKey(scene))
321 _sceneAttendees[scene] = new List<UUID>();
322
323 List<UUID> attendees = _sceneAttendees[scene];
324 if (!attendees.Contains(agentID))
325 {
326 attendees.Add(agentID);
327 _attendeeNames[agentID] = name;
328 }
329 }
330 }
331
332 protected void RemoveFromAttendeeList(UUID agentID, String name, IScene scene)
333 {
334 lock (_sceneAttendees)
335 {
336 if (!_sceneAttendees.ContainsKey(scene))
337 {
338 _log.WarnFormat("[Concierge]: attendee list missing for region {0}", scene.RegionInfo.RegionName);
339 return;
340 }
341
342 List<UUID> attendees = _sceneAttendees[scene];
343 if (!attendees.Contains(agentID))
344 {
345 _log.WarnFormat("[Concierge]: avatar {0} must have sneaked in to region {1} earlier",
346 name, scene.RegionInfo.RegionName);
347 return;
348 }
349
350 attendees.Remove(agentID);
351 _attendeeNames.Remove(agentID);
352 }
353 }
354
355 protected void UpdateBroker(IScene scene)
356 {
357 if (String.IsNullOrEmpty(_brokerURI))
358 return;
359
360 string uri = String.Format(_brokerURI, scene.RegionInfo.RegionName, scene.RegionInfo.RegionID);
361
362 // get attendee list for the scene
363 List<UUID> attendees;
364 lock (_sceneAttendees)
365 {
366 if (!_sceneAttendees.ContainsKey(scene))
367 {
368 _log.DebugFormat("[Concierge]: attendee list missing for region {0}", scene.RegionInfo.RegionName);
369 return;
370 }
371
372 attendees = _sceneAttendees[scene];
373 }
374
375 // create XML sniplet
376 StringBuilder list = new StringBuilder();
377 if (0 == attendees.Count)
378 {
379 list.Append(String.Format("<avatars count=\"0\" region_name=\"{0}\" region_uuid=\"{1}\" timestamp=\"{2}\" />",
380 scene.RegionInfo.RegionName, scene.RegionInfo.RegionID,
381 DateTime.UtcNow.ToString("s")));
382 }
383 else
384 {
385 list.Append(String.Format("<avatars count=\"{0}\" region_name=\"{1}\" region_uuid=\"{2}\" timestamp=\"{3}\">\n",
386 attendees.Count, scene.RegionInfo.RegionName,
387 scene.RegionInfo.RegionID,
388 DateTime.UtcNow.ToString("s")));
389 foreach (UUID uuid in attendees)
390 {
391 string name = _attendeeNames[uuid];
392 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", name, uuid));
393 }
394 list.Append("</avatars>");
395 }
396 string payload = list.ToString();
397
398 // post via REST to broker
399 HttpWebRequest updatePost = WebRequest.Create(uri) as HttpWebRequest;
400 updatePost.Method = "POST";
401 updatePost.ContentType = "text/xml";
402 updatePost.ContentLength = payload.Length;
403 updatePost.UserAgent = "OpenSim.Concierge";
404
405 try
406 {
407 StreamWriter payloadStream = new StreamWriter(updatePost.GetRequestStream());
408 payloadStream.Write(payload);
409 payloadStream.Close();
410
411 updatePost.BeginGetResponse(UpdateBrokerDone, updatePost);
412 _log.DebugFormat("[Concierge] async broker POST to {0} started", uri);
413 }
414 catch (WebException we)
415 {
416 _log.ErrorFormat("[Concierge] async broker POST to {0} failed: {1}", uri, we.Status);
417 }
418 }
419
420 private void UpdateBrokerDone(IAsyncResult result)
421 {
422 HttpWebRequest updatePost = null;
423 try
424 {
425 updatePost = result.AsyncState as HttpWebRequest;
426 using (HttpWebResponse response = updatePost.EndGetResponse(result) as HttpWebResponse)
427 {
428 _log.DebugFormat("[Concierge] broker update: status {0}", response.StatusCode);
429 }
430 }
431 catch (WebException we)
432 {
433 string uri = updatePost.RequestUri.OriginalString;
434 _log.ErrorFormat("[Concierge] broker update to {0} failed with status {1}", uri, we.Status);
435 if (null != we.Response)
436 {
437 using (HttpWebResponse resp = we.Response as HttpWebResponse)
438 {
439 _log.ErrorFormat("[Concierge] response from {0} status code: {1}", uri, resp.StatusCode);
440 _log.ErrorFormat("[Concierge] response from {0} status desc: {1}", uri, resp.StatusDescription);
441 _log.ErrorFormat("[Concierge] response from {0} server: {1}", uri, resp.Server);
442
443 if (resp.ContentLength > 0)
444 {
445 StreamReader content = new StreamReader(resp.GetResponseStream());
446 _log.ErrorFormat("[Concierge] response from {0} content: {1}", uri, content.ReadToEnd());
447 content.Close();
448 }
449 }
450 }
451 }
452 }
453
454 protected void WelcomeAvatar(ScenePresence agent, Scene scene)
455 {
456 // welcome mechanics: check whether we have a welcomes
457 // directory set and wether there is a region specific
458 // welcome file there: if yes, send it to the agent
459 if (!String.IsNullOrEmpty(_welcomes))
460 {
461 string[] welcomes = new string[] {
462 Path.Combine(_welcomes, agent.Scene.RegionInfo.RegionName),
463 Path.Combine(_welcomes, "DEFAULT")};
464 foreach (string welcome in welcomes)
465 {
466 if (File.Exists(welcome))
467 {
468 try
469 {
470 string[] welcomeLines = File.ReadAllLines(welcome);
471 foreach (string l in welcomeLines)
472 {
473 AnnounceToAgent(agent, String.Format(l, agent.Name, scene.RegionInfo.RegionName, _whoami));
474 }
475 }
476 catch (IOException ioe)
477 {
478 _log.ErrorFormat("[Concierge]: run into trouble reading welcome file {0} for region {1} for avatar {2}: {3}",
479 welcome, scene.RegionInfo.RegionName, agent.Name, ioe);
480 }
481 catch (FormatException fe)
482 {
483 _log.ErrorFormat("[Concierge]: welcome file {0} is malformed: {1}", welcome, fe);
484 }
485 }
486 return;
487 }
488 _log.DebugFormat("[Concierge]: no welcome message for region {0}", scene.RegionInfo.RegionName);
489 }
490 }
491
492 static private Vector3 PosOfGod = new Vector3(128, 128, 9999);
493
494 // protected void AnnounceToAgentsRegion(Scene scene, string msg)
495 // {
496 // ScenePresence agent = null;
497 // if ((client.Scene is Scene) && (client.Scene as Scene).TryGetAvatar(client.AgentId, out agent))
498 // AnnounceToAgentsRegion(agent, msg);
499 // else
500 // _log.DebugFormat("[Concierge]: could not find an agent for client {0}", client.Name);
501 // }
502
503 protected void AnnounceToAgentsRegion(IScene scene, string msg)
504 {
505 OSChatMessage c = new OSChatMessage();
506 c.Message = msg;
507 c.Type = ChatTypeEnum.Say;
508 c.Channel = 0;
509 c.Position = PosOfGod;
510 c.From = _whoami;
511 c.Sender = null;
512 c.SenderUUID = UUID.Zero;
513 c.Scene = scene;
514
515 if (scene is Scene)
516 (scene as Scene).EventManager.TriggerOnChatBroadcast(this, c);
517 }
518
519 protected void AnnounceToAgent(ScenePresence agent, string msg)
520 {
521 OSChatMessage c = new OSChatMessage();
522 c.Message = msg;
523 c.Type = ChatTypeEnum.Say;
524 c.Channel = 0;
525 c.Position = PosOfGod;
526 c.From = _whoami;
527 c.Sender = null;
528 c.SenderUUID = UUID.Zero;
529 c.Scene = agent.Scene;
530
531 agent.ControllingClient.SendChatMessage(msg, (byte) ChatTypeEnum.Say, PosOfGod, _whoami, UUID.Zero,
532 (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
533 }
534
535 private static void checkStringParameters(XmlRpcRequest request, string[] param)
536 {
537 Hashtable requestData = (Hashtable) request.Params[0];
538 foreach (string p in param)
539 {
540 if (!requestData.Contains(p))
541 throw new Exception(String.Format("missing string parameter {0}", p));
542 if (String.IsNullOrEmpty((string)requestData[p]))
543 throw new Exception(String.Format("parameter {0} is empty", p));
544 }
545 }
546
547 public XmlRpcResponse XmlRpcUpdateWelcomeMethod(XmlRpcRequest request)
548 {
549 _log.Info("[Concierge]: processing UpdateWelcome request");
550 XmlRpcResponse response = new XmlRpcResponse();
551 Hashtable responseData = new Hashtable();
552
553 try
554 {
555 Hashtable requestData = (Hashtable)request.Params[0];
556 checkStringParameters(request, new string[] { "password", "region", "welcome" });
557
558 // check password
559 if (!String.IsNullOrEmpty(_xmlRpcPassword) &&
560 (string)requestData["password"] != _xmlRpcPassword) throw new Exception("wrong password");
561
562 if (String.IsNullOrEmpty(_welcomes))
563 throw new Exception("welcome templates are not enabled, ask your OpenSim operator to set the \"welcomes\" option in the [Concierge] section of OpenSim.ini");
564
565 string msg = (string)requestData["welcome"];
566 if (String.IsNullOrEmpty(msg))
567 throw new Exception("empty parameter \"welcome\"");
568
569 string regionName = (string)requestData["region"];
570 IScene scene = _scenes.Find(delegate(IScene s) { return s.RegionInfo.RegionName == regionName; });
571 if (scene == null)
572 throw new Exception(String.Format("unknown region \"{0}\"", regionName));
573
574 if (!_conciergedScenes.Contains(scene))
575 throw new Exception(String.Format("region \"{0}\" is not a concierged region.", regionName));
576
577 string welcome = Path.Combine(_welcomes, regionName);
578 if (File.Exists(welcome))
579 {
580 _log.InfoFormat("[Concierge]: UpdateWelcome: updating existing template \"{0}\"", welcome);
581 string welcomeBackup = String.Format("{0}~", welcome);
582 if (File.Exists(welcomeBackup))
583 File.Delete(welcomeBackup);
584 File.Move(welcome, welcomeBackup);
585 }
586 File.WriteAllText(welcome, msg);
587
588 responseData["success"] = "true";
589 response.Value = responseData;
590 }
591 catch (Exception e)
592 {
593 _log.InfoFormat("[Concierge]: UpdateWelcome failed: {0}", e.Message);
594
595 responseData["success"] = "false";
596 responseData["error"] = e.Message;
597
598 response.Value = responseData;
599 }
600 _log.Debug("[Concierge]: done processing UpdateWelcome request");
601 return response;
602 }
603 }
604}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeServer.py b/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeServer.py
deleted file mode 100755
index 1c088fb..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeServer.py
+++ /dev/null
@@ -1,130 +0,0 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3#
4# Copyright (c) Contributors, http://opensimulator.org/
5# See CONTRIBUTORS.TXT for a full list of copyright holders.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# * Neither the name of the OpenSim Project nor the
15# names of its contributors may be used to endorse or promote products
16# derived from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
19# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
22# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29
30import logging
31import BaseHTTPServer
32import optparse
33import xml.etree.ElementTree as ET
34import xml.parsers.expat
35
36
37# enable debug level logging
38logging.basicConfig(level = logging.DEBUG,
39 format='%(asctime)s %(levelname)s %(message)s')
40
41options = None
42
43# subclassed HTTPRequestHandler
44class ConciergeHandler(BaseHTTPServer.BaseHTTPRequestHandler):
45 def logRequest(self):
46 logging.info('[ConciergeHandler] %(command)s request: %(host)s:%(port)d --- %(path)s',
47 dict(command = self.command,
48 host = self.client_address[0],
49 port = self.client_address[1],
50 path = self.path))
51
52 def logResponse(self, status):
53 logging.info('[ConciergeHandler] %(command)s returned %(status)d',
54 dict(command = self.command,
55 status = status))
56
57
58 def do_HEAD(self):
59 self.logRequest()
60
61 self.send_response(200)
62 self.send_header('Content-type', 'text/html')
63 self.end_headers()
64
65 self.logResponse(200)
66
67 def dumpXml(self, xml):
68 logging.debug('[ConciergeHandler] %s', xml.tag)
69 for attr in xml.attrib:
70 logging.debug('[ConciergeHandler] %s [%s] %s', xml.tag, attr, xml.attrib[attr])
71 for kid in xml.getchildren():
72 self.dumpXml(kid)
73
74 def do_POST(self):
75 self.logRequest()
76 hdrs = {}
77 for hdr in self.headers.headers:
78 logging.debug('[ConciergeHandler] POST: header: %s', hdr.rstrip())
79
80 length = int(self.headers.getheader('Content-Length'))
81 content = self.rfile.read(length)
82 self.rfile.close()
83
84 logging.debug('[ConciergeHandler] POST: content: %s', content)
85 try:
86 postXml = ET.fromstring(content)
87 self.dumpXml(postXml)
88 except xml.parsers.expat.ExpatError, xmlError:
89 logging.error('[ConciergeHandler] POST illformed:%s', xmlError)
90 self.send_response(500)
91 return
92
93 if not options.fail:
94 self.send_response(200)
95 self.send_header('Content-Type', 'text/html')
96 self.send_header('Content-Length', len('<success/>'))
97 self.end_headers()
98 self.logResponse(200)
99 self.wfile.write('<success/>')
100 self.wfile.close()
101 else:
102 self.send_response(500)
103 self.send_header('Content-Type', 'text/html')
104 self.send_header('Content-Length', len('<error>gotcha!</error>'))
105 self.end_headers()
106 self.wfile.write('<error>gotcha!</error>')
107 self.wfile.close()
108
109 self.logResponse(500)
110
111 def log_request(code, size):
112 pass
113
114if __name__ == '__main__':
115
116 logging.info('[ConciergeServer] Concierge Broker Test Server starting')
117
118 parser = optparse.OptionParser()
119 parser.add_option('-p', '--port', dest = 'port', help = 'port to listen on', metavar = 'PORT')
120 parser.add_option('-f', '--fail', dest = 'fail', action = 'store_true', help = 'always fail POST requests')
121
122 (options, args) = parser.parse_args()
123
124 httpServer = BaseHTTPServer.HTTPServer(('', 8080), ConciergeHandler)
125 try:
126 httpServer.serve_forever()
127 except KeyboardInterrupt:
128 logging.info('[ConciergeServer] terminating')
129
130 httpServer.server_close()
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs
deleted file mode 100644
index 1ec5e9b..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Currency/SampleMoney/SampleMoneyModule.cs
+++ /dev/null
@@ -1,1605 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Dialog/DialogModule.cs
deleted file mode 100644
index d3ac2c0..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Dialog/DialogModule.cs
+++ /dev/null
@@ -1,143 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs
deleted file mode 100644
index 0ed962e..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs
+++ /dev/null
@@ -1,1003 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Gestures/GesturesModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Gestures/GesturesModule.cs
deleted file mode 100644
index 969c1d8..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Gestures/GesturesModule.cs
+++ /dev/null
@@ -1,104 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs
deleted file mode 100644
index e654912..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Groups/GroupsModule.cs
+++ /dev/null
@@ -1,223 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs
deleted file mode 100644
index 3a1b282..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs
+++ /dev/null
@@ -1,170 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs
deleted file mode 100644
index 347c305..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs
+++ /dev/null
@@ -1,655 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/InstantMessage/PresenceModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/PresenceModule.cs
deleted file mode 100644
index c84d3d5..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/PresenceModule.cs
+++ /dev/null
@@ -1,426 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
deleted file mode 100644
index 3a58202..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ /dev/null
@@ -1,279 +0,0 @@
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.Environment.Modules.World.Archiver;
37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Communications.Cache;
40using log4net;
41using OpenSim.Region.Environment.Modules.World.Serialiser;
42
43
44namespace OpenSim.Region.Environment.Modules.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/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
deleted file mode 100644
index e23f2a8..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
+++ /dev/null
@@ -1,247 +0,0 @@
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.Environment.Modules.World.Archiver;
37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Communications.Cache;
40using log4net;
41
42
43namespace OpenSim.Region.Environment.Modules.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/Environment/Modules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
deleted file mode 100644
index 62fb3a2..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ /dev/null
@@ -1,389 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Lure/LureModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Lure/LureModule.cs
deleted file mode 100644
index 79d5409..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Lure/LureModule.cs
+++ /dev/null
@@ -1,176 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/Environment/Modules/Avatar/ObjectCaps/ObjectAdd.cs
deleted file mode 100644
index c853582..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/ObjectCaps/ObjectAdd.cs
+++ /dev/null
@@ -1,368 +0,0 @@
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.Environment.Modules.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/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs
deleted file mode 100644
index a7e9849..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Profiles/AvatarProfilesModule.cs
+++ /dev/null
@@ -1,145 +0,0 @@
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.Environment.Modules.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}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
deleted file mode 100644
index 33d7135..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
+++ /dev/null
@@ -1,292 +0,0 @@
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 OpenMetaverse;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications.Cache;
37using OpenSim.Framework.Communications.Capabilities;
38using OpenSim.Framework.Servers;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using Caps=OpenSim.Framework.Communications.Capabilities.Caps;
42
43namespace OpenSim.Region.Environment.Modules.Avatar.Voice.AsterixVoice
44{
45 public class AsteriskVoiceModule : IRegionModule
46 {
47 private static readonly ILog m_log =
48 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
51 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
52
53 private string m_asterisk;
54 private string m_asterisk_password;
55 private string m_asterisk_salt;
56 private int m_asterisk_timeout;
57 private string m_confDomain;
58 private IConfig m_config;
59 private Scene m_scene;
60 private string m_sipDomain;
61
62 #region IRegionModule Members
63
64 public void Initialise(Scene scene, IConfigSource config)
65 {
66 m_scene = scene;
67 m_config = config.Configs["AsteriskVoice"];
68
69 if (null == m_config)
70 {
71 m_log.Info("[ASTERISKVOICE] no config found, plugin disabled");
72 return;
73 }
74
75 if (!m_config.GetBoolean("enabled", false))
76 {
77 m_log.Info("[ASTERISKVOICE] plugin disabled by configuration");
78 return;
79 }
80 m_log.Info("[ASTERISKVOICE] plugin enabled");
81
82 try
83 {
84 m_sipDomain = m_config.GetString("sip_domain", String.Empty);
85 m_log.InfoFormat("[ASTERISKVOICE] using SIP domain {0}", m_sipDomain);
86
87 m_confDomain = m_config.GetString("conf_domain", String.Empty);
88 m_log.InfoFormat("[ASTERISKVOICE] using conf domain {0}", m_confDomain);
89
90 m_asterisk = m_config.GetString("asterisk_frontend", String.Empty);
91 m_asterisk_password = m_config.GetString("asterisk_password", String.Empty);
92 m_asterisk_timeout = m_config.GetInt("asterisk_timeout", 3000);
93 m_asterisk_salt = m_config.GetString("asterisk_salt", "Wuffwuff");
94 if (String.IsNullOrEmpty(m_asterisk)) throw new Exception("missing asterisk_frontend config parameter");
95 if (String.IsNullOrEmpty(m_asterisk_password)) throw new Exception("missing asterisk_password config parameter");
96 m_log.InfoFormat("[ASTERISKVOICE] using asterisk front end {0}", m_asterisk);
97
98 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
99 }
100 catch (Exception e)
101 {
102 m_log.ErrorFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.Message);
103 m_log.DebugFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.ToString());
104 return;
105 }
106 }
107
108 public void PostInitialise()
109 {
110 }
111
112 public void Close()
113 {
114 }
115
116 public string Name
117 {
118 get { return "AsteriskVoiceModule"; }
119 }
120
121 public bool IsSharedModule
122 {
123 get { return false; }
124 }
125
126 #endregion
127
128 public void OnRegisterCaps(UUID agentID, Caps caps)
129 {
130 m_log.DebugFormat("[ASTERISKVOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
131 string capsBase = "/CAPS/" + caps.CapsObjectPath;
132 caps.RegisterHandler("ParcelVoiceInfoRequest",
133 new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath,
134 delegate(string request, string path, string param,
135 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
136 {
137 return ParcelVoiceInfoRequest(request, path, param,
138 agentID, caps);
139 }));
140 caps.RegisterHandler("ProvisionVoiceAccountRequest",
141 new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath,
142 delegate(string request, string path, string param,
143 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
144 {
145 return ProvisionVoiceAccountRequest(request, path, param,
146 agentID, caps);
147 }));
148 }
149
150 /// <summary>
151 /// Callback for a client request for ParcelVoiceInfo
152 /// </summary>
153 /// <param name="request"></param>
154 /// <param name="path"></param>
155 /// <param name="param"></param>
156 /// <param name="agentID"></param>
157 /// <param name="caps"></param>
158 /// <returns></returns>
159 public string ParcelVoiceInfoRequest(string request, string path, string param,
160 UUID agentID, Caps caps)
161 {
162 // we need to do:
163 // - send channel_uri: as "sip:regionID@m_sipDomain"
164 try
165 {
166 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}",
167 request, path, param);
168
169
170 // setup response to client
171 Hashtable creds = new Hashtable();
172 creds["channel_uri"] = String.Format("sip:{0}@{1}",
173 m_scene.RegionInfo.RegionID, m_sipDomain);
174
175 string regionName = m_scene.RegionInfo.RegionName;
176 ScenePresence avatar = m_scene.GetScenePresence(agentID);
177 if (null == m_scene.LandChannel) throw new Exception("land data not yet available");
178 LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
179
180 LLSDParcelVoiceInfoResponse parcelVoiceInfo =
181 new LLSDParcelVoiceInfoResponse(regionName, land.LocalID, creds);
182
183 string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
184
185
186 // update region on asterisk-opensim frontend
187 Hashtable requestData = new Hashtable();
188 requestData["admin_password"] = m_asterisk_password;
189 requestData["region"] = m_scene.RegionInfo.RegionID.ToString();
190 if (!String.IsNullOrEmpty(m_confDomain))
191 {
192 requestData["region"] += String.Format("@{0}", m_confDomain);
193 }
194
195 ArrayList SendParams = new ArrayList();
196 SendParams.Add(requestData);
197 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("region_update", SendParams);
198 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
199 Hashtable responseData = (Hashtable) updateAccountResponse.Value;
200
201 if (!responseData.ContainsKey("success")) throw new Exception("region_update call failed");
202
203 bool success = Convert.ToBoolean((string) responseData["success"]);
204 if (!success) throw new Exception("region_update failed");
205
206
207 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: {0}", r);
208 return r;
209 }
210 catch (Exception e)
211 {
212 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0}, retry later", e.Message);
213 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0} failed", e.ToString());
214
215 return "<llsd>undef</llsd>";
216 }
217 }
218
219 /// <summary>
220 /// Callback for a client request for Voice Account Details
221 /// </summary>
222 /// <param name="request"></param>
223 /// <param name="path"></param>
224 /// <param name="param"></param>
225 /// <param name="agentID"></param>
226 /// <param name="caps"></param>
227 /// <returns></returns>
228 public string ProvisionVoiceAccountRequest(string request, string path, string param,
229 UUID agentID, Caps caps)
230 {
231 // we need to
232 // - get user data from UserProfileCacheService
233 // - generate nonce for user voice account password
234 // - issue XmlRpc request to asterisk opensim front end:
235 // + user: base 64 encoded user name (otherwise SL
236 // client is unhappy)
237 // + password: nonce
238 // - the XmlRpc call to asteris-opensim was successful:
239 // send account details back to client
240 try
241 {
242 m_log.DebugFormat("[ASTERISKVOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
243 request, path, param);
244
245 // get user data & prepare voice account response
246 string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes());
247 voiceUser = voiceUser.Replace('+', '-').Replace('/', '_');
248
249 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
250 if (null == userInfo) throw new Exception("cannot get user details");
251
252 // we generate a nonce everytime
253 string voicePassword = "$1$" + Util.Md5Hash(DateTime.UtcNow.ToLongTimeString() + m_asterisk_salt);
254 LLSDVoiceAccountResponse voiceAccountResponse =
255 new LLSDVoiceAccountResponse(voiceUser, voicePassword);
256 string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
257 m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r);
258
259
260 // update user account on asterisk frontend
261 Hashtable requestData = new Hashtable();
262 requestData["admin_password"] = m_asterisk_password;
263 requestData["username"] = voiceUser;
264 if (!String.IsNullOrEmpty(m_sipDomain))
265 {
266 requestData["username"] += String.Format("@{0}", m_sipDomain);
267 }
268 requestData["password"] = voicePassword;
269
270 ArrayList SendParams = new ArrayList();
271 SendParams.Add(requestData);
272 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("account_update", SendParams);
273 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
274 Hashtable responseData = (Hashtable) updateAccountResponse.Value;
275
276 if (!responseData.ContainsKey("success")) throw new Exception("account_update call failed");
277
278 bool success = Convert.ToBoolean((string) responseData["success"]);
279 if (!success) throw new Exception("account_update failed");
280
281 return r;
282 }
283 catch (Exception e)
284 {
285 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0}, retry later", e.Message);
286 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0} failed", e.ToString());
287
288 return "<llsd>undef</llsd>";
289 }
290 }
291 }
292}
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs
deleted file mode 100644
index e4d9b7c..0000000
--- a/OpenSim/Region/Environment/Modules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs
+++ /dev/null
@@ -1,202 +0,0 @@
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 OpenMetaverse;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Framework.Communications.Capabilities;
37using OpenSim.Framework.Servers;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using Caps=OpenSim.Framework.Communications.Capabilities.Caps;
41
42namespace OpenSim.Region.Environment.Modules.Avatar.Voice.SIPVoice
43{
44 public class SIPVoiceModule : IRegionModule
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
50 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
51 private IConfig m_config;
52 private Scene m_scene;
53 private string m_sipDomain;
54
55 #region IRegionModule Members
56
57 public void Initialise(Scene scene, IConfigSource config)
58 {
59 m_scene = scene;
60 m_config = config.Configs["Voice"];
61
62 if (null == m_config || !m_config.GetBoolean("enabled", false))
63 {
64 m_log.Info("[VOICE] plugin disabled");
65 return;
66 }
67 m_log.Info("[VOICE] plugin enabled");
68
69 m_sipDomain = m_config.GetString("sip_domain", String.Empty);
70 if (String.IsNullOrEmpty(m_sipDomain))
71 {
72 m_log.Error("[VOICE] plugin mis-configured: missing sip_domain configuration");
73 m_log.Info("[VOICE] plugin disabled");
74 return;
75 }
76 m_log.InfoFormat("[VOICE] using SIP domain {0}", m_sipDomain);
77
78 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
79 }
80
81 public void PostInitialise()
82 {
83 }
84
85 public void Close()
86 {
87 }
88
89 public string Name
90 {
91 get { return "VoiceModule"; }
92 }
93
94 public bool IsSharedModule
95 {
96 get { return false; }
97 }
98
99 #endregion
100
101 public void OnRegisterCaps(UUID agentID, Caps caps)
102 {
103 m_log.DebugFormat("[VOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
104 string capsBase = "/CAPS/" + caps.CapsObjectPath;
105 caps.RegisterHandler("ParcelVoiceInfoRequest",
106 new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath,
107 delegate(string request, string path, string param,
108 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
109 {
110 return ParcelVoiceInfoRequest(request, path, param,
111 agentID, caps);
112 }));
113 caps.RegisterHandler("ProvisionVoiceAccountRequest",
114 new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath,
115 delegate(string request, string path, string param,
116 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
117 {
118 return ProvisionVoiceAccountRequest(request, path, param,
119 agentID, caps);
120 }));
121 }
122
123 /// <summary>
124 /// Callback for a client request for ParcelVoiceInfo
125 /// </summary>
126 /// <param name="request"></param>
127 /// <param name="path"></param>
128 /// <param name="param"></param>
129 /// <param name="agentID"></param>
130 /// <param name="caps"></param>
131 /// <returns></returns>
132 public string ParcelVoiceInfoRequest(string request, string path, string param,
133 UUID agentID, Caps caps)
134 {
135 try
136 {
137 m_log.DebugFormat("[VOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}", request, path, param);
138
139 // FIXME: get the creds from region file or from config
140 Hashtable creds = new Hashtable();
141
142 creds["channel_uri"] = String.Format("sip:{0}@{1}", agentID, m_sipDomain);
143
144 string regionName = m_scene.RegionInfo.RegionName;
145 ScenePresence avatar = m_scene.GetScenePresence(agentID);
146 if (null == m_scene.LandChannel) throw new Exception("land data not yet available");
147 LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
148
149 LLSDParcelVoiceInfoResponse parcelVoiceInfo =
150 new LLSDParcelVoiceInfoResponse(regionName, land.LocalID, creds);
151
152 string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
153 m_log.DebugFormat("[VOICE][PARCELVOICE]: {0}", r);
154
155 return r;
156 }
157 catch (Exception e)
158 {
159 m_log.ErrorFormat("[CAPS]: {0}, try again later", e.ToString());
160 }
161
162 return null;
163 }
164
165 /// <summary>
166 /// Callback for a client request for Voice Account Details
167 /// </summary>
168 /// <param name="request"></param>
169 /// <param name="path"></param>
170 /// <param name="param"></param>
171 /// <param name="agentID"></param>
172 /// <param name="caps"></param>
173 /// <returns></returns>
174 public string ProvisionVoiceAccountRequest(string request, string path, string param,
175 UUID agentID, Caps caps)
176 {
177 try
178 {
179 m_log.DebugFormat("[VOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
180 request, path, param);
181
182 string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes());
183 voiceUser = voiceUser.Replace('+', '-').Replace('/', '_');
184
185 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
186 if (null == userInfo) throw new Exception("cannot get user details");
187
188 LLSDVoiceAccountResponse voiceAccountResponse =
189 new LLSDVoiceAccountResponse(voiceUser, "$1$" + userInfo.UserProfile.PasswordHash);
190 string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
191 m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r);
192 return r;
193 }
194 catch (Exception e)
195 {
196 m_log.ErrorFormat("[CAPS][PROVISIONVOICE]: {0}, retry later", e.Message);
197 }
198
199 return null;
200 }
201 }
202}