aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/HypergridService
diff options
context:
space:
mode:
authorUbitUmarov2015-09-01 11:43:07 +0100
committerUbitUmarov2015-09-01 11:43:07 +0100
commitfb78b182520fc9bb0f971afd0322029c70278ea6 (patch)
treeb4e30d383938fdeef8c92d1d1c2f44bb61d329bd /OpenSim/Services/HypergridService
parentlixo (diff)
parentMantis #7713: fixed bug introduced by 1st MOSES patch. (diff)
downloadopensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.zip
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.gz
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.bz2
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.xz
Merge remote-tracking branch 'os/master'
Diffstat (limited to 'OpenSim/Services/HypergridService')
-rw-r--r--OpenSim/Services/HypergridService/GatekeeperService.cs559
-rw-r--r--OpenSim/Services/HypergridService/HGAssetService.cs193
-rw-r--r--OpenSim/Services/HypergridService/HGFSAssetService.cs189
-rw-r--r--OpenSim/Services/HypergridService/HGFriendsService.cs409
-rw-r--r--OpenSim/Services/HypergridService/HGInstantMessageService.cs376
-rw-r--r--OpenSim/Services/HypergridService/HGInventoryService.cs321
-rw-r--r--OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs652
-rw-r--r--OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Services/HypergridService/UserAccountCache.cs111
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs746
-rw-r--r--OpenSim/Services/HypergridService/UserAgentServiceBase.cs84
11 files changed, 3673 insertions, 0 deletions
diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs
new file mode 100644
index 0000000..44b26d5
--- /dev/null
+++ b/OpenSim/Services/HypergridService/GatekeeperService.cs
@@ -0,0 +1,559 @@
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;
32using System.Text.RegularExpressions;
33
34using OpenSim.Framework;
35using OpenSim.Services.Interfaces;
36using GridRegion = OpenSim.Services.Interfaces.GridRegion;
37using OpenSim.Server.Base;
38using OpenSim.Services.Connectors.Hypergrid;
39
40using OpenMetaverse;
41
42using Nini.Config;
43using log4net;
44
45namespace OpenSim.Services.HypergridService
46{
47 public class GatekeeperService : IGatekeeperService
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(
51 MethodBase.GetCurrentMethod().DeclaringType);
52
53 private static bool m_Initialized = false;
54
55 private static IGridService m_GridService;
56 private static IPresenceService m_PresenceService;
57 private static IUserAccountService m_UserAccountService;
58 private static IUserAgentService m_UserAgentService;
59 private static ISimulationService m_SimulationService;
60 private static IGridUserService m_GridUserService;
61 private static IBansService m_BansService;
62
63 private static string m_AllowedClients = string.Empty;
64 private static string m_DeniedClients = string.Empty;
65 private static bool m_ForeignAgentsAllowed = true;
66 private static List<string> m_ForeignsAllowedExceptions = new List<string>();
67 private static List<string> m_ForeignsDisallowedExceptions = new List<string>();
68
69 private static UUID m_ScopeID;
70 private static bool m_AllowTeleportsToAnyRegion;
71 private static string m_ExternalName;
72 private static Uri m_Uri;
73 private static GridRegion m_DefaultGatewayRegion;
74
75 public GatekeeperService(IConfigSource config, ISimulationService simService)
76 {
77 if (!m_Initialized)
78 {
79 m_Initialized = true;
80
81 IConfig serverConfig = config.Configs["GatekeeperService"];
82 if (serverConfig == null)
83 throw new Exception(String.Format("No section GatekeeperService in config file"));
84
85 string accountService = serverConfig.GetString("UserAccountService", String.Empty);
86 string homeUsersService = serverConfig.GetString("UserAgentService", string.Empty);
87 string gridService = serverConfig.GetString("GridService", String.Empty);
88 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
89 string simulationService = serverConfig.GetString("SimulationService", String.Empty);
90 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
91 string bansService = serverConfig.GetString("BansService", String.Empty);
92
93 // These are mandatory, the others aren't
94 if (gridService == string.Empty || presenceService == string.Empty)
95 throw new Exception("Incomplete specifications, Gatekeeper Service cannot function.");
96
97 string scope = serverConfig.GetString("ScopeID", UUID.Zero.ToString());
98 UUID.TryParse(scope, out m_ScopeID);
99 //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!");
100 m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true);
101 m_ExternalName = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
102 new string[] { "Startup", "Hypergrid", "GatekeeperService" }, String.Empty);
103 m_ExternalName = serverConfig.GetString("ExternalName", m_ExternalName);
104 if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
105 m_ExternalName = m_ExternalName + "/";
106
107 try
108 {
109 m_Uri = new Uri(m_ExternalName);
110 }
111 catch
112 {
113 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed gatekeeper address {0}", m_ExternalName);
114 }
115
116 Object[] args = new Object[] { config };
117 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
118 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
119
120 if (accountService != string.Empty)
121 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
122 if (homeUsersService != string.Empty)
123 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args);
124 if (gridUserService != string.Empty)
125 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
126 if (bansService != string.Empty)
127 m_BansService = ServerUtils.LoadPlugin<IBansService>(bansService, args);
128
129 if (simService != null)
130 m_SimulationService = simService;
131 else if (simulationService != string.Empty)
132 m_SimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args);
133
134 m_AllowedClients = serverConfig.GetString("AllowedClients", string.Empty);
135 m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty);
136 m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true);
137
138 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_ForeignsAllowedExceptions);
139 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_ForeignsDisallowedExceptions);
140
141 if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
142 throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
143
144 m_log.Debug("[GATEKEEPER SERVICE]: Starting...");
145 }
146 }
147
148 public GatekeeperService(IConfigSource config)
149 : this(config, null)
150 {
151 }
152
153 protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, List<string> exceptions)
154 {
155 string value = config.GetString(variable, string.Empty);
156 string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
157
158 foreach (string s in parts)
159 exceptions.Add(s.Trim());
160 }
161
162 public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
163 {
164 regionID = UUID.Zero;
165 regionHandle = 0;
166 externalName = m_ExternalName + ((regionName != string.Empty) ? " " + regionName : "");
167 imageURL = string.Empty;
168 reason = string.Empty;
169 GridRegion region = null;
170
171 m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName);
172 if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty)
173 {
174 List<GridRegion> defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID);
175 if (defs != null && defs.Count > 0)
176 {
177 region = defs[0];
178 m_DefaultGatewayRegion = region;
179 }
180 else
181 {
182 reason = "Grid setup problem. Try specifying a particular region here.";
183 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to send information. Please specify a default region for this grid!");
184 return false;
185 }
186 }
187 else
188 {
189 region = m_GridService.GetRegionByName(m_ScopeID, regionName);
190 if (region == null)
191 {
192 reason = "Region not found";
193 return false;
194 }
195 }
196
197 regionID = region.RegionID;
198 regionHandle = region.RegionHandle;
199
200 string regionimage = "regionImage" + regionID.ToString();
201 regionimage = regionimage.Replace("-", "");
202 imageURL = region.ServerURI + "index.php?method=" + regionimage;
203
204 return true;
205 }
206
207 public GridRegion GetHyperlinkRegion(UUID regionID, UUID agentID, string agentHomeURI, out string message)
208 {
209 message = null;
210
211 if (!m_AllowTeleportsToAnyRegion)
212 {
213 // Don't even check the given regionID
214 m_log.DebugFormat(
215 "[GATEKEEPER SERVICE]: Returning gateway region {0} {1} @ {2} to user {3}{4} as teleporting to arbitrary regions is not allowed.",
216 m_DefaultGatewayRegion.RegionName,
217 m_DefaultGatewayRegion.RegionID,
218 m_DefaultGatewayRegion.ServerURI,
219 agentID,
220 agentHomeURI == null ? "" : " @ " + agentHomeURI);
221
222 message = "Teleporting to the default region.";
223 return m_DefaultGatewayRegion;
224 }
225
226 GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID);
227
228 if (region == null)
229 {
230 m_log.DebugFormat(
231 "[GATEKEEPER SERVICE]: Could not find region with ID {0} as requested by user {1}{2}. Returning null.",
232 regionID, agentID, (agentHomeURI == null) ? "" : " @ " + agentHomeURI);
233
234 message = "The teleport destination could not be found.";
235 return null;
236 }
237
238 m_log.DebugFormat(
239 "[GATEKEEPER SERVICE]: Returning region {0} {1} @ {2} to user {3}{4}.",
240 region.RegionName,
241 region.RegionID,
242 region.ServerURI,
243 agentID,
244 agentHomeURI == null ? "" : " @ " + agentHomeURI);
245
246 return region;
247 }
248
249 #region Login Agent
250 public bool LoginAgent(GridRegion source, AgentCircuitData aCircuit, GridRegion destination, out string reason)
251 {
252 reason = string.Empty;
253
254 string authURL = string.Empty;
255 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
256 authURL = aCircuit.ServiceURLs["HomeURI"].ToString();
257
258 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9}, Teleport Flags: {10}. From region {11}",
259 aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionID,
260 aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, (TeleportFlags)aCircuit.teleportFlags,
261 (source == null) ? "Unknown" : string.Format("{0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI));
262
263 string curViewer = Util.GetViewerName(aCircuit);
264
265 //
266 // Check client
267 //
268 if (m_AllowedClients != string.Empty)
269 {
270 Regex arx = new Regex(m_AllowedClients);
271 Match am = arx.Match(curViewer);
272
273 if (!am.Success)
274 {
275 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", curViewer);
276 return false;
277 }
278 }
279
280 if (m_DeniedClients != string.Empty)
281 {
282 Regex drx = new Regex(m_DeniedClients);
283 Match dm = drx.Match(curViewer);
284
285 if (dm.Success)
286 {
287 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", curViewer);
288 return false;
289 }
290 }
291
292 //
293 // Authenticate the user
294 //
295 if (!Authenticate(aCircuit))
296 {
297 reason = "Unable to verify identity";
298 m_log.InfoFormat("[GATEKEEPER SERVICE]: Unable to verify identity of agent {0} {1}. Refusing service.", aCircuit.firstname, aCircuit.lastname);
299 return false;
300 }
301 m_log.DebugFormat("[GATEKEEPER SERVICE]: Identity verified for {0} {1} @ {2}", aCircuit.firstname, aCircuit.lastname, authURL);
302
303 //
304 // Check for impersonations
305 //
306 UserAccount account = null;
307 if (m_UserAccountService != null)
308 {
309 // Check to see if we have a local user with that UUID
310 account = m_UserAccountService.GetUserAccount(m_ScopeID, aCircuit.AgentID);
311 if (account != null)
312 {
313 // Make sure this is the user coming home, and not a foreign user with same UUID as a local user
314 if (m_UserAgentService != null)
315 {
316 if (!m_UserAgentService.IsAgentComingHome(aCircuit.SessionID, m_ExternalName))
317 {
318 // Can't do, sorry
319 reason = "Unauthorized";
320 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agent {0} {1} has same ID as local user. Refusing service.",
321 aCircuit.firstname, aCircuit.lastname);
322 return false;
323
324 }
325 }
326 }
327 }
328
329 //
330 // Foreign agents allowed? Exceptions?
331 //
332 if (account == null)
333 {
334 bool allowed = m_ForeignAgentsAllowed;
335
336 if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
337 allowed = false;
338
339 if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
340 allowed = true;
341
342 if (!allowed)
343 {
344 reason = "Destination does not allow visitors from your world";
345 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1} @ {2}. Refusing service.",
346 aCircuit.firstname, aCircuit.lastname, aCircuit.ServiceURLs["HomeURI"]);
347 return false;
348 }
349 }
350
351 //
352 // Is the user banned?
353 // This uses a Ban service that's more powerful than the configs
354 //
355 string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit));
356 if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL))
357 {
358 reason = "You are banned from this world";
359 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui);
360 return false;
361 }
362
363 m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name);
364
365 bool isFirstLogin = false;
366 //
367 // Login the presence, if it's not there yet (by the login service)
368 //
369 PresenceInfo presence = m_PresenceService.GetAgent(aCircuit.SessionID);
370 if (presence != null) // it has been placed there by the login service
371 isFirstLogin = true;
372
373 else
374 {
375 if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
376 {
377 reason = "Unable to login presence";
378 m_log.InfoFormat("[GATEKEEPER SERVICE]: Presence login failed for foreign agent {0} {1}. Refusing service.",
379 aCircuit.firstname, aCircuit.lastname);
380 return false;
381 }
382
383 m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name);
384
385 // Also login foreigners with GridUser service
386 if (m_GridUserService != null && account == null)
387 {
388 string userId = aCircuit.AgentID.ToString();
389 string first = aCircuit.firstname, last = aCircuit.lastname;
390 if (last.StartsWith("@"))
391 {
392 string[] parts = aCircuit.firstname.Split('.');
393 if (parts.Length >= 2)
394 {
395 first = parts[0];
396 last = parts[1];
397 }
398 }
399
400 userId += ";" + aCircuit.ServiceURLs["HomeURI"] + ";" + first + " " + last;
401 m_GridUserService.LoggedIn(userId);
402 }
403 }
404
405 //
406 // Get the region
407 //
408 destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID);
409 if (destination == null)
410 {
411 reason = "Destination region not found";
412 return false;
413 }
414
415 m_log.DebugFormat(
416 "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name);
417
418 //
419 // Adjust the visible name
420 //
421 if (account != null)
422 {
423 aCircuit.firstname = account.FirstName;
424 aCircuit.lastname = account.LastName;
425 }
426 if (account == null)
427 {
428 if (!aCircuit.lastname.StartsWith("@"))
429 aCircuit.firstname = aCircuit.firstname + "." + aCircuit.lastname;
430 try
431 {
432 Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString());
433 aCircuit.lastname = "@" + uri.Authority;
434 }
435 catch
436 {
437 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed HomeURI (this should never happen): {0}", aCircuit.ServiceURLs["HomeURI"]);
438 aCircuit.lastname = "@" + aCircuit.ServiceURLs["HomeURI"].ToString();
439 }
440 }
441
442 //
443 // Finally launch the agent at the destination
444 //
445 Constants.TeleportFlags loginFlag = isFirstLogin ? Constants.TeleportFlags.ViaLogin : Constants.TeleportFlags.ViaHGLogin;
446
447 // Preserve our TeleportFlags we have gathered so-far
448 loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags;
449
450 m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0}, Teleport Flags: {1}", aCircuit.Name, loginFlag);
451
452 string version;
453
454 if (!m_SimulationService.QueryAccess(
455 destination, aCircuit.AgentID, aCircuit.ServiceURLs["HomeURI"].ToString(),
456 true, aCircuit.startpos, "SIMULATION/0.3", new List<UUID>(), out version, out reason))
457 return false;
458
459 return m_SimulationService.CreateAgent(source, destination, aCircuit, (uint)loginFlag, out reason);
460 }
461
462 protected bool Authenticate(AgentCircuitData aCircuit)
463 {
464 if (!CheckAddress(aCircuit.ServiceSessionID))
465 return false;
466
467 if (string.IsNullOrEmpty(aCircuit.IPAddress))
468 {
469 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide a client IP address.");
470 return false;
471 }
472
473 string userURL = string.Empty;
474 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
475 userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
476
477 if (userURL == string.Empty)
478 {
479 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide an authentication server URL");
480 return false;
481 }
482
483 if (userURL == m_ExternalName)
484 {
485 return m_UserAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
486 }
487 else
488 {
489 IUserAgentService userAgentService = new UserAgentServiceConnector(userURL);
490
491 try
492 {
493 return userAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
494 }
495 catch
496 {
497 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to contact authentication service at {0}", userURL);
498 return false;
499 }
500 }
501 }
502
503 // Check that the service token was generated for *this* grid.
504 // If it wasn't then that's a fake agent.
505 protected bool CheckAddress(string serviceToken)
506 {
507 string[] parts = serviceToken.Split(new char[] { ';' });
508 if (parts.Length < 2)
509 return false;
510
511 char[] trailing_slash = new char[] { '/' };
512 string addressee = parts[0].TrimEnd(trailing_slash);
513 string externalname = m_ExternalName.TrimEnd(trailing_slash);
514 m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
515
516 Uri uri;
517 try
518 {
519 uri = new Uri(addressee);
520 }
521 catch
522 {
523 m_log.DebugFormat("[GATEKEEPER SERVICE]: Visitor provided malformed service address {0}", addressee);
524 return false;
525 }
526
527 return string.Equals(uri.GetLeftPart(UriPartial.Authority), m_Uri.GetLeftPart(UriPartial.Authority), StringComparison.OrdinalIgnoreCase) ;
528 }
529
530 #endregion
531
532
533 #region Misc
534
535 private bool IsException(AgentCircuitData aCircuit, List<string> exceptions)
536 {
537 bool exception = false;
538 if (exceptions.Count > 0) // we have exceptions
539 {
540 // Retrieve the visitor's origin
541 string userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
542 if (!userURL.EndsWith("/"))
543 userURL += "/";
544
545 if (exceptions.Find(delegate(string s)
546 {
547 if (!s.EndsWith("/"))
548 s += "/";
549 return s == userURL;
550 }) != null)
551 exception = true;
552 }
553
554 return exception;
555 }
556
557 #endregion
558 }
559}
diff --git a/OpenSim/Services/HypergridService/HGAssetService.cs b/OpenSim/Services/HypergridService/HGAssetService.cs
new file mode 100644
index 0000000..b83fb1e
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGAssetService.cs
@@ -0,0 +1,193 @@
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.IO;
30using System.Reflection;
31using System.Xml;
32
33using Nini.Config;
34using log4net;
35using OpenMetaverse;
36
37using OpenSim.Framework;
38using OpenSim.Framework.Serialization.External;
39using OpenSim.Server.Base;
40using OpenSim.Services.Interfaces;
41using OpenSim.Services.AssetService;
42
43namespace OpenSim.Services.HypergridService
44{
45 /// <summary>
46 /// Hypergrid asset service. It serves the IAssetService interface,
47 /// but implements it in ways that are appropriate for inter-grid
48 /// asset exchanges.
49 /// </summary>
50 public class HGAssetService : OpenSim.Services.AssetService.AssetService, IAssetService
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private string m_HomeURL;
57 private IUserAccountService m_UserAccountService;
58
59 private UserAccountCache m_Cache;
60
61 private AssetPermissions m_AssetPerms;
62
63 public HGAssetService(IConfigSource config, string configName) : base(config, configName)
64 {
65 m_log.Debug("[HGAsset Service]: Starting");
66 IConfig assetConfig = config.Configs[configName];
67 if (assetConfig == null)
68 throw new Exception("No HGAssetService configuration");
69
70 string userAccountsDll = assetConfig.GetString("UserAccountsService", string.Empty);
71 if (userAccountsDll == string.Empty)
72 throw new Exception("Please specify UserAccountsService in HGAssetService configuration");
73
74 Object[] args = new Object[] { config };
75 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args);
76 if (m_UserAccountService == null)
77 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll));
78
79 m_HomeURL = Util.GetConfigVarFromSections<string>(config, "HomeURI",
80 new string[] { "Startup", "Hypergrid", configName }, string.Empty);
81 if (m_HomeURL == string.Empty)
82 throw new Exception("[HGAssetService] No HomeURI specified");
83
84 m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
85
86 // Permissions
87 m_AssetPerms = new AssetPermissions(assetConfig);
88
89 }
90
91 #region IAssetService overrides
92 public override AssetBase Get(string id)
93 {
94 AssetBase asset = base.Get(id);
95
96 if (asset == null)
97 return null;
98
99 if (!m_AssetPerms.AllowedExport(asset.Type))
100 return null;
101
102 if (asset.Metadata.Type == (sbyte)AssetType.Object)
103 asset.Data = AdjustIdentifiers(asset.Data);
104
105 AdjustIdentifiers(asset.Metadata);
106
107 return asset;
108 }
109
110 public override AssetMetadata GetMetadata(string id)
111 {
112 AssetMetadata meta = base.GetMetadata(id);
113
114 if (meta == null)
115 return null;
116
117 AdjustIdentifiers(meta);
118
119 return meta;
120 }
121
122 public override byte[] GetData(string id)
123 {
124 AssetBase asset = Get(id);
125
126 if (asset == null)
127 return null;
128
129 if (!m_AssetPerms.AllowedExport(asset.Type))
130 return null;
131
132 // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
133 // Fix bad assets before sending them elsewhere
134 if (asset.Type == (int)AssetType.Object && asset.Data != null)
135 {
136 string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data));
137 asset.Data = Utils.StringToBytes(xml);
138 }
139
140 return asset.Data;
141 }
142
143 //public virtual bool Get(string id, Object sender, AssetRetrieved handler)
144
145 public override string Store(AssetBase asset)
146 {
147 if (!m_AssetPerms.AllowedImport(asset.Type))
148 return string.Empty;
149
150 // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
151 // Fix bad assets before storing on this server
152 if (asset.Type == (int)AssetType.Object && asset.Data != null)
153 {
154 string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data));
155 asset.Data = Utils.StringToBytes(xml);
156 }
157
158 return base.Store(asset);
159 }
160
161 public override bool Delete(string id)
162 {
163 // NOGO
164 return false;
165 }
166
167 #endregion
168
169 protected void AdjustIdentifiers(AssetMetadata meta)
170 {
171 if (meta == null || m_Cache == null)
172 return;
173
174 UserAccount creator = m_Cache.GetUser(meta.CreatorID);
175 if (creator != null)
176 meta.CreatorID = meta.CreatorID + ";" + m_HomeURL + "/" + creator.FirstName + " " + creator.LastName;
177 }
178
179 // Only for Object
180 protected byte[] AdjustIdentifiers(byte[] data)
181 {
182 string xml = Utils.BytesToString(data);
183
184 // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
185 // Fix bad assets before sending them elsewhere
186 xml = ExternalRepresentationUtils.SanitizeXml(xml);
187
188 return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, "HGAssetService", m_HomeURL, m_Cache, UUID.Zero));
189 }
190
191 }
192
193}
diff --git a/OpenSim/Services/HypergridService/HGFSAssetService.cs b/OpenSim/Services/HypergridService/HGFSAssetService.cs
new file mode 100644
index 0000000..54e8ccb
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGFSAssetService.cs
@@ -0,0 +1,189 @@
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.Reflection;
29
30using Nini.Config;
31using log4net;
32using OpenMetaverse;
33
34using OpenSim.Framework;
35using OpenSim.Framework.Serialization.External;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38using OpenSim.Services.FSAssetService;
39
40namespace OpenSim.Services.HypergridService
41{
42 /// <summary>
43 /// Hypergrid asset service. It serves the IAssetService interface,
44 /// but implements it in ways that are appropriate for inter-grid
45 /// asset exchanges. This version is for FSAssets.
46 /// </summary>
47 public class HGFSAssetService : FSAssetConnector, IAssetService
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(
51 MethodBase.GetCurrentMethod().DeclaringType);
52
53 private string m_HomeURL;
54 private IUserAccountService m_UserAccountService;
55
56 private UserAccountCache m_Cache;
57
58 private AssetPermissions m_AssetPerms;
59
60 public HGFSAssetService(IConfigSource config, string configName) : base(config, "AssetService")
61 {
62 m_log.Debug("[HGAsset Service]: Starting in FSAsset mode");
63 IConfig assetConfig = config.Configs[configName];
64 if (assetConfig == null)
65 throw new Exception("No HGAssetService configuration");
66
67 string userAccountsDll = assetConfig.GetString("UserAccountsService", string.Empty);
68 if (userAccountsDll == string.Empty)
69 throw new Exception("Please specify UserAccountsService in HGAssetService configuration");
70
71 Object[] args = new Object[] { config };
72 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args);
73 if (m_UserAccountService == null)
74 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll));
75
76 m_HomeURL = Util.GetConfigVarFromSections<string>(config, "HomeURI",
77 new string[] { "Startup", "Hypergrid", configName }, string.Empty);
78 if (m_HomeURL == string.Empty)
79 throw new Exception("[HGAssetService] No HomeURI specified");
80
81 m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
82
83 // Permissions
84 m_AssetPerms = new AssetPermissions(assetConfig);
85 }
86
87 #region IAssetService overrides
88 public override AssetBase Get(string id)
89 {
90 AssetBase asset = base.Get(id);
91
92 if (asset == null)
93 return null;
94
95 if (!m_AssetPerms.AllowedExport(asset.Type))
96 return null;
97
98 if (asset.Metadata.Type == (sbyte)AssetType.Object)
99 asset.Data = AdjustIdentifiers(asset.Data);
100
101 AdjustIdentifiers(asset.Metadata);
102
103 return asset;
104 }
105
106 public override AssetMetadata GetMetadata(string id)
107 {
108 AssetMetadata meta = base.GetMetadata(id);
109
110 if (meta == null)
111 return null;
112
113 AdjustIdentifiers(meta);
114
115 return meta;
116 }
117
118 public override byte[] GetData(string id)
119 {
120 AssetBase asset = Get(id);
121
122 if (asset == null)
123 return null;
124
125 if (!m_AssetPerms.AllowedExport(asset.Type))
126 return null;
127
128 // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
129 // Fix bad assets before sending them elsewhere
130 if (asset.Type == (int)AssetType.Object && asset.Data != null)
131 {
132 string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data));
133 asset.Data = Utils.StringToBytes(xml);
134 }
135
136 return asset.Data;
137 }
138
139 //public virtual bool Get(string id, Object sender, AssetRetrieved handler)
140
141 public override string Store(AssetBase asset)
142 {
143 if (!m_AssetPerms.AllowedImport(asset.Type))
144 return string.Empty;
145
146 // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
147 // Fix bad assets before storing on this server
148 if (asset.Type == (int)AssetType.Object && asset.Data != null)
149 {
150 string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data));
151 asset.Data = Utils.StringToBytes(xml);
152 }
153
154 return base.Store(asset);
155 }
156
157 public override bool Delete(string id)
158 {
159 // NOGO
160 return false;
161 }
162
163 #endregion
164
165 protected void AdjustIdentifiers(AssetMetadata meta)
166 {
167 if (meta == null || m_Cache == null)
168 return;
169
170 UserAccount creator = m_Cache.GetUser(meta.CreatorID);
171 if (creator != null)
172 meta.CreatorID = meta.CreatorID + ";" + m_HomeURL + "/" + creator.FirstName + " " + creator.LastName;
173 }
174
175 // Only for Object
176 protected byte[] AdjustIdentifiers(byte[] data)
177 {
178 string xml = Utils.BytesToString(data);
179
180 // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
181 // Fix bad assets before sending them elsewhere
182 xml = ExternalRepresentationUtils.SanitizeXml(xml);
183
184 return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, "HGAssetService", m_HomeURL, m_Cache, UUID.Zero));
185 }
186
187 }
188
189}
diff --git a/OpenSim/Services/HypergridService/HGFriendsService.cs b/OpenSim/Services/HypergridService/HGFriendsService.cs
new file mode 100644
index 0000000..6e35a88
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGFriendsService.cs
@@ -0,0 +1,409 @@
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 GridRegion = OpenSim.Services.Interfaces.GridRegion;
38using OpenSim.Server.Base;
39using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
40
41using OpenMetaverse;
42using log4net;
43using Nini.Config;
44
45namespace OpenSim.Services.HypergridService
46{
47 /// <summary>
48 /// W2W social networking
49 /// </summary>
50 public class HGFriendsService : IHGFriendsService
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 static bool m_Initialized = false;
57
58 protected static IGridUserService m_GridUserService;
59 protected static IGridService m_GridService;
60 protected static IGatekeeperService m_GatekeeperService;
61 protected static IFriendsService m_FriendsService;
62 protected static IPresenceService m_PresenceService;
63 protected static IUserAccountService m_UserAccountService;
64 protected static IFriendsSimConnector m_FriendsLocalSimConnector; // standalone, points to HGFriendsModule
65 protected static FriendsSimConnector m_FriendsSimConnector; // grid
66
67 private static string m_ConfigName = "HGFriendsService";
68
69 public HGFriendsService(IConfigSource config, String configName, IFriendsSimConnector localSimConn)
70 {
71 if (m_FriendsLocalSimConnector == null)
72 m_FriendsLocalSimConnector = localSimConn;
73
74 if (!m_Initialized)
75 {
76 m_Initialized = true;
77
78 if (configName != String.Empty)
79 m_ConfigName = configName;
80
81 Object[] args = new Object[] { config };
82
83 IConfig serverConfig = config.Configs[m_ConfigName];
84 if (serverConfig == null)
85 throw new Exception(String.Format("No section {0} in config file", m_ConfigName));
86
87 string theService = serverConfig.GetString("FriendsService", string.Empty);
88 if (theService == String.Empty)
89 throw new Exception("No FriendsService in config file " + m_ConfigName);
90 m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(theService, args);
91
92 theService = serverConfig.GetString("UserAccountService", string.Empty);
93 if (theService == String.Empty)
94 throw new Exception("No UserAccountService in " + m_ConfigName);
95 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(theService, args);
96
97 theService = serverConfig.GetString("GridService", string.Empty);
98 if (theService == String.Empty)
99 throw new Exception("No GridService in " + m_ConfigName);
100 m_GridService = ServerUtils.LoadPlugin<IGridService>(theService, args);
101
102 theService = serverConfig.GetString("PresenceService", string.Empty);
103 if (theService == String.Empty)
104 throw new Exception("No PresenceService in " + m_ConfigName);
105 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(theService, args);
106
107 m_FriendsSimConnector = new FriendsSimConnector();
108
109 m_log.DebugFormat("[HGFRIENDS SERVICE]: Starting...");
110
111 }
112 }
113
114 #region IHGFriendsService
115
116 public int GetFriendPerms(UUID userID, UUID friendID)
117 {
118 FriendInfo[] friendsInfo = m_FriendsService.GetFriends(userID);
119 foreach (FriendInfo finfo in friendsInfo)
120 {
121 if (finfo.Friend.StartsWith(friendID.ToString()))
122 return finfo.TheirFlags;
123 }
124 return -1;
125 }
126
127 public bool NewFriendship(FriendInfo friend, bool verified)
128 {
129 UUID friendID;
130 string tmp = string.Empty, url = String.Empty, first = String.Empty, last = String.Empty;
131 if (!Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out url, out first, out last, out tmp))
132 return false;
133
134 m_log.DebugFormat("[HGFRIENDS SERVICE]: New friendship {0} {1} ({2})", friend.PrincipalID, friend.Friend, verified);
135
136 // Does the friendship already exist?
137 FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID);
138 foreach (FriendInfo finfo in finfos)
139 {
140 if (finfo.Friend.StartsWith(friendID.ToString()))
141 return false;
142 }
143 // Verified user session. But the user needs to confirm friendship when he gets home
144 if (verified)
145 return m_FriendsService.StoreFriend(friend.PrincipalID.ToString(), friend.Friend, 0);
146
147 // Does the reverted friendship exist? meaning that this user initiated the request
148 finfos = m_FriendsService.GetFriends(friendID);
149 bool userInitiatedOffer = false;
150 foreach (FriendInfo finfo in finfos)
151 {
152 if (friend.Friend.StartsWith(finfo.PrincipalID.ToString()) && finfo.Friend.StartsWith(friend.PrincipalID.ToString()) && finfo.TheirFlags == -1)
153 {
154 userInitiatedOffer = true;
155 // Let's delete the existing friendship relations that was stored
156 m_FriendsService.Delete(friendID, finfo.Friend);
157 break;
158 }
159 }
160
161 if (userInitiatedOffer)
162 {
163 m_FriendsService.StoreFriend(friend.PrincipalID.ToString(), friend.Friend, 1);
164 m_FriendsService.StoreFriend(friend.Friend, friend.PrincipalID.ToString(), 1);
165 // notify the user
166 ForwardToSim("ApproveFriendshipRequest", friendID, Util.UniversalName(first, last, url), "", friend.PrincipalID, "");
167 return true;
168 }
169 return false;
170 }
171
172 public bool DeleteFriendship(FriendInfo friend, string secret)
173 {
174 FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID);
175 foreach (FriendInfo finfo in finfos)
176 {
177 // We check the secret here. Or if the friendship request was initiated here, and was declined
178 if (finfo.Friend.StartsWith(friend.Friend) && finfo.Friend.EndsWith(secret))
179 {
180 m_log.DebugFormat("[HGFRIENDS SERVICE]: Delete friendship {0} {1}", friend.PrincipalID, friend.Friend);
181 m_FriendsService.Delete(friend.PrincipalID, finfo.Friend);
182 m_FriendsService.Delete(finfo.Friend, friend.PrincipalID.ToString());
183
184 return true;
185 }
186 }
187
188 return false;
189 }
190
191 public bool FriendshipOffered(UUID fromID, string fromName, UUID toID, string message)
192 {
193 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, toID);
194 if (account == null)
195 return false;
196
197 // OK, we have that user here.
198 // So let's send back the call, but start a thread to continue
199 // with the verification and the actual action.
200
201 Util.FireAndForget(
202 o => ProcessFriendshipOffered(fromID, fromName, toID, message), null, "HGFriendsService.ProcessFriendshipOffered");
203
204 return true;
205 }
206
207 public bool ValidateFriendshipOffered(UUID fromID, UUID toID)
208 {
209 FriendInfo[] finfos = m_FriendsService.GetFriends(toID.ToString());
210 foreach (FriendInfo fi in finfos)
211 {
212 if (fi.Friend.StartsWith(fromID.ToString()) && fi.TheirFlags == -1)
213 return true;
214 }
215 return false;
216 }
217
218 public List<UUID> StatusNotification(List<string> friends, UUID foreignUserID, bool online)
219 {
220 if (m_FriendsService == null || m_PresenceService == null)
221 {
222 m_log.WarnFormat("[HGFRIENDS SERVICE]: Unable to perform status notifications because friends or presence services are missing");
223 return new List<UUID>();
224 }
225
226 // Let's unblock the caller right now, and take it from here async
227
228 List<UUID> localFriendsOnline = new List<UUID>();
229
230 m_log.DebugFormat("[HGFRIENDS SERVICE]: Status notification: foreign user {0} wants to notify {1} local friends of {2} status",
231 foreignUserID, friends.Count, (online ? "online" : "offline"));
232
233 // First, let's double check that the reported friends are, indeed, friends of that user
234 // And let's check that the secret matches
235 List<string> usersToBeNotified = new List<string>();
236 foreach (string uui in friends)
237 {
238 UUID localUserID;
239 string secret = string.Empty, tmp = string.Empty;
240 if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret))
241 {
242 FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID);
243 foreach (FriendInfo finfo in friendInfos)
244 {
245 if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret))
246 {
247 // great!
248 usersToBeNotified.Add(localUserID.ToString());
249 }
250 }
251 }
252 }
253
254 // Now, let's send the notifications
255 //m_log.DebugFormat("[HGFRIENDS SERVICE]: Status notification: user has {0} local friends", usersToBeNotified.Count);
256
257 // First, let's send notifications to local users who are online in the home grid
258 PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray());
259 if (friendSessions != null && friendSessions.Length > 0)
260 {
261 PresenceInfo friendSession = null;
262 foreach (PresenceInfo pinfo in friendSessions)
263 if (pinfo.RegionID != UUID.Zero) // let's guard against traveling agents
264 {
265 friendSession = pinfo;
266 break;
267 }
268
269 if (friendSession != null)
270 {
271 ForwardStatusNotificationToSim(friendSession.RegionID, foreignUserID, friendSession.UserID, online);
272 usersToBeNotified.Remove(friendSession.UserID.ToString());
273 UUID id;
274 if (UUID.TryParse(friendSession.UserID, out id))
275 localFriendsOnline.Add(id);
276
277 }
278 }
279
280// // Lastly, let's notify the rest who may be online somewhere else
281// foreach (string user in usersToBeNotified)
282// {
283// UUID id = new UUID(user);
284// //m_UserAgentService.LocateUser(id);
285// //etc...
286// //if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName)
287// //{
288// // string url = m_TravelingAgents[id].GridExternalName;
289// // // forward
290// //}
291// //m_log.WarnFormat("[HGFRIENDS SERVICE]: User {0} is visiting another grid. HG Status notifications still not implemented.", user);
292// }
293
294 // and finally, let's send the online friends
295 if (online)
296 {
297 return localFriendsOnline;
298 }
299 else
300 return new List<UUID>();
301 }
302
303 #endregion IHGFriendsService
304
305 #region Aux
306
307 private void ProcessFriendshipOffered(UUID fromID, String fromName, UUID toID, String message)
308 {
309 // Great, it's a genuine request. Let's proceed.
310 // But now we need to confirm that the requester is who he says he is
311 // before we act on the friendship request.
312
313 if (!fromName.Contains("@"))
314 return;
315
316 string[] parts = fromName.Split(new char[] {'@'});
317 if (parts.Length != 2)
318 return;
319
320 string uriStr = "http://" + parts[1];
321 try
322 {
323 new Uri(uriStr);
324 }
325 catch (UriFormatException)
326 {
327 return;
328 }
329
330 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr);
331 Dictionary<string, object> servers = uasConn.GetServerURLs(fromID);
332 if (!servers.ContainsKey("FriendsServerURI"))
333 return;
334
335 HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(servers["FriendsServerURI"].ToString());
336 if (!friendsConn.ValidateFriendshipOffered(fromID, toID))
337 {
338 m_log.WarnFormat("[HGFRIENDS SERVICE]: Friendship request from {0} to {1} is invalid. Impersonations?", fromID, toID);
339 return;
340 }
341
342 string fromUUI = Util.UniversalIdentifier(fromID, parts[0], "@" + parts[1], uriStr);
343 // OK, we're good!
344 ForwardToSim("FriendshipOffered", fromID, fromName, fromUUI, toID, message);
345 }
346
347 private bool ForwardToSim(string op, UUID fromID, string name, String fromUUI, UUID toID, string message)
348 {
349 PresenceInfo session = null;
350 GridRegion region = null;
351 PresenceInfo[] sessions = m_PresenceService.GetAgents(new string[] { toID.ToString() });
352 if (sessions != null && sessions.Length > 0)
353 session = sessions[0];
354 if (session != null)
355 region = m_GridService.GetRegionByUUID(UUID.Zero, session.RegionID);
356
357 switch (op)
358 {
359 case "FriendshipOffered":
360 // Let's store backwards
361 string secret = UUID.Random().ToString().Substring(0, 8);
362 m_FriendsService.StoreFriend(toID.ToString(), fromUUI + ";" + secret, 0);
363 if (m_FriendsLocalSimConnector != null) // standalone
364 {
365 GridInstantMessage im = new GridInstantMessage(null, fromID, name, toID,
366 (byte)InstantMessageDialog.FriendshipOffered, message, false, Vector3.Zero);
367 // !! HACK
368 im.imSessionID = im.fromAgentID;
369 return m_FriendsLocalSimConnector.LocalFriendshipOffered(toID, im);
370 }
371 else if (region != null) // grid
372 return m_FriendsSimConnector.FriendshipOffered(region, fromID, toID, message, name);
373 break;
374 case "ApproveFriendshipRequest":
375 if (m_FriendsLocalSimConnector != null) // standalone
376 return m_FriendsLocalSimConnector.LocalFriendshipApproved(fromID, name, toID);
377 else if (region != null) //grid
378 return m_FriendsSimConnector.FriendshipApproved(region, fromID, name, toID);
379 break;
380 }
381
382 return false;
383 }
384
385 protected void ForwardStatusNotificationToSim(UUID regionID, UUID foreignUserID, string user, bool online)
386 {
387 UUID userID;
388 if (UUID.TryParse(user, out userID))
389 {
390 if (m_FriendsLocalSimConnector != null)
391 {
392 m_log.DebugFormat("[HGFRIENDS SERVICE]: Local Notify, user {0} is {1}", foreignUserID, (online ? "online" : "offline"));
393 m_FriendsLocalSimConnector.StatusNotify(foreignUserID, userID, online);
394 }
395 else
396 {
397 GridRegion region = m_GridService.GetRegionByUUID(UUID.Zero /* !!! */, regionID);
398 if (region != null)
399 {
400 m_log.DebugFormat("[HGFRIENDS SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
401 m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID.ToString(), online);
402 }
403 }
404 }
405 }
406
407 #endregion Aux
408 }
409}
diff --git a/OpenSim/Services/HypergridService/HGInstantMessageService.cs b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
new file mode 100644
index 0000000..32ca09a
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
@@ -0,0 +1,376 @@
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 protected static IOfflineIMService m_OfflineIMService;
65
66 protected static IInstantMessageSimConnector m_IMSimConnector;
67
68 protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>();
69 private static ExpiringCache<UUID, GridRegion> m_RegionCache;
70
71 private static bool m_ForwardOfflineGroupMessages;
72 private static bool m_InGatekeeper;
73
74 public HGInstantMessageService(IConfigSource config)
75 : this(config, null)
76 {
77 }
78
79 public HGInstantMessageService(IConfigSource config, IInstantMessageSimConnector imConnector)
80 {
81 if (imConnector != null)
82 m_IMSimConnector = imConnector;
83
84 if (!m_Initialized)
85 {
86 m_Initialized = true;
87
88 IConfig serverConfig = config.Configs["HGInstantMessageService"];
89 if (serverConfig == null)
90 throw new Exception(String.Format("No section HGInstantMessageService in config file"));
91
92 string gridService = serverConfig.GetString("GridService", String.Empty);
93 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
94 string userAgentService = serverConfig.GetString("UserAgentService", String.Empty);
95 m_InGatekeeper = serverConfig.GetBoolean("InGatekeeper", false);
96 m_log.DebugFormat("[HG IM SERVICE]: Starting... InRobust? {0}", m_InGatekeeper);
97
98 if (gridService == string.Empty || presenceService == string.Empty)
99 throw new Exception(String.Format("Incomplete specifications, InstantMessage Service cannot function."));
100
101 Object[] args = new Object[] { config };
102 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
103 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
104 try
105 {
106 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(userAgentService, args);
107 }
108 catch
109 {
110 m_log.WarnFormat("[HG IM SERVICE]: Unable to create User Agent Service. Missing config var in [HGInstantMessageService]?");
111 }
112
113 m_RegionCache = new ExpiringCache<UUID, GridRegion>();
114
115 IConfig cnf = config.Configs["Messaging"];
116 if (cnf == null)
117 {
118 return;
119 }
120
121 m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false);
122
123 if (m_InGatekeeper)
124 {
125 string offlineIMService = cnf.GetString("OfflineIMService", string.Empty);
126 if (offlineIMService != string.Empty)
127 m_OfflineIMService = ServerUtils.LoadPlugin<IOfflineIMService>(offlineIMService, args);
128 }
129 }
130 }
131
132 public bool IncomingInstantMessage(GridInstantMessage im)
133 {
134// m_log.DebugFormat("[HG IM SERVICE]: Received message from {0} to {1}", im.fromAgentID, im.toAgentID);
135// UUID toAgentID = new UUID(im.toAgentID);
136
137 bool success = false;
138 if (m_IMSimConnector != null)
139 {
140 //m_log.DebugFormat("[XXX] SendIMToRegion local im connector");
141 success = m_IMSimConnector.SendInstantMessage(im);
142 }
143 else
144 {
145 success = TrySendInstantMessage(im, "", true, false);
146 }
147
148 if (!success && m_InGatekeeper) // we do this only in the Gatekeeper IM service
149 UndeliveredMessage(im);
150
151 return success;
152 }
153
154 public bool OutgoingInstantMessage(GridInstantMessage im, string url, bool foreigner)
155 {
156// m_log.DebugFormat("[HG IM SERVICE]: Sending message from {0} to {1}@{2}", im.fromAgentID, im.toAgentID, url);
157 if (url != string.Empty)
158 return TrySendInstantMessage(im, url, true, foreigner);
159 else
160 {
161 PresenceInfo upd = new PresenceInfo();
162 upd.RegionID = UUID.Zero;
163 return TrySendInstantMessage(im, upd, true, foreigner);
164 }
165
166 }
167
168 protected bool TrySendInstantMessage(GridInstantMessage im, object previousLocation, bool firstTime, bool foreigner)
169 {
170 UUID toAgentID = new UUID(im.toAgentID);
171
172 PresenceInfo upd = null;
173 string url = string.Empty;
174
175 bool lookupAgent = false;
176
177 lock (m_UserLocationMap)
178 {
179 if (m_UserLocationMap.ContainsKey(toAgentID))
180 {
181 object o = m_UserLocationMap[toAgentID];
182 if (o is PresenceInfo)
183 upd = (PresenceInfo)o;
184 else if (o is string)
185 url = (string)o;
186
187 // We need to compare the current location with the previous
188 // or the recursive loop will never end because it will never try to lookup the agent again
189 if (!firstTime)
190 {
191 lookupAgent = true;
192 upd = null;
193 }
194 }
195 else
196 {
197 lookupAgent = true;
198 }
199 }
200
201 //m_log.DebugFormat("[XXX] Neeed lookup ? {0}", (lookupAgent ? "yes" : "no"));
202
203 // Are we needing to look-up an agent?
204 if (lookupAgent)
205 {
206 // Non-cached user agent lookup.
207 PresenceInfo[] presences = m_PresenceService.GetAgents(new string[] { toAgentID.ToString() });
208 if (presences != null && presences.Length > 0)
209 {
210 foreach (PresenceInfo p in presences)
211 {
212 if (p.RegionID != UUID.Zero)
213 {
214 //m_log.DebugFormat("[XXX]: Found presence in {0}", p.RegionID);
215 upd = p;
216 break;
217 }
218 }
219 }
220
221 if (upd == null && !foreigner)
222 {
223 // Let's check with the UAS if the user is elsewhere
224 m_log.DebugFormat("[HG IM SERVICE]: User is not present. Checking location with User Agent service");
225 try
226 {
227 url = m_UserAgentService.LocateUser(toAgentID);
228 }
229 catch (Exception e)
230 {
231 m_log.Warn("[HG IM SERVICE]: LocateUser call failed ", e);
232 url = string.Empty;
233 }
234 }
235
236 // check if we've tried this before..
237 // This is one way to end the recursive loop
238 //
239 if (!firstTime && ((previousLocation is PresenceInfo && upd != null && upd.RegionID == ((PresenceInfo)previousLocation).RegionID) ||
240 (previousLocation is string && upd == null && previousLocation.Equals(url))))
241 {
242 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
243 m_log.DebugFormat("[HG IM SERVICE]: Fail 2 {0} {1}", previousLocation, url);
244
245 return false;
246 }
247 }
248
249 if (upd != null)
250 {
251 // ok, the user is around somewhere. Let's send back the reply with "success"
252 // even though the IM may still fail. Just don't keep the caller waiting for
253 // the entire time we're trying to deliver the IM
254 return SendIMToRegion(upd, im, toAgentID, foreigner);
255 }
256 else if (url != string.Empty)
257 {
258 // ok, the user is around somewhere. Let's send back the reply with "success"
259 // even though the IM may still fail. Just don't keep the caller waiting for
260 // the entire time we're trying to deliver the IM
261 return ForwardIMToGrid(url, im, toAgentID, foreigner);
262 }
263 else if (firstTime && previousLocation is string && (string)previousLocation != string.Empty)
264 {
265 return ForwardIMToGrid((string)previousLocation, im, toAgentID, foreigner);
266 }
267 else
268 m_log.DebugFormat("[HG IM SERVICE]: Unable to locate user {0}", toAgentID);
269 return false;
270 }
271
272 bool SendIMToRegion(PresenceInfo upd, GridInstantMessage im, UUID toAgentID, bool foreigner)
273 {
274 bool imresult = false;
275 GridRegion reginfo = null;
276 if (!m_RegionCache.TryGetValue(upd.RegionID, out reginfo))
277 {
278 reginfo = m_GridService.GetRegionByUUID(UUID.Zero /*!!!*/, upd.RegionID);
279 if (reginfo != null)
280 m_RegionCache.AddOrUpdate(upd.RegionID, reginfo, CACHE_EXPIRATION_SECONDS);
281 }
282
283 if (reginfo != null)
284 {
285 imresult = InstantMessageServiceConnector.SendInstantMessage(reginfo.ServerURI, im);
286 }
287 else
288 {
289 m_log.DebugFormat("[HG IM SERVICE]: Failed to deliver message to {0}", reginfo.ServerURI);
290 return false;
291 }
292
293 if (imresult)
294 {
295 // IM delivery successful, so store the Agent's location in our local cache.
296 lock (m_UserLocationMap)
297 {
298 if (m_UserLocationMap.ContainsKey(toAgentID))
299 {
300 m_UserLocationMap[toAgentID] = upd;
301 }
302 else
303 {
304 m_UserLocationMap.Add(toAgentID, upd);
305 }
306 }
307 return true;
308 }
309 else
310 {
311 // try again, but lookup user this time.
312 // Warning, this must call the Async version
313 // of this method or we'll be making thousands of threads
314 // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
315 // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
316
317 // This is recursive!!!!!
318 return TrySendInstantMessage(im, upd, false, foreigner);
319 }
320 }
321
322 bool ForwardIMToGrid(string url, GridInstantMessage im, UUID toAgentID, bool foreigner)
323 {
324 if (InstantMessageServiceConnector.SendInstantMessage(url, im))
325 {
326 // IM delivery successful, so store the Agent's location in our local cache.
327 lock (m_UserLocationMap)
328 {
329 if (m_UserLocationMap.ContainsKey(toAgentID))
330 {
331 m_UserLocationMap[toAgentID] = url;
332 }
333 else
334 {
335 m_UserLocationMap.Add(toAgentID, url);
336 }
337 }
338
339 return true;
340 }
341 else
342 {
343 // try again, but lookup user this time.
344
345 // This is recursive!!!!!
346 return TrySendInstantMessage(im, url, false, foreigner);
347 }
348 }
349
350 private bool UndeliveredMessage(GridInstantMessage im)
351 {
352 if (m_OfflineIMService == null)
353 return false;
354
355 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
356 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
357 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
358 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
359 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
360 {
361 return false;
362 }
363
364 if (!m_ForwardOfflineGroupMessages)
365 {
366 if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
367 im.dialog == (byte)InstantMessageDialog.GroupInvitation)
368 return false;
369 }
370
371// m_log.DebugFormat("[HG IM SERVICE]: Message saved");
372 string reason = string.Empty;
373 return m_OfflineIMService.StoreMessage(im, out reason);
374 }
375 }
376} \ No newline at end of file
diff --git a/OpenSim/Services/HypergridService/HGInventoryService.cs b/OpenSim/Services/HypergridService/HGInventoryService.cs
new file mode 100644
index 0000000..9158b41
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGInventoryService.cs
@@ -0,0 +1,321 @@
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 OpenMetaverse;
31using log4net;
32using Nini.Config;
33using System.Reflection;
34using OpenSim.Services.Base;
35using OpenSim.Services.Interfaces;
36using OpenSim.Services.InventoryService;
37using OpenSim.Data;
38using OpenSim.Framework;
39using OpenSim.Server.Base;
40
41namespace OpenSim.Services.HypergridService
42{
43 /// <summary>
44 /// Hypergrid inventory service. It serves the IInventoryService interface,
45 /// but implements it in ways that are appropriate for inter-grid
46 /// inventory exchanges. Specifically, it does not performs deletions
47 /// and it responds to GetRootFolder requests with the ID of the
48 /// Suitcase folder, not the actual "My Inventory" folder.
49 /// </summary>
50 public class HGInventoryService : XInventoryService, IInventoryService
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private string m_HomeURL;
57 private IUserAccountService m_UserAccountService;
58
59 private UserAccountCache m_Cache;
60
61 public HGInventoryService(IConfigSource config, string configName)
62 : base(config, configName)
63 {
64 m_log.Debug("[HGInventory Service]: Starting");
65 if (configName != string.Empty)
66 m_ConfigName = configName;
67
68 //
69 // Try reading the [InventoryService] section, if it exists
70 //
71 IConfig invConfig = config.Configs[m_ConfigName];
72 if (invConfig != null)
73 {
74 // realm = authConfig.GetString("Realm", realm);
75 string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty);
76 if (userAccountsDll == string.Empty)
77 throw new Exception("Please specify UserAccountsService in HGInventoryService configuration");
78
79 Object[] args = new Object[] { config };
80 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args);
81 if (m_UserAccountService == null)
82 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll));
83
84 m_HomeURL = Util.GetConfigVarFromSections<string>(config, "HomeURI",
85 new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty);
86
87 m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
88 }
89
90 m_log.Debug("[HG INVENTORY SERVICE]: Starting...");
91 }
92
93 public override bool CreateUserInventory(UUID principalID)
94 {
95 // NOGO
96 return false;
97 }
98
99
100 public override List<InventoryFolderBase> GetInventorySkeleton(UUID principalID)
101 {
102 // NOGO for this inventory service
103 return new List<InventoryFolderBase>();
104 }
105
106 public override InventoryFolderBase GetRootFolder(UUID principalID)
107 {
108 //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetRootFolder for {0}", principalID);
109 // Warp! Root folder for travelers
110 XInventoryFolder[] folders = m_Database.GetFolders(
111 new string[] { "agentID", "folderName"},
112 new string[] { principalID.ToString(), "My Suitcase" });
113
114 if (folders.Length > 0)
115 return ConvertToOpenSim(folders[0]);
116
117 // make one
118 XInventoryFolder suitcase = CreateFolder(principalID, UUID.Zero, (int)FolderType.Suitcase, "My Suitcase");
119 return ConvertToOpenSim(suitcase);
120 }
121
122 //private bool CreateSystemFolders(UUID principalID, XInventoryFolder suitcase)
123 //{
124
125 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Animation, "Animations");
126 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Bodypart, "Body Parts");
127 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.CallingCard, "Calling Cards");
128 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Clothing, "Clothing");
129 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Gesture, "Gestures");
130 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Landmark, "Landmarks");
131 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.LostAndFoundFolder, "Lost And Found");
132 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Notecard, "Notecards");
133 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Object, "Objects");
134 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.SnapshotFolder, "Photo Album");
135 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.LSLText, "Scripts");
136 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Sound, "Sounds");
137 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Texture, "Textures");
138 // CreateFolder(principalID, suitcase.folderID, (int)AssetType.TrashFolder, "Trash");
139
140 // return true;
141 //}
142
143
144 public override InventoryFolderBase GetFolderForType(UUID principalID, FolderType type)
145 {
146 //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type);
147 return GetRootFolder(principalID);
148 }
149
150 //
151 // Use the inherited methods
152 //
153 //public InventoryCollection GetFolderContent(UUID principalID, UUID folderID)
154 //{
155 //}
156
157 // NOGO
158 //
159 public override InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderID)
160 {
161 return new InventoryCollection[0];
162 }
163
164 //public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
165 //{
166 //}
167
168 //public override bool AddFolder(InventoryFolderBase folder)
169 //{
170 // // Check if it's under the Suitcase folder
171 // List<InventoryFolderBase> skel = base.GetInventorySkeleton(folder.Owner);
172 // InventoryFolderBase suitcase = GetRootFolder(folder.Owner);
173 // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID);
174
175 // foreach (InventoryFolderBase f in suitDescendents)
176 // if (folder.ParentID == f.ID)
177 // {
178 // XInventoryFolder xFolder = ConvertFromOpenSim(folder);
179 // return m_Database.StoreFolder(xFolder);
180 // }
181 // return false;
182 //}
183
184 private List<InventoryFolderBase> GetDescendents(List<InventoryFolderBase> lst, UUID root)
185 {
186 List<InventoryFolderBase> direct = lst.FindAll(delegate(InventoryFolderBase f) { return f.ParentID == root; });
187 if (direct == null)
188 return new List<InventoryFolderBase>();
189
190 List<InventoryFolderBase> indirect = new List<InventoryFolderBase>();
191 foreach (InventoryFolderBase f in direct)
192 indirect.AddRange(GetDescendents(lst, f.ID));
193
194 direct.AddRange(indirect);
195 return direct;
196 }
197
198 // Use inherited method
199 //public bool UpdateFolder(InventoryFolderBase folder)
200 //{
201 //}
202
203 //public override bool MoveFolder(InventoryFolderBase folder)
204 //{
205 // XInventoryFolder[] x = m_Database.GetFolders(
206 // new string[] { "folderID" },
207 // new string[] { folder.ID.ToString() });
208
209 // if (x.Length == 0)
210 // return false;
211
212 // // Check if it's under the Suitcase folder
213 // List<InventoryFolderBase> skel = base.GetInventorySkeleton(folder.Owner);
214 // InventoryFolderBase suitcase = GetRootFolder(folder.Owner);
215 // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID);
216
217 // foreach (InventoryFolderBase f in suitDescendents)
218 // if (folder.ParentID == f.ID)
219 // {
220 // x[0].parentFolderID = folder.ParentID;
221 // return m_Database.StoreFolder(x[0]);
222 // }
223
224 // return false;
225 //}
226
227 public override bool DeleteFolders(UUID principalID, List<UUID> folderIDs)
228 {
229 // NOGO
230 return false;
231 }
232
233 public override bool PurgeFolder(InventoryFolderBase folder)
234 {
235 // NOGO
236 return false;
237 }
238
239 // Unfortunately we need to use the inherited method because of how DeRez works.
240 // The viewer sends the folderID hard-wired in the derez message
241 //public override bool AddItem(InventoryItemBase item)
242 //{
243 // // Check if it's under the Suitcase folder
244 // List<InventoryFolderBase> skel = base.GetInventorySkeleton(item.Owner);
245 // InventoryFolderBase suitcase = GetRootFolder(item.Owner);
246 // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID);
247
248 // foreach (InventoryFolderBase f in suitDescendents)
249 // if (item.Folder == f.ID)
250 // return m_Database.StoreItem(ConvertFromOpenSim(item));
251
252 // return false;
253 //}
254
255 //public override bool UpdateItem(InventoryItemBase item)
256 //{
257 // // Check if it's under the Suitcase folder
258 // List<InventoryFolderBase> skel = base.GetInventorySkeleton(item.Owner);
259 // InventoryFolderBase suitcase = GetRootFolder(item.Owner);
260 // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID);
261
262 // foreach (InventoryFolderBase f in suitDescendents)
263 // if (item.Folder == f.ID)
264 // return m_Database.StoreItem(ConvertFromOpenSim(item));
265
266 // return false;
267 //}
268
269 //public override bool MoveItems(UUID principalID, List<InventoryItemBase> items)
270 //{
271 // // Principal is b0rked. *sigh*
272 // //
273 // // Let's assume they all have the same principal
274 // // Check if it's under the Suitcase folder
275 // List<InventoryFolderBase> skel = base.GetInventorySkeleton(items[0].Owner);
276 // InventoryFolderBase suitcase = GetRootFolder(items[0].Owner);
277 // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID);
278
279 // foreach (InventoryItemBase i in items)
280 // {
281 // foreach (InventoryFolderBase f in suitDescendents)
282 // if (i.Folder == f.ID)
283 // m_Database.MoveItem(i.ID.ToString(), i.Folder.ToString());
284 // }
285
286 // return true;
287 //}
288
289 // Let these pass. Use inherited methods.
290 //public bool DeleteItems(UUID principalID, List<UUID> itemIDs)
291 //{
292 //}
293
294 public override InventoryItemBase GetItem(InventoryItemBase item)
295 {
296 InventoryItemBase it = base.GetItem(item);
297 if (it != null)
298 {
299 UserAccount user = m_Cache.GetUser(it.CreatorId);
300
301 // Adjust the creator data
302 if (user != null && it != null && string.IsNullOrEmpty(it.CreatorData))
303 it.CreatorData = m_HomeURL + ";" + user.FirstName + " " + user.LastName;
304 }
305 return it;
306 }
307
308 //public InventoryFolderBase GetFolder(InventoryFolderBase folder)
309 //{
310 //}
311
312 //public List<InventoryItemBase> GetActiveGestures(UUID principalID)
313 //{
314 //}
315
316 //public int GetAssetPermissions(UUID principalID, UUID assetID)
317 //{
318 //}
319
320 }
321}
diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
new file mode 100644
index 0000000..40eb6d4
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
@@ -0,0 +1,652 @@
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 OpenMetaverse;
32using log4net;
33using Nini.Config;
34using System.Reflection;
35using OpenSim.Services.Base;
36using OpenSim.Services.Interfaces;
37using OpenSim.Services.InventoryService;
38using OpenSim.Data;
39using OpenSim.Framework;
40using OpenSim.Server.Base;
41
42namespace OpenSim.Services.HypergridService
43{
44 /// <summary>
45 /// Hypergrid inventory service. It serves the IInventoryService interface,
46 /// but implements it in ways that are appropriate for inter-grid
47 /// inventory exchanges. Specifically, it does not performs deletions
48 /// and it responds to GetRootFolder requests with the ID of the
49 /// Suitcase folder, not the actual "My Inventory" folder.
50 /// </summary>
51 public class HGSuitcaseInventoryService : XInventoryService, IInventoryService
52 {
53 private static readonly ILog m_log =
54 LogManager.GetLogger(
55 MethodBase.GetCurrentMethod().DeclaringType);
56
57// private string m_HomeURL;
58 private IUserAccountService m_UserAccountService;
59 private IAvatarService m_AvatarService;
60
61// private UserAccountCache m_Cache;
62
63 private ExpiringCache<UUID, List<XInventoryFolder>> m_SuitcaseTrees = new ExpiringCache<UUID, List<XInventoryFolder>>();
64 private ExpiringCache<UUID, AvatarAppearance> m_Appearances = new ExpiringCache<UUID, AvatarAppearance>();
65
66 public HGSuitcaseInventoryService(IConfigSource config, string configName)
67 : base(config, configName)
68 {
69 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Starting with config name {0}", configName);
70 if (configName != string.Empty)
71 m_ConfigName = configName;
72
73 if (m_Database == null)
74 m_log.ErrorFormat("[HG SUITCASE INVENTORY SERVICE]: m_Database is null!");
75
76 //
77 // Try reading the [InventoryService] section, if it exists
78 //
79 IConfig invConfig = config.Configs[m_ConfigName];
80 if (invConfig != null)
81 {
82 string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty);
83 if (userAccountsDll == string.Empty)
84 throw new Exception("Please specify UserAccountsService in HGInventoryService configuration");
85
86 Object[] args = new Object[] { config };
87 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args);
88 if (m_UserAccountService == null)
89 throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll));
90
91 string avatarDll = invConfig.GetString("AvatarService", string.Empty);
92 if (avatarDll == string.Empty)
93 throw new Exception("Please specify AvatarService in HGInventoryService configuration");
94
95 m_AvatarService = ServerUtils.LoadPlugin<IAvatarService>(avatarDll, args);
96 if (m_AvatarService == null)
97 throw new Exception(String.Format("Unable to create m_AvatarService from {0}", avatarDll));
98
99// m_HomeURL = Util.GetConfigVarFromSections<string>(config, "HomeURI",
100// new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty);
101
102// m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
103 }
104
105 m_log.Debug("[HG SUITCASE INVENTORY SERVICE]: Starting...");
106 }
107
108 public override bool CreateUserInventory(UUID principalID)
109 {
110 // NOGO
111 return false;
112 }
113
114 public override List<InventoryFolderBase> GetInventorySkeleton(UUID principalID)
115 {
116 XInventoryFolder suitcase = GetSuitcaseXFolder(principalID);
117
118 if (suitcase == null)
119 {
120 m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no suitcase folder for user {0} when looking for inventory skeleton", principalID);
121 return null;
122 }
123
124 List<XInventoryFolder> tree = GetFolderTree(principalID, suitcase.folderID);
125 if (tree.Count == 0)
126 return null;
127
128 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
129 foreach (XInventoryFolder x in tree)
130 {
131 folders.Add(ConvertToOpenSim(x));
132 }
133
134 SetAsNormalFolder(suitcase);
135 folders.Add(ConvertToOpenSim(suitcase));
136
137 return folders;
138 }
139
140 public override InventoryFolderBase GetRootFolder(UUID principalID)
141 {
142 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetRootFolder for {0}", principalID);
143
144 // Let's find out the local root folder
145 XInventoryFolder root = GetRootXFolder(principalID);
146
147 if (root == null)
148 {
149 m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to retrieve local root folder for user {0}", principalID);
150 return null;
151 }
152
153 // Warp! Root folder for travelers is the suitcase folder
154 XInventoryFolder suitcase = GetSuitcaseXFolder(principalID);
155
156 if (suitcase == null)
157 {
158 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder. Creating it...", principalID);
159 // Create the My Suitcase folder under the user's root folder.
160 // In the DB we tag it as type 100, but we use type 8 (Folder) outside, as this affects the sort order.
161 suitcase = CreateFolder(principalID, root.folderID, (int)FolderType.Suitcase, InventoryFolderBase.SUITCASE_FOLDER_NAME);
162 if (suitcase == null)
163 {
164 m_log.ErrorFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to create suitcase folder");
165 return null;
166 }
167
168 CreateSystemFolders(principalID, suitcase.folderID);
169 }
170
171 SetAsNormalFolder(suitcase);
172
173 return ConvertToOpenSim(suitcase);
174 }
175
176 protected void CreateSystemFolders(UUID principalID, UUID rootID)
177 {
178 m_log.Debug("[HG SUITCASE INVENTORY SERVICE]: Creating System folders under Suitcase...");
179 XInventoryFolder[] sysFolders = GetSystemFolders(principalID, rootID);
180
181 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Animation) return true; return false; }))
182 CreateFolder(principalID, rootID, (int)FolderType.Animation, "Animations");
183 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.BodyPart) return true; return false; }))
184 CreateFolder(principalID, rootID, (int)FolderType.BodyPart, "Body Parts");
185 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.CallingCard) return true; return false; }))
186 CreateFolder(principalID, rootID, (int)FolderType.CallingCard, "Calling Cards");
187 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Clothing) return true; return false; }))
188 CreateFolder(principalID, rootID, (int)FolderType.Clothing, "Clothing");
189 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.CurrentOutfit) return true; return false; }))
190 CreateFolder(principalID, rootID, (int)FolderType.CurrentOutfit, "Current Outfit");
191 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Favorites) return true; return false; }))
192 CreateFolder(principalID, rootID, (int)FolderType.Favorites, "Favorites");
193 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Gesture) return true; return false; }))
194 CreateFolder(principalID, rootID, (int)FolderType.Gesture, "Gestures");
195 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Landmark) return true; return false; }))
196 CreateFolder(principalID, rootID, (int)FolderType.Landmark, "Landmarks");
197 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.LostAndFound) return true; return false; }))
198 CreateFolder(principalID, rootID, (int)FolderType.LostAndFound, "Lost And Found");
199 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Notecard) return true; return false; }))
200 CreateFolder(principalID, rootID, (int)FolderType.Notecard, "Notecards");
201 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Object) return true; return false; }))
202 CreateFolder(principalID, rootID, (int)FolderType.Object, "Objects");
203 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Snapshot) return true; return false; }))
204 CreateFolder(principalID, rootID, (int)FolderType.Snapshot, "Photo Album");
205 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.LSLText) return true; return false; }))
206 CreateFolder(principalID, rootID, (int)FolderType.LSLText, "Scripts");
207 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Sound) return true; return false; }))
208 CreateFolder(principalID, rootID, (int)FolderType.Sound, "Sounds");
209 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Texture) return true; return false; }))
210 CreateFolder(principalID, rootID, (int)FolderType.Texture, "Textures");
211 if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Trash) return true; return false; }))
212 CreateFolder(principalID, rootID, (int)FolderType.Trash, "Trash");
213 }
214
215 public override InventoryFolderBase GetFolderForType(UUID principalID, FolderType type)
216 {
217 //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type);
218 XInventoryFolder suitcase = GetSuitcaseXFolder(principalID);
219
220 if (suitcase == null)
221 {
222 m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no suitcase folder for user {0} when looking for child type folder {1}", principalID, type);
223 return null;
224 }
225
226 XInventoryFolder[] folders = m_Database.GetFolders(
227 new string[] { "agentID", "type", "parentFolderID" },
228 new string[] { principalID.ToString(), ((int)type).ToString(), suitcase.folderID.ToString() });
229
230 if (folders.Length == 0)
231 {
232 m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no folder for type {0} for user {1}", type, principalID);
233 return null;
234 }
235
236 m_log.DebugFormat(
237 "[HG SUITCASE INVENTORY SERVICE]: Found folder {0} {1} for type {2} for user {3}",
238 folders[0].folderName, folders[0].folderID, type, principalID);
239
240 return ConvertToOpenSim(folders[0]);
241 }
242
243 public override InventoryCollection GetFolderContent(UUID principalID, UUID folderID)
244 {
245 InventoryCollection coll = null;
246
247 if (!IsWithinSuitcaseTree(principalID, folderID))
248 {
249 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderContent: folder {0} (user {1}) is not within Suitcase tree", folderID, principalID);
250 return new InventoryCollection();
251 }
252
253 coll = base.GetFolderContent(principalID, folderID);
254
255 if (coll == null)
256 {
257 m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Something wrong with user {0}'s suitcase folder", principalID);
258 coll = new InventoryCollection();
259 }
260 return coll;
261 }
262
263 public override List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
264 {
265 // Let's do a bit of sanity checking, more than the base service does
266 // make sure the given folder exists under the suitcase tree of this user
267 if (!IsWithinSuitcaseTree(principalID, folderID))
268 {
269 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderItems: folder {0} (user {1}) is not within Suitcase tree", folderID, principalID);
270 return new List<InventoryItemBase>();
271 }
272
273 return base.GetFolderItems(principalID, folderID);
274 }
275
276 public override bool AddFolder(InventoryFolderBase folder)
277 {
278 //m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder {0} {1}", folder.Name, folder.ParentID);
279 // Let's do a bit of sanity checking, more than the base service does
280 // make sure the given folder's parent folder exists under the suitcase tree of this user
281
282 if (!IsWithinSuitcaseTree(folder.Owner, folder.ParentID))
283 {
284 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder: folder {0} (user {1}) is not within Suitcase tree", folder.ParentID, folder.Owner);
285 return false;
286 }
287
288 // OK, it's legit
289 if (base.AddFolder(folder))
290 {
291 List<XInventoryFolder> tree;
292 if (m_SuitcaseTrees.TryGetValue(folder.Owner, out tree))
293 tree.Add(ConvertFromOpenSim(folder));
294
295 return true;
296 }
297
298 return false;
299 }
300
301 public override bool UpdateFolder(InventoryFolderBase folder)
302 {
303 //m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Update folder {0}, version {1}", folder.ID, folder.Version);
304 if (!IsWithinSuitcaseTree(folder.Owner, folder.ID))
305 {
306 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: UpdateFolder: folder {0}/{1} (user {2}) is not within Suitcase tree", folder.Name, folder.ID, folder.Owner);
307 return false;
308 }
309
310 // For all others
311 return base.UpdateFolder(folder);
312 }
313
314 public override bool MoveFolder(InventoryFolderBase folder)
315 {
316 if (!IsWithinSuitcaseTree(folder.Owner, folder.ID))
317 {
318 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveFolder: folder {0} (user {1}) is not within Suitcase tree", folder.ID, folder.Owner);
319 return false;
320 }
321
322 if (!IsWithinSuitcaseTree(folder.Owner, folder.ParentID))
323 {
324 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveFolder: folder {0} (user {1}) is not within Suitcase tree", folder.ParentID, folder.Owner);
325 return false;
326 }
327
328 return base.MoveFolder(folder);
329 }
330
331 public override bool DeleteFolders(UUID principalID, List<UUID> folderIDs)
332 {
333 // NOGO
334 return false;
335 }
336
337 public override bool PurgeFolder(InventoryFolderBase folder)
338 {
339 // NOGO
340 return false;
341 }
342
343 public override bool AddItem(InventoryItemBase item)
344 {
345 // Let's do a bit of sanity checking, more than the base service does
346 // make sure the given folder's parent folder exists under the suitcase tree of this user
347 if (!IsWithinSuitcaseTree(item.Owner, item.Folder))
348 {
349 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddItem: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner);
350 return false;
351 }
352
353 // OK, it's legit
354 return base.AddItem(item);
355
356 }
357
358 public override bool UpdateItem(InventoryItemBase item)
359 {
360 if (!IsWithinSuitcaseTree(item.Owner, item.Folder))
361 {
362 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: UpdateItem: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner);
363 return false;
364 }
365
366 return base.UpdateItem(item);
367 }
368
369 public override bool MoveItems(UUID principalID, List<InventoryItemBase> items)
370 {
371 // Principal is b0rked. *sigh*
372
373 // Check the items' destination folders
374 foreach (InventoryItemBase item in items)
375 {
376 if (!IsWithinSuitcaseTree(item.Owner, item.Folder))
377 {
378 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveItems: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner);
379 return false;
380 }
381 }
382
383 // Check the items' current folders
384 foreach (InventoryItemBase item in items)
385 {
386 InventoryItemBase originalItem = base.GetItem(item);
387 if (!IsWithinSuitcaseTree(originalItem.Owner, originalItem.Folder))
388 {
389 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveItems: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner);
390 return false;
391 }
392 }
393
394 return base.MoveItems(principalID, items);
395 }
396
397 public override bool DeleteItems(UUID principalID, List<UUID> itemIDs)
398 {
399 return false;
400 }
401
402 public new InventoryItemBase GetItem(InventoryItemBase item)
403 {
404 InventoryItemBase it = base.GetItem(item);
405 if (it == null)
406 {
407 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to retrieve item {0} ({1}) in folder {2}",
408 item.Name, item.ID, item.Folder);
409 return null;
410 }
411
412 if (!IsWithinSuitcaseTree(it.Owner, it.Folder) && !IsPartOfAppearance(it.Owner, it.ID))
413 {
414 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetItem: item {0}/{1} (folder {2}) (user {3}) is not within Suitcase tree or Appearance",
415 it.Name, it.ID, it.Folder, it.Owner);
416 return null;
417 }
418
419 // UserAccount user = m_Cache.GetUser(it.CreatorId);
420
421 // // Adjust the creator data
422 // if (user != null && it != null && (it.CreatorData == null || it.CreatorData == string.Empty))
423 // it.CreatorData = m_HomeURL + ";" + user.FirstName + " " + user.LastName;
424 //}
425
426 return it;
427 }
428
429 public new InventoryFolderBase GetFolder(InventoryFolderBase folder)
430 {
431 InventoryFolderBase f = base.GetFolder(folder);
432
433 if (f != null)
434 {
435 if (!IsWithinSuitcaseTree(f.Owner, f.ID))
436 {
437 m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolder: folder {0}/{1} (user {2}) is not within Suitcase tree",
438 f.Name, f.ID, f.Owner);
439 return null;
440 }
441 }
442
443 return f;
444 }
445
446 //public List<InventoryItemBase> GetActiveGestures(UUID principalID)
447 //{
448 //}
449
450 //public int GetAssetPermissions(UUID principalID, UUID assetID)
451 //{
452 //}
453
454 #region Auxiliary functions
455 private XInventoryFolder GetXFolder(UUID userID, UUID folderID)
456 {
457 XInventoryFolder[] folders = m_Database.GetFolders(
458 new string[] { "agentID", "folderID" },
459 new string[] { userID.ToString(), folderID.ToString() });
460
461 if (folders.Length == 0)
462 return null;
463
464 return folders[0];
465 }
466
467 private XInventoryFolder GetRootXFolder(UUID principalID)
468 {
469 XInventoryFolder[] folders = m_Database.GetFolders(
470 new string[] { "agentID", "folderName", "type" },
471 new string[] { principalID.ToString(), InventoryFolderBase.ROOT_FOLDER_NAME, ((int)FolderType.Root).ToString() });
472
473 if (folders != null && folders.Length > 0)
474 return folders[0];
475
476 // OK, so the RootFolder type didn't work. Let's look for any type with parent UUID.Zero.
477 folders = m_Database.GetFolders(
478 new string[] { "agentID", "folderName", "parentFolderID" },
479 new string[] { principalID.ToString(), InventoryFolderBase.ROOT_FOLDER_NAME, UUID.Zero.ToString() });
480
481 if (folders != null && folders.Length > 0)
482 return folders[0];
483
484 return null;
485 }
486
487 private XInventoryFolder GetCurrentOutfitXFolder(UUID userID)
488 {
489 XInventoryFolder root = GetRootXFolder(userID);
490 if (root == null)
491 return null;
492
493 XInventoryFolder[] folders = m_Database.GetFolders(
494 new string[] { "agentID", "type", "parentFolderID" },
495 new string[] { userID.ToString(), ((int)FolderType.CurrentOutfit).ToString(), root.folderID.ToString() });
496
497 if (folders.Length == 0)
498 return null;
499
500 return folders[0];
501 }
502
503 private XInventoryFolder GetSuitcaseXFolder(UUID principalID)
504 {
505 // Warp! Root folder for travelers
506 XInventoryFolder[] folders = m_Database.GetFolders(
507 new string[] { "agentID", "type" },
508 new string[] { principalID.ToString(), ((int)FolderType.Suitcase).ToString() });
509
510 if (folders != null && folders.Length > 0)
511 return folders[0];
512
513 // check to see if we have the old Suitcase folder
514 folders = m_Database.GetFolders(
515 new string[] { "agentID", "folderName", "parentFolderID" },
516 new string[] { principalID.ToString(), InventoryFolderBase.SUITCASE_FOLDER_NAME, UUID.Zero.ToString() });
517 if (folders != null && folders.Length > 0)
518 {
519 // Move it to under the root folder
520 XInventoryFolder root = GetRootXFolder(principalID);
521 folders[0].parentFolderID = root.folderID;
522 folders[0].type = (int)FolderType.Suitcase;
523 m_Database.StoreFolder(folders[0]);
524 return folders[0];
525 }
526
527 return null;
528 }
529
530 private void SetAsNormalFolder(XInventoryFolder suitcase)
531 {
532 //suitcase.type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE;
533 }
534
535 private List<XInventoryFolder> GetFolderTree(UUID principalID, UUID folder)
536 {
537 List<XInventoryFolder> t;
538 if (m_SuitcaseTrees.TryGetValue(principalID, out t))
539 return t;
540
541 // Get the tree of the suitcase folder
542 t = GetFolderTreeRecursive(folder);
543 m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5 minutes
544 return t;
545 }
546
547 private List<XInventoryFolder> GetFolderTreeRecursive(UUID root)
548 {
549 List<XInventoryFolder> tree = new List<XInventoryFolder>();
550 XInventoryFolder[] folders = m_Database.GetFolders(
551 new string[] { "parentFolderID" },
552 new string[] { root.ToString() });
553
554 if (folders == null || folders.Length == 0)
555 {
556 return tree; // empty tree
557 }
558 else
559 {
560 foreach (XInventoryFolder f in folders)
561 {
562 tree.Add(f);
563 tree.AddRange(GetFolderTreeRecursive(f.folderID));
564 }
565 return tree;
566 }
567
568 }
569
570 /// <summary>
571 /// Return true if the folderID is a subfolder of the Suitcase or the suitcase folder itself
572 /// </summary>
573 /// <param name="folderID"></param>
574 /// <param name="root"></param>
575 /// <param name="suitcase"></param>
576 /// <returns></returns>
577 private bool IsWithinSuitcaseTree(UUID principalID, UUID folderID)
578 {
579 XInventoryFolder suitcase = GetSuitcaseXFolder(principalID);
580
581 if (suitcase == null)
582 {
583 m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder", principalID);
584 return false;
585 }
586
587 List<XInventoryFolder> tree = new List<XInventoryFolder>();
588 tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder
589 tree.AddRange(GetFolderTree(principalID, suitcase.folderID));
590
591 // Also add the Current Outfit folder to the list of available folders
592 XInventoryFolder folder = GetCurrentOutfitXFolder(principalID);
593 if (folder != null)
594 tree.Add(folder);
595
596 XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl)
597 {
598 return (fl.folderID == folderID);
599 });
600
601 return (f != null);
602 }
603 #endregion
604
605 #region Avatar Appearance
606
607 private AvatarAppearance GetAppearance(UUID principalID)
608 {
609 AvatarAppearance a = null;
610 if (m_Appearances.TryGetValue(principalID, out a))
611 return a;
612
613 a = m_AvatarService.GetAppearance(principalID);
614 m_Appearances.AddOrUpdate(principalID, a, 5 * 60); // 5minutes
615 return a;
616 }
617
618 private bool IsPartOfAppearance(UUID principalID, UUID itemID)
619 {
620 AvatarAppearance a = GetAppearance(principalID);
621
622 if (a == null)
623 return false;
624
625 // Check wearables (body parts and clothes)
626 for (int i = 0; i < a.Wearables.Length; i++)
627 {
628 for (int j = 0; j < a.Wearables[i].Count; j++)
629 {
630 if (a.Wearables[i][j].ItemID == itemID)
631 {
632 //m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is a wearable", itemID);
633 return true;
634 }
635 }
636 }
637
638 // Check attachments
639 if (a.GetAttachmentForItem(itemID) != null)
640 {
641 //m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: item {0} is an attachment", itemID);
642 return true;
643 }
644
645 return false;
646 }
647
648 #endregion
649
650 }
651
652}
diff --git a/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs b/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a565729
--- /dev/null
+++ b/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Services.HypergridService")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("8584f3c1-26dd-4d95-86f4-cd8f0110a18f")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.8.2.*")]
33
diff --git a/OpenSim/Services/HypergridService/UserAccountCache.cs b/OpenSim/Services/HypergridService/UserAccountCache.cs
new file mode 100644
index 0000000..fa7dd0b
--- /dev/null
+++ b/OpenSim/Services/HypergridService/UserAccountCache.cs
@@ -0,0 +1,111 @@
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4
5using log4net;
6using OpenMetaverse;
7
8using OpenSim.Services.Interfaces;
9
10namespace OpenSim.Services.HypergridService
11{
12 public class UserAccountCache : IUserAccountService
13 {
14 private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours!
15
16// private static readonly ILog m_log =
17// LogManager.GetLogger(
18// MethodBase.GetCurrentMethod().DeclaringType);
19
20 private ExpiringCache<UUID, UserAccount> m_UUIDCache;
21
22 private IUserAccountService m_UserAccountService;
23
24 private static UserAccountCache m_Singleton;
25
26 public static UserAccountCache CreateUserAccountCache(IUserAccountService u)
27 {
28 if (m_Singleton == null)
29 m_Singleton = new UserAccountCache(u);
30
31 return m_Singleton;
32 }
33
34 private UserAccountCache(IUserAccountService u)
35 {
36 m_UUIDCache = new ExpiringCache<UUID, UserAccount>();
37 m_UserAccountService = u;
38 }
39
40 public void Cache(UUID userID, UserAccount account)
41 {
42 // Cache even null accounts
43 m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS);
44
45 //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID);
46 }
47
48 public UserAccount Get(UUID userID, out bool inCache)
49 {
50 UserAccount account = null;
51 inCache = false;
52 if (m_UUIDCache.TryGetValue(userID, out account))
53 {
54 //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName);
55 inCache = true;
56 return account;
57 }
58
59 return null;
60 }
61
62 public UserAccount GetUser(string id)
63 {
64 UUID uuid = UUID.Zero;
65 UUID.TryParse(id, out uuid);
66 bool inCache = false;
67 UserAccount account = Get(uuid, out inCache);
68 if (!inCache)
69 {
70 account = m_UserAccountService.GetUserAccount(UUID.Zero, uuid);
71 Cache(uuid, account);
72 }
73
74 return account;
75 }
76
77 #region IUserAccountService
78 public UserAccount GetUserAccount(UUID scopeID, UUID userID)
79 {
80 return GetUser(userID.ToString());
81 }
82
83 public UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName)
84 {
85 return null;
86 }
87
88 public UserAccount GetUserAccount(UUID scopeID, string Email)
89 {
90 return null;
91 }
92
93 public List<UserAccount> GetUserAccounts(UUID scopeID, string query)
94 {
95 return null;
96 }
97
98 public void InvalidateCache(UUID userID)
99 {
100 m_UUIDCache.Remove(userID);
101 }
102
103 public bool StoreUserAccount(UserAccount data)
104 {
105 return false;
106 }
107 #endregion
108
109 }
110
111}
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs
new file mode 100644
index 0000000..c65122a
--- /dev/null
+++ b/OpenSim/Services/HypergridService/UserAgentService.cs
@@ -0,0 +1,746 @@
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.Data;
34using OpenSim.Framework;
35using OpenSim.Services.Connectors.Friends;
36using OpenSim.Services.Connectors.Hypergrid;
37using OpenSim.Services.Interfaces;
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 /// This service is for HG1.5 only, to make up for the fact that clients don't
50 /// keep any private information in themselves, and that their 'home service'
51 /// needs to do it for them.
52 /// Once we have better clients, this shouldn't be needed.
53 /// </summary>
54 public class UserAgentService : UserAgentServiceBase, IUserAgentService
55 {
56 private static readonly ILog m_log =
57 LogManager.GetLogger(
58 MethodBase.GetCurrentMethod().DeclaringType);
59
60 // This will need to go into a DB table
61 //static Dictionary<UUID, TravelingAgentInfo> m_Database = new Dictionary<UUID, TravelingAgentInfo>();
62
63 static bool m_Initialized = false;
64
65 protected static IGridUserService m_GridUserService;
66 protected static IGridService m_GridService;
67 protected static GatekeeperServiceConnector m_GatekeeperConnector;
68 protected static IGatekeeperService m_GatekeeperService;
69 protected static IFriendsService m_FriendsService;
70 protected static IPresenceService m_PresenceService;
71 protected static IUserAccountService m_UserAccountService;
72 protected static IFriendsSimConnector m_FriendsLocalSimConnector; // standalone, points to HGFriendsModule
73 protected static FriendsSimConnector m_FriendsSimConnector; // grid
74
75 protected static string m_GridName;
76
77 protected static int m_LevelOutsideContacts;
78 protected static bool m_ShowDetails;
79
80 protected static bool m_BypassClientVerification;
81
82 private static Dictionary<int, bool> m_ForeignTripsAllowed = new Dictionary<int, bool>();
83 private static Dictionary<int, List<string>> m_TripsAllowedExceptions = new Dictionary<int, List<string>>();
84 private static Dictionary<int, List<string>> m_TripsDisallowedExceptions = new Dictionary<int, List<string>>();
85
86 public UserAgentService(IConfigSource config) : this(config, null)
87 {
88 }
89
90 public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector)
91 : base(config)
92 {
93 // Let's set this always, because we don't know the sequence
94 // of instantiations
95 if (friendsConnector != null)
96 m_FriendsLocalSimConnector = friendsConnector;
97
98 if (!m_Initialized)
99 {
100 m_Initialized = true;
101
102 m_log.DebugFormat("[HOME USERS SECURITY]: Starting...");
103
104 m_FriendsSimConnector = new FriendsSimConnector();
105
106 IConfig serverConfig = config.Configs["UserAgentService"];
107 if (serverConfig == null)
108 throw new Exception(String.Format("No section UserAgentService in config file"));
109
110 string gridService = serverConfig.GetString("GridService", String.Empty);
111 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
112 string gatekeeperService = serverConfig.GetString("GatekeeperService", String.Empty);
113 string friendsService = serverConfig.GetString("FriendsService", String.Empty);
114 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
115 string userAccountService = serverConfig.GetString("UserAccountService", String.Empty);
116
117 m_BypassClientVerification = serverConfig.GetBoolean("BypassClientVerification", false);
118
119 if (gridService == string.Empty || gridUserService == string.Empty || gatekeeperService == string.Empty)
120 throw new Exception(String.Format("Incomplete specifications, UserAgent Service cannot function."));
121
122 Object[] args = new Object[] { config };
123 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
124 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
125 m_GatekeeperConnector = new GatekeeperServiceConnector();
126 m_GatekeeperService = ServerUtils.LoadPlugin<IGatekeeperService>(gatekeeperService, args);
127 m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(friendsService, args);
128 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
129 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountService, args);
130
131 m_LevelOutsideContacts = serverConfig.GetInt("LevelOutsideContacts", 0);
132 m_ShowDetails = serverConfig.GetBoolean("ShowUserDetailsInHGProfile", true);
133
134 LoadTripPermissionsFromConfig(serverConfig, "ForeignTripsAllowed");
135 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_TripsAllowedExceptions);
136 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_TripsDisallowedExceptions);
137
138 m_GridName = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
139 new string[] { "Startup", "Hypergrid", "UserAgentService" }, String.Empty);
140 if (string.IsNullOrEmpty(m_GridName)) // Legacy. Remove soon.
141 {
142 m_GridName = serverConfig.GetString("ExternalName", string.Empty);
143 if (m_GridName == string.Empty)
144 {
145 serverConfig = config.Configs["GatekeeperService"];
146 m_GridName = serverConfig.GetString("ExternalName", string.Empty);
147 }
148 }
149
150 if (!m_GridName.EndsWith("/"))
151 m_GridName = m_GridName + "/";
152
153 // Finally some cleanup
154 m_Database.DeleteOld();
155
156 }
157 }
158
159 protected void LoadTripPermissionsFromConfig(IConfig config, string variable)
160 {
161 foreach (string keyName in config.GetKeys())
162 {
163 if (keyName.StartsWith(variable + "_Level_"))
164 {
165 int level = 0;
166 if (Int32.TryParse(keyName.Replace(variable + "_Level_", ""), out level))
167 m_ForeignTripsAllowed.Add(level, config.GetBoolean(keyName, true));
168 }
169 }
170 }
171
172 protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, Dictionary<int, List<string>> exceptions)
173 {
174 foreach (string keyName in config.GetKeys())
175 {
176 if (keyName.StartsWith(variable + "_Level_"))
177 {
178 int level = 0;
179 if (Int32.TryParse(keyName.Replace(variable + "_Level_", ""), out level) && !exceptions.ContainsKey(level))
180 {
181 exceptions.Add(level, new List<string>());
182 string value = config.GetString(keyName, string.Empty);
183 string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
184
185 foreach (string s in parts)
186 exceptions[level].Add(s.Trim());
187 }
188 }
189 }
190 }
191
192
193 public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt)
194 {
195 position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY;
196
197 m_log.DebugFormat("[USER AGENT SERVICE]: Request to get home region of user {0}", userID);
198
199 GridRegion home = null;
200 GridUserInfo uinfo = m_GridUserService.GetGridUserInfo(userID.ToString());
201 if (uinfo != null)
202 {
203 if (uinfo.HomeRegionID != UUID.Zero)
204 {
205 home = m_GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
206 position = uinfo.HomePosition;
207 lookAt = uinfo.HomeLookAt;
208 }
209 if (home == null)
210 {
211 List<GridRegion> defs = m_GridService.GetDefaultRegions(UUID.Zero);
212 if (defs != null && defs.Count > 0)
213 home = defs[0];
214 }
215 }
216
217 return home;
218 }
219
220 public bool LoginAgentToGrid(GridRegion source, AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, bool fromLogin, out string reason)
221 {
222 m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}",
223 agentCircuit.firstname, agentCircuit.lastname, (fromLogin ? agentCircuit.IPAddress : "stored IP"), gatekeeper.ServerURI);
224
225 string gridName = gatekeeper.ServerURI;
226
227 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, agentCircuit.AgentID);
228 if (account == null)
229 {
230 m_log.WarnFormat("[USER AGENT SERVICE]: Someone attempted to lauch a foreign user from here {0} {1}", agentCircuit.firstname, agentCircuit.lastname);
231 reason = "Forbidden to launch your agents from here";
232 return false;
233 }
234
235 // Is this user allowed to go there?
236 if (m_GridName != gridName)
237 {
238 if (m_ForeignTripsAllowed.ContainsKey(account.UserLevel))
239 {
240 bool allowed = m_ForeignTripsAllowed[account.UserLevel];
241
242 if (m_ForeignTripsAllowed[account.UserLevel] && IsException(gridName, account.UserLevel, m_TripsAllowedExceptions))
243 allowed = false;
244
245 if (!m_ForeignTripsAllowed[account.UserLevel] && IsException(gridName, account.UserLevel, m_TripsDisallowedExceptions))
246 allowed = true;
247
248 if (!allowed)
249 {
250 reason = "Your world does not allow you to visit the destination";
251 m_log.InfoFormat("[USER AGENT SERVICE]: Agents not permitted to visit {0}. Refusing service.", gridName);
252 return false;
253 }
254 }
255 }
256
257
258 // Take the IP address + port of the gatekeeper (reg) plus the info of finalDestination
259 GridRegion region = new GridRegion(gatekeeper);
260 region.ServerURI = gatekeeper.ServerURI;
261 region.ExternalHostName = finalDestination.ExternalHostName;
262 region.InternalEndPoint = finalDestination.InternalEndPoint;
263 region.RegionName = finalDestination.RegionName;
264 region.RegionID = finalDestination.RegionID;
265 region.RegionLocX = finalDestination.RegionLocX;
266 region.RegionLocY = finalDestination.RegionLocY;
267
268 // Generate a new service session
269 agentCircuit.ServiceSessionID = region.ServerURI + ";" + UUID.Random();
270 TravelingAgentInfo old = null;
271 TravelingAgentInfo travel = CreateTravelInfo(agentCircuit, region, fromLogin, out old);
272
273 bool success = false;
274 string myExternalIP = string.Empty;
275
276 m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}, desired region: {2}", m_GridName, gridName, region.RegionID);
277
278 if (m_GridName == gridName)
279 {
280 success = m_GatekeeperService.LoginAgent(source, agentCircuit, finalDestination, out reason);
281 }
282 else
283 {
284 success = m_GatekeeperConnector.CreateAgent(source, region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, out myExternalIP, out reason);
285 }
286
287 if (!success)
288 {
289 m_log.DebugFormat("[USER AGENT SERVICE]: Unable to login user {0} {1} to grid {2}, reason: {3}",
290 agentCircuit.firstname, agentCircuit.lastname, region.ServerURI, reason);
291
292 if (old != null)
293 StoreTravelInfo(old);
294 else
295 m_Database.Delete(agentCircuit.SessionID);
296
297 return false;
298 }
299
300 // Everything is ok
301
302 // Update the perceived IP Address of our grid
303 m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP);
304 travel.MyIpAddress = myExternalIP;
305
306 StoreTravelInfo(travel);
307
308 return true;
309 }
310
311 public bool LoginAgentToGrid(GridRegion source, AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, out string reason)
312 {
313 reason = string.Empty;
314 return LoginAgentToGrid(source, agentCircuit, gatekeeper, finalDestination, false, out reason);
315 }
316
317 TravelingAgentInfo CreateTravelInfo(AgentCircuitData agentCircuit, GridRegion region, bool fromLogin, out TravelingAgentInfo existing)
318 {
319 HGTravelingData hgt = m_Database.Get(agentCircuit.SessionID);
320 existing = null;
321
322 if (hgt != null)
323 {
324 // Very important! Override whatever this agent comes with.
325 // UserAgentService always sets the IP for every new agent
326 // with the original IP address.
327 existing = new TravelingAgentInfo(hgt);
328 agentCircuit.IPAddress = existing.ClientIPAddress;
329 }
330
331 TravelingAgentInfo travel = new TravelingAgentInfo(existing);
332 travel.SessionID = agentCircuit.SessionID;
333 travel.UserID = agentCircuit.AgentID;
334 travel.GridExternalName = region.ServerURI;
335 travel.ServiceToken = agentCircuit.ServiceSessionID;
336
337 if (fromLogin)
338 travel.ClientIPAddress = agentCircuit.IPAddress;
339
340 StoreTravelInfo(travel);
341
342 return travel;
343 }
344
345 public void LogoutAgent(UUID userID, UUID sessionID)
346 {
347 m_log.DebugFormat("[USER AGENT SERVICE]: User {0} logged out", userID);
348
349 m_Database.Delete(sessionID);
350
351 GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(userID.ToString());
352 if (guinfo != null)
353 m_GridUserService.LoggedOut(userID.ToString(), sessionID, guinfo.LastRegionID, guinfo.LastPosition, guinfo.LastLookAt);
354 }
355
356 // We need to prevent foreign users with the same UUID as a local user
357 public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName)
358 {
359 HGTravelingData hgt = m_Database.Get(sessionID);
360 if (hgt == null)
361 return false;
362
363 TravelingAgentInfo travel = new TravelingAgentInfo(hgt);
364
365 return travel.GridExternalName.ToLower() == thisGridExternalName.ToLower();
366 }
367
368 public bool VerifyClient(UUID sessionID, string reportedIP)
369 {
370 if (m_BypassClientVerification)
371 return true;
372
373 m_log.DebugFormat("[USER AGENT SERVICE]: Verifying Client session {0} with reported IP {1}.",
374 sessionID, reportedIP);
375
376 HGTravelingData hgt = m_Database.Get(sessionID);
377 if (hgt == null)
378 return false;
379
380 TravelingAgentInfo travel = new TravelingAgentInfo(hgt);
381
382 bool result = travel.ClientIPAddress == reportedIP || travel.MyIpAddress == reportedIP; // NATed
383
384 m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}",
385 reportedIP, travel.ClientIPAddress, travel.MyIpAddress, result);
386
387 return result;
388 }
389
390 public bool VerifyAgent(UUID sessionID, string token)
391 {
392 HGTravelingData hgt = m_Database.Get(sessionID);
393 if (hgt == null)
394 {
395 m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID);
396 return false;
397 }
398
399 TravelingAgentInfo travel = new TravelingAgentInfo(hgt);
400 m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, travel.ServiceToken);
401 return travel.ServiceToken == token;
402 }
403
404 [Obsolete]
405 public List<UUID> StatusNotification(List<string> friends, UUID foreignUserID, bool online)
406 {
407 if (m_FriendsService == null || m_PresenceService == null)
408 {
409 m_log.WarnFormat("[USER AGENT SERVICE]: Unable to perform status notifications because friends or presence services are missing");
410 return new List<UUID>();
411 }
412
413 List<UUID> localFriendsOnline = new List<UUID>();
414
415 m_log.DebugFormat("[USER AGENT SERVICE]: Status notification: foreign user {0} wants to notify {1} local friends", foreignUserID, friends.Count);
416
417 // First, let's double check that the reported friends are, indeed, friends of that user
418 // And let's check that the secret matches
419 List<string> usersToBeNotified = new List<string>();
420 foreach (string uui in friends)
421 {
422 UUID localUserID;
423 string secret = string.Empty, tmp = string.Empty;
424 if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret))
425 {
426 FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID);
427 foreach (FriendInfo finfo in friendInfos)
428 {
429 if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret))
430 {
431 // great!
432 usersToBeNotified.Add(localUserID.ToString());
433 }
434 }
435 }
436 }
437
438 // Now, let's send the notifications
439 m_log.DebugFormat("[USER AGENT SERVICE]: Status notification: user has {0} local friends", usersToBeNotified.Count);
440
441 // First, let's send notifications to local users who are online in the home grid
442 PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray());
443 if (friendSessions != null && friendSessions.Length > 0)
444 {
445 PresenceInfo friendSession = null;
446 foreach (PresenceInfo pinfo in friendSessions)
447 if (pinfo.RegionID != UUID.Zero) // let's guard against traveling agents
448 {
449 friendSession = pinfo;
450 break;
451 }
452
453 if (friendSession != null)
454 {
455 ForwardStatusNotificationToSim(friendSession.RegionID, foreignUserID, friendSession.UserID, online);
456 usersToBeNotified.Remove(friendSession.UserID.ToString());
457 UUID id;
458 if (UUID.TryParse(friendSession.UserID, out id))
459 localFriendsOnline.Add(id);
460
461 }
462 }
463
464 //// Lastly, let's notify the rest who may be online somewhere else
465 //foreach (string user in usersToBeNotified)
466 //{
467 // UUID id = new UUID(user);
468 // if (m_Database.ContainsKey(id) && m_Database[id].GridExternalName != m_GridName)
469 // {
470 // string url = m_Database[id].GridExternalName;
471 // // forward
472 // m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url);
473 // }
474 //}
475
476 // and finally, let's send the online friends
477 if (online)
478 {
479 return localFriendsOnline;
480 }
481 else
482 return new List<UUID>();
483 }
484
485 [Obsolete]
486 protected void ForwardStatusNotificationToSim(UUID regionID, UUID foreignUserID, string user, bool online)
487 {
488 UUID userID;
489 if (UUID.TryParse(user, out userID))
490 {
491 if (m_FriendsLocalSimConnector != null)
492 {
493 m_log.DebugFormat("[USER AGENT SERVICE]: Local Notify, user {0} is {1}", foreignUserID, (online ? "online" : "offline"));
494 m_FriendsLocalSimConnector.StatusNotify(foreignUserID, userID, online);
495 }
496 else
497 {
498 GridRegion region = m_GridService.GetRegionByUUID(UUID.Zero /* !!! */, regionID);
499 if (region != null)
500 {
501 m_log.DebugFormat("[USER AGENT SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
502 m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID.ToString(), online);
503 }
504 }
505 }
506 }
507
508 public List<UUID> GetOnlineFriends(UUID foreignUserID, List<string> friends)
509 {
510 List<UUID> online = new List<UUID>();
511
512 if (m_FriendsService == null || m_PresenceService == null)
513 {
514 m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get online friends because friends or presence services are missing");
515 return online;
516 }
517
518 m_log.DebugFormat("[USER AGENT SERVICE]: Foreign user {0} wants to know status of {1} local friends", foreignUserID, friends.Count);
519
520 // First, let's double check that the reported friends are, indeed, friends of that user
521 // And let's check that the secret matches and the rights
522 List<string> usersToBeNotified = new List<string>();
523 foreach (string uui in friends)
524 {
525 UUID localUserID;
526 string secret = string.Empty, tmp = string.Empty;
527 if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret))
528 {
529 FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID);
530 foreach (FriendInfo finfo in friendInfos)
531 {
532 if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret) &&
533 (finfo.TheirFlags & (int)FriendRights.CanSeeOnline) != 0 && (finfo.TheirFlags != -1))
534 {
535 // great!
536 usersToBeNotified.Add(localUserID.ToString());
537 }
538 }
539 }
540 }
541
542 // Now, let's find out their status
543 m_log.DebugFormat("[USER AGENT SERVICE]: GetOnlineFriends: user has {0} local friends with status rights", usersToBeNotified.Count);
544
545 // First, let's send notifications to local users who are online in the home grid
546 PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray());
547 if (friendSessions != null && friendSessions.Length > 0)
548 {
549 foreach (PresenceInfo pi in friendSessions)
550 {
551 UUID presenceID;
552 if (UUID.TryParse(pi.UserID, out presenceID))
553 online.Add(presenceID);
554 }
555 }
556
557 return online;
558 }
559
560 public Dictionary<string, object> GetUserInfo(UUID userID)
561 {
562 Dictionary<string, object> info = new Dictionary<string, object>();
563
564 if (m_UserAccountService == null)
565 {
566 m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get user flags because user account service is missing");
567 info["result"] = "fail";
568 info["message"] = "UserAccountService is missing!";
569 return info;
570 }
571
572 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero /*!!!*/, userID);
573
574 if (account != null)
575 {
576 info.Add("user_firstname", account.FirstName);
577 info.Add("user_lastname", account.LastName);
578 info.Add("result", "success");
579
580 if (m_ShowDetails)
581 {
582 info.Add("user_flags", account.UserFlags);
583 info.Add("user_created", account.Created);
584 info.Add("user_title", account.UserTitle);
585 }
586 else
587 {
588 info.Add("user_flags", 0);
589 info.Add("user_created", 0);
590 info.Add("user_title", string.Empty);
591 }
592 }
593
594 return info;
595 }
596
597 public Dictionary<string, object> GetServerURLs(UUID userID)
598 {
599 if (m_UserAccountService == null)
600 {
601 m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get server URLs because user account service is missing");
602 return new Dictionary<string, object>();
603 }
604 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero /*!!!*/, userID);
605 if (account != null)
606 return account.ServiceURLs;
607
608 return new Dictionary<string, object>();
609 }
610
611 public string LocateUser(UUID userID)
612 {
613 HGTravelingData[] hgts = m_Database.GetSessions(userID);
614 if (hgts == null)
615 return string.Empty;
616
617 foreach (HGTravelingData t in hgts)
618 if (t.Data.ContainsKey("GridExternalName") && !m_GridName.Equals(t.Data["GridExternalName"]))
619 return t.Data["GridExternalName"];
620
621 return string.Empty;
622 }
623
624 public string GetUUI(UUID userID, UUID targetUserID)
625 {
626 // Let's see if it's a local user
627 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, targetUserID);
628 if (account != null)
629 return targetUserID.ToString() + ";" + m_GridName + ";" + account.FirstName + " " + account.LastName ;
630
631 // Let's try the list of friends
632 FriendInfo[] friends = m_FriendsService.GetFriends(userID);
633 if (friends != null && friends.Length > 0)
634 {
635 foreach (FriendInfo f in friends)
636 if (f.Friend.StartsWith(targetUserID.ToString()))
637 {
638 // Let's remove the secret
639 UUID id; string tmp = string.Empty, secret = string.Empty;
640 if (Util.ParseUniversalUserIdentifier(f.Friend, out id, out tmp, out tmp, out tmp, out secret))
641 return f.Friend.Replace(secret, "0");
642 }
643 }
644
645 return string.Empty;
646 }
647
648 public UUID GetUUID(String first, String last)
649 {
650 // Let's see if it's a local user
651 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, first, last);
652 if (account != null)
653 {
654 // check user level
655 if (account.UserLevel < m_LevelOutsideContacts)
656 return UUID.Zero;
657 else
658 return account.PrincipalID;
659 }
660 else
661 return UUID.Zero;
662 }
663
664 #region Misc
665
666 private bool IsException(string dest, int level, Dictionary<int, List<string>> exceptions)
667 {
668 if (!exceptions.ContainsKey(level))
669 return false;
670
671 bool exception = false;
672 if (exceptions[level].Count > 0) // we have exceptions
673 {
674 string destination = dest;
675 if (!destination.EndsWith("/"))
676 destination += "/";
677
678 if (exceptions[level].Find(delegate(string s)
679 {
680 if (!s.EndsWith("/"))
681 s += "/";
682 return s == destination;
683 }) != null)
684 exception = true;
685 }
686
687 return exception;
688 }
689
690 private void StoreTravelInfo(TravelingAgentInfo travel)
691 {
692 if (travel == null)
693 return;
694
695 HGTravelingData hgt = new HGTravelingData();
696 hgt.SessionID = travel.SessionID;
697 hgt.UserID = travel.UserID;
698 hgt.Data = new Dictionary<string, string>();
699 hgt.Data["GridExternalName"] = travel.GridExternalName;
700 hgt.Data["ServiceToken"] = travel.ServiceToken;
701 hgt.Data["ClientIPAddress"] = travel.ClientIPAddress;
702 hgt.Data["MyIPAddress"] = travel.MyIpAddress;
703
704 m_Database.Store(hgt);
705 }
706 #endregion
707
708 }
709
710 class TravelingAgentInfo
711 {
712 public UUID SessionID;
713 public UUID UserID;
714 public string GridExternalName = string.Empty;
715 public string ServiceToken = string.Empty;
716 public string ClientIPAddress = string.Empty; // as seen from this user agent service
717 public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper
718
719 public TravelingAgentInfo(HGTravelingData t)
720 {
721 if (t.Data != null)
722 {
723 SessionID = new UUID(t.SessionID);
724 UserID = new UUID(t.UserID);
725 GridExternalName = t.Data["GridExternalName"];
726 ServiceToken = t.Data["ServiceToken"];
727 ClientIPAddress = t.Data["ClientIPAddress"];
728 MyIpAddress = t.Data["MyIPAddress"];
729 }
730 }
731
732 public TravelingAgentInfo(TravelingAgentInfo old)
733 {
734 if (old != null)
735 {
736 SessionID = old.SessionID;
737 UserID = old.UserID;
738 GridExternalName = old.GridExternalName;
739 ServiceToken = old.ServiceToken;
740 ClientIPAddress = old.ClientIPAddress;
741 MyIpAddress = old.MyIpAddress;
742 }
743 }
744 }
745
746}
diff --git a/OpenSim/Services/HypergridService/UserAgentServiceBase.cs b/OpenSim/Services/HypergridService/UserAgentServiceBase.cs
new file mode 100644
index 0000000..a00e5a6
--- /dev/null
+++ b/OpenSim/Services/HypergridService/UserAgentServiceBase.cs
@@ -0,0 +1,84 @@
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 Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Data;
33using OpenSim.Services.Interfaces;
34using OpenSim.Services.Base;
35
36namespace OpenSim.Services.HypergridService
37{
38 public class UserAgentServiceBase : ServiceBase
39 {
40 protected IHGTravelingData m_Database = null;
41
42 public UserAgentServiceBase(IConfigSource config)
43 : base(config)
44 {
45 string dllName = String.Empty;
46 string connString = String.Empty;
47 string realm = "hg_traveling_data";
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 // [UserAgentService] section overrides [DatabaseService], if it exists
63 //
64 IConfig gridConfig = config.Configs["UserAgentService"];
65 if (gridConfig != null)
66 {
67 dllName = gridConfig.GetString("StorageProvider", dllName);
68 connString = gridConfig.GetString("ConnectionString", connString);
69 realm = gridConfig.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<IHGTravelingData>(dllName, new Object[] { connString, realm });
79 if (m_Database == null)
80 throw new Exception("Could not find a storage interface in the given module");
81
82 }
83 }
84}