diff options
author | onefang | 2019-05-19 21:24:15 +1000 |
---|---|---|
committer | onefang | 2019-05-19 21:24:15 +1000 |
commit | 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb (patch) | |
tree | a9fbc62df9eb2d1d9ba2698d8552eae71eca20d8 /OpenSim/Region/CoreModules/Avatar/InstantMessage | |
parent | Add a build script. (diff) | |
download | opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.zip opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.gz opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.bz2 opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.xz |
Dump OpenSim 0.9.0.1 into it's own branch.
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/InstantMessage')
7 files changed, 824 insertions, 177 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs index a1b918a..16e2ec3 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs | |||
@@ -144,11 +144,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
144 | foreach (Scene scene in m_Scenes) | 144 | foreach (Scene scene in m_Scenes) |
145 | { | 145 | { |
146 | // m_log.DebugFormat( | 146 | // m_log.DebugFormat( |
147 | // "[HG INSTANT MESSAGE]: Looking for root agent {0} in {1}", | 147 | // "[HG INSTANT MESSAGE]: Looking for root agent {0} in {1}", |
148 | // toAgentID.ToString(), scene.RegionInfo.RegionName); | 148 | // toAgentID.ToString(), scene.RegionInfo.RegionName); |
149 | ScenePresence sp = scene.GetScenePresence(toAgentID); | 149 | ScenePresence sp = scene.GetScenePresence(toAgentID); |
150 | if (sp != null && !sp.IsChildAgent) | 150 | if (sp != null && !sp.IsChildAgent && !sp.IsDeleted) |
151 | { | 151 | { |
152 | // Local message | 152 | // Local message |
153 | // m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID); | 153 | // m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID); |
154 | sp.ControllingClient.SendInstantMessage(im); | 154 | sp.ControllingClient.SendInstantMessage(im); |
@@ -159,25 +159,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | // try child avatar second | ||
163 | foreach (Scene scene in m_Scenes) | ||
164 | { | ||
165 | // m_log.DebugFormat( | ||
166 | // "[HG INSTANT MESSAGE]: Looking for child of {0} in {1}", | ||
167 | // toAgentID, scene.RegionInfo.RegionName); | ||
168 | ScenePresence sp = scene.GetScenePresence(toAgentID); | ||
169 | if (sp != null) | ||
170 | { | ||
171 | // Local message | ||
172 | // m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); | ||
173 | sp.ControllingClient.SendInstantMessage(im); | ||
174 | |||
175 | // Message sent | ||
176 | result(true); | ||
177 | return; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | // m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); | 162 | // m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); |
182 | // Is the user a local user? | 163 | // Is the user a local user? |
183 | string url = string.Empty; | 164 | string url = string.Empty; |
@@ -224,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
224 | foreach (Scene scene in m_Scenes) | 205 | foreach (Scene scene in m_Scenes) |
225 | { | 206 | { |
226 | ScenePresence sp = scene.GetScenePresence(toAgentID); | 207 | ScenePresence sp = scene.GetScenePresence(toAgentID); |
227 | if(sp != null && !sp.IsChildAgent) | 208 | if(sp != null && !sp.IsChildAgent && !sp.IsDeleted) |
228 | { | 209 | { |
229 | scene.EventManager.TriggerIncomingInstantMessage(gim); | 210 | scene.EventManager.TriggerIncomingInstantMessage(gim); |
230 | successful = true; | 211 | successful = true; |
@@ -310,7 +291,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
310 | foreach (Scene scene in m_Scenes) | 291 | foreach (Scene scene in m_Scenes) |
311 | { | 292 | { |
312 | ScenePresence presence = scene.GetScenePresence(agentID); | 293 | ScenePresence presence = scene.GetScenePresence(agentID); |
313 | if (presence != null && !presence.IsChildAgent) | 294 | if (presence != null && !presence.IsChildAgent && !presence.IsDeleted) |
314 | return presence.ControllingClient; | 295 | return presence.ControllingClient; |
315 | } | 296 | } |
316 | } | 297 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs index c33a296..71c0a8a 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Reflection; | 29 | using System.Reflection; |
30 | using System.Timers; | ||
30 | using log4net; | 31 | using log4net; |
31 | using Mono.Addins; | 32 | using Mono.Addins; |
32 | using Nini.Config; | 33 | using Nini.Config; |
@@ -47,15 +48,15 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
47 | /// <value> | 48 | /// <value> |
48 | /// Is this module enabled? | 49 | /// Is this module enabled? |
49 | /// </value> | 50 | /// </value> |
50 | private bool m_enabled = false; | 51 | protected bool m_enabled = false; |
51 | 52 | ||
52 | private readonly List<Scene> m_scenes = new List<Scene>(); | 53 | protected readonly List<Scene> m_scenes = new List<Scene>(); |
53 | 54 | ||
54 | #region Region Module interface | 55 | #region Region Module interface |
55 | 56 | ||
56 | private IMessageTransferModule m_TransferModule = null; | 57 | protected IMessageTransferModule m_TransferModule = null; |
57 | 58 | ||
58 | public void Initialise(IConfigSource config) | 59 | public virtual void Initialise(IConfigSource config) |
59 | { | 60 | { |
60 | if (config.Configs["Messaging"] != null) | 61 | if (config.Configs["Messaging"] != null) |
61 | { | 62 | { |
@@ -64,11 +65,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
64 | "InstantMessageModule") | 65 | "InstantMessageModule") |
65 | return; | 66 | return; |
66 | } | 67 | } |
67 | 68 | ||
68 | m_enabled = true; | 69 | m_enabled = true; |
69 | } | 70 | } |
70 | 71 | ||
71 | public void AddRegion(Scene scene) | 72 | public virtual void AddRegion(Scene scene) |
72 | { | 73 | { |
73 | if (!m_enabled) | 74 | if (!m_enabled) |
74 | return; | 75 | return; |
@@ -84,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
84 | } | 85 | } |
85 | } | 86 | } |
86 | 87 | ||
87 | public void RegionLoaded(Scene scene) | 88 | public virtual void RegionLoaded(Scene scene) |
88 | { | 89 | { |
89 | if (!m_enabled) | 90 | if (!m_enabled) |
90 | return; | 91 | return; |
@@ -106,7 +107,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
106 | } | 107 | } |
107 | } | 108 | } |
108 | 109 | ||
109 | public void RemoveRegion(Scene scene) | 110 | public virtual void RemoveRegion(Scene scene) |
110 | { | 111 | { |
111 | if (!m_enabled) | 112 | if (!m_enabled) |
112 | return; | 113 | return; |
@@ -117,7 +118,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
117 | } | 118 | } |
118 | } | 119 | } |
119 | 120 | ||
120 | void OnClientConnect(IClientCore client) | 121 | protected virtual void OnClientConnect(IClientCore client) |
121 | { | 122 | { |
122 | IClientIM clientIM; | 123 | IClientIM clientIM; |
123 | if (client.TryGet(out clientIM)) | 124 | if (client.TryGet(out clientIM)) |
@@ -126,27 +127,33 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
126 | } | 127 | } |
127 | } | 128 | } |
128 | 129 | ||
129 | public void PostInitialise() | 130 | public virtual void PostInitialise() |
130 | { | 131 | { |
131 | } | 132 | } |
132 | 133 | ||
133 | public void Close() | 134 | public virtual void Close() |
134 | { | 135 | { |
135 | } | 136 | } |
136 | 137 | ||
137 | public string Name | 138 | public virtual string Name |
138 | { | 139 | { |
139 | get { return "InstantMessageModule"; } | 140 | get { return "InstantMessageModule"; } |
140 | } | 141 | } |
141 | 142 | ||
142 | public Type ReplaceableInterface | 143 | public virtual Type ReplaceableInterface |
143 | { | 144 | { |
144 | get { return null; } | 145 | get { return null; } |
145 | } | 146 | } |
146 | 147 | ||
147 | #endregion | 148 | #endregion |
148 | 149 | /* | |
149 | public void OnInstantMessage(IClientAPI client, GridInstantMessage im) | 150 | public virtual void OnViewerInstantMessage(IClientAPI client, GridInstantMessage im) |
151 | { | ||
152 | im.fromAgentName = client.FirstName + " " + client.LastName; | ||
153 | OnInstantMessage(client, im); | ||
154 | } | ||
155 | */ | ||
156 | public virtual void OnInstantMessage(IClientAPI client, GridInstantMessage im) | ||
150 | { | 157 | { |
151 | byte dialog = im.dialog; | 158 | byte dialog = im.dialog; |
152 | 159 | ||
@@ -159,10 +166,34 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
159 | return; | 166 | return; |
160 | } | 167 | } |
161 | 168 | ||
169 | //DateTime dt = DateTime.UtcNow; | ||
170 | |||
171 | // Ticks from UtcNow, but make it look like local. Evil, huh? | ||
172 | //dt = DateTime.SpecifyKind(dt, DateTimeKind.Local); | ||
173 | |||
174 | //try | ||
175 | //{ | ||
176 | // // Convert that to the PST timezone | ||
177 | // TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles"); | ||
178 | // dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo); | ||
179 | //} | ||
180 | //catch | ||
181 | //{ | ||
182 | // //m_log.Info("[OFFLINE MESSAGING]: No PST timezone found on this machine. Saving with local timestamp."); | ||
183 | //} | ||
184 | |||
185 | //// And make it look local again to fool the unix time util | ||
186 | //dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc); | ||
187 | |||
188 | // If client is null, this message comes from storage and IS offline | ||
189 | if (client != null) | ||
190 | im.offline = 0; | ||
191 | |||
192 | if (im.offline == 0) | ||
193 | im.timestamp = (uint)Util.UnixTimeSinceEpoch(); | ||
194 | |||
162 | if (m_TransferModule != null) | 195 | if (m_TransferModule != null) |
163 | { | 196 | { |
164 | if (client != null) | ||
165 | im.fromAgentName = client.FirstName + " " + client.LastName; | ||
166 | m_TransferModule.SendInstantMessage(im, | 197 | m_TransferModule.SendInstantMessage(im, |
167 | delegate(bool success) | 198 | delegate(bool success) |
168 | { | 199 | { |
@@ -193,7 +224,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
193 | /// | 224 | /// |
194 | /// </summary> | 225 | /// </summary> |
195 | /// <param name="msg"></param> | 226 | /// <param name="msg"></param> |
196 | private void OnGridInstantMessage(GridInstantMessage msg) | 227 | protected virtual void OnGridInstantMessage(GridInstantMessage msg) |
197 | { | 228 | { |
198 | // Just call the Text IM handler above | 229 | // Just call the Text IM handler above |
199 | // This event won't be raised unless we have that agent, | 230 | // This event won't be raised unless we have that agent, |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index 2462ff8..efb9421 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs | |||
@@ -50,6 +50,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
51 | 51 | ||
52 | private bool m_Enabled = false; | 52 | private bool m_Enabled = false; |
53 | protected string m_MessageKey = String.Empty; | ||
53 | protected List<Scene> m_Scenes = new List<Scene>(); | 54 | protected List<Scene> m_Scenes = new List<Scene>(); |
54 | protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>(); | 55 | protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>(); |
55 | 56 | ||
@@ -69,14 +70,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
69 | public virtual void Initialise(IConfigSource config) | 70 | public virtual void Initialise(IConfigSource config) |
70 | { | 71 | { |
71 | IConfig cnf = config.Configs["Messaging"]; | 72 | IConfig cnf = config.Configs["Messaging"]; |
72 | if (cnf != null && cnf.GetString( | 73 | if (cnf != null) |
73 | "MessageTransferModule", "MessageTransferModule") != | ||
74 | "MessageTransferModule") | ||
75 | { | 74 | { |
76 | m_log.Debug("[MESSAGE TRANSFER]: Disabled by configuration"); | 75 | if (cnf.GetString("MessageTransferModule", |
77 | return; | 76 | "MessageTransferModule") != "MessageTransferModule") |
78 | } | 77 | { |
78 | return; | ||
79 | } | ||
79 | 80 | ||
81 | m_MessageKey = cnf.GetString("MessageKey", String.Empty); | ||
82 | } | ||
83 | m_log.Debug("[MESSAGE TRANSFER]: Module enabled"); | ||
80 | m_Enabled = true; | 84 | m_Enabled = true; |
81 | } | 85 | } |
82 | 86 | ||
@@ -135,53 +139,45 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
135 | { | 139 | { |
136 | UUID toAgentID = new UUID(im.toAgentID); | 140 | UUID toAgentID = new UUID(im.toAgentID); |
137 | 141 | ||
142 | if (toAgentID == UUID.Zero) | ||
143 | return; | ||
144 | |||
145 | IClientAPI client = null; | ||
146 | |||
138 | // Try root avatar only first | 147 | // Try root avatar only first |
139 | foreach (Scene scene in m_Scenes) | 148 | foreach (Scene scene in m_Scenes) |
140 | { | 149 | { |
141 | // m_log.DebugFormat( | ||
142 | // "[INSTANT MESSAGE]: Looking for root agent {0} in {1}", | ||
143 | // toAgentID.ToString(), scene.RegionInfo.RegionName); | ||
144 | |||
145 | ScenePresence sp = scene.GetScenePresence(toAgentID); | 150 | ScenePresence sp = scene.GetScenePresence(toAgentID); |
146 | if (sp != null && !sp.IsChildAgent) | 151 | if (sp != null && !sp.IsDeleted && sp.ControllingClient.IsActive) |
147 | { | 152 | { |
148 | // Local message | 153 | // actualy don't send via child agents |
149 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); | 154 | // ims can be complex things, and not sure viewers will not mess up |
150 | 155 | if(sp.IsChildAgent) | |
151 | sp.ControllingClient.SendInstantMessage(im); | 156 | continue; |
152 | 157 | ||
153 | // Message sent | 158 | client = sp.ControllingClient; |
154 | result(true); | 159 | if(!sp.IsChildAgent) |
155 | return; | 160 | break; |
156 | } | 161 | } |
157 | } | 162 | } |
158 | 163 | ||
159 | // try child avatar second | 164 | if(client != null) |
160 | foreach (Scene scene in m_Scenes) | ||
161 | { | 165 | { |
162 | // m_log.DebugFormat( | 166 | // Local message |
163 | // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); | 167 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); |
164 | |||
165 | ScenePresence sp = scene.GetScenePresence(toAgentID); | ||
166 | if (sp != null) | ||
167 | { | ||
168 | // Local message | ||
169 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); | ||
170 | 168 | ||
171 | sp.ControllingClient.SendInstantMessage(im); | 169 | client.SendInstantMessage(im); |
172 | 170 | ||
173 | // Message sent | 171 | // Message sent |
174 | result(true); | 172 | result(true); |
175 | return; | 173 | return; |
176 | } | ||
177 | } | 174 | } |
178 | |||
179 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); | 175 | // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); |
180 | 176 | ||
181 | SendGridInstantMessageViaXMLRPC(im, result); | 177 | SendGridInstantMessageViaXMLRPC(im, result); |
182 | } | 178 | } |
183 | 179 | ||
184 | public void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result) | 180 | public virtual void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result) |
185 | { | 181 | { |
186 | UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; | 182 | UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; |
187 | 183 | ||
@@ -211,10 +207,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
211 | protected virtual XmlRpcResponse processXMLRPCGridInstantMessage(XmlRpcRequest request, IPEndPoint remoteClient) | 207 | protected virtual XmlRpcResponse processXMLRPCGridInstantMessage(XmlRpcRequest request, IPEndPoint remoteClient) |
212 | { | 208 | { |
213 | bool successful = false; | 209 | bool successful = false; |
214 | 210 | ||
215 | // TODO: For now, as IMs seem to be a bit unreliable on OSGrid, catch all exception that | 211 | // TODO: For now, as IMs seem to be a bit unreliable on OSGrid, catch all exception that |
216 | // happen here and aren't caught and log them. | 212 | // happen here and aren't caught and log them. |
217 | try | 213 | try |
218 | { | 214 | { |
219 | // various rational defaults | 215 | // various rational defaults |
220 | UUID fromAgentID = UUID.Zero; | 216 | UUID fromAgentID = UUID.Zero; |
@@ -236,7 +232,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
236 | float pos_z = 0; | 232 | float pos_z = 0; |
237 | //m_log.Info("Processing IM"); | 233 | //m_log.Info("Processing IM"); |
238 | 234 | ||
239 | |||
240 | Hashtable requestData = (Hashtable)request.Params[0]; | 235 | Hashtable requestData = (Hashtable)request.Params[0]; |
241 | // Check if it's got all the data | 236 | // Check if it's got all the data |
242 | if (requestData.ContainsKey("from_agent_id") | 237 | if (requestData.ContainsKey("from_agent_id") |
@@ -249,6 +244,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
249 | && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") | 244 | && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") |
250 | && requestData.ContainsKey("binary_bucket")) | 245 | && requestData.ContainsKey("binary_bucket")) |
251 | { | 246 | { |
247 | if (m_MessageKey != String.Empty) | ||
248 | { | ||
249 | XmlRpcResponse error_resp = new XmlRpcResponse(); | ||
250 | Hashtable error_respdata = new Hashtable(); | ||
251 | error_respdata["success"] = "FALSE"; | ||
252 | error_resp.Value = error_respdata; | ||
253 | |||
254 | if (!requestData.Contains("message_key")) | ||
255 | return error_resp; | ||
256 | if (m_MessageKey != (string)requestData["message_key"]) | ||
257 | return error_resp; | ||
258 | } | ||
259 | |||
252 | // Do the easy way of validating the UUIDs | 260 | // Do the easy way of validating the UUIDs |
253 | UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); | 261 | UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); |
254 | UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); | 262 | UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); |
@@ -382,7 +390,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
382 | gim.Position = Position; | 390 | gim.Position = Position; |
383 | gim.binaryBucket = binaryBucket; | 391 | gim.binaryBucket = binaryBucket; |
384 | 392 | ||
385 | |||
386 | // Trigger the Instant message in the scene. | 393 | // Trigger the Instant message in the scene. |
387 | foreach (Scene scene in m_Scenes) | 394 | foreach (Scene scene in m_Scenes) |
388 | { | 395 | { |
@@ -425,104 +432,191 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
425 | return resp; | 432 | return resp; |
426 | } | 433 | } |
427 | 434 | ||
435 | |||
428 | /// <summary> | 436 | /// <summary> |
429 | /// delegate for sending a grid instant message asynchronously | 437 | /// delegate for sending a grid instant message asynchronously |
430 | /// </summary> | 438 | /// </summary> |
431 | public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); | 439 | private delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); |
440 | |||
441 | private class GIM { | ||
442 | public GridInstantMessage im; | ||
443 | public MessageResultNotification result; | ||
444 | }; | ||
432 | 445 | ||
433 | protected virtual void GridInstantMessageCompleted(IAsyncResult iar) | 446 | private Queue<GIM> pendingInstantMessages = new Queue<GIM>(); |
447 | private int numInstantMessageThreads = 0; | ||
448 | |||
449 | private void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) | ||
434 | { | 450 | { |
435 | GridInstantMessageDelegate icon = | 451 | lock (pendingInstantMessages) { |
436 | (GridInstantMessageDelegate)iar.AsyncState; | 452 | if (numInstantMessageThreads >= 4) { |
437 | icon.EndInvoke(iar); | 453 | GIM gim = new GIM(); |
454 | gim.im = im; | ||
455 | gim.result = result; | ||
456 | pendingInstantMessages.Enqueue(gim); | ||
457 | } else { | ||
458 | ++ numInstantMessageThreads; | ||
459 | //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: ++numInstantMessageThreads={0}", numInstantMessageThreads); | ||
460 | GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsyncMain; | ||
461 | d.BeginInvoke(im, result, GridInstantMessageCompleted, d); | ||
462 | } | ||
463 | } | ||
438 | } | 464 | } |
439 | 465 | ||
440 | 466 | ||
441 | protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) | 467 | private void GridInstantMessageCompleted(IAsyncResult iar) |
442 | { | 468 | { |
443 | GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; | 469 | GridInstantMessageDelegate d = (GridInstantMessageDelegate)iar.AsyncState; |
444 | 470 | d.EndInvoke(iar); | |
445 | d.BeginInvoke(im, result, GridInstantMessageCompleted, d); | ||
446 | } | 471 | } |
447 | 472 | ||
448 | /// <summary> | 473 | /// <summary> |
449 | /// Internal SendGridInstantMessage over XMLRPC method. | 474 | /// Internal SendGridInstantMessage over XMLRPC method. |
450 | /// </summary> | 475 | /// </summary> |
451 | /// <remarks> | 476 | |
452 | /// This is called from within a dedicated thread. | 477 | /// <param name="prevRegionHandle"> |
453 | /// </remarks> | 478 | /// Pass in 0 the first time this method is called. It will be called recursively with the last |
454 | private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) | 479 | /// regionhandle tried |
480 | /// </param> | ||
481 | private void SendGridInstantMessageViaXMLRPCAsyncMain(GridInstantMessage im, MessageResultNotification result) | ||
482 | { | ||
483 | GIM gim; | ||
484 | do { | ||
485 | try { | ||
486 | SendGridInstantMessageViaXMLRPCAsync(im, result, UUID.Zero); | ||
487 | } catch (Exception e) { | ||
488 | m_log.Error("[SendGridInstantMessageViaXMLRPC]: exception " + e.Message); | ||
489 | } | ||
490 | lock (pendingInstantMessages) { | ||
491 | if (pendingInstantMessages.Count > 0) { | ||
492 | gim = pendingInstantMessages.Dequeue(); | ||
493 | im = gim.im; | ||
494 | result = gim.result; | ||
495 | } else { | ||
496 | gim = null; | ||
497 | -- numInstantMessageThreads; | ||
498 | //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: --numInstantMessageThreads={0}", numInstantMessageThreads); | ||
499 | } | ||
500 | } | ||
501 | } while (gim != null); | ||
502 | } | ||
503 | |||
504 | private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) | ||
455 | { | 505 | { |
506 | |||
456 | UUID toAgentID = new UUID(im.toAgentID); | 507 | UUID toAgentID = new UUID(im.toAgentID); |
457 | UUID regionID; | 508 | PresenceInfo upd = null; |
458 | bool needToLookupAgent; | 509 | bool lookupAgent = false; |
459 | 510 | ||
460 | lock (m_UserRegionMap) | 511 | lock (m_UserRegionMap) |
461 | needToLookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID); | ||
462 | |||
463 | while (true) | ||
464 | { | 512 | { |
465 | if (needToLookupAgent) | 513 | if (m_UserRegionMap.ContainsKey(toAgentID)) |
466 | { | 514 | { |
467 | PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); | 515 | upd = new PresenceInfo(); |
468 | 516 | upd.RegionID = m_UserRegionMap[toAgentID]; | |
469 | UUID foundRegionID = UUID.Zero; | ||
470 | 517 | ||
471 | if (presences != null) | 518 | // We need to compare the current regionhandle with the previous region handle |
519 | // or the recursive loop will never end because it will never try to lookup the agent again | ||
520 | if (prevRegionID == upd.RegionID) | ||
472 | { | 521 | { |
473 | foreach (PresenceInfo p in presences) | 522 | lookupAgent = true; |
474 | { | ||
475 | if (p.RegionID != UUID.Zero) | ||
476 | { | ||
477 | foundRegionID = p.RegionID; | ||
478 | break; | ||
479 | } | ||
480 | } | ||
481 | } | 523 | } |
482 | |||
483 | // If not found or the found region is the same as the last lookup, then message is undeliverable | ||
484 | if (foundRegionID == UUID.Zero || foundRegionID == regionID) | ||
485 | break; | ||
486 | else | ||
487 | regionID = foundRegionID; | ||
488 | } | 524 | } |
489 | 525 | else | |
490 | GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID); | ||
491 | if (reginfo == null) | ||
492 | { | 526 | { |
493 | m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); | 527 | lookupAgent = true; |
494 | break; | ||
495 | } | 528 | } |
529 | } | ||
496 | 530 | ||
497 | // Try to send the message to the agent via the retrieved region. | ||
498 | Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); | ||
499 | msgdata["region_handle"] = 0; | ||
500 | bool imresult = doIMSending(reginfo, msgdata); | ||
501 | 531 | ||
502 | // If the message delivery was successful, then cache the entry. | 532 | // Are we needing to look-up an agent? |
503 | if (imresult) | 533 | if (lookupAgent) |
534 | { | ||
535 | // Non-cached user agent lookup. | ||
536 | PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); | ||
537 | if (presences != null && presences.Length > 0) | ||
504 | { | 538 | { |
505 | lock (m_UserRegionMap) | 539 | foreach (PresenceInfo p in presences) |
506 | { | 540 | { |
507 | m_UserRegionMap[toAgentID] = regionID; | 541 | if (p.RegionID != UUID.Zero) |
542 | { | ||
543 | upd = p; | ||
544 | break; | ||
545 | } | ||
508 | } | 546 | } |
509 | result(true); | ||
510 | return; | ||
511 | } | 547 | } |
512 | 548 | ||
513 | // If we reach this point in the first iteration of the while, then we may have unsuccessfully tried | 549 | if (upd != null) |
514 | // to use a locally cached region ID. All subsequent attempts need to lookup agent details from | 550 | { |
515 | // the presence service. | 551 | // check if we've tried this before.. |
516 | needToLookupAgent = true; | 552 | // This is one way to end the recursive loop |
553 | // | ||
554 | if (upd.RegionID == prevRegionID) | ||
555 | { | ||
556 | // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | ||
557 | HandleUndeliverableMessage(im, result); | ||
558 | return; | ||
559 | } | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | ||
564 | HandleUndeliverableMessage(im, result); | ||
565 | return; | ||
566 | } | ||
517 | } | 567 | } |
518 | 568 | ||
519 | // If we reached this point then the message was not deliverable. Remove the bad cache entry and | 569 | if (upd != null) |
520 | // signal the delivery failure. | 570 | { |
521 | lock (m_UserRegionMap) | 571 | GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(UUID.Zero, |
522 | m_UserRegionMap.Remove(toAgentID); | 572 | upd.RegionID); |
573 | if (reginfo != null) | ||
574 | { | ||
575 | Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); | ||
576 | // Not actually used anymore, left in for compatibility | ||
577 | // Remove at next interface change | ||
578 | // | ||
579 | msgdata["region_handle"] = 0; | ||
580 | bool imresult = doIMSending(reginfo, msgdata); | ||
581 | if (imresult) | ||
582 | { | ||
583 | // IM delivery successful, so store the Agent's location in our local cache. | ||
584 | lock (m_UserRegionMap) | ||
585 | { | ||
586 | if (m_UserRegionMap.ContainsKey(toAgentID)) | ||
587 | { | ||
588 | m_UserRegionMap[toAgentID] = upd.RegionID; | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | m_UserRegionMap.Add(toAgentID, upd.RegionID); | ||
593 | } | ||
594 | } | ||
595 | result(true); | ||
596 | } | ||
597 | else | ||
598 | { | ||
599 | // try again, but lookup user this time. | ||
600 | // Warning, this must call the Async version | ||
601 | // of this method or we'll be making thousands of threads | ||
602 | // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync | ||
603 | // The version that spawns the thread is SendGridInstantMessageViaXMLRPC | ||
523 | 604 | ||
524 | // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | 605 | // This is recursive!!!!! |
525 | HandleUndeliverableMessage(im, result); | 606 | SendGridInstantMessageViaXMLRPCAsync(im, result, |
607 | upd.RegionID); | ||
608 | } | ||
609 | } | ||
610 | else | ||
611 | { | ||
612 | m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); | ||
613 | HandleUndeliverableMessage(im, result); | ||
614 | } | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | HandleUndeliverableMessage(im, result); | ||
619 | } | ||
526 | } | 620 | } |
527 | 621 | ||
528 | /// <summary> | 622 | /// <summary> |
@@ -622,8 +716,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
622 | gim["position_z"] = msg.Position.Z.ToString(); | 716 | gim["position_z"] = msg.Position.Z.ToString(); |
623 | gim["region_id"] = new UUID(msg.RegionID).ToString(); | 717 | gim["region_id"] = new UUID(msg.RegionID).ToString(); |
624 | gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); | 718 | gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); |
719 | if (m_MessageKey != String.Empty) | ||
720 | gim["message_key"] = m_MessageKey; | ||
625 | return gim; | 721 | return gim; |
626 | } | 722 | } |
627 | |||
628 | } | 723 | } |
629 | } | 724 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs index 315d372..2d57193 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs | |||
@@ -118,11 +118,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
118 | { | 118 | { |
119 | get { return null; } | 119 | get { return null; } |
120 | } | 120 | } |
121 | 121 | ||
122 | public void Close() | 122 | public void Close() |
123 | { | 123 | { |
124 | } | 124 | } |
125 | 125 | ||
126 | private void OnNewClient(IClientAPI client) | 126 | private void OnNewClient(IClientAPI client) |
127 | { | 127 | { |
128 | client.OnMuteListRequest += OnMuteListRequest; | 128 | client.OnMuteListRequest += OnMuteListRequest; |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs new file mode 100644 index 0000000..6857f35 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs | |||
@@ -0,0 +1,229 @@ | |||
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 OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using System.Text; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Servers; | ||
36 | using OpenSim.Framework.Client; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using Mono.Addins; | ||
40 | |||
41 | using OpenSim.Server.Base; | ||
42 | using OpenSim.Services.Interfaces; | ||
43 | |||
44 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | ||
45 | { | ||
46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MuteListModuleTst")] | ||
47 | public class MuteListModuleTst : ISharedRegionModule | ||
48 | { | ||
49 | private static readonly ILog m_log = LogManager.GetLogger( | ||
50 | MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | protected bool m_Enabled = false; | ||
53 | protected List<Scene> m_SceneList = new List<Scene>(); | ||
54 | protected IMuteListService m_service = null; | ||
55 | |||
56 | public void Initialise(IConfigSource config) | ||
57 | { | ||
58 | IConfig cnf = config.Configs["Messaging"]; | ||
59 | if (cnf == null) | ||
60 | return; | ||
61 | |||
62 | if (cnf.GetString("MuteListModule", "None") != "MuteListModuleTst") | ||
63 | return; | ||
64 | |||
65 | m_Enabled = true; | ||
66 | } | ||
67 | |||
68 | public void AddRegion(Scene scene) | ||
69 | { | ||
70 | } | ||
71 | |||
72 | public void RegionLoaded(Scene scene) | ||
73 | { | ||
74 | if (!m_Enabled) | ||
75 | return; | ||
76 | |||
77 | IXfer xfer = scene.RequestModuleInterface<IXfer>(); | ||
78 | if (xfer == null) | ||
79 | { | ||
80 | m_log.ErrorFormat("[MuteListModuleTst]: Xfer not availble in region {0}. Module Disabled", scene.Name); | ||
81 | m_Enabled = false; | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | IMuteListService srv = scene.RequestModuleInterface<IMuteListService>(); | ||
86 | if(srv == null) | ||
87 | { | ||
88 | m_log.ErrorFormat("[MuteListModuleTst]: MuteListService not availble in region {0}. Module Disabled", scene.Name); | ||
89 | m_Enabled = false; | ||
90 | return; | ||
91 | } | ||
92 | lock (m_SceneList) | ||
93 | { | ||
94 | if(m_service == null) | ||
95 | m_service = srv; | ||
96 | m_SceneList.Add(scene); | ||
97 | scene.EventManager.OnNewClient += OnNewClient; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | public void RemoveRegion(Scene scene) | ||
102 | { | ||
103 | lock (m_SceneList) | ||
104 | { | ||
105 | if(m_SceneList.Contains(scene)) | ||
106 | { | ||
107 | m_SceneList.Remove(scene); | ||
108 | scene.EventManager.OnNewClient -= OnNewClient; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | public void PostInitialise() | ||
114 | { | ||
115 | if (!m_Enabled) | ||
116 | return; | ||
117 | |||
118 | m_log.Debug("[MuteListModuleTst]: enabled"); | ||
119 | } | ||
120 | |||
121 | public string Name | ||
122 | { | ||
123 | get { return "MuteListModuleTst"; } | ||
124 | } | ||
125 | |||
126 | public Type ReplaceableInterface | ||
127 | { | ||
128 | get { return null; } | ||
129 | } | ||
130 | |||
131 | public void Close() | ||
132 | { | ||
133 | } | ||
134 | |||
135 | private void OnNewClient(IClientAPI client) | ||
136 | { | ||
137 | client.OnMuteListRequest += OnMuteListRequest; | ||
138 | client.OnUpdateMuteListEntry += OnUpdateMuteListEntry; | ||
139 | client.OnRemoveMuteListEntry += OnRemoveMuteListEntry; | ||
140 | } | ||
141 | |||
142 | private void OnMuteListRequest(IClientAPI client, uint crc) | ||
143 | { | ||
144 | if (!m_Enabled) | ||
145 | { | ||
146 | if(crc == 0) | ||
147 | client.SendEmpytMuteList(); | ||
148 | else | ||
149 | client.SendUseCachedMuteList(); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | IXfer xfer = client.Scene.RequestModuleInterface<IXfer>(); | ||
154 | if (xfer == null) | ||
155 | { | ||
156 | if(crc == 0) | ||
157 | client.SendEmpytMuteList(); | ||
158 | else | ||
159 | client.SendUseCachedMuteList(); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | Byte[] data = m_service.MuteListRequest(client.AgentId, crc); | ||
164 | if (data == null) | ||
165 | { | ||
166 | if(crc == 0) | ||
167 | client.SendEmpytMuteList(); | ||
168 | else | ||
169 | client.SendUseCachedMuteList(); | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | if (data.Length == 0) | ||
174 | { | ||
175 | client.SendEmpytMuteList(); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | if (data.Length == 1) | ||
180 | { | ||
181 | if(crc == 0) | ||
182 | client.SendEmpytMuteList(); | ||
183 | else | ||
184 | client.SendUseCachedMuteList(); | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | string filename = "mutes" + client.AgentId.ToString(); | ||
189 | xfer.AddNewFile(filename, data); | ||
190 | client.SendMuteListUpdate(filename); | ||
191 | } | ||
192 | |||
193 | private void OnUpdateMuteListEntry(IClientAPI client, UUID muteID, string muteName, int muteType, uint muteFlags) | ||
194 | { | ||
195 | if (!m_Enabled) | ||
196 | return; | ||
197 | |||
198 | UUID agentID = client.AgentId; | ||
199 | if(muteType == 1) // agent | ||
200 | { | ||
201 | if(agentID == muteID) | ||
202 | return; | ||
203 | if(m_SceneList[0].Permissions.IsAdministrator(muteID)) | ||
204 | { | ||
205 | OnMuteListRequest(client, 0); | ||
206 | return; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | MuteData mute = new MuteData(); | ||
211 | mute.AgentID = agentID; | ||
212 | mute.MuteID = muteID; | ||
213 | mute.MuteName = muteName; | ||
214 | mute.MuteType = muteType; | ||
215 | mute.MuteFlags = (int)muteFlags; | ||
216 | mute.Stamp = Util.UnixTimeSinceEpoch(); | ||
217 | |||
218 | m_service.UpdateMute(mute); | ||
219 | } | ||
220 | |||
221 | private void OnRemoveMuteListEntry(IClientAPI client, UUID muteID, string muteName) | ||
222 | { | ||
223 | if (!m_Enabled) | ||
224 | return; | ||
225 | m_service.RemoveMute(client.AgentId, muteID, muteName); | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 9cdb1c2..315ce1b 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | |||
@@ -39,16 +39,25 @@ using OpenSim.Region.Framework.Scenes; | |||
39 | 39 | ||
40 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | 40 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage |
41 | { | 41 | { |
42 | public struct SendReply | ||
43 | { | ||
44 | public bool Success; | ||
45 | public string Message; | ||
46 | public int Disposition; | ||
47 | } | ||
48 | |||
42 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineMessageModule")] | 49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineMessageModule")] |
43 | public class OfflineMessageModule : ISharedRegionModule | 50 | public class OfflineMessageModule : ISharedRegionModule |
44 | { | 51 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 53 | ||
47 | private bool enabled = true; | 54 | private bool enabled = true; |
55 | private bool m_UseNewAvnCode = false; | ||
48 | private List<Scene> m_SceneList = new List<Scene>(); | 56 | private List<Scene> m_SceneList = new List<Scene>(); |
49 | private string m_RestURL = String.Empty; | 57 | private string m_RestURL = String.Empty; |
50 | IMessageTransferModule m_TransferModule = null; | 58 | IMessageTransferModule m_TransferModule = null; |
51 | private bool m_ForwardOfflineGroupMessages = true; | 59 | private bool m_ForwardOfflineGroupMessages = true; |
60 | private Dictionary<IClientAPI, List<UUID>> m_repliesSent= new Dictionary<IClientAPI, List<UUID>>(); | ||
52 | 61 | ||
53 | public void Initialise(IConfigSource config) | 62 | public void Initialise(IConfigSource config) |
54 | { | 63 | { |
@@ -74,6 +83,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
74 | } | 83 | } |
75 | 84 | ||
76 | m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages); | 85 | m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages); |
86 | m_UseNewAvnCode = cnf.GetBoolean("UseNewAvnCode", m_UseNewAvnCode); | ||
77 | } | 87 | } |
78 | 88 | ||
79 | public void AddRegion(Scene scene) | 89 | public void AddRegion(Scene scene) |
@@ -138,7 +148,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
138 | { | 148 | { |
139 | get { return null; } | 149 | get { return null; } |
140 | } | 150 | } |
141 | 151 | ||
142 | public void Close() | 152 | public void Close() |
143 | { | 153 | { |
144 | } | 154 | } |
@@ -168,11 +178,21 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
168 | private void OnNewClient(IClientAPI client) | 178 | private void OnNewClient(IClientAPI client) |
169 | { | 179 | { |
170 | client.OnRetrieveInstantMessages += RetrieveInstantMessages; | 180 | client.OnRetrieveInstantMessages += RetrieveInstantMessages; |
181 | client.OnLogout += OnClientLoggedOut; | ||
182 | } | ||
183 | |||
184 | public void OnClientLoggedOut(IClientAPI client) | ||
185 | { | ||
186 | m_repliesSent.Remove(client); | ||
171 | } | 187 | } |
172 | 188 | ||
173 | private void RetrieveInstantMessages(IClientAPI client) | 189 | private void RetrieveInstantMessages(IClientAPI client) |
174 | { | 190 | { |
175 | if (m_RestURL != "") | 191 | if (m_RestURL == String.Empty) |
192 | { | ||
193 | return; | ||
194 | } | ||
195 | else | ||
176 | { | 196 | { |
177 | m_log.DebugFormat("[OFFLINE MESSAGING]: Retrieving stored messages for {0}", client.AgentId); | 197 | m_log.DebugFormat("[OFFLINE MESSAGING]: Retrieving stored messages for {0}", client.AgentId); |
178 | 198 | ||
@@ -180,28 +200,28 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
180 | = SynchronousRestObjectRequester.MakeRequest<UUID, List<GridInstantMessage>>( | 200 | = SynchronousRestObjectRequester.MakeRequest<UUID, List<GridInstantMessage>>( |
181 | "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); | 201 | "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); |
182 | 202 | ||
183 | if (msglist == null) | 203 | if (msglist != null) |
184 | { | ||
185 | m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list."); | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | foreach (GridInstantMessage im in msglist) | ||
190 | { | 204 | { |
191 | if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) | 205 | foreach (GridInstantMessage im in msglist) |
192 | // send it directly or else the item will be given twice | ||
193 | client.SendInstantMessage(im); | ||
194 | else | ||
195 | { | 206 | { |
196 | // Send through scene event manager so all modules get a chance | 207 | if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) |
197 | // to look at this message before it gets delivered. | 208 | // send it directly or else the item will be given twice |
198 | // | 209 | client.SendInstantMessage(im); |
199 | // Needed for proper state management for stored group | 210 | else |
200 | // invitations | 211 | { |
201 | // | 212 | // Send through scene event manager so all modules get a chance |
202 | Scene s = FindScene(client.AgentId); | 213 | // to look at this message before it gets delivered. |
203 | if (s != null) | 214 | // |
204 | s.EventManager.TriggerIncomingInstantMessage(im); | 215 | // Needed for proper state management for stored group |
216 | // invitations | ||
217 | // | ||
218 | |||
219 | im.offline = 1; | ||
220 | |||
221 | Scene s = FindScene(client.AgentId); | ||
222 | if (s != null) | ||
223 | s.EventManager.TriggerIncomingInstantMessage(im); | ||
224 | } | ||
205 | } | 225 | } |
206 | } | 226 | } |
207 | } | 227 | } |
@@ -213,7 +233,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
213 | im.dialog != (byte)InstantMessageDialog.MessageFromAgent && | 233 | im.dialog != (byte)InstantMessageDialog.MessageFromAgent && |
214 | im.dialog != (byte)InstantMessageDialog.GroupNotice && | 234 | im.dialog != (byte)InstantMessageDialog.GroupNotice && |
215 | im.dialog != (byte)InstantMessageDialog.GroupInvitation && | 235 | im.dialog != (byte)InstantMessageDialog.GroupInvitation && |
216 | im.dialog != (byte)InstantMessageDialog.InventoryOffered) | 236 | im.dialog != (byte)InstantMessageDialog.InventoryOffered && |
237 | im.dialog != (byte)InstantMessageDialog.TaskInventoryOffered) | ||
217 | { | 238 | { |
218 | return; | 239 | return; |
219 | } | 240 | } |
@@ -225,22 +246,73 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
225 | return; | 246 | return; |
226 | } | 247 | } |
227 | 248 | ||
228 | bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( | 249 | if(m_UseNewAvnCode) |
229 | "POST", m_RestURL+"/SaveMessage/", im, 10000); | 250 | { |
251 | Scene scene = FindScene(new UUID(im.fromAgentID)); | ||
252 | if (scene == null) | ||
253 | scene = m_SceneList[0]; | ||
230 | 254 | ||
231 | if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) | 255 | UUID scopeID = scene.RegionInfo.ScopeID; |
256 | SendReply reply = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, SendReply>( | ||
257 | "POST", m_RestURL+"/SaveMessage/?scope=" + scopeID.ToString(), im, 20000); | ||
258 | |||
259 | if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) | ||
260 | { | ||
261 | IClientAPI client = FindClient(new UUID(im.fromAgentID)); | ||
262 | if (client == null) | ||
263 | return; | ||
264 | |||
265 | if (string.IsNullOrEmpty(reply.Message)) | ||
266 | reply.Message = "User is not logged in. " + (reply.Success ? "Message saved." : "Message not saved"); | ||
267 | |||
268 | bool sendReply = true; | ||
269 | |||
270 | switch (reply.Disposition) | ||
271 | { | ||
272 | case 0: // Normal | ||
273 | break; | ||
274 | case 1: // Only once per user | ||
275 | if (m_repliesSent.ContainsKey(client) && m_repliesSent[client].Contains(new UUID(im.toAgentID))) | ||
276 | sendReply = false; | ||
277 | else | ||
278 | { | ||
279 | if (!m_repliesSent.ContainsKey(client)) | ||
280 | m_repliesSent[client] = new List<UUID>(); | ||
281 | m_repliesSent[client].Add(new UUID(im.toAgentID)); | ||
282 | } | ||
283 | break; | ||
284 | } | ||
285 | |||
286 | if (sendReply) | ||
287 | { | ||
288 | client.SendInstantMessage(new GridInstantMessage( | ||
289 | null, new UUID(im.toAgentID), | ||
290 | "System", new UUID(im.fromAgentID), | ||
291 | (byte)InstantMessageDialog.MessageFromAgent, | ||
292 | reply.Message, | ||
293 | false, new Vector3())); | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | else | ||
232 | { | 298 | { |
233 | IClientAPI client = FindClient(new UUID(im.fromAgentID)); | 299 | bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( |
234 | if (client == null) | 300 | "POST", m_RestURL+"/SaveMessage/", im, 20000); |
235 | return; | 301 | |
302 | if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) | ||
303 | { | ||
304 | IClientAPI client = FindClient(new UUID(im.fromAgentID)); | ||
305 | if (client == null) | ||
306 | return; | ||
236 | 307 | ||
237 | client.SendInstantMessage(new GridInstantMessage( | 308 | client.SendInstantMessage(new GridInstantMessage( |
238 | null, new UUID(im.toAgentID), | 309 | null, new UUID(im.toAgentID), |
239 | "System", new UUID(im.fromAgentID), | 310 | "System", new UUID(im.fromAgentID), |
240 | (byte)InstantMessageDialog.MessageFromAgent, | 311 | (byte)InstantMessageDialog.MessageFromAgent, |
241 | "User is not logged in. "+ | 312 | "User is not logged in. "+ |
242 | (success ? "Message saved." : "Message not saved"), | 313 | (success ? "Message saved." : "Message not saved"), |
243 | false, new Vector3())); | 314 | false, new Vector3())); |
315 | } | ||
244 | } | 316 | } |
245 | } | 317 | } |
246 | } | 318 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs new file mode 100644 index 0000000..b61e848 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs | |||
@@ -0,0 +1,239 @@ | |||
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 OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using System.Text; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.Framework.Interfaces; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using Mono.Addins; | ||
38 | using OpenSim.Data.MySQL; | ||
39 | using MySql.Data.MySqlClient; | ||
40 | |||
41 | |||
42 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | ||
43 | { | ||
44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XMute")] | ||
45 | public class XMuteModule : ISharedRegionModule | ||
46 | { | ||
47 | private static readonly ILog m_log = LogManager.GetLogger( | ||
48 | MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | protected bool m_Enabled = true; | ||
51 | protected List<Scene> m_SceneList = new List<Scene>(); | ||
52 | protected MuteTableHandler m_MuteTable; | ||
53 | protected string m_DatabaseConnect; | ||
54 | |||
55 | public void Initialise(IConfigSource config) | ||
56 | { | ||
57 | IConfig cnf = config.Configs["Messaging"]; | ||
58 | if (cnf == null) | ||
59 | { | ||
60 | m_Enabled = false; | ||
61 | return; | ||
62 | } | ||
63 | |||
64 | if (cnf.GetString("MuteListModule", "None") != | ||
65 | "XMute") | ||
66 | { | ||
67 | m_Enabled = false; | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | m_DatabaseConnect = cnf.GetString("MuteDatabaseConnect", String.Empty); | ||
72 | if (m_DatabaseConnect == String.Empty) | ||
73 | { | ||
74 | m_log.Debug("[XMute]: MuteDatabaseConnect missing or empty"); | ||
75 | m_Enabled = false; | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | m_MuteTable = new MuteTableHandler( | ||
80 | m_DatabaseConnect, "XMute", String.Empty); | ||
81 | } | ||
82 | |||
83 | public void AddRegion(Scene scene) | ||
84 | { | ||
85 | if (!m_Enabled) | ||
86 | return; | ||
87 | |||
88 | lock (m_SceneList) | ||
89 | { | ||
90 | m_SceneList.Add(scene); | ||
91 | |||
92 | scene.EventManager.OnNewClient += OnNewClient; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | public void RegionLoaded(Scene scene) | ||
97 | { | ||
98 | } | ||
99 | |||
100 | public void RemoveRegion(Scene scene) | ||
101 | { | ||
102 | if (!m_Enabled) | ||
103 | return; | ||
104 | |||
105 | lock (m_SceneList) | ||
106 | { | ||
107 | m_SceneList.Remove(scene); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | public void PostInitialise() | ||
112 | { | ||
113 | if (!m_Enabled) | ||
114 | return; | ||
115 | |||
116 | m_log.Debug("[XMute]: Mute list enabled"); | ||
117 | } | ||
118 | |||
119 | public string Name | ||
120 | { | ||
121 | get { return "XMuteModule"; } | ||
122 | } | ||
123 | |||
124 | public Type ReplaceableInterface | ||
125 | { | ||
126 | get { return null; } | ||
127 | } | ||
128 | |||
129 | public void Close() | ||
130 | { | ||
131 | } | ||
132 | |||
133 | private void OnNewClient(IClientAPI client) | ||
134 | { | ||
135 | client.OnMuteListRequest += OnMuteListRequest; | ||
136 | client.OnUpdateMuteListEntry += OnUpdateMuteListEntry; | ||
137 | client.OnRemoveMuteListEntry += OnRemoveMuteListEntry; | ||
138 | } | ||
139 | |||
140 | private void OnMuteListRequest(IClientAPI client, uint crc) | ||
141 | { | ||
142 | string filename = "mutes"+client.AgentId.ToString(); | ||
143 | |||
144 | IXfer xfer = client.Scene.RequestModuleInterface<IXfer>(); | ||
145 | if (xfer != null) | ||
146 | { | ||
147 | MuteData[] data = m_MuteTable.Get("AgentID", client.AgentId.ToString()); | ||
148 | if (data == null || data.Length == 0) | ||
149 | { | ||
150 | xfer.AddNewFile(filename, new Byte[0]); | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | StringBuilder sb = new StringBuilder(1024); | ||
155 | |||
156 | foreach (MuteData d in data) | ||
157 | sb.AppendFormat("{0} {1} {2}|{3}\n", | ||
158 | d.MuteType, | ||
159 | d.MuteID.ToString(), | ||
160 | d.MuteName, | ||
161 | d.MuteFlags); | ||
162 | |||
163 | Byte[] filedata = Util.UTF8.GetBytes(sb.ToString()); | ||
164 | |||
165 | uint dataCrc = Crc32.Compute(filedata); | ||
166 | |||
167 | if (dataCrc == crc) | ||
168 | { | ||
169 | client.SendUseCachedMuteList(); | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | xfer.AddNewFile(filename, filedata); | ||
174 | } | ||
175 | |||
176 | client.SendMuteListUpdate(filename); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | private void OnUpdateMuteListEntry(IClientAPI client, UUID muteID, string muteName, int muteType, uint muteFlags) | ||
181 | { | ||
182 | MuteData mute = new MuteData(); | ||
183 | |||
184 | mute.AgentID = client.AgentId; | ||
185 | mute.MuteID = muteID; | ||
186 | mute.MuteName = muteName; | ||
187 | mute.MuteType = muteType; | ||
188 | mute.MuteFlags = (int)muteFlags; | ||
189 | mute.Stamp = Util.UnixTimeSinceEpoch(); | ||
190 | |||
191 | m_MuteTable.Store(mute); | ||
192 | } | ||
193 | |||
194 | private void OnRemoveMuteListEntry(IClientAPI client, UUID muteID, string muteName) | ||
195 | { | ||
196 | m_MuteTable.Delete(new string[] { "AgentID", | ||
197 | "MuteID", | ||
198 | "MuteName" }, | ||
199 | new string[] { client.AgentId.ToString(), | ||
200 | muteID.ToString(), | ||
201 | muteName }); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | public class MuteTableHandler : MySQLGenericTableHandler<MuteData> | ||
206 | { | ||
207 | public MuteTableHandler(string conn, string realm, string m) : base(conn, realm, m) | ||
208 | { | ||
209 | } | ||
210 | |||
211 | public bool Delete(string[] fields, string[] val) | ||
212 | { | ||
213 | if (fields.Length != val.Length) | ||
214 | return false; | ||
215 | |||
216 | using (MySqlCommand cmd = new MySqlCommand()) | ||
217 | { | ||
218 | string text = String.Format("delete from {0} where ", m_Realm); | ||
219 | |||
220 | List<string> terms = new List<string>(); | ||
221 | |||
222 | for (int i = 0 ; i < fields.Length ; i++) | ||
223 | { | ||
224 | terms.Add(String.Format("{0} = ?{0}", fields[i])); | ||
225 | cmd.Parameters.AddWithValue("?" + fields[i], val[i]); | ||
226 | } | ||
227 | |||
228 | text += string.Join(" and ", terms.ToArray()); | ||
229 | |||
230 | cmd.CommandText = text; | ||
231 | |||
232 | if (ExecuteNonQuery(cmd) > 0) | ||
233 | return true; | ||
234 | return false; | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||