diff options
author | diva | 2009-03-29 20:29:13 +0000 |
---|---|---|
committer | diva | 2009-03-29 20:29:13 +0000 |
commit | 08732b65be3ce13e8dd965a4542991a766dbd920 (patch) | |
tree | 6468b2da6513dc5be0859c196d14fc015fdeeb05 /OpenSim/Framework/Communications/Services | |
parent | Don't let a missing configuration cause a NRE (diff) | |
download | opensim-SC-08732b65be3ce13e8dd965a4542991a766dbd920.zip opensim-SC-08732b65be3ce13e8dd965a4542991a766dbd920.tar.gz opensim-SC-08732b65be3ce13e8dd965a4542991a766dbd920.tar.bz2 opensim-SC-08732b65be3ce13e8dd965a4542991a766dbd920.tar.xz |
Moved some files around, so that it's easier to share code between standalone and the grid services. Should not affect any functionality.
Diffstat (limited to 'OpenSim/Framework/Communications/Services')
-rw-r--r-- | OpenSim/Framework/Communications/Services/HGInventoryService.cs | 636 | ||||
-rw-r--r-- | OpenSim/Framework/Communications/Services/HGLoginAuthService.cs | 329 |
2 files changed, 965 insertions, 0 deletions
diff --git a/OpenSim/Framework/Communications/Services/HGInventoryService.cs b/OpenSim/Framework/Communications/Services/HGInventoryService.cs new file mode 100644 index 0000000..f0b2259 --- /dev/null +++ b/OpenSim/Framework/Communications/Services/HGInventoryService.cs | |||
@@ -0,0 +1,636 @@ | |||
1 | /** | ||
2 | * Copyright (c) 2008, Contributors. All rights reserved. | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without modification, | ||
6 | * are permitted provided that the following conditions are met: | ||
7 | * | ||
8 | * * Redistributions of source code must retain the above copyright notice, | ||
9 | * this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
11 | * this list of conditions and the following disclaimer in the documentation | ||
12 | * and/or other materials provided with the distribution. | ||
13 | * * Neither the name of the Organizations nor the names of Individual | ||
14 | * Contributors may be used to endorse or promote products derived from | ||
15 | * this software without specific prior written permission. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | ||
20 | * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | ||
22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
25 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | using System; | ||
30 | using System.Collections; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Reflection; | ||
33 | using log4net; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenSim.Data; | ||
37 | using OpenSim.Framework; | ||
38 | //using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Framework.Communications.Cache; | ||
40 | using Caps = OpenSim.Framework.Communications.Capabilities.Caps; | ||
41 | using LLSDHelpers = OpenSim.Framework.Communications.Capabilities.LLSDHelpers; | ||
42 | using OpenSim.Framework.Servers; | ||
43 | using OpenSim.Framework.Servers.Interfaces; | ||
44 | |||
45 | using OpenMetaverse.StructuredData; | ||
46 | |||
47 | namespace OpenSim.Framework.Communications.Services | ||
48 | { | ||
49 | public class HGInventoryService | ||
50 | { | ||
51 | private static readonly ILog m_log | ||
52 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | |||
54 | private InventoryServiceBase m_inventoryService; | ||
55 | private UserManagerBase m_userService; | ||
56 | IAssetDataPlugin m_assetProvider; | ||
57 | IHttpServer httpServer; | ||
58 | private string m_thisInventoryUrl = "http://localhost:9000"; | ||
59 | private string m_thisHostname = "127.0.0.1"; | ||
60 | private uint m_thisPort = 9000; | ||
61 | |||
62 | |||
63 | public HGInventoryService(InventoryServiceBase invService, IAssetDataPlugin assetService, UserManagerBase userService, IHttpServer httpserver, string url) | ||
64 | { | ||
65 | m_inventoryService = invService; | ||
66 | m_userService = userService; | ||
67 | m_thisInventoryUrl = url; | ||
68 | if (!m_thisInventoryUrl.EndsWith("/")) | ||
69 | m_thisInventoryUrl += "/"; | ||
70 | |||
71 | Uri uri = new Uri(m_thisInventoryUrl); | ||
72 | if (uri != null) | ||
73 | { | ||
74 | m_thisHostname = uri.Host; | ||
75 | m_thisPort = (uint)uri.Port; | ||
76 | } | ||
77 | |||
78 | m_assetProvider = assetService; | ||
79 | httpServer = httpserver; | ||
80 | |||
81 | AddHttpHandlers(); | ||
82 | } | ||
83 | |||
84 | public virtual void AddHttpHandlers() | ||
85 | { | ||
86 | httpServer.AddHTTPHandler("/InvCap/", CapHandler); | ||
87 | } | ||
88 | |||
89 | public bool CheckAuthSession(string session_id, string avatar_id) | ||
90 | { | ||
91 | return true; | ||
92 | } | ||
93 | |||
94 | |||
95 | // In truth, this is not called from the outside, for standalones. I'm just making it | ||
96 | // a handler already so that this can be reused for the InventoryServer. | ||
97 | public string CreateCapUrl(Guid _userid) | ||
98 | { | ||
99 | UUID userID = new UUID(_userid); | ||
100 | UUID random = UUID.Random(); | ||
101 | string url = m_thisInventoryUrl + random.ToString() + "/"; | ||
102 | m_log.InfoFormat("[HGStandaloneInvService] Creating Cap URL {0} for user {1}", url, userID.ToString()); | ||
103 | return url; | ||
104 | } | ||
105 | |||
106 | /// <summary> | ||
107 | /// Return a user's entire inventory | ||
108 | /// </summary> | ||
109 | /// <param name="rawUserID"></param> | ||
110 | /// <returns>The user's inventory. If an inventory cannot be found then an empty collection is returned.</returns> | ||
111 | public InventoryCollection GetUserInventory(Guid rawUserID) | ||
112 | { | ||
113 | UUID userID = new UUID(rawUserID); | ||
114 | |||
115 | m_log.Info("[HGStandaloneInvModule]: Processing request for inventory of " + userID); | ||
116 | |||
117 | // Uncomment me to simulate a slow responding inventory server | ||
118 | //Thread.Sleep(16000); | ||
119 | |||
120 | InventoryCollection invCollection = new InventoryCollection(); | ||
121 | |||
122 | List<InventoryFolderBase> allFolders = m_inventoryService.GetInventorySkeleton(userID); | ||
123 | |||
124 | if (null == allFolders) | ||
125 | { | ||
126 | m_log.WarnFormat("[HGStandaloneInvModule]: No inventory found for user {0}", rawUserID); | ||
127 | |||
128 | return invCollection; | ||
129 | } | ||
130 | |||
131 | List<InventoryItemBase> allItems = new List<InventoryItemBase>(); | ||
132 | |||
133 | foreach (InventoryFolderBase folder in allFolders) | ||
134 | { | ||
135 | List<InventoryItemBase> items = m_inventoryService.RequestFolderItems(folder.ID); | ||
136 | |||
137 | if (items != null) | ||
138 | { | ||
139 | allItems.InsertRange(0, items); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | invCollection.UserID = userID; | ||
144 | invCollection.Folders = allFolders; | ||
145 | invCollection.Items = allItems; | ||
146 | |||
147 | // foreach (InventoryFolderBase folder in invCollection.Folders) | ||
148 | // { | ||
149 | // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back folder {0} {1}", folder.Name, folder.ID); | ||
150 | // } | ||
151 | // | ||
152 | // foreach (InventoryItemBase item in invCollection.Items) | ||
153 | // { | ||
154 | // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back item {0} {1}, folder {2}", item.Name, item.ID, item.Folder); | ||
155 | // } | ||
156 | |||
157 | m_log.InfoFormat( | ||
158 | "[HGStandaloneInvModule]: Sending back inventory response to user {0} containing {1} folders and {2} items", | ||
159 | invCollection.UserID, invCollection.Folders.Count, invCollection.Items.Count); | ||
160 | |||
161 | return invCollection; | ||
162 | } | ||
163 | |||
164 | public InventoryCollection FetchDescendants(InventoryFolderBase fb) | ||
165 | { | ||
166 | m_log.Info("[HGStandaloneInvService]: Processing request for folder " + fb.ID); | ||
167 | |||
168 | // Uncomment me to simulate a slow responding inventory server | ||
169 | //Thread.Sleep(16000); | ||
170 | |||
171 | InventoryCollection invCollection = new InventoryCollection(); | ||
172 | |||
173 | List<InventoryItemBase> items = m_inventoryService.RequestFolderItems(fb.ID); | ||
174 | List<InventoryFolderBase> folders = m_inventoryService.RequestSubFolders(fb.ID); | ||
175 | |||
176 | invCollection.UserID = fb.Owner; | ||
177 | invCollection.Folders = folders; | ||
178 | invCollection.Items = items; | ||
179 | |||
180 | m_log.DebugFormat("[HGStandaloneInvService]: Found {0} items and {1} folders", items.Count, folders.Count); | ||
181 | |||
182 | return invCollection; | ||
183 | } | ||
184 | |||
185 | public bool RemoveFolder(InventoryFolderBase folder) | ||
186 | { | ||
187 | m_log.Debug("[HGStandaloneInvService]: Removefolder: Operation not implemented yet."); | ||
188 | return false; | ||
189 | } | ||
190 | |||
191 | public InventoryItemBase GetInventoryItem(InventoryItemBase item) | ||
192 | { | ||
193 | m_log.Info("[HGStandaloneInvService]: Get item " + item.ID); | ||
194 | |||
195 | item = m_inventoryService.GetInventoryItem(item.ID); | ||
196 | if (item == null) | ||
197 | m_log.Debug("[HGStandaloneInvService]: null item"); | ||
198 | return item; | ||
199 | } | ||
200 | |||
201 | public InventoryItemBase AddItem(InventoryItemBase item) | ||
202 | { | ||
203 | m_log.DebugFormat("[HGStandaloneInvService]: Add item {0} from {1}", item.ID, item.Owner); | ||
204 | if (m_inventoryService.AddItem(item)) | ||
205 | return item; | ||
206 | else | ||
207 | { | ||
208 | item.ID = UUID.Zero; | ||
209 | return item; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | public InventoryItemBase UpdateItem(InventoryItemBase item) | ||
214 | { | ||
215 | m_log.DebugFormat("[HGStandaloneInvService]: Update item {0} from {1}", item.ID, item.Owner); | ||
216 | InventoryItemBase it = m_inventoryService.GetInventoryItem(item.ID); | ||
217 | item.CurrentPermissions = it.CurrentPermissions; | ||
218 | item.AssetID = it.AssetID; | ||
219 | if (m_inventoryService.UpdateItem(item)) | ||
220 | return item; | ||
221 | else | ||
222 | { | ||
223 | item.ID = UUID.Zero; | ||
224 | return item; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | public InventoryItemBase MoveItem(InventoryItemBase newitem) | ||
229 | { | ||
230 | m_log.DebugFormat("[HGStandaloneInvService]: Move item {0} from {1}", newitem.ID, newitem.Owner); | ||
231 | InventoryItemBase Item = m_inventoryService.GetInventoryItem(newitem.ID); | ||
232 | if (Item != null) | ||
233 | { | ||
234 | if (newitem.Name != String.Empty) | ||
235 | { | ||
236 | Item.Name = newitem.Name; | ||
237 | } | ||
238 | Item.Folder = newitem.Folder; | ||
239 | m_inventoryService.UpdateItem(Item); | ||
240 | return Item; | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | m_log.Debug("[HGStandaloneInvService]: Failed to find item " + newitem.ID); | ||
245 | newitem.ID = UUID.Zero; | ||
246 | return newitem; | ||
247 | } | ||
248 | |||
249 | } | ||
250 | |||
251 | public InventoryItemBase DeleteItem(InventoryItemBase item) | ||
252 | { | ||
253 | item = m_inventoryService.GetInventoryItem(item.ID); | ||
254 | if (m_inventoryService.DeleteItem(item)) | ||
255 | return item; | ||
256 | else | ||
257 | { | ||
258 | item.ID = UUID.Zero; | ||
259 | return item; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | public InventoryItemBase CopyItem(InventoryItemBase olditem) | ||
264 | { | ||
265 | m_log.DebugFormat("[HGStandaloneInvService]: Copy item {0} from {1}", olditem.ID, olditem.Owner); | ||
266 | InventoryItemBase Item = m_inventoryService.GetInventoryItem(olditem.ID); // this is the old item id | ||
267 | // BIG HACK here | ||
268 | UUID newID = olditem.AssetID; | ||
269 | if (Item != null) | ||
270 | { | ||
271 | if (olditem.Name != String.Empty) | ||
272 | { | ||
273 | Item.Name = olditem.Name; | ||
274 | } | ||
275 | Item.ID = newID; | ||
276 | Item.Folder = olditem.Folder; | ||
277 | Item.Owner = olditem.Owner; | ||
278 | // There should be some tests here about the owner, etc but I'm going to ignore that | ||
279 | // because I'm not sure it makes any sense | ||
280 | // Also I should probably close the asset... | ||
281 | m_inventoryService.AddItem(Item); | ||
282 | return Item; | ||
283 | } | ||
284 | else | ||
285 | { | ||
286 | m_log.Debug("[HGStandaloneInvService]: Failed to find item " + olditem.ID); | ||
287 | olditem.ID = UUID.Zero; | ||
288 | return olditem; | ||
289 | } | ||
290 | |||
291 | } | ||
292 | |||
293 | /// <summary> | ||
294 | /// Guid to UUID wrapper for same name IInventoryServices method | ||
295 | /// </summary> | ||
296 | /// <param name="rawUserID"></param> | ||
297 | /// <returns></returns> | ||
298 | public List<InventoryFolderBase> GetInventorySkeleton(Guid rawUserID) | ||
299 | { | ||
300 | UUID userID = new UUID(rawUserID); | ||
301 | return ((InventoryServiceBase)m_inventoryService).GetInventorySkeleton(userID); | ||
302 | } | ||
303 | |||
304 | public List<InventoryItemBase> GetActiveGestures(Guid rawUserID) | ||
305 | { | ||
306 | UUID userID = new UUID(rawUserID); | ||
307 | |||
308 | m_log.InfoFormat("[HGStandaloneInvService]: fetching active gestures for user {0}", userID); | ||
309 | |||
310 | return ((InventoryServiceBase)m_inventoryService).GetActiveGestures(userID); | ||
311 | } | ||
312 | |||
313 | public AssetBase GetAsset(InventoryItemBase item) | ||
314 | { | ||
315 | m_log.Info("[HGStandaloneInvService]: Get asset " + item.AssetID + " for item " + item.ID); | ||
316 | AssetBase asset = new AssetBase(item.AssetID, "NULL"); // send an asset with no data | ||
317 | InventoryItemBase item2 = m_inventoryService.GetInventoryItem(item.ID); | ||
318 | if (item2 == null) | ||
319 | { | ||
320 | m_log.Debug("[HGStandaloneInvService]: null item"); | ||
321 | return asset; | ||
322 | } | ||
323 | if (item2.Owner != item.Owner) | ||
324 | { | ||
325 | m_log.DebugFormat("[HGStandaloneInvService]: client with uuid {0} is trying to get an item of owner {1}", item.Owner, item2.Owner); | ||
326 | return asset; | ||
327 | } | ||
328 | |||
329 | // All good, get the asset | ||
330 | AssetBase theasset = m_assetProvider.FetchAsset(item.AssetID); | ||
331 | m_log.Debug("[HGStandaloneInvService] Found asset " + ((theasset == null)? "NULL" : "Not Null")); | ||
332 | if (theasset != null) | ||
333 | { | ||
334 | asset = theasset; | ||
335 | //m_log.Debug(" >> Sending assetID " + item.AssetID); | ||
336 | } | ||
337 | return asset; | ||
338 | } | ||
339 | |||
340 | public bool PostAsset(AssetBase asset) | ||
341 | { | ||
342 | m_log.Info("[HGStandaloneInvService]: Post asset " + asset.FullID); | ||
343 | m_assetProvider.CreateAsset(asset); | ||
344 | |||
345 | return true; | ||
346 | } | ||
347 | |||
348 | /// <summary> | ||
349 | /// <see>CapsUpdatedInventoryItemAsset(IClientAPI, UUID, byte[])</see> | ||
350 | /// </summary> | ||
351 | public UUID UpdateInventoryItemAsset(UUID userID, UUID itemID, byte[] data) | ||
352 | { | ||
353 | m_log.Debug("[HGStandaloneInvService]: UpdateInventoryitemAsset for user " + userID + " item " + itemID); | ||
354 | InventoryItemBase item = m_inventoryService.GetInventoryItem(itemID); | ||
355 | |||
356 | if (item != null) | ||
357 | { | ||
358 | // We're still not dealing with permissions | ||
359 | //if ((InventoryType)item.InvType == InventoryType.Notecard) | ||
360 | //{ | ||
361 | // if (!Permissions.CanEditNotecard(itemID, UUID.Zero, userID)) | ||
362 | // { | ||
363 | // //remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false); | ||
364 | // return UUID.Zero; | ||
365 | // } | ||
366 | |||
367 | // //remoteClient.SendAgentAlertMessage("Notecard saved", false); | ||
368 | //} | ||
369 | //else if ((InventoryType)item.InvType == InventoryType.LSL) | ||
370 | //{ | ||
371 | // if (!Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId)) | ||
372 | // { | ||
373 | // //remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false); | ||
374 | // return UUID.Zero; | ||
375 | // } | ||
376 | |||
377 | // //remoteClient.SendAgentAlertMessage("Script saved", false); | ||
378 | //} | ||
379 | |||
380 | AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data); | ||
381 | PostAsset(asset); | ||
382 | |||
383 | item.AssetID = asset.FullID; | ||
384 | item.Owner = userID; | ||
385 | m_inventoryService.UpdateItem(item); | ||
386 | |||
387 | return (asset.FullID); | ||
388 | } | ||
389 | return UUID.Zero; | ||
390 | } | ||
391 | |||
392 | private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data) | ||
393 | { | ||
394 | AssetBase asset = new AssetBase(); | ||
395 | asset.Name = name; | ||
396 | asset.Description = description; | ||
397 | asset.Type = assetType; | ||
398 | asset.FullID = UUID.Random(); | ||
399 | asset.Data = (data == null) ? new byte[1] : data; | ||
400 | |||
401 | return asset; | ||
402 | } | ||
403 | |||
404 | #region Caps | ||
405 | |||
406 | Dictionary<UUID, Hashtable> invCaps = new Dictionary<UUID, Hashtable>(); | ||
407 | |||
408 | public Hashtable CapHandler(Hashtable request) | ||
409 | { | ||
410 | m_log.Debug("[CONNECTION DEBUGGING]: InvCapHandler Called"); | ||
411 | |||
412 | m_log.Debug("---------------------------"); | ||
413 | m_log.Debug(" >> uri=" + request["uri"]); | ||
414 | m_log.Debug(" >> content-type=" + request["content-type"]); | ||
415 | m_log.Debug(" >> http-method=" + request["http-method"]); | ||
416 | m_log.Debug("---------------------------\n"); | ||
417 | |||
418 | // these are requests if the type | ||
419 | // http://inventoryserver/InvCap/uuuuuuuu-uuuu-uuuu-uuuu-uuuuuuuuuuuu/kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk/ | ||
420 | |||
421 | Hashtable responsedata = new Hashtable(); | ||
422 | responsedata["content_type"] = "text/plain"; | ||
423 | |||
424 | UUID userID; | ||
425 | string authToken = string.Empty; | ||
426 | string authority = string.Empty; | ||
427 | if (!GetParams(request, out userID, out authority, out authToken)) | ||
428 | { | ||
429 | m_log.InfoFormat("[HGStandaloneInvService]: Invalid parameters for InvCap message {0}", request["uri"]); | ||
430 | responsedata["int_response_code"] = 404; | ||
431 | responsedata["str_response_string"] = "Not found"; | ||
432 | |||
433 | return responsedata; | ||
434 | } | ||
435 | |||
436 | // Next, let's parse the verb | ||
437 | string method = (string)request["http-method"]; | ||
438 | if (method.Equals("GET")) | ||
439 | { | ||
440 | DoInvCapPost(request, responsedata, userID, authToken); | ||
441 | return responsedata; | ||
442 | } | ||
443 | //else if (method.Equals("DELETE")) | ||
444 | //{ | ||
445 | // DoAgentDelete(request, responsedata, agentID, action, regionHandle); | ||
446 | |||
447 | // return responsedata; | ||
448 | //} | ||
449 | else | ||
450 | { | ||
451 | m_log.InfoFormat("[HGStandaloneInvService]: method {0} not supported in agent message", method); | ||
452 | responsedata["int_response_code"] = 405; | ||
453 | responsedata["str_response_string"] = "Method not allowed"; | ||
454 | |||
455 | return responsedata; | ||
456 | } | ||
457 | |||
458 | } | ||
459 | |||
460 | public virtual void DoInvCapPost(Hashtable request, Hashtable responsedata, UUID userID, string authToken) | ||
461 | { | ||
462 | |||
463 | // This is the meaning of POST agent | ||
464 | |||
465 | // Check Auth Token | ||
466 | if (!(m_userService is IAuthentication)) | ||
467 | { | ||
468 | m_log.Debug("[HGStandaloneInvService]: UserService is not IAuthentication. Denying access to inventory."); | ||
469 | responsedata["int_response_code"] = 501; | ||
470 | responsedata["str_response_string"] = "Not implemented"; | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | bool success = ((IAuthentication)m_userService).VerifyKey(userID, authToken); | ||
475 | |||
476 | if (success) | ||
477 | { | ||
478 | |||
479 | m_log.DebugFormat("[HGStandaloneInvService]: User has been authorized. Creating service handlers."); | ||
480 | |||
481 | // Then establish secret service handlers | ||
482 | |||
483 | Hashtable usercaps = RegisterCaps(userID, authToken); | ||
484 | |||
485 | responsedata["int_response_code"] = 200; | ||
486 | //responsedata["str_response_string"] = "OK"; | ||
487 | responsedata["str_response_string"] = SerializeHashtable(usercaps); | ||
488 | } | ||
489 | else | ||
490 | { | ||
491 | m_log.DebugFormat("[HGStandaloneInvService]: User has is unauthorized. Denying service handlers."); | ||
492 | responsedata["int_response_code"] = 403; | ||
493 | responsedata["str_response_string"] = "Forbidden"; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | |||
498 | /// <summary> | ||
499 | /// Extract the params from a request. | ||
500 | /// </summary> | ||
501 | public static bool GetParams(Hashtable request, out UUID uuid, out string authority, out string authKey) | ||
502 | { | ||
503 | uuid = UUID.Zero; | ||
504 | authority = string.Empty; | ||
505 | authKey = string.Empty; | ||
506 | |||
507 | string uri = (string)request["uri"]; | ||
508 | uri = uri.Trim(new char[] { '/' }); | ||
509 | string[] parts = uri.Split('/'); | ||
510 | if (parts.Length <= 1) | ||
511 | { | ||
512 | return false; | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | if (!UUID.TryParse(parts[1], out uuid)) | ||
517 | return false; | ||
518 | |||
519 | if (parts.Length >= 3) | ||
520 | { | ||
521 | authKey = parts[2]; | ||
522 | return true; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | Uri authUri; | ||
527 | Hashtable headers = (Hashtable)request["headers"]; | ||
528 | |||
529 | // Authorization keys look like this: | ||
530 | // http://orgrid.org:8002/<uuid> | ||
531 | if (headers.ContainsKey("authorization")) | ||
532 | { | ||
533 | if (Uri.TryCreate((string)headers["authorization"], UriKind.Absolute, out authUri)) | ||
534 | { | ||
535 | authority = authUri.Authority; | ||
536 | authKey = authUri.PathAndQuery.Trim('/'); | ||
537 | m_log.DebugFormat("[HGStandaloneInvService]: Got authority {0} and key {1}", authority, authKey); | ||
538 | return true; | ||
539 | } | ||
540 | else | ||
541 | m_log.Debug("[HGStandaloneInvService]: Wrong format for Authorization header: " + (string)headers["authorization"]); | ||
542 | } | ||
543 | else | ||
544 | m_log.Debug("[HGStandaloneInvService]: Authorization header not found"); | ||
545 | |||
546 | return false; | ||
547 | } | ||
548 | |||
549 | string SerializeHashtable(Hashtable hash) | ||
550 | { | ||
551 | string result = string.Empty; | ||
552 | foreach (object key in hash.Keys) | ||
553 | { | ||
554 | result += key.ToString() + "," + hash[key].ToString() + ";"; | ||
555 | } | ||
556 | return result; | ||
557 | } | ||
558 | |||
559 | Hashtable RegisterCaps(UUID userID, string authToken) | ||
560 | { | ||
561 | lock (invCaps) | ||
562 | { | ||
563 | if (invCaps.ContainsKey(userID)) | ||
564 | { | ||
565 | // Remove the old ones | ||
566 | DeregisterCaps(httpServer, invCaps[userID]); | ||
567 | invCaps.Remove(userID); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | Caps caps = new Caps(null, httpServer, m_thisHostname, m_thisPort, authToken, userID, false, "Inventory"); | ||
572 | caps.RegisterInventoryServiceHandlers("/" + authToken + "/InventoryCap/"); | ||
573 | caps.ItemUpdatedCall = UpdateInventoryItemAsset; | ||
574 | Hashtable capsHandlers = caps.CapsHandlers.CapsDetails; | ||
575 | |||
576 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<Guid, InventoryCollection>( | ||
577 | "POST", AddAndGetCapUrl(authToken, "GetInventory", capsHandlers), GetUserInventory, CheckAuthSession)); | ||
578 | |||
579 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, InventoryCollection>( | ||
580 | "POST", AddAndGetCapUrl(authToken, "FetchDescendants", capsHandlers), FetchDescendants, CheckAuthSession)); | ||
581 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>( | ||
582 | "POST", AddAndGetCapUrl(authToken, "NewFolder", capsHandlers), m_inventoryService.AddFolder, CheckAuthSession)); | ||
583 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>( | ||
584 | "POST", AddAndGetCapUrl(authToken, "UpdateFolder", capsHandlers), m_inventoryService.UpdateFolder, CheckAuthSession)); | ||
585 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>( | ||
586 | "POST", AddAndGetCapUrl(authToken, "MoveFolder", capsHandlers), m_inventoryService.MoveFolder, CheckAuthSession)); | ||
587 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>( | ||
588 | "POST", AddAndGetCapUrl(authToken, "PurgeFolder", capsHandlers), m_inventoryService.PurgeFolder, CheckAuthSession)); | ||
589 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryFolderBase, bool>( | ||
590 | "POST", AddAndGetCapUrl(authToken, "RemoveFolder", capsHandlers), RemoveFolder, CheckAuthSession)); | ||
591 | |||
592 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, InventoryItemBase>( | ||
593 | "POST", AddAndGetCapUrl(authToken, "GetItem", capsHandlers), GetInventoryItem, CheckAuthSession)); | ||
594 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, InventoryItemBase>( | ||
595 | "POST", AddAndGetCapUrl(authToken, "NewItem", capsHandlers), AddItem, CheckAuthSession)); | ||
596 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, InventoryItemBase>( | ||
597 | "POST", AddAndGetCapUrl(authToken, "UpdateItem", capsHandlers), UpdateItem, CheckAuthSession)); | ||
598 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, InventoryItemBase>( | ||
599 | "POST", AddAndGetCapUrl(authToken, "MoveItem", capsHandlers), MoveItem, CheckAuthSession)); | ||
600 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, InventoryItemBase>( | ||
601 | "POST", AddAndGetCapUrl(authToken, "DeleteItem", capsHandlers), DeleteItem, CheckAuthSession)); | ||
602 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, InventoryItemBase>( | ||
603 | "POST", AddAndGetCapUrl(authToken, "CopyItem", capsHandlers), CopyItem, CheckAuthSession)); | ||
604 | |||
605 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<InventoryItemBase, AssetBase>( | ||
606 | "POST", AddAndGetCapUrl(authToken, "GetAsset", capsHandlers), GetAsset, CheckAuthSession)); | ||
607 | httpServer.AddStreamHandler(new RestDeserialiseSecureHandler<AssetBase, bool>( | ||
608 | "POST", AddAndGetCapUrl(authToken, "PostAsset", capsHandlers), PostAsset, CheckAuthSession)); | ||
609 | |||
610 | lock (invCaps) | ||
611 | invCaps.Add(userID, capsHandlers); | ||
612 | |||
613 | return capsHandlers; | ||
614 | } | ||
615 | |||
616 | string AddAndGetCapUrl(string authToken, string capType, Hashtable caps) | ||
617 | { | ||
618 | string capUrl = "/" + authToken + "/" + capType + "/"; | ||
619 | |||
620 | m_log.Debug("[HGStandaloneInvService] Adding inventory cap " + capUrl); | ||
621 | caps.Add(capType, capUrl); | ||
622 | return capUrl; | ||
623 | } | ||
624 | |||
625 | void DeregisterCaps(IHttpServer httpServer, Hashtable caps) | ||
626 | { | ||
627 | foreach (string capUrl in caps.Values) | ||
628 | { | ||
629 | m_log.Debug("[HGStandaloneInvService] Removing inventory cap " + capUrl); | ||
630 | httpServer.RemoveStreamHandler("POST", capUrl); | ||
631 | } | ||
632 | } | ||
633 | |||
634 | #endregion Caps | ||
635 | } | ||
636 | } | ||
diff --git a/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs b/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs new file mode 100644 index 0000000..37c8846 --- /dev/null +++ b/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs | |||
@@ -0,0 +1,329 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Text.RegularExpressions; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Communications.Cache; | ||
36 | using OpenSim.Framework.Communications.Capabilities; | ||
37 | using OpenSim.Framework.Servers; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | using log4net; | ||
42 | using Nini.Config; | ||
43 | using Nwc.XmlRpc; | ||
44 | |||
45 | namespace OpenSim.Framework.Communications.Services | ||
46 | { | ||
47 | public class HGLoginAuthService : LoginService | ||
48 | { | ||
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
50 | |||
51 | protected NetworkServersInfo m_serversInfo; | ||
52 | protected bool m_authUsers = false; | ||
53 | |||
54 | /// <summary> | ||
55 | /// Used by the login service to make requests to the inventory service. | ||
56 | /// </summary> | ||
57 | protected IInterServiceInventoryServices m_interServiceInventoryService; | ||
58 | |||
59 | /// <summary> | ||
60 | /// Used to make requests to the local regions. | ||
61 | /// </summary> | ||
62 | protected ILoginServiceToRegionsConnector m_regionsConnector; | ||
63 | |||
64 | |||
65 | public HGLoginAuthService( | ||
66 | UserManagerBase userManager, string welcomeMess, | ||
67 | IInterServiceInventoryServices interServiceInventoryService, | ||
68 | NetworkServersInfo serversInfo, | ||
69 | bool authenticate, LibraryRootFolder libraryRootFolder, ILoginServiceToRegionsConnector regionsConnector) | ||
70 | : base(userManager, libraryRootFolder, welcomeMess) | ||
71 | { | ||
72 | this.m_serversInfo = serversInfo; | ||
73 | if (m_serversInfo != null) | ||
74 | { | ||
75 | m_defaultHomeX = this.m_serversInfo.DefaultHomeLocX; | ||
76 | m_defaultHomeY = this.m_serversInfo.DefaultHomeLocY; | ||
77 | } | ||
78 | m_authUsers = authenticate; | ||
79 | |||
80 | m_interServiceInventoryService = interServiceInventoryService; | ||
81 | m_regionsConnector = regionsConnector; | ||
82 | m_inventoryService = interServiceInventoryService; | ||
83 | } | ||
84 | |||
85 | public void SetServersInfo(NetworkServersInfo sinfo) | ||
86 | { | ||
87 | m_serversInfo = sinfo; | ||
88 | } | ||
89 | |||
90 | public override XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request) | ||
91 | { | ||
92 | m_log.Info("[HGLOGIN] HGLogin called " + request.MethodName); | ||
93 | XmlRpcResponse response = base.XmlRpcLoginMethod(request); | ||
94 | Hashtable responseData = (Hashtable)response.Value; | ||
95 | |||
96 | responseData["grid_service"] = m_serversInfo.GridURL; | ||
97 | responseData["grid_service_send_key"] = m_serversInfo.GridSendKey; | ||
98 | responseData["inventory_service"] = m_serversInfo.InventoryURL; | ||
99 | responseData["asset_service"] = m_serversInfo.AssetURL; | ||
100 | responseData["asset_service_send_key"] = m_serversInfo.AssetSendKey; | ||
101 | int x = (Int32)responseData["region_x"]; | ||
102 | int y = (Int32)responseData["region_y"]; | ||
103 | uint ux = (uint)(x / Constants.RegionSize); | ||
104 | uint uy = (uint)(y / Constants.RegionSize); | ||
105 | ulong regionHandle = Util.UIntsToLong(ux, uy); | ||
106 | responseData["region_handle"] = regionHandle.ToString(); | ||
107 | |||
108 | // Let's remove the seed cap from the login | ||
109 | //responseData.Remove("seed_capability"); | ||
110 | |||
111 | // Let's add the appearance | ||
112 | UUID userID = UUID.Zero; | ||
113 | UUID.TryParse((string)responseData["agent_id"], out userID); | ||
114 | AvatarAppearance appearance = m_userManager.GetUserAppearance(userID); | ||
115 | if (appearance == null) | ||
116 | { | ||
117 | m_log.WarnFormat("[INTER]: Appearance not found for {0}. Creating default.", userID); | ||
118 | appearance = new AvatarAppearance(); | ||
119 | } | ||
120 | |||
121 | responseData["appearance"] = appearance.ToHashTable(); | ||
122 | |||
123 | // Let's also send the auth token | ||
124 | UUID token = UUID.Random(); | ||
125 | responseData["auth_token"] = token.ToString(); | ||
126 | UserProfileData userProfile = m_userManager.GetUserProfile(userID); | ||
127 | if (userProfile != null) | ||
128 | { | ||
129 | userProfile.WebLoginKey = token; | ||
130 | m_userManager.CommitAgent(ref userProfile); | ||
131 | } | ||
132 | |||
133 | return response; | ||
134 | } | ||
135 | |||
136 | public XmlRpcResponse XmlRpcGenerateKeyMethod(XmlRpcRequest request) | ||
137 | { | ||
138 | |||
139 | // Verify the key of who's calling | ||
140 | UUID userID = UUID.Zero; | ||
141 | UUID authKey = UUID.Zero; | ||
142 | UUID.TryParse((string)request.Params[0], out userID); | ||
143 | UUID.TryParse((string)request.Params[1], out authKey); | ||
144 | |||
145 | m_log.InfoFormat("[HGLOGIN] HGGenerateKey called with authToken ", authKey); | ||
146 | string newKey = string.Empty; | ||
147 | |||
148 | if (!(m_userManager is IAuthentication)) | ||
149 | { | ||
150 | m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Returning empty key."); | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | newKey = ((IAuthentication)m_userManager).GetNewKey(m_serversInfo.UserURL, userID, authKey); | ||
155 | } | ||
156 | |||
157 | XmlRpcResponse response = new XmlRpcResponse(); | ||
158 | response.Value = (string) newKey; | ||
159 | return response; | ||
160 | } | ||
161 | |||
162 | public XmlRpcResponse XmlRpcVerifyKeyMethod(XmlRpcRequest request) | ||
163 | { | ||
164 | foreach (object o in request.Params) | ||
165 | { | ||
166 | if (o != null) | ||
167 | m_log.Debug(" >> Param " + o.ToString()); | ||
168 | else | ||
169 | m_log.Debug(" >> Null"); | ||
170 | } | ||
171 | |||
172 | // Verify the key of who's calling | ||
173 | UUID userID = UUID.Zero; | ||
174 | string authKey = string.Empty; | ||
175 | UUID.TryParse((string)request.Params[0], out userID); | ||
176 | authKey = (string)request.Params[1]; | ||
177 | |||
178 | m_log.InfoFormat("[HGLOGIN] HGVerifyKey called with key ", authKey); | ||
179 | bool success = false; | ||
180 | |||
181 | if (!(m_userManager is IAuthentication)) | ||
182 | { | ||
183 | m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Denying."); | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | success = ((IAuthentication)m_userManager).VerifyKey(userID, authKey); | ||
188 | } | ||
189 | |||
190 | XmlRpcResponse response = new XmlRpcResponse(); | ||
191 | response.Value = (string)success.ToString(); | ||
192 | return response; | ||
193 | } | ||
194 | |||
195 | public override UserProfileData GetTheUser(string firstname, string lastname) | ||
196 | { | ||
197 | UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname); | ||
198 | if (profile != null) | ||
199 | { | ||
200 | return profile; | ||
201 | } | ||
202 | |||
203 | if (!m_authUsers) | ||
204 | { | ||
205 | //no current user account so make one | ||
206 | m_log.Info("[LOGIN]: No user account found so creating a new one."); | ||
207 | |||
208 | m_userManager.AddUser(firstname, lastname, "test", "", m_defaultHomeX, m_defaultHomeY); | ||
209 | |||
210 | return m_userManager.GetUserProfile(firstname, lastname); | ||
211 | } | ||
212 | |||
213 | return null; | ||
214 | } | ||
215 | |||
216 | public override bool AuthenticateUser(UserProfileData profile, string password) | ||
217 | { | ||
218 | if (!m_authUsers) | ||
219 | { | ||
220 | //for now we will accept any password in sandbox mode | ||
221 | m_log.Info("[LOGIN]: Authorising user (no actual password check)"); | ||
222 | |||
223 | return true; | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | m_log.Info( | ||
228 | "[LOGIN]: Authenticating " + profile.FirstName + " " + profile.SurName); | ||
229 | |||
230 | if (!password.StartsWith("$1$")) | ||
231 | password = "$1$" + Util.Md5Hash(password); | ||
232 | |||
233 | password = password.Remove(0, 3); //remove $1$ | ||
234 | |||
235 | string s = Util.Md5Hash(password + ":" + profile.PasswordSalt); | ||
236 | |||
237 | bool loginresult = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase) | ||
238 | || profile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase)); | ||
239 | return loginresult; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | protected override RegionInfo RequestClosestRegion(string region) | ||
244 | { | ||
245 | return m_regionsConnector.RequestClosestRegion(region); | ||
246 | } | ||
247 | |||
248 | protected override RegionInfo GetRegionInfo(ulong homeRegionHandle) | ||
249 | { | ||
250 | return m_regionsConnector.RequestNeighbourInfo(homeRegionHandle); | ||
251 | } | ||
252 | |||
253 | protected override RegionInfo GetRegionInfo(UUID homeRegionId) | ||
254 | { | ||
255 | return m_regionsConnector.RequestNeighbourInfo(homeRegionId); | ||
256 | } | ||
257 | |||
258 | |||
259 | /// <summary> | ||
260 | /// Not really informing the region. Just filling out the response fields related to the region. | ||
261 | /// </summary> | ||
262 | /// <param name="sim"></param> | ||
263 | /// <param name="user"></param> | ||
264 | /// <param name="response"></param> | ||
265 | /// <returns>true if the region was successfully contacted, false otherwise</returns> | ||
266 | protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response) | ||
267 | { | ||
268 | IPEndPoint endPoint = regionInfo.ExternalEndPoint; | ||
269 | response.SimAddress = endPoint.Address.ToString(); | ||
270 | response.SimPort = (uint)endPoint.Port; | ||
271 | response.RegionX = regionInfo.RegionLocX; | ||
272 | response.RegionY = regionInfo.RegionLocY; | ||
273 | response.SimHttpPort = regionInfo.HttpPort; | ||
274 | |||
275 | string capsPath = CapsUtil.GetRandomCapsObjectPath(); | ||
276 | string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath); | ||
277 | |||
278 | // Don't use the following! It Fails for logging into any region not on the same port as the http server! | ||
279 | // Kept here so it doesn't happen again! | ||
280 | // response.SeedCapability = regionInfo.ServerURI + capsSeedPath; | ||
281 | |||
282 | string seedcap = "http://"; | ||
283 | |||
284 | if (m_serversInfo.HttpUsesSSL) | ||
285 | { | ||
286 | seedcap = "https://" + m_serversInfo.HttpSSLCN + ":" + regionInfo.HttpPort + capsSeedPath; | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | seedcap = "http://" + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort + capsSeedPath; | ||
291 | } | ||
292 | |||
293 | response.SeedCapability = seedcap; | ||
294 | |||
295 | // Notify the target of an incoming user | ||
296 | m_log.InfoFormat( | ||
297 | "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection", | ||
298 | regionInfo.RegionName, response.RegionX, response.RegionY, regionInfo.ServerURI); | ||
299 | |||
300 | // Update agent with target sim | ||
301 | user.CurrentAgent.Region = regionInfo.RegionID; | ||
302 | user.CurrentAgent.Handle = regionInfo.RegionHandle; | ||
303 | |||
304 | return true; | ||
305 | } | ||
306 | |||
307 | public override void LogOffUser(UserProfileData theUser, string message) | ||
308 | { | ||
309 | RegionInfo SimInfo; | ||
310 | try | ||
311 | { | ||
312 | SimInfo = this.m_regionsConnector.RequestNeighbourInfo(theUser.CurrentAgent.Handle); | ||
313 | |||
314 | if (SimInfo == null) | ||
315 | { | ||
316 | m_log.Error("[LOCAL LOGIN]: Region user was in isn't currently logged in"); | ||
317 | return; | ||
318 | } | ||
319 | } | ||
320 | catch (Exception) | ||
321 | { | ||
322 | m_log.Error("[LOCAL LOGIN]: Unable to look up region to log user off"); | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | m_regionsConnector.LogOffUserFromGrid(SimInfo.RegionHandle, theUser.ID, theUser.CurrentAgent.SecureSessionID, "Logging you off"); | ||
327 | } | ||
328 | } | ||
329 | } | ||