aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services')
-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
6 files changed, 522 insertions, 0 deletions
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}