aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs268
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs280
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs48
-rw-r--r--OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs58
-rw-r--r--OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs129
-rw-r--r--OpenSim/Services/HypergridService/HGInstantMessageService.cs311
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs11
-rw-r--r--OpenSim/Services/Interfaces/IGatekeeperService.cs8
-rw-r--r--OpenSim/Services/Interfaces/ISimulatorSocialService.cs5
9 files changed, 1118 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
new file mode 100644
index 0000000..9ba4e49
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
@@ -0,0 +1,268 @@
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;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using Mono.Addins;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using GridRegion = OpenSim.Services.Interfaces.GridRegion;
41using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
42using OpenSim.Services.Interfaces;
43using OpenSim.Services.Connectors.InstantMessage;
44using OpenSim.Services.Connectors.Hypergrid;
45using OpenSim.Server.Handlers.Hypergrid;
46
47namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
48{
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
50 public class HGMessageTransferModule : ISharedRegionModule, IMessageTransferModule, IInstantMessageSimConnector
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 protected bool m_Enabled = false;
55 protected List<Scene> m_Scenes = new List<Scene>();
56
57 protected IInstantMessage m_IMService;
58 protected Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>();
59
60 public event UndeliveredMessage OnUndeliveredMessage;
61
62 IUserManagement m_uMan;
63 IUserManagement UserManagementModule
64 {
65 get
66 {
67 if (m_uMan == null)
68 m_uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>();
69 return m_uMan;
70 }
71 }
72
73 public virtual void Initialise(IConfigSource config)
74 {
75 IConfig cnf = config.Configs["Messaging"];
76 if (cnf != null && cnf.GetString(
77 "MessageTransferModule", "MessageTransferModule") != Name)
78 {
79 m_log.Debug("[HG MESSAGE TRANSFER]: Disabled by configuration");
80 return;
81 }
82
83 InstantMessageServerConnector imServer = new InstantMessageServerConnector(config, MainServer.Instance, this);
84 m_IMService = imServer.GetService();
85 m_Enabled = true;
86 }
87
88 public virtual void AddRegion(Scene scene)
89 {
90 if (!m_Enabled)
91 return;
92
93 lock (m_Scenes)
94 {
95 m_log.DebugFormat("[HG MESSAGE TRANSFER]: Message transfer module {0} active", Name);
96 scene.RegisterModuleInterface<IMessageTransferModule>(this);
97 m_Scenes.Add(scene);
98 }
99 }
100
101 public virtual void PostInitialise()
102 {
103 if (!m_Enabled)
104 return;
105
106 }
107
108 public virtual void RegionLoaded(Scene scene)
109 {
110 }
111
112 public virtual void RemoveRegion(Scene scene)
113 {
114 if (!m_Enabled)
115 return;
116
117 lock (m_Scenes)
118 {
119 m_Scenes.Remove(scene);
120 }
121 }
122
123 public virtual void Close()
124 {
125 }
126
127 public virtual string Name
128 {
129 get { return "HGMessageTransferModule"; }
130 }
131
132 public virtual Type ReplaceableInterface
133 {
134 get { return null; }
135 }
136
137 public void SendInstantMessage(GridInstantMessage im, MessageResultNotification result)
138 {
139 UUID toAgentID = new UUID(im.toAgentID);
140
141 // Try root avatar only first
142 foreach (Scene scene in m_Scenes)
143 {
144 if (scene.Entities.ContainsKey(toAgentID) &&
145 scene.Entities[toAgentID] is ScenePresence)
146 {
147// m_log.DebugFormat(
148// "[INSTANT MESSAGE]: Looking for root agent {0} in {1}",
149// toAgentID.ToString(), scene.RegionInfo.RegionName);
150
151 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
152 if (!user.IsChildAgent)
153 {
154 // Local message
155// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID);
156 user.ControllingClient.SendInstantMessage(im);
157
158 // Message sent
159 result(true);
160 return;
161 }
162 }
163 }
164
165 // try child avatar second
166 foreach (Scene scene in m_Scenes)
167 {
168// m_log.DebugFormat(
169// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
170
171 if (scene.Entities.ContainsKey(toAgentID) &&
172 scene.Entities[toAgentID] is ScenePresence)
173 {
174 // Local message
175 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
176
177// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID);
178 user.ControllingClient.SendInstantMessage(im);
179
180 // Message sent
181 result(true);
182 return;
183 }
184 }
185
186// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
187 // Is the user a local user?
188 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, toAgentID);
189 string url = string.Empty;
190 PresenceInfo upd;
191 if (account == null) // foreign user
192 url = UserManagementModule.GetUserServerURL(toAgentID, "IMServerURI");
193
194 Util.FireAndForget(delegate
195 {
196 bool success = m_IMService.OutgoingInstantMessage(im, url);
197 result(success);
198 });
199
200 return;
201 }
202
203 protected bool SendIMToScene(GridInstantMessage gim, UUID toAgentID)
204 {
205 bool successful = false;
206 foreach (Scene scene in m_Scenes)
207 {
208 if (scene.Entities.ContainsKey(toAgentID) &&
209 scene.Entities[toAgentID] is ScenePresence)
210 {
211 ScenePresence user =
212 (ScenePresence)scene.Entities[toAgentID];
213
214 if (!user.IsChildAgent)
215 {
216 scene.EventManager.TriggerIncomingInstantMessage(gim);
217 successful = true;
218 }
219 }
220 }
221 if (!successful)
222 {
223 // If the message can't be delivered to an agent, it
224 // is likely to be a group IM. On a group IM, the
225 // imSessionID = toAgentID = group id. Raise the
226 // unhandled IM event to give the groups module
227 // a chance to pick it up. We raise that in a random
228 // scene, since the groups module is shared.
229 //
230 m_Scenes[0].EventManager.TriggerUnhandledInstantMessage(gim);
231 }
232
233 return successful;
234 }
235
236 protected void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result)
237 {
238 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage;
239
240 // If this event has handlers, then an IM from an agent will be
241 // considered delivered. This will suppress the error message.
242 //
243 if (handlerUndeliveredMessage != null)
244 {
245 handlerUndeliveredMessage(im);
246 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
247 result(true);
248 else
249 result(false);
250 return;
251 }
252
253 //m_log.DebugFormat("[INSTANT MESSAGE]: Undeliverable");
254 result(false);
255 }
256
257 #region IInstantMessageSimConnector
258 public bool SendInstantMessage(GridInstantMessage im)
259 {
260 //m_log.DebugFormat("[XXX] Hook SendInstantMessage {0}", im.message);
261 UUID agentID = new UUID(im.toAgentID);
262 return SendIMToScene(im, agentID);
263 }
264 #endregion
265
266
267 }
268}
diff --git a/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs
new file mode 100644
index 0000000..138313a
--- /dev/null
+++ b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs
@@ -0,0 +1,280 @@
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.Net;
32using System.Reflection;
33
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 GridRegion = OpenSim.Services.Interfaces.GridRegion;
41
42using log4net;
43using Nwc.XmlRpc;
44using OpenMetaverse;
45
46namespace OpenSim.Server.Handlers.Hypergrid
47{
48 public class InstantMessageServerConnector : ServiceConnector
49 {
50 private static readonly ILog m_log =
51 LogManager.GetLogger(
52 MethodBase.GetCurrentMethod().DeclaringType);
53
54 private IInstantMessage m_IMService;
55
56 public InstantMessageServerConnector(IConfigSource config, IHttpServer server) :
57 this(config, server, null)
58 {
59 }
60
61 public InstantMessageServerConnector(IConfigSource config, IHttpServer server, IInstantMessageSimConnector simConnector) :
62 base(config, server, String.Empty)
63 {
64 IConfig gridConfig = config.Configs["HGInstantMessageService"];
65 if (gridConfig != null)
66 {
67 string serviceDll = gridConfig.GetString("LocalServiceModule", string.Empty);
68
69 Object[] args = new Object[] { config, simConnector };
70 m_IMService = ServerUtils.LoadPlugin<IInstantMessage>(serviceDll, args);
71 }
72 if (m_IMService == null)
73 throw new Exception("InstantMessage server connector cannot proceed because of missing service");
74
75 MainServer.Instance.AddXmlRPCHandler("grid_instant_message", ProcessInstantMessage, false);
76
77 }
78
79 public IInstantMessage GetService()
80 {
81 return m_IMService;
82 }
83
84 protected virtual XmlRpcResponse ProcessInstantMessage(XmlRpcRequest request, IPEndPoint remoteClient)
85 {
86 bool successful = false;
87
88 try
89 {
90 // various rational defaults
91 UUID fromAgentID = UUID.Zero;
92 UUID toAgentID = UUID.Zero;
93 UUID imSessionID = UUID.Zero;
94 uint timestamp = 0;
95 string fromAgentName = "";
96 string message = "";
97 byte dialog = (byte)0;
98 bool fromGroup = false;
99 byte offline = (byte)0;
100 uint ParentEstateID = 0;
101 Vector3 Position = Vector3.Zero;
102 UUID RegionID = UUID.Zero;
103 byte[] binaryBucket = new byte[0];
104
105 float pos_x = 0;
106 float pos_y = 0;
107 float pos_z = 0;
108 //m_log.Info("Processing IM");
109
110
111 Hashtable requestData = (Hashtable)request.Params[0];
112 // Check if it's got all the data
113 if (requestData.ContainsKey("from_agent_id")
114 && requestData.ContainsKey("to_agent_id") && requestData.ContainsKey("im_session_id")
115 && requestData.ContainsKey("timestamp") && requestData.ContainsKey("from_agent_name")
116 && requestData.ContainsKey("message") && requestData.ContainsKey("dialog")
117 && requestData.ContainsKey("from_group")
118 && requestData.ContainsKey("offline") && requestData.ContainsKey("parent_estate_id")
119 && requestData.ContainsKey("position_x") && requestData.ContainsKey("position_y")
120 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
121 && requestData.ContainsKey("binary_bucket"))
122 {
123 // Do the easy way of validating the UUIDs
124 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
125 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
126 UUID.TryParse((string)requestData["im_session_id"], out imSessionID);
127 UUID.TryParse((string)requestData["region_id"], out RegionID);
128
129 try
130 {
131 timestamp = (uint)Convert.ToInt32((string)requestData["timestamp"]);
132 }
133 catch (ArgumentException)
134 {
135 }
136 catch (FormatException)
137 {
138 }
139 catch (OverflowException)
140 {
141 }
142
143 fromAgentName = (string)requestData["from_agent_name"];
144 message = (string)requestData["message"];
145 if (message == null)
146 message = string.Empty;
147
148 // Bytes don't transfer well over XMLRPC, so, we Base64 Encode them.
149 string requestData1 = (string)requestData["dialog"];
150 if (string.IsNullOrEmpty(requestData1))
151 {
152 dialog = 0;
153 }
154 else
155 {
156 byte[] dialogdata = Convert.FromBase64String(requestData1);
157 dialog = dialogdata[0];
158 }
159
160 if ((string)requestData["from_group"] == "TRUE")
161 fromGroup = true;
162
163 string requestData2 = (string)requestData["offline"];
164 if (String.IsNullOrEmpty(requestData2))
165 {
166 offline = 0;
167 }
168 else
169 {
170 byte[] offlinedata = Convert.FromBase64String(requestData2);
171 offline = offlinedata[0];
172 }
173
174 try
175 {
176 ParentEstateID = (uint)Convert.ToInt32((string)requestData["parent_estate_id"]);
177 }
178 catch (ArgumentException)
179 {
180 }
181 catch (FormatException)
182 {
183 }
184 catch (OverflowException)
185 {
186 }
187
188 try
189 {
190 pos_x = (uint)Convert.ToInt32((string)requestData["position_x"]);
191 }
192 catch (ArgumentException)
193 {
194 }
195 catch (FormatException)
196 {
197 }
198 catch (OverflowException)
199 {
200 }
201 try
202 {
203 pos_y = (uint)Convert.ToInt32((string)requestData["position_y"]);
204 }
205 catch (ArgumentException)
206 {
207 }
208 catch (FormatException)
209 {
210 }
211 catch (OverflowException)
212 {
213 }
214 try
215 {
216 pos_z = (uint)Convert.ToInt32((string)requestData["position_z"]);
217 }
218 catch (ArgumentException)
219 {
220 }
221 catch (FormatException)
222 {
223 }
224 catch (OverflowException)
225 {
226 }
227
228 Position = new Vector3(pos_x, pos_y, pos_z);
229
230 string requestData3 = (string)requestData["binary_bucket"];
231 if (string.IsNullOrEmpty(requestData3))
232 {
233 binaryBucket = new byte[0];
234 }
235 else
236 {
237 binaryBucket = Convert.FromBase64String(requestData3);
238 }
239
240 // Create a New GridInstantMessageObject the the data
241 GridInstantMessage gim = new GridInstantMessage();
242 gim.fromAgentID = fromAgentID.Guid;
243 gim.fromAgentName = fromAgentName;
244 gim.fromGroup = fromGroup;
245 gim.imSessionID = imSessionID.Guid;
246 gim.RegionID = UUID.Zero.Guid; // RegionID.Guid;
247 gim.timestamp = timestamp;
248 gim.toAgentID = toAgentID.Guid;
249 gim.message = message;
250 gim.dialog = dialog;
251 gim.offline = offline;
252 gim.ParentEstateID = ParentEstateID;
253 gim.Position = Position;
254 gim.binaryBucket = binaryBucket;
255
256 successful = m_IMService.IncomingInstantMessage(gim);
257
258 }
259 }
260 catch (Exception e)
261 {
262 m_log.Error("[INSTANT MESSAGE]: Caught unexpected exception:", e);
263 successful = false;
264 }
265
266 //Send response back to region calling if it was successful
267 // calling region uses this to know when to look up a user's location again.
268 XmlRpcResponse resp = new XmlRpcResponse();
269 Hashtable respdata = new Hashtable();
270 if (successful)
271 respdata["success"] = "TRUE";
272 else
273 respdata["success"] = "FALSE";
274 resp.Value = respdata;
275
276 return resp;
277 }
278
279 }
280}
diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
index e51fe0b..942d960 100644
--- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
+++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs
@@ -52,6 +52,7 @@ namespace OpenSim.Server.Handlers.Hypergrid
52// MethodBase.GetCurrentMethod().DeclaringType); 52// MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 private IUserAgentService m_HomeUsersService; 54 private IUserAgentService m_HomeUsersService;
55 private string[] m_AuthorizedCallers;
55 56
56 public UserAgentServerConnector(IConfigSource config, IHttpServer server) : 57 public UserAgentServerConnector(IConfigSource config, IHttpServer server) :
57 this(config, server, null) 58 this(config, server, null)
@@ -75,6 +76,10 @@ namespace OpenSim.Server.Handlers.Hypergrid
75 string loginServerIP = gridConfig.GetString("LoginServerIP", "127.0.0.1"); 76 string loginServerIP = gridConfig.GetString("LoginServerIP", "127.0.0.1");
76 bool proxy = gridConfig.GetBoolean("HasProxy", false); 77 bool proxy = gridConfig.GetBoolean("HasProxy", false);
77 78
79 string csv = gridConfig.GetString("AuthorizedCallers", "127.0.0.1");
80 csv = csv.Replace(" ", "");
81 m_AuthorizedCallers = csv.Split(',');
82
78 server.AddXmlRPCHandler("agent_is_coming_home", AgentIsComingHome, false); 83 server.AddXmlRPCHandler("agent_is_coming_home", AgentIsComingHome, false);
79 server.AddXmlRPCHandler("get_home_region", GetHomeRegion, false); 84 server.AddXmlRPCHandler("get_home_region", GetHomeRegion, false);
80 server.AddXmlRPCHandler("verify_agent", VerifyAgent, false); 85 server.AddXmlRPCHandler("verify_agent", VerifyAgent, false);
@@ -85,6 +90,8 @@ namespace OpenSim.Server.Handlers.Hypergrid
85 server.AddXmlRPCHandler("get_online_friends", GetOnlineFriends, false); 90 server.AddXmlRPCHandler("get_online_friends", GetOnlineFriends, false);
86 server.AddXmlRPCHandler("get_server_urls", GetServerURLs, false); 91 server.AddXmlRPCHandler("get_server_urls", GetServerURLs, false);
87 92
93 server.AddXmlRPCHandler("locate_user", LocateUser, false);
94
88 server.AddHTTPHandler("/homeagent/", new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy).Handler); 95 server.AddHTTPHandler("/homeagent/", new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy).Handler);
89 } 96 }
90 97
@@ -306,5 +313,46 @@ namespace OpenSim.Server.Handlers.Hypergrid
306 313
307 } 314 }
308 315
316 /// <summary>
317 /// Locates the user.
318 /// This is a sensitive operation, only authorized IP addresses can perform it.
319 /// </summary>
320 /// <param name="request"></param>
321 /// <param name="remoteClient"></param>
322 /// <returns></returns>
323 public XmlRpcResponse LocateUser(XmlRpcRequest request, IPEndPoint remoteClient)
324 {
325 Hashtable hash = new Hashtable();
326
327 bool authorized = false;
328 foreach (string s in m_AuthorizedCallers)
329 if (s == remoteClient.Address.ToString())
330 {
331 authorized = true;
332 break;
333 }
334
335 if (authorized)
336 {
337 Hashtable requestData = (Hashtable)request.Params[0];
338 //string host = (string)requestData["host"];
339 //string portstr = (string)requestData["port"];
340 if (requestData.ContainsKey("userID"))
341 {
342 string userID_str = (string)requestData["userID"];
343 UUID userID = UUID.Zero;
344 UUID.TryParse(userID_str, out userID);
345
346 string url = m_HomeUsersService.LocateUser(userID);
347 if (url != string.Empty)
348 hash["URL"] = url;
349 }
350 }
351
352 XmlRpcResponse response = new XmlRpcResponse();
353 response.Value = hash;
354 return response;
355
356 }
309 } 357 }
310} 358}
diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs
index 265bacf..50036b3 100644
--- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs
@@ -560,6 +560,64 @@ namespace OpenSim.Services.Connectors.Hypergrid
560 return serverURLs; 560 return serverURLs;
561 } 561 }
562 562
563 public string LocateUser(UUID userID)
564 {
565 Hashtable hash = new Hashtable();
566 hash["userID"] = userID.ToString();
567
568 IList paramList = new ArrayList();
569 paramList.Add(hash);
570
571 XmlRpcRequest request = new XmlRpcRequest("locate_user", paramList);
572 string reason = string.Empty;
573
574 // Send and get reply
575 string url = string.Empty;
576 XmlRpcResponse response = null;
577 try
578 {
579 response = request.Send(m_ServerURL, 10000);
580 }
581 catch (Exception e)
582 {
583 m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL);
584 reason = "Exception: " + e.Message;
585 return url;
586 }
587
588 if (response.IsFault)
589 {
590 m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString);
591 reason = "XMLRPC Fault";
592 return url;
593 }
594
595 hash = (Hashtable)response.Value;
596 //foreach (Object o in hash)
597 // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value);
598 try
599 {
600 if (hash == null)
601 {
602 m_log.ErrorFormat("[USER AGENT CONNECTOR]: LocateUser Got null response from {0}! THIS IS BAAAAD", m_ServerURL);
603 reason = "Internal error 1";
604 return url;
605 }
606
607 // Here's the actual response
608 if (hash.ContainsKey("URL"))
609 url = hash["URL"].ToString();
610
611 }
612 catch (Exception e)
613 {
614 m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on LocateUser response.");
615 reason = "Exception: " + e.Message;
616 }
617
618 return url;
619 }
620
563 private bool GetBoolResponse(XmlRpcRequest request, out string reason) 621 private bool GetBoolResponse(XmlRpcRequest request, out string reason)
564 { 622 {
565 //m_log.Debug("[USER AGENT CONNECTOR]: GetBoolResponse from/to " + m_ServerURL); 623 //m_log.Debug("[USER AGENT CONNECTOR]: GetBoolResponse from/to " + m_ServerURL);
diff --git a/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs
new file mode 100644
index 0000000..65ee7c7
--- /dev/null
+++ b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs
@@ -0,0 +1,129 @@
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;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32
33using OpenMetaverse;
34using Nwc.XmlRpc;
35using log4net;
36
37using OpenSim.Framework;
38
39namespace OpenSim.Services.Connectors.InstantMessage
40{
41 public class InstantMessageServiceConnector
42 {
43 private static readonly ILog m_log =
44 LogManager.GetLogger(
45 MethodBase.GetCurrentMethod().DeclaringType);
46
47 /// <summary>
48 /// This actually does the XMLRPC Request
49 /// </summary>
50 /// <param name="url">URL we pull the data out of to send the request to</param>
51 /// <param name="im">The Instant Message </param>
52 /// <returns>Bool if the message was successfully delivered at the other side.</returns>
53 public static bool SendInstantMessage(string url, GridInstantMessage im)
54 {
55 Hashtable xmlrpcdata = ConvertGridInstantMessageToXMLRPC(im);
56 xmlrpcdata["region_handle"] = 0;
57
58 ArrayList SendParams = new ArrayList();
59 SendParams.Add(xmlrpcdata);
60 XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams);
61 try
62 {
63
64 XmlRpcResponse GridResp = GridReq.Send(url, 3000);
65
66 Hashtable responseData = (Hashtable)GridResp.Value;
67
68 if (responseData.ContainsKey("success"))
69 {
70 if ((string)responseData["success"] == "TRUE")
71 {
72 m_log.DebugFormat("[XXX] Success");
73 return true;
74 }
75 else
76 {
77 m_log.DebugFormat("[XXX] Fail");
78 return false;
79 }
80 }
81 else
82 {
83 return false;
84 }
85 }
86 catch (WebException e)
87 {
88 m_log.ErrorFormat("[GRID INSTANT MESSAGE]: Error sending message to {0} the host didn't respond " + e.ToString(), url);
89 }
90
91 return false;
92 }
93
94 /// <summary>
95 /// Takes a GridInstantMessage and converts it into a Hashtable for XMLRPC
96 /// </summary>
97 /// <param name="msg">The GridInstantMessage object</param>
98 /// <returns>Hashtable containing the XMLRPC request</returns>
99 protected static Hashtable ConvertGridInstantMessageToXMLRPC(GridInstantMessage msg)
100 {
101 Hashtable gim = new Hashtable();
102 gim["from_agent_id"] = msg.fromAgentID.ToString();
103 // Kept for compatibility
104 gim["from_agent_session"] = UUID.Zero.ToString();
105 gim["to_agent_id"] = msg.toAgentID.ToString();
106 gim["im_session_id"] = msg.imSessionID.ToString();
107 gim["timestamp"] = msg.timestamp.ToString();
108 gim["from_agent_name"] = msg.fromAgentName;
109 gim["message"] = msg.message;
110 byte[] dialogdata = new byte[1]; dialogdata[0] = msg.dialog;
111 gim["dialog"] = Convert.ToBase64String(dialogdata, Base64FormattingOptions.None);
112
113 if (msg.fromGroup)
114 gim["from_group"] = "TRUE";
115 else
116 gim["from_group"] = "FALSE";
117 byte[] offlinedata = new byte[1]; offlinedata[0] = msg.offline;
118 gim["offline"] = Convert.ToBase64String(offlinedata, Base64FormattingOptions.None);
119 gim["parent_estate_id"] = msg.ParentEstateID.ToString();
120 gim["position_x"] = msg.Position.X.ToString();
121 gim["position_y"] = msg.Position.Y.ToString();
122 gim["position_z"] = msg.Position.Z.ToString();
123 gim["region_id"] = msg.RegionID.ToString();
124 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket, Base64FormattingOptions.None);
125 return gim;
126 }
127
128 }
129}
diff --git a/OpenSim/Services/HypergridService/HGInstantMessageService.cs b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
new file mode 100644
index 0000000..6178ca1
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
@@ -0,0 +1,311 @@
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.Net;
31using System.Reflection;
32
33using OpenSim.Framework;
34using OpenSim.Services.Connectors.Friends;
35using OpenSim.Services.Connectors.Hypergrid;
36using OpenSim.Services.Interfaces;
37using OpenSim.Services.Connectors.InstantMessage;
38using GridRegion = OpenSim.Services.Interfaces.GridRegion;
39using OpenSim.Server.Base;
40using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
41
42using OpenMetaverse;
43using log4net;
44using Nini.Config;
45
46namespace OpenSim.Services.HypergridService
47{
48 /// <summary>
49 /// Inter-grid IM
50 /// </summary>
51 public class HGInstantMessageService : IInstantMessage
52 {
53 private static readonly ILog m_log =
54 LogManager.GetLogger(
55 MethodBase.GetCurrentMethod().DeclaringType);
56
57 private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours
58
59 static bool m_Initialized = false;
60
61 protected static IGridService m_GridService;
62 protected static IPresenceService m_PresenceService;
63 protected static IUserAgentService m_UserAgentService;
64
65 protected static IInstantMessageSimConnector m_IMSimConnector;
66
67 protected Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>();
68 private ExpiringCache<UUID, GridRegion> m_RegionCache;
69
70 public HGInstantMessageService(IConfigSource config)
71 : this(config, null)
72 {
73 }
74
75 public HGInstantMessageService(IConfigSource config, IInstantMessageSimConnector imConnector)
76 {
77 if (imConnector != null)
78 m_IMSimConnector = imConnector;
79
80 if (!m_Initialized)
81 {
82 m_Initialized = true;
83
84 m_log.DebugFormat("[HG IM SERVICE]: Starting...");
85
86 IConfig serverConfig = config.Configs["HGInstantMessageService"];
87 if (serverConfig == null)
88 throw new Exception(String.Format("No section HGInstantMessageService in config file"));
89
90 string gridService = serverConfig.GetString("GridService", String.Empty);
91 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
92 string userAgentService = serverConfig.GetString("UserAgentService", String.Empty);
93
94 if (gridService == string.Empty || presenceService == string.Empty)
95 throw new Exception(String.Format("Incomplete specifications, InstantMessage Service cannot function."));
96
97 Object[] args = new Object[] { config };
98 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
99 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
100 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(userAgentService, args);
101
102 m_RegionCache = new ExpiringCache<UUID, GridRegion>();
103
104 }
105 }
106
107 public bool IncomingInstantMessage(GridInstantMessage im)
108 {
109 m_log.DebugFormat("[HG IM SERVICE]: Received message {0} from {1} to {2}", im.message, im.fromAgentID, im.toAgentID);
110 UUID toAgentID = new UUID(im.toAgentID);
111
112 if (m_IMSimConnector != null)
113 {
114 m_log.DebugFormat("[XXX] SendIMToRegion local im connector");
115 return m_IMSimConnector.SendInstantMessage(im);
116 }
117 else
118 return TrySendInstantMessage(im, "", true);
119 }
120
121 public bool OutgoingInstantMessage(GridInstantMessage im, string url)
122 {
123 m_log.DebugFormat("[HG IM SERVICE]: Sending message {0} from {1} to {2}@{3}", im.message, im.fromAgentID, im.toAgentID, url);
124 if (url != string.Empty)
125 return TrySendInstantMessage(im, url, true);
126 else
127 {
128 PresenceInfo upd = new PresenceInfo();
129 upd.RegionID = UUID.Zero;
130 return TrySendInstantMessage(im, upd, true);
131 }
132 }
133
134 protected bool TrySendInstantMessage(GridInstantMessage im, object previousLocation, bool firstTime)
135 {
136 UUID toAgentID = new UUID(im.toAgentID);
137
138 PresenceInfo upd = null;
139 string url = string.Empty;
140
141 bool lookupAgent = false;
142
143 lock (m_UserLocationMap)
144 {
145 if (m_UserLocationMap.ContainsKey(toAgentID))
146 {
147 object o = m_UserLocationMap[toAgentID];
148 if (o is PresenceInfo)
149 upd = (PresenceInfo)o;
150 else if (o is string)
151 url = (string)o;
152
153 // We need to compare the current location with the previous
154 // or the recursive loop will never end because it will never try to lookup the agent again
155 if (!firstTime)
156 {
157 lookupAgent = true;
158 }
159 }
160 else
161 {
162 lookupAgent = true;
163 }
164 }
165
166 m_log.DebugFormat("[XXX] Neeed lookup ? {0}", (lookupAgent ? "yes" : "no"));
167
168 // Are we needing to look-up an agent?
169 if (lookupAgent)
170 {
171 bool isPresent = false;
172 // Non-cached user agent lookup.
173 PresenceInfo[] presences = m_PresenceService.GetAgents(new string[] { toAgentID.ToString() });
174 if (presences != null && presences.Length > 0)
175 {
176 foreach (PresenceInfo p in presences)
177 {
178 if (p.RegionID != UUID.Zero)
179 {
180 upd = p;
181 break;
182 }
183 else
184 isPresent = true;
185 }
186 }
187
188 if (upd == null && isPresent)
189 {
190 // Let's check with the UAS if the user is elsewhere
191 url = m_UserAgentService.LocateUser(toAgentID);
192 }
193
194 if (upd != null || url != string.Empty)
195 {
196 // check if we've tried this before..
197 // This is one way to end the recursive loop
198 //
199 if (!firstTime && ((previousLocation is PresenceInfo && upd != null && upd.RegionID == ((PresenceInfo)previousLocation).RegionID) ||
200 (previousLocation is string && previousLocation.Equals(url))))
201 {
202 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
203 m_log.DebugFormat("[XXX] Fail 1 {0} {1}", previousLocation, url);
204
205 return false;
206 }
207 }
208 }
209
210 if (upd != null)
211 {
212 // ok, the user is around somewhere. Let's send back the reply with "success"
213 // even though the IM may still fail. Just don't keep the caller waiting for
214 // the entire time we're trying to deliver the IM
215 return SendIMToRegion(upd, im, toAgentID);
216 }
217 else if (url != string.Empty)
218 {
219 // ok, the user is around somewhere. Let's send back the reply with "success"
220 // even though the IM may still fail. Just don't keep the caller waiting for
221 // the entire time we're trying to deliver the IM
222 return ForwardIMToGrid(url, im, toAgentID);
223 }
224 else if (firstTime && previousLocation is string && (string)previousLocation != string.Empty)
225 {
226 return ForwardIMToGrid((string)previousLocation, im, toAgentID);
227 }
228 else
229 m_log.DebugFormat("[HG IM SERVICE]: Unable to locate user {0}", toAgentID);
230 return false;
231 }
232
233 bool SendIMToRegion(PresenceInfo upd, GridInstantMessage im, UUID toAgentID)
234 {
235 bool imresult = false;
236 GridRegion reginfo = null;
237 if (!m_RegionCache.TryGetValue(upd.RegionID, out reginfo))
238 {
239 reginfo = m_GridService.GetRegionByUUID(UUID.Zero /*!!!*/, upd.RegionID);
240 if (reginfo != null)
241 m_RegionCache.AddOrUpdate(upd.RegionID, reginfo, CACHE_EXPIRATION_SECONDS);
242 }
243
244 if (reginfo != null)
245 imresult = InstantMessageServiceConnector.SendInstantMessage(reginfo.ServerURI, im);
246 else
247 return false;
248
249 if (imresult)
250 {
251 // IM delivery successful, so store the Agent's location in our local cache.
252 lock (m_UserLocationMap)
253 {
254 if (m_UserLocationMap.ContainsKey(toAgentID))
255 {
256 m_UserLocationMap[toAgentID] = upd;
257 }
258 else
259 {
260 m_UserLocationMap.Add(toAgentID, upd);
261 }
262 }
263 return true;
264 }
265 else
266 {
267 // try again, but lookup user this time.
268 // Warning, this must call the Async version
269 // of this method or we'll be making thousands of threads
270 // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
271 // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
272
273 // This is recursive!!!!!
274 return TrySendInstantMessage(im, upd, false);
275 }
276 }
277
278 bool ForwardIMToGrid(string url, GridInstantMessage im, UUID toAgentID)
279 {
280 if (InstantMessageServiceConnector.SendInstantMessage(url, im))
281 {
282 // IM delivery successful, so store the Agent's location in our local cache.
283 lock (m_UserLocationMap)
284 {
285 if (m_UserLocationMap.ContainsKey(toAgentID))
286 {
287 m_UserLocationMap[toAgentID] = url;
288 }
289 else
290 {
291 m_UserLocationMap.Add(toAgentID, url);
292 }
293 }
294
295 return true;
296 }
297 else
298 {
299 // try again, but lookup user this time.
300 // Warning, this must call the Async version
301 // of this method or we'll be making thousands of threads
302 // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
303 // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
304
305 // This is recursive!!!!!
306 return TrySendInstantMessage(im, url, false);
307 }
308
309 }
310 }
311}
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs
index e63f941..59ad043 100644
--- a/OpenSim/Services/HypergridService/UserAgentService.cs
+++ b/OpenSim/Services/HypergridService/UserAgentService.cs
@@ -474,6 +474,17 @@ namespace OpenSim.Services.HypergridService
474 474
475 return new Dictionary<string, object>(); 475 return new Dictionary<string, object>();
476 } 476 }
477
478 public string LocateUser(UUID userID)
479 {
480 foreach (TravelingAgentInfo t in m_TravelingAgents.Values)
481 {
482 if (t.UserID == userID)
483 return t.GridExternalName;
484 }
485
486 return string.Empty;
487 }
477 } 488 }
478 489
479 class TravelingAgentInfo 490 class TravelingAgentInfo
diff --git a/OpenSim/Services/Interfaces/IGatekeeperService.cs b/OpenSim/Services/Interfaces/IGatekeeperService.cs
index f1860cc..ffab9ea 100644
--- a/OpenSim/Services/Interfaces/IGatekeeperService.cs
+++ b/OpenSim/Services/Interfaces/IGatekeeperService.cs
@@ -56,6 +56,8 @@ namespace OpenSim.Services.Interfaces
56 GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt); 56 GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt);
57 Dictionary<string, object> GetServerURLs(UUID userID); 57 Dictionary<string, object> GetServerURLs(UUID userID);
58 58
59 string LocateUser(UUID userID);
60
59 void StatusNotification(List<string> friends, UUID userID, bool online); 61 void StatusNotification(List<string> friends, UUID userID, bool online);
60 List<UUID> GetOnlineFriends(UUID userID, List<string> friends); 62 List<UUID> GetOnlineFriends(UUID userID, List<string> friends);
61 63
@@ -63,4 +65,10 @@ namespace OpenSim.Services.Interfaces
63 bool VerifyAgent(UUID sessionID, string token); 65 bool VerifyAgent(UUID sessionID, string token);
64 bool VerifyClient(UUID sessionID, string reportedIP); 66 bool VerifyClient(UUID sessionID, string reportedIP);
65 } 67 }
68
69 public interface IInstantMessage
70 {
71 bool IncomingInstantMessage(GridInstantMessage im);
72 bool OutgoingInstantMessage(GridInstantMessage im, string url);
73 }
66} 74}
diff --git a/OpenSim/Services/Interfaces/ISimulatorSocialService.cs b/OpenSim/Services/Interfaces/ISimulatorSocialService.cs
index 0b7aefc..df9e7e7 100644
--- a/OpenSim/Services/Interfaces/ISimulatorSocialService.cs
+++ b/OpenSim/Services/Interfaces/ISimulatorSocialService.cs
@@ -37,4 +37,9 @@ namespace OpenSim.Services.Interfaces
37 { 37 {
38 bool StatusNotify(UUID userID, UUID friendID, bool online); 38 bool StatusNotify(UUID userID, UUID friendID, bool online);
39 } 39 }
40
41 public interface IInstantMessageSimConnector
42 {
43 bool SendInstantMessage(GridInstantMessage im);
44 }
40} 45}