aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Addons/OfflineIM
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Addons/OfflineIM/Data/IOfflineIMData.cs49
-rw-r--r--OpenSim/Addons/OfflineIM/Data/MySQLOfflineIMData.cs68
-rw-r--r--OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs267
-rw-r--r--OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs37
-rw-r--r--OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs143
-rw-r--r--OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs215
-rw-r--r--OpenSim/Addons/OfflineIM/Resources/IM_Store.migrations23
-rw-r--r--OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs131
-rw-r--r--OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs83
9 files changed, 1016 insertions, 0 deletions
diff --git a/OpenSim/Addons/OfflineIM/Data/IOfflineIMData.cs b/OpenSim/Addons/OfflineIM/Data/IOfflineIMData.cs
new file mode 100644
index 0000000..a507f7d
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Data/IOfflineIMData.cs
@@ -0,0 +1,49 @@
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
28using System.Collections.Generic;
29using OpenSim.Data;
30using OpenMetaverse;
31
32namespace OpenSim.OfflineIM
33{
34 public class OfflineIMData
35 {
36 public UUID PrincipalID;
37 public Dictionary<string, string> Data;
38 }
39
40
41 public interface IOfflineIMData
42 {
43 OfflineIMData[] Get(string field, string val);
44 long GetCount(string field, string key);
45 bool Store(OfflineIMData data);
46 bool Delete(string field, string val);
47 void DeleteOld();
48 }
49}
diff --git a/OpenSim/Addons/OfflineIM/Data/MySQLOfflineIMData.cs b/OpenSim/Addons/OfflineIM/Data/MySQLOfflineIMData.cs
new file mode 100644
index 0000000..0a61cd2
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Data/MySQLOfflineIMData.cs
@@ -0,0 +1,68 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32
33using OpenSim.Framework;
34using OpenSim.Data.MySQL;
35
36using OpenMetaverse;
37using MySql.Data.MySqlClient;
38
39namespace OpenSim.OfflineIM
40{
41 public class MySQLOfflineIMData : MySQLGenericTableHandler<OfflineIMData>, IOfflineIMData
42 {
43 protected override Assembly Assembly
44 {
45 // WARNING! Moving migrations to this assembly!!!
46 get { return GetType().Assembly; }
47 }
48
49 public MySQLOfflineIMData(string connectionString, string realm)
50 : base(connectionString, realm, "IM_Store")
51 {
52 }
53
54 public void DeleteOld()
55 {
56 uint now = (uint)Util.UnixTimeSinceEpoch();
57
58 using (MySqlCommand cmd = new MySqlCommand())
59 {
60 cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm);
61 cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old
62
63 ExecuteNonQuery(cmd);
64 }
65
66 }
67 }
68}
diff --git a/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs
new file mode 100644
index 0000000..050ebd2
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs
@@ -0,0 +1,267 @@
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 log4net;
31using Mono.Addins;
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 OpenSim.Services.Interfaces;
40
41namespace OpenSim.OfflineIM
42{
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineIMConnectorModule")]
44 public class OfflineIMRegionModule : ISharedRegionModule, IOfflineIMService
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(serviceLocation);
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 Scene scene = FindScene(new UUID(im.fromAgentID));
230 if (scene == null)
231 scene = m_SceneList[0];
232
233 string reason = string.Empty;
234 bool success = m_OfflineIMService.StoreMessage(im, out reason);
235
236 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
237 {
238 IClientAPI client = FindClient(new UUID(im.fromAgentID));
239 if (client == null)
240 return;
241
242 client.SendInstantMessage(new GridInstantMessage(
243 null, new UUID(im.toAgentID),
244 "System", new UUID(im.fromAgentID),
245 (byte)InstantMessageDialog.MessageFromAgent,
246 "User is not logged in. " +
247 (success ? "Message saved." : "Message not saved: " + reason),
248 false, new Vector3()));
249 }
250 }
251
252 #region IOfflineIM
253
254 public List<GridInstantMessage> GetMessages(UUID principalID)
255 {
256 return m_OfflineIMService.GetMessages(principalID);
257 }
258
259 public bool StoreMessage(GridInstantMessage im, out string reason)
260 {
261 return m_OfflineIMService.StoreMessage(im, out reason);
262 }
263
264 #endregion
265 }
266}
267
diff --git a/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..31667eb
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs
@@ -0,0 +1,37 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim.Addons.OfflineIM")]
14[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("a16a9905-4393-4872-9fca-4c81bedbd9f2")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.7.5.*")]
34[assembly: AssemblyFileVersion("1.0.0.0")]
35
36[assembly: Addin("OpenSim.OfflineIM", "0.1")]
37[assembly: AddinDependency("OpenSim", "0.5")]
diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs
new file mode 100644
index 0000000..69feb76
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs
@@ -0,0 +1,143 @@
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36using OpenSim.Services.Interfaces;
37
38using OpenMetaverse;
39using log4net;
40using Nini.Config;
41
42namespace OpenSim.OfflineIM
43{
44 public class OfflineIMServiceRemoteConnector : IOfflineIMService
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private string m_ServerURI = string.Empty;
49 private object m_Lock = new object();
50
51 public OfflineIMServiceRemoteConnector(string url)
52 {
53 m_ServerURI = url;
54 m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0}", m_ServerURI);
55 }
56
57 public OfflineIMServiceRemoteConnector(IConfigSource config)
58 {
59 IConfig cnf = config.Configs["Messaging"];
60 if (cnf == null)
61 {
62 m_log.WarnFormat("[OfflineIM.V2.RemoteConnector]: Missing Messaging configuration");
63 return;
64 }
65
66 m_ServerURI = cnf.GetString("OfflineMessageURL", string.Empty);
67
68 }
69
70 #region IOfflineIMService
71 public List<GridInstantMessage> GetMessages(UUID principalID)
72 {
73 List<GridInstantMessage> ims = new List<GridInstantMessage>();
74
75 Dictionary<string, object> sendData = new Dictionary<string, object>();
76 sendData["PrincipalID"] = principalID;
77 Dictionary<string, object> ret = MakeRequest("GET", sendData);
78
79 if (ret == null)
80 return ims;
81
82 if (!ret.ContainsKey("RESULT"))
83 return ims;
84
85 if (ret["RESULT"].ToString() == "NULL")
86 return ims;
87
88 foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
89 {
90 GridInstantMessage m = OfflineIMDataUtils.GridInstantMessage((Dictionary<string, object>)v);
91 ims.Add(m);
92 }
93
94 return ims;
95 }
96
97 public bool StoreMessage(GridInstantMessage im, out string reason)
98 {
99 reason = string.Empty;
100 Dictionary<string, object> sendData = OfflineIMDataUtils.GridInstantMessage(im);
101
102 Dictionary<string, object> ret = MakeRequest("STORE", sendData);
103
104 if (ret == null)
105 {
106 reason = "Bad response from server";
107 return false;
108 }
109
110 string result = ret["RESULT"].ToString();
111 if (result == "NULL" || result.ToLower() == "false")
112 {
113 reason = ret["REASON"].ToString();
114 return false;
115 }
116
117 return true;
118 }
119
120 #endregion
121
122
123 #region Make Request
124
125 private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
126 {
127 sendData["METHOD"] = method;
128
129 string reply = string.Empty;
130 lock (m_Lock)
131 reply = SynchronousRestFormsRequester.MakeRequest("POST",
132 m_ServerURI + "/offlineim",
133 ServerUtils.BuildQueryString(sendData));
134
135 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
136 reply);
137
138 return replyData;
139 }
140 #endregion
141
142 }
143}
diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs
new file mode 100644
index 0000000..2b3a01d
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs
@@ -0,0 +1,215 @@
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
28using System;
29using System.Reflection;
30using System.Text;
31using System.Xml;
32using System.Collections.Generic;
33using System.IO;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Framework.Servers.HttpServer;
39using OpenSim.Server.Handlers.Base;
40using log4net;
41using OpenMetaverse;
42
43namespace OpenSim.OfflineIM
44{
45 public class OfflineIMServiceRobustConnector : ServiceConnector
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private IOfflineIMService m_OfflineIMService;
50 private string m_ConfigName = "Messaging";
51
52 public OfflineIMServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
53 base(config, server, configName)
54 {
55 if (configName != String.Empty)
56 m_ConfigName = configName;
57
58 m_log.DebugFormat("[OfflineIM.V2.RobustConnector]: Starting with config name {0}", m_ConfigName);
59
60 m_OfflineIMService = new OfflineIMService(config);
61
62 server.AddStreamHandler(new OfflineIMServicePostHandler(m_OfflineIMService));
63 }
64 }
65
66 public class OfflineIMServicePostHandler : BaseStreamHandler
67 {
68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69
70 private IOfflineIMService m_OfflineIMService;
71
72 public OfflineIMServicePostHandler(IOfflineIMService service) :
73 base("POST", "/offlineim")
74 {
75 m_OfflineIMService = service;
76 }
77
78 public override byte[] Handle(string path, Stream requestData,
79 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
80 {
81 StreamReader sr = new StreamReader(requestData);
82 string body = sr.ReadToEnd();
83 sr.Close();
84 body = body.Trim();
85
86 //m_log.DebugFormat("[XXX]: query String: {0}", body);
87
88 try
89 {
90 Dictionary<string, object> request =
91 ServerUtils.ParseQueryString(body);
92
93 if (!request.ContainsKey("METHOD"))
94 return FailureResult();
95
96 string method = request["METHOD"].ToString();
97 request.Remove("METHOD");
98
99 m_log.DebugFormat("[OfflineIM.V2.Handler]: {0}", method);
100 switch (method)
101 {
102 case "GET":
103 return HandleGet(request);
104 case "STORE":
105 return HandleStore(request);
106 }
107 m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method);
108 }
109 catch (Exception e)
110 {
111 m_log.DebugFormat("[OFFLINE IM HANDLER]: Exception {0}", e.StackTrace);
112 }
113
114 return FailureResult();
115 }
116
117 byte[] HandleStore(Dictionary<string, object> request)
118 {
119 Dictionary<string, object> result = new Dictionary<string, object>();
120
121 GridInstantMessage im = OfflineIMDataUtils.GridInstantMessage(request);
122
123 string reason = string.Empty;
124
125 bool success = m_OfflineIMService.StoreMessage(im, out reason);
126
127 result["RESULT"] = success.ToString();
128 if (!success)
129 result["REASON"] = reason;
130
131 string xmlString = ServerUtils.BuildXmlResponse(result);
132
133 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
134 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
135 }
136
137 byte[] HandleGet(Dictionary<string, object> request)
138 {
139 Dictionary<string, object> result = new Dictionary<string, object>();
140
141 if (!request.ContainsKey("PrincipalID"))
142 NullResult(result, "Bad network data");
143 else
144 {
145 UUID principalID = new UUID(request["PrincipalID"].ToString());
146 List<GridInstantMessage> ims = m_OfflineIMService.GetMessages(principalID);
147
148 Dictionary<string, object> dict = new Dictionary<string, object>();
149 int i = 0;
150 foreach (GridInstantMessage m in ims)
151 dict["im-" + i++] = OfflineIMDataUtils.GridInstantMessage(m);
152
153 result["RESULT"] = dict;
154 }
155
156 string xmlString = ServerUtils.BuildXmlResponse(result);
157
158 //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
159 return Util.UTF8NoBomEncoding.GetBytes(xmlString);
160 }
161
162 #region Helpers
163
164 private void NullResult(Dictionary<string, object> result, string reason)
165 {
166 result["RESULT"] = "NULL";
167 result["REASON"] = reason;
168 }
169
170 private byte[] FailureResult()
171 {
172 return BoolResult(false);
173 }
174
175 private byte[] SuccessResult()
176 {
177 return BoolResult(true);
178 }
179
180 private byte[] BoolResult(bool value)
181 {
182 XmlDocument doc = new XmlDocument();
183
184 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
185 "", "");
186
187 doc.AppendChild(xmlnode);
188
189 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
190 "");
191
192 doc.AppendChild(rootElement);
193
194 XmlElement result = doc.CreateElement("", "RESULT", "");
195 result.AppendChild(doc.CreateTextNode(value.ToString()));
196
197 rootElement.AppendChild(result);
198
199 return DocToBytes(doc);
200 }
201
202 private byte[] DocToBytes(XmlDocument doc)
203 {
204 MemoryStream ms = new MemoryStream();
205 XmlTextWriter xw = new XmlTextWriter(ms, null);
206 xw.Formatting = Formatting.Indented;
207 doc.WriteTo(xw);
208 xw.Flush();
209
210 return ms.ToArray();
211 }
212
213 #endregion
214 }
215}
diff --git a/OpenSim/Addons/OfflineIM/Resources/IM_Store.migrations b/OpenSim/Addons/OfflineIM/Resources/IM_Store.migrations
new file mode 100644
index 0000000..d1cff8e
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Resources/IM_Store.migrations
@@ -0,0 +1,23 @@
1:VERSION 1 # --------------------------
2
3BEGIN;
4
5CREATE TABLE `im_offline` (
6 `ID` MEDIUMINT NOT NULL AUTO_INCREMENT,
7 `PrincipalID` char(36) NOT NULL default '',
8 `Message` text NOT NULL,
9 `TMStamp` timestamp NOT NULL,
10 PRIMARY KEY (`ID`),
11 KEY `PrincipalID` (`PrincipalID`)
12) ENGINE=MyISAM;
13
14COMMIT;
15
16:VERSION 2 # --------------------------
17
18BEGIN;
19
20INSERT INTO `im_offline` SELECT * from `diva_im_offline`;
21DROP TABLE `diva_im_offline`;
22
23COMMIT; \ No newline at end of file
diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs
new file mode 100644
index 0000000..6ba022c
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs
@@ -0,0 +1,131 @@
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
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Runtime.Serialization;
33using System.Text;
34using System.Timers;
35using System.Xml;
36using System.Xml.Serialization;
37using log4net;
38using Nini.Config;
39
40using OpenMetaverse;
41using OpenSim.Data;
42using OpenSim.Framework;
43using OpenSim.Services.Interfaces;
44
45namespace OpenSim.OfflineIM
46{
47 public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 private const int MAX_IM = 25;
51
52 private XmlSerializer m_serializer;
53 private static bool m_Initialized = false;
54
55 public OfflineIMService(IConfigSource config)
56 : base(config)
57 {
58 m_serializer = new XmlSerializer(typeof(GridInstantMessage));
59 if (!m_Initialized)
60 {
61 m_Database.DeleteOld();
62 m_Initialized = true;
63 }
64 }
65
66 public List<GridInstantMessage> GetMessages(UUID principalID)
67 {
68 List<GridInstantMessage> ims = new List<GridInstantMessage>();
69
70 OfflineIMData[] messages = m_Database.Get("PrincipalID", principalID.ToString());
71
72 if (messages == null || (messages != null && messages.Length == 0))
73 return ims;
74
75 foreach (OfflineIMData m in messages)
76 {
77 using (MemoryStream mstream = new MemoryStream(Encoding.UTF8.GetBytes(m.Data["Message"])))
78 {
79 GridInstantMessage im = (GridInstantMessage)m_serializer.Deserialize(mstream);
80 ims.Add(im);
81 }
82 }
83
84 // Then, delete them
85 m_Database.Delete("PrincipalID", principalID.ToString());
86
87 return ims;
88 }
89
90 public bool StoreMessage(GridInstantMessage im, out string reason)
91 {
92 reason = string.Empty;
93
94 // TODO Check limits
95 UUID principalID = new UUID(im.toAgentID);
96 long count = m_Database.GetCount("PrincipalID", principalID.ToString());
97 if (count >= MAX_IM)
98 {
99 reason = "Number of offline IMs has maxed out";
100 return false;
101 }
102
103 string imXml = string.Empty;
104 using (MemoryStream mstream = new MemoryStream())
105 {
106 XmlWriterSettings settings = new XmlWriterSettings();
107 settings.Encoding = Encoding.UTF8;
108
109 using (XmlWriter writer = XmlWriter.Create(mstream, settings))
110 {
111 m_serializer.Serialize(writer, im);
112 writer.Flush();
113
114 mstream.Position = 0;
115 using (StreamReader sreader = new StreamReader(mstream))
116 {
117 imXml = sreader.ReadToEnd();
118 }
119 }
120 }
121
122 OfflineIMData data = new OfflineIMData();
123 data.PrincipalID = principalID;
124 data.Data = new Dictionary<string, string>();
125 data.Data["Message"] = imXml;
126
127 return m_Database.Store(data);
128
129 }
130 }
131}
diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs
new file mode 100644
index 0000000..3376be4
--- /dev/null
+++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs
@@ -0,0 +1,83 @@
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 Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Data;
33using OpenSim.Services.Interfaces;
34using OpenSim.Services.Base;
35
36namespace OpenSim.OfflineIM
37{
38 public class OfflineIMServiceBase : ServiceBase
39 {
40 protected IOfflineIMData m_Database = null;
41
42 public OfflineIMServiceBase(IConfigSource config)
43 : base(config)
44 {
45 string dllName = String.Empty;
46 string connString = String.Empty;
47 string realm = "im_offline";
48
49 //
50 // Try reading the [DatabaseService] section, if it exists
51 //
52 IConfig dbConfig = config.Configs["DatabaseService"];
53 if (dbConfig != null)
54 {
55 if (dllName == String.Empty)
56 dllName = dbConfig.GetString("StorageProvider", String.Empty);
57 if (connString == String.Empty)
58 connString = dbConfig.GetString("ConnectionString", String.Empty);
59 }
60
61 //
62 // [Messaging] section overrides [DatabaseService], if it exists
63 //
64 IConfig imConfig = config.Configs["Messaging"];
65 if (imConfig != null)
66 {
67 dllName = imConfig.GetString("StorageProvider", dllName);
68 connString = imConfig.GetString("ConnectionString", connString);
69 realm = imConfig.GetString("Realm", realm);
70 }
71
72 //
73 // We tried, but this doesn't exist. We can't proceed.
74 //
75 if (dllName.Equals(String.Empty))
76 throw new Exception("No StorageProvider configured");
77
78 m_Database = LoadPlugin<IOfflineIMData>(dllName, new Object[] { connString, realm });
79 if (m_Database == null)
80 throw new Exception("Could not find a storage interface in the given module " + dllName);
81 }
82 }
83}