/Aurora/Modules/Avatar/AuroraChat/AuroraOfflineMessagesModule.cs

https://bitbucket.org/VirtualReality/software-testing · C# · 273 lines · 212 code · 29 blank · 32 comment · 73 complexity · 9b5f4c550c86584d3eca86da7f9ae451 MD5 · raw file

  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.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 Aurora-Sim 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 Aurora.Framework;
  28. using Aurora.Framework.ClientInterfaces;
  29. using Aurora.Framework.ConsoleFramework;
  30. using Aurora.Framework.DatabaseInterfaces;
  31. using Aurora.Framework.Modules;
  32. using Aurora.Framework.PresenceInfo;
  33. using Aurora.Framework.SceneInfo;
  34. using Aurora.Framework.Services;
  35. using Aurora.Framework.Services.ClassHelpers.Profile;
  36. using Aurora.Framework.Utilities;
  37. using Nini.Config;
  38. using OpenMetaverse;
  39. using System;
  40. using System.Collections.Generic;
  41. namespace Aurora.Modules.Chat
  42. {
  43. public class AuroraOfflineMessageModule : INonSharedRegionModule
  44. {
  45. private bool enabled = true;
  46. private IScene m_Scene;
  47. private IMessageTransferModule m_TransferModule = null;
  48. private IOfflineMessagesConnector OfflineMessagesConnector;
  49. private bool m_SendOfflineMessagesToEmail = false;
  50. private Dictionary<UUID, List<GridInstantMessage>> m_offlineMessagesCache =
  51. new Dictionary<UUID, List<GridInstantMessage>>();
  52. public void Initialise(IConfigSource config)
  53. {
  54. IConfig cnf = config.Configs["Messaging"];
  55. if (cnf == null)
  56. {
  57. enabled = false;
  58. return;
  59. }
  60. if (cnf.GetString("OfflineMessageModule", "AuroraOfflineMessageModule") !=
  61. "AuroraOfflineMessageModule")
  62. {
  63. enabled = false;
  64. return;
  65. }
  66. m_SendOfflineMessagesToEmail = cnf.GetBoolean("SendOfflineMessagesToEmail", m_SendOfflineMessagesToEmail);
  67. }
  68. public void AddRegion(IScene scene)
  69. {
  70. if (!enabled)
  71. return;
  72. m_Scene = scene;
  73. scene.EventManager.OnNewClient += OnNewClient;
  74. scene.EventManager.OnClosingClient += OnClosingClient;
  75. scene.EventManager.OnCachedUserInfo += UpdateCachedInfo;
  76. }
  77. public void RegionLoaded(IScene scene)
  78. {
  79. if (!enabled)
  80. return;
  81. if (m_TransferModule == null)
  82. {
  83. OfflineMessagesConnector = Framework.Utilities.DataManager.RequestPlugin<IOfflineMessagesConnector>();
  84. m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
  85. if (m_TransferModule == null || OfflineMessagesConnector == null)
  86. {
  87. scene.EventManager.OnNewClient -= OnNewClient;
  88. scene.EventManager.OnClosingClient -= OnClosingClient;
  89. enabled = false;
  90. m_Scene = null;
  91. MainConsole.Instance.Error(
  92. "[OFFLINE MESSAGING] No message transfer module or OfflineMessagesConnector is enabled. Diabling offline messages");
  93. return;
  94. }
  95. m_TransferModule.OnUndeliveredMessage += UndeliveredMessage;
  96. }
  97. }
  98. public void RemoveRegion(IScene scene)
  99. {
  100. if (!enabled)
  101. return;
  102. m_Scene = null;
  103. if (m_TransferModule != null)
  104. {
  105. scene.EventManager.OnNewClient -= OnNewClient;
  106. scene.EventManager.OnClosingClient -= OnClosingClient;
  107. scene.EventManager.OnCachedUserInfo -= UpdateCachedInfo;
  108. m_TransferModule.OnUndeliveredMessage -= UndeliveredMessage;
  109. }
  110. }
  111. public string Name
  112. {
  113. get { return "AuroraOfflineMessageModule"; }
  114. }
  115. public Type ReplaceableInterface
  116. {
  117. get { return null; }
  118. }
  119. public void Close()
  120. {
  121. }
  122. private IClientAPI FindClient(UUID agentID)
  123. {
  124. IScenePresence presence = m_Scene.GetScenePresence(agentID);
  125. return (presence != null && !presence.IsChildAgent) ? presence.ControllingClient : null;
  126. }
  127. private void UpdateCachedInfo(UUID agentID, CachedUserInfo info)
  128. {
  129. lock (m_offlineMessagesCache)
  130. m_offlineMessagesCache[agentID] = info.OfflineMessages;
  131. }
  132. private void OnNewClient(IClientAPI client)
  133. {
  134. client.OnRetrieveInstantMessages += RetrieveInstantMessages;
  135. }
  136. private void OnClosingClient(IClientAPI client)
  137. {
  138. client.OnRetrieveInstantMessages -= RetrieveInstantMessages;
  139. }
  140. private void RetrieveInstantMessages(IClientAPI client)
  141. {
  142. if (OfflineMessagesConnector == null)
  143. return;
  144. List<GridInstantMessage> msglist;
  145. lock (m_offlineMessagesCache)
  146. {
  147. if (m_offlineMessagesCache.TryGetValue(client.AgentId, out msglist))
  148. m_offlineMessagesCache.Remove(client.AgentId);
  149. }
  150. if (msglist == null)
  151. msglist = OfflineMessagesConnector.GetOfflineMessages(client.AgentId);
  152. msglist.Sort(
  153. delegate(GridInstantMessage a, GridInstantMessage b) { return a.timestamp.CompareTo(b.timestamp); });
  154. foreach (GridInstantMessage IM in msglist)
  155. {
  156. // Send through scene event manager so all modules get a chance
  157. // to look at this message before it gets delivered.
  158. //
  159. // Needed for proper state management for stored group
  160. // invitations
  161. //
  162. IM.offline = 1;
  163. m_Scene.EventManager.TriggerIncomingInstantMessage(IM);
  164. }
  165. }
  166. private void UndeliveredMessage(GridInstantMessage im, string reason)
  167. {
  168. if (OfflineMessagesConnector == null || im == null)
  169. return;
  170. IClientAPI client = FindClient(im.fromAgentID);
  171. if ((client == null) && (im.dialog != 32))
  172. return;
  173. if (!OfflineMessagesConnector.AddOfflineMessage(im))
  174. {
  175. if ((!im.fromGroup) && (reason != "User does not exist.") && (client != null))
  176. client.SendInstantMessage(new GridInstantMessage(
  177. null, im.toAgentID,
  178. "System", im.fromAgentID,
  179. (byte) InstantMessageDialog.MessageFromAgent,
  180. "User has too many IMs already, please try again later.",
  181. false, Vector3.Zero));
  182. else if (client == null)
  183. return;
  184. }
  185. else if ((im.offline != 0)
  186. && (!im.fromGroup || im.fromGroup))
  187. {
  188. if (im.dialog == 32) //Group notice
  189. {
  190. IGroupsModule module = m_Scene.RequestModuleInterface<IGroupsModule>();
  191. if (module != null)
  192. im = module.BuildOfflineGroupNotice(im);
  193. return;
  194. }
  195. if (client == null) return;
  196. IEmailModule emailModule = m_Scene.RequestModuleInterface<IEmailModule>();
  197. if (emailModule != null && m_SendOfflineMessagesToEmail)
  198. {
  199. IUserProfileInfo profile =
  200. Framework.Utilities.DataManager.RequestPlugin<IProfileConnector>().GetUserProfile(im.toAgentID);
  201. if (profile != null && profile.IMViaEmail)
  202. {
  203. UserAccount account = m_Scene.UserAccountService.GetUserAccount(null, im.toAgentID.ToString());
  204. if (account != null && !string.IsNullOrEmpty(account.Email))
  205. {
  206. emailModule.SendEmail(UUID.Zero, account.Email,
  207. string.Format("Offline Message from {0}", im.fromAgentName),
  208. string.Format("Time: {0}\n",
  209. Util.ToDateTime(im.timestamp).ToShortDateString()) +
  210. string.Format("From: {0}\n", im.fromAgentName) +
  211. string.Format("Message: {0}\n", im.message), m_Scene);
  212. }
  213. }
  214. }
  215. if (im.dialog == (byte) InstantMessageDialog.MessageFromAgent && !im.fromGroup)
  216. {
  217. client.SendInstantMessage(new GridInstantMessage(
  218. null, im.toAgentID,
  219. "System", im.fromAgentID,
  220. (byte) InstantMessageDialog.MessageFromAgent,
  221. "Message saved, reason: " + reason,
  222. false, new Vector3()));
  223. }
  224. if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
  225. client.SendAlertMessage("User is not online. Inventory has been saved");
  226. }
  227. else if (im.offline == 0)
  228. {
  229. if (client == null) return;
  230. if (im.dialog == (byte) InstantMessageDialog.MessageFromAgent && !im.fromGroup)
  231. {
  232. client.SendInstantMessage(new GridInstantMessage(
  233. null, im.toAgentID,
  234. "System", im.fromAgentID,
  235. (byte) InstantMessageDialog.MessageFromAgent,
  236. "Message saved, reason: " + reason,
  237. false, new Vector3()));
  238. }
  239. if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
  240. client.SendAlertMessage("User not able to be found. Inventory has been saved");
  241. }
  242. }
  243. }
  244. }