OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
OfflineIMRegionModule.cs
Go to the documentation of this file.
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 log4net;
31 using Mono.Addins;
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 OpenSim.Services.Interfaces;
40 
41 namespace OpenSim.OfflineIM
42 {
43  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineIMConnectorModule")]
45  {
46  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 
48  private bool m_Enabled = false;
49  private List<Scene> m_SceneList = new List<Scene>();
50  IMessageTransferModule m_TransferModule = null;
51  private bool m_ForwardOfflineGroupMessages = true;
52 
53  private IOfflineIMService m_OfflineIMService;
54 
55  public void Initialise(IConfigSource config)
56  {
57  IConfig cnf = config.Configs["Messaging"];
58  if (cnf == null)
59  return;
60  if (cnf != null && cnf.GetString("OfflineMessageModule", string.Empty) != Name)
61  return;
62 
63  m_Enabled = true;
64 
65  string serviceLocation = cnf.GetString("OfflineMessageURL", string.Empty);
66  if (serviceLocation == string.Empty)
67  m_OfflineIMService = new OfflineIMService(config);
68  else
69  m_OfflineIMService = new OfflineIMServiceRemoteConnector(config);
70 
71  m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages);
72  m_log.DebugFormat("[OfflineIM.V2]: Offline messages enabled by {0}", Name);
73  }
74 
75  public void AddRegion(Scene scene)
76  {
77  if (!m_Enabled)
78  return;
79 
80  scene.RegisterModuleInterface<IOfflineIMService>(this);
81  m_SceneList.Add(scene);
82  scene.EventManager.OnNewClient += OnNewClient;
83  }
84 
85  public void RegionLoaded(Scene scene)
86  {
87  if (!m_Enabled)
88  return;
89 
90  if (m_TransferModule == null)
91  {
92  m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
93  if (m_TransferModule == null)
94  {
95  scene.EventManager.OnNewClient -= OnNewClient;
96 
97  m_SceneList.Clear();
98 
99  m_log.Error("[OfflineIM.V2]: No message transfer module is enabled. Disabling offline messages");
100  }
101  m_TransferModule.OnUndeliveredMessage += UndeliveredMessage;
102  }
103  }
104 
105  public void RemoveRegion(Scene scene)
106  {
107  if (!m_Enabled)
108  return;
109 
110  m_SceneList.Remove(scene);
111  scene.EventManager.OnNewClient -= OnNewClient;
112  m_TransferModule.OnUndeliveredMessage -= UndeliveredMessage;
113 
114  scene.ForEachClient(delegate(IClientAPI client)
115  {
116  client.OnRetrieveInstantMessages -= RetrieveInstantMessages;
117  client.OnMuteListRequest -= OnMuteListRequest;
118  });
119  }
120 
121  public void PostInitialise()
122  {
123  }
124 
125  public string Name
126  {
127  get { return "Offline Message Module V2"; }
128  }
129 
130  public Type ReplaceableInterface
131  {
132  get { return null; }
133  }
134 
135  public void Close()
136  {
137  m_SceneList.Clear();
138  }
139 
140  private Scene FindScene(UUID agentID)
141  {
142  foreach (Scene s in m_SceneList)
143  {
144  ScenePresence presence = s.GetScenePresence(agentID);
145  if (presence != null && !presence.IsChildAgent)
146  return s;
147  }
148  return null;
149  }
150 
151  private IClientAPI FindClient(UUID agentID)
152  {
153  foreach (Scene s in m_SceneList)
154  {
155  ScenePresence presence = s.GetScenePresence(agentID);
156  if (presence != null && !presence.IsChildAgent)
157  return presence.ControllingClient;
158  }
159  return null;
160  }
161 
162  private void OnNewClient(IClientAPI client)
163  {
164  client.OnRetrieveInstantMessages += RetrieveInstantMessages;
165  client.OnMuteListRequest += OnMuteListRequest;
166  }
167 
168  private void RetrieveInstantMessages(IClientAPI client)
169  {
170  m_log.DebugFormat("[OfflineIM.V2]: Retrieving stored messages for {0}", client.AgentId);
171 
172  List<GridInstantMessage> msglist = m_OfflineIMService.GetMessages(client.AgentId);
173 
174  if (msglist == null)
175  m_log.DebugFormat("[OfflineIM.V2]: WARNING null message list.");
176 
177  foreach (GridInstantMessage im in msglist)
178  {
179  if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
180  // send it directly or else the item will be given twice
181  client.SendInstantMessage(im);
182  else
183  {
184  // Send through scene event manager so all modules get a chance
185  // to look at this message before it gets delivered.
186  //
187  // Needed for proper state management for stored group
188  // invitations
189  //
190  Scene s = FindScene(client.AgentId);
191  if (s != null)
192  s.EventManager.TriggerIncomingInstantMessage(im);
193  }
194  }
195  }
196 
197  // Apparently this is needed in order for the viewer to request the IMs.
198  private void OnMuteListRequest(IClientAPI client, uint crc)
199  {
200  m_log.DebugFormat("[OfflineIM.V2] Got mute list request for crc {0}", crc);
201  string filename = "mutes" + client.AgentId.ToString();
202 
203  IXfer xfer = client.Scene.RequestModuleInterface<IXfer>();
204  if (xfer != null)
205  {
206  xfer.AddNewFile(filename, new Byte[0]);
207  client.SendMuteListUpdate(filename);
208  }
209  }
210 
211  private void UndeliveredMessage(GridInstantMessage im)
212  {
213  if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
214  im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
215  im.dialog != (byte)InstantMessageDialog.GroupNotice &&
216  im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
217  im.dialog != (byte)InstantMessageDialog.InventoryOffered)
218  {
219  return;
220  }
221 
222  if (!m_ForwardOfflineGroupMessages)
223  {
224  if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
225  im.dialog == (byte)InstantMessageDialog.GroupInvitation)
226  return;
227  }
228 
229  string reason = string.Empty;
230  bool success = m_OfflineIMService.StoreMessage(im, out reason);
231 
232  if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
233  {
234  IClientAPI client = FindClient(new UUID(im.fromAgentID));
235  if (client == null)
236  return;
237 
238  client.SendInstantMessage(new GridInstantMessage(
239  null, new UUID(im.toAgentID),
240  "System", new UUID(im.fromAgentID),
241  (byte)InstantMessageDialog.MessageFromAgent,
242  "User is not logged in. " +
243  (success ? "Message saved." : "Message not saved: " + reason),
244  false, new Vector3()));
245  }
246  }
247 
248  #region IOfflineIM
249 
250  public List<GridInstantMessage> GetMessages(UUID principalID)
251  {
252  return m_OfflineIMService.GetMessages(principalID);
253  }
254 
255  public bool StoreMessage(GridInstantMessage im, out string reason)
256  {
257  return m_OfflineIMService.StoreMessage(im, out reason);
258  }
259 
260  public void DeleteMessages(UUID userID)
261  {
262  m_OfflineIMService.DeleteMessages(userID);
263  }
264 
265  #endregion
266  }
267 }
268 
delegate void UndeliveredMessage(GridInstantMessage im)
void DeleteMessages(UUID userID)
Delete messages to or from this user (or group).
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
List< GridInstantMessage > GetMessages(UUID principalID)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
bool StoreMessage(GridInstantMessage im, out string reason)
Interactive OpenSim region server
Definition: OpenSim.cs:55
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void SendInstantMessage(GridInstantMessage im)
delegate void RetrieveInstantMessages(IClientAPI client)