aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/InstantMessage
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/InstantMessage')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs31
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs69
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs297
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs229
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs132
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs239
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 @@
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using System.Timers;
30using log4net; 31using log4net;
31using Mono.Addins; 32using Mono.Addins;
32using Nini.Config; 33using 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 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using System.Text;
31using log4net;
32using Nini.Config;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Servers;
36using OpenSim.Framework.Client;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using Mono.Addins;
40
41using OpenSim.Server.Base;
42using OpenSim.Services.Interfaces;
43
44namespace 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
40namespace OpenSim.Region.CoreModules.Avatar.InstantMessage 40namespace 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 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using System.Text;
31using log4net;
32using Nini.Config;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37using Mono.Addins;
38using OpenSim.Data.MySQL;
39using MySql.Data.MySqlClient;
40
41
42namespace 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