OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
OfflineMessageModule.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 
40 namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
41 {
42  public struct SendReply
43  {
44  public bool Success;
45  public string Message;
46  public int Disposition;
47  }
48 
49  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineMessageModule")]
51  {
52  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 
54  private bool enabled = true;
55  private List<Scene> m_SceneList = new List<Scene>();
56  private string m_RestURL = String.Empty;
57  IMessageTransferModule m_TransferModule = null;
58  private bool m_ForwardOfflineGroupMessages = true;
59  private Dictionary<IClientAPI, List<UUID>> m_repliesSent= new Dictionary<IClientAPI, List<UUID>>();
60 
61  public void Initialise(IConfigSource config)
62  {
63  IConfig cnf = config.Configs["Messaging"];
64  if (cnf == null)
65  {
66  enabled = false;
67  return;
68  }
69  if (cnf != null && cnf.GetString("OfflineMessageModule", "None") !=
70  "OfflineMessageModule")
71  {
72  enabled = false;
73  return;
74  }
75 
76  m_RestURL = cnf.GetString("OfflineMessageURL", "");
77  if (m_RestURL == "")
78  {
79  m_log.Error("[OFFLINE MESSAGING] Module was enabled, but no URL is given, disabling");
80  enabled = false;
81  return;
82  }
83 
84  m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages);
85  }
86 
87  public void AddRegion(Scene scene)
88  {
89  if (!enabled)
90  return;
91 
92  lock (m_SceneList)
93  {
94  m_SceneList.Add(scene);
95 
96  scene.EventManager.OnNewClient += OnNewClient;
97  }
98  }
99 
100  public void RegionLoaded(Scene scene)
101  {
102  if (!enabled)
103  return;
104 
105  if (m_TransferModule == null)
106  {
107  m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
108  if (m_TransferModule == null)
109  {
110  scene.EventManager.OnNewClient -= OnNewClient;
111 
112  enabled = false;
113  m_SceneList.Clear();
114 
115  m_log.Error("[OFFLINE MESSAGING] No message transfer module is enabled. Diabling offline messages");
116  }
117  m_TransferModule.OnUndeliveredMessage += UndeliveredMessage;
118  }
119  }
120 
121  public void RemoveRegion(Scene scene)
122  {
123  if (!enabled)
124  return;
125 
126  lock (m_SceneList)
127  {
128  m_SceneList.Remove(scene);
129  }
130  }
131 
132  public void PostInitialise()
133  {
134  if (!enabled)
135  return;
136 
137  m_log.Debug("[OFFLINE MESSAGING] Offline messages enabled");
138  }
139 
140  public string Name
141  {
142  get { return "OfflineMessageModule"; }
143  }
144 
145  public Type ReplaceableInterface
146  {
147  get { return null; }
148  }
149 
150  public void Close()
151  {
152  }
153 
154  private Scene FindScene(UUID agentID)
155  {
156  foreach (Scene s in m_SceneList)
157  {
158  ScenePresence presence = s.GetScenePresence(agentID);
159  if (presence != null && !presence.IsChildAgent)
160  return s;
161  }
162  return null;
163  }
164 
165  private IClientAPI FindClient(UUID agentID)
166  {
167  foreach (Scene s in m_SceneList)
168  {
169  ScenePresence presence = s.GetScenePresence(agentID);
170  if (presence != null && !presence.IsChildAgent)
171  return presence.ControllingClient;
172  }
173  return null;
174  }
175 
176  private void OnNewClient(IClientAPI client)
177  {
178  client.OnRetrieveInstantMessages += RetrieveInstantMessages;
179  client.OnLogout += OnClientLoggedOut;
180  }
181 
182  public void OnClientLoggedOut(IClientAPI client)
183  {
184  m_repliesSent.Remove(client);
185  }
186 
187  private void RetrieveInstantMessages(IClientAPI client)
188  {
189  if (m_RestURL == String.Empty)
190  {
191  return;
192  }
193  else
194  {
195  m_log.DebugFormat("[OFFLINE MESSAGING]: Retrieving stored messages for {0}", client.AgentId);
196 
197  List<GridInstantMessage> msglist
198  = SynchronousRestObjectRequester.MakeRequest<UUID, List<GridInstantMessage>>(
199  "POST", m_RestURL + "/RetrieveMessages/", client.AgentId);
200 
201  if (msglist != null)
202  {
203  foreach (GridInstantMessage im in msglist)
204  {
205  if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
206  // send it directly or else the item will be given twice
207  client.SendInstantMessage(im);
208  else
209  {
210  // Send through scene event manager so all modules get a chance
211  // to look at this message before it gets delivered.
212  //
213  // Needed for proper state management for stored group
214  // invitations
215  //
216 
217  im.offline = 1;
218 
219  Scene s = FindScene(client.AgentId);
220  if (s != null)
221  s.EventManager.TriggerIncomingInstantMessage(im);
222  }
223  }
224  }
225  }
226  }
227 
228  private void UndeliveredMessage(GridInstantMessage im)
229  {
230  if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
231  im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
232  im.dialog != (byte)InstantMessageDialog.GroupNotice &&
233  im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
234  im.dialog != (byte)InstantMessageDialog.InventoryOffered &&
235  im.dialog != (byte)InstantMessageDialog.TaskInventoryOffered)
236  {
237  return;
238  }
239 
240  if (!m_ForwardOfflineGroupMessages)
241  {
242  if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
243  im.dialog == (byte)InstantMessageDialog.GroupInvitation)
244  return;
245  }
246 
247  Scene scene = FindScene(new UUID(im.fromAgentID));
248  if (scene == null)
249  scene = m_SceneList[0];
250 
251 // Avination new code
252 // SendReply reply = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, SendReply>(
253 // "POST", m_RestURL+"/SaveMessage/?scope=" +
254 // scene.RegionInfo.ScopeID.ToString(), im);
255 
256 // current opensim and osgrid compatible
257  bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>(
258  "POST", m_RestURL+"/SaveMessage/", im, 10000);
259 // current opensim and osgrid compatible end
260 
261  if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
262  {
263  IClientAPI client = FindClient(new UUID(im.fromAgentID));
264  if (client == null)
265  return;
266 /* Avination new code
267  if (reply.Message == String.Empty)
268  reply.Message = "User is not logged in. " + (reply.Success ? "Message saved." : "Message not saved");
269 
270  bool sendReply = true;
271 
272  switch (reply.Disposition)
273  {
274  case 0: // Normal
275  break;
276  case 1: // Only once per user
277  if (m_repliesSent.ContainsKey(client) && m_repliesSent[client].Contains(new UUID(im.toAgentID)))
278  {
279  sendReply = false;
280  }
281  else
282  {
283  if (!m_repliesSent.ContainsKey(client))
284  m_repliesSent[client] = new List<UUID>();
285  m_repliesSent[client].Add(new UUID(im.toAgentID));
286  }
287  break;
288  }
289 
290  if (sendReply)
291  {
292  client.SendInstantMessage(new GridInstantMessage(
293  null, new UUID(im.toAgentID),
294  "System", new UUID(im.fromAgentID),
295  (byte)InstantMessageDialog.MessageFromAgent,
296  reply.Message,
297  false, new Vector3()));
298  }
299 */
300 // current opensim and osgrid compatible
301  client.SendInstantMessage(new GridInstantMessage(
302  null, new UUID(im.toAgentID),
303  "System", new UUID(im.fromAgentID),
304  (byte)InstantMessageDialog.MessageFromAgent,
305  "User is not logged in. "+
306  (success ? "Message saved." : "Message not saved"),
307  false, new Vector3()));
308 // current opensim and osgrid compatible end
309  }
310  }
311  }
312 }
313 
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 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...
delegate void UndeliveredMessage(GridInstantMessage im)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
void SendInstantMessage(GridInstantMessage im)
delegate void RetrieveInstantMessages(IClientAPI client)