clockwerk-opensim – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 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 | using System; |
||
28 | using System.Collections.Generic; |
||
29 | using System.IO; |
||
30 | using System.Reflection; |
||
31 | using System.Threading; |
||
32 | |||
33 | using OpenSim.Framework; |
||
34 | using OpenSim.Framework.Console; |
||
35 | using OpenSim.Framework.Monitoring; |
||
36 | using OpenSim.Region.ClientStack.LindenUDP; |
||
37 | using OpenSim.Region.Framework; |
||
38 | using OpenSim.Region.Framework.Interfaces; |
||
39 | using OpenSim.Region.Framework.Scenes; |
||
40 | using OpenSim.Services.Interfaces; |
||
41 | using OpenSim.Services.Connectors.Hypergrid; |
||
42 | |||
43 | using OpenMetaverse; |
||
44 | using OpenMetaverse.Packets; |
||
45 | using log4net; |
||
46 | using Nini.Config; |
||
47 | using Mono.Addins; |
||
48 | |||
49 | using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; |
||
50 | |||
51 | namespace OpenSim.Region.CoreModules.Framework.UserManagement |
||
52 | { |
||
53 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] |
||
54 | public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople |
||
55 | { |
||
56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
57 | |||
58 | protected bool m_Enabled; |
||
59 | protected List<Scene> m_Scenes = new List<Scene>(); |
||
60 | |||
61 | protected IServiceThrottleModule m_ServiceThrottle; |
||
62 | // The cache |
||
63 | protected Dictionary<UUID, UserData> m_UserCache = new Dictionary<UUID, UserData>(); |
||
64 | |||
65 | #region ISharedRegionModule |
||
66 | |||
67 | public void Initialise(IConfigSource config) |
||
68 | { |
||
69 | string umanmod = config.Configs["Modules"].GetString("UserManagementModule", Name); |
||
70 | if (umanmod == Name) |
||
71 | { |
||
72 | m_Enabled = true; |
||
73 | Init(); |
||
74 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); |
||
75 | } |
||
76 | } |
||
77 | |||
78 | public bool IsSharedModule |
||
79 | { |
||
80 | get { return true; } |
||
81 | } |
||
82 | |||
83 | public virtual string Name |
||
84 | { |
||
85 | get { return "BasicUserManagementModule"; } |
||
86 | } |
||
87 | |||
88 | public Type ReplaceableInterface |
||
89 | { |
||
90 | get { return null; } |
||
91 | } |
||
92 | |||
93 | public void AddRegion(Scene scene) |
||
94 | { |
||
95 | if (m_Enabled) |
||
96 | { |
||
97 | m_Scenes.Add(scene); |
||
98 | |||
99 | scene.RegisterModuleInterface<IUserManagement>(this); |
||
100 | scene.RegisterModuleInterface<IPeople>(this); |
||
101 | scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); |
||
102 | scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); |
||
103 | } |
||
104 | } |
||
105 | |||
106 | public void RemoveRegion(Scene scene) |
||
107 | { |
||
108 | if (m_Enabled) |
||
109 | { |
||
110 | scene.UnregisterModuleInterface<IUserManagement>(this); |
||
111 | m_Scenes.Remove(scene); |
||
112 | } |
||
113 | } |
||
114 | |||
115 | public void RegionLoaded(Scene s) |
||
116 | { |
||
117 | if (m_Enabled && m_ServiceThrottle == null) |
||
118 | m_ServiceThrottle = s.RequestModuleInterface<IServiceThrottleModule>(); |
||
119 | } |
||
120 | |||
121 | public void PostInitialise() |
||
122 | { |
||
123 | } |
||
124 | |||
125 | public void Close() |
||
126 | { |
||
127 | m_Scenes.Clear(); |
||
128 | |||
129 | lock (m_UserCache) |
||
130 | m_UserCache.Clear(); |
||
131 | } |
||
132 | |||
133 | #endregion ISharedRegionModule |
||
134 | |||
135 | |||
136 | #region Event Handlers |
||
137 | |||
138 | void EventManager_OnPrimsLoaded(Scene s) |
||
139 | { |
||
140 | // let's sniff all the user names referenced by objects in the scene |
||
141 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: Caching creators' data from {0} ({1} objects)...", s.RegionInfo.RegionName, s.GetEntities().Length); |
||
142 | s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); |
||
143 | } |
||
144 | |||
145 | void EventManager_OnNewClient(IClientAPI client) |
||
146 | { |
||
147 | client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed); |
||
148 | client.OnNameFromUUIDRequest += new UUIDNameRequest(HandleUUIDNameRequest); |
||
149 | client.OnAvatarPickerRequest += new AvatarPickerRequest(HandleAvatarPickerRequest); |
||
150 | } |
||
151 | |||
152 | void HandleConnectionClosed(IClientAPI client) |
||
153 | { |
||
154 | client.OnNameFromUUIDRequest -= new UUIDNameRequest(HandleUUIDNameRequest); |
||
155 | client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); |
||
156 | } |
||
157 | |||
158 | void HandleUUIDNameRequest(UUID uuid, IClientAPI client) |
||
159 | { |
||
160 | // m_log.DebugFormat( |
||
161 | // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", |
||
162 | // uuid, remote_client.Name); |
||
163 | |||
164 | if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) |
||
165 | { |
||
166 | client.SendNameReply(uuid, "Mr", "OpenSim"); |
||
167 | } |
||
168 | else |
||
169 | { |
||
170 | string[] names = new string[2]; |
||
171 | if (TryGetUserNamesFromCache(uuid, names)) |
||
172 | { |
||
173 | client.SendNameReply(uuid, names[0], names[1]); |
||
174 | return; |
||
175 | } |
||
176 | |||
177 | // Not found in cache, queue continuation |
||
178 | m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate |
||
179 | { |
||
180 | //m_log.DebugFormat("[YYY]: Name request {0}", uuid); |
||
181 | |||
182 | // As least upto September 2013, clients permanently cache UUID -> Name bindings. Some clients |
||
183 | // appear to clear this when the user asks it to clear the cache, but others may not. |
||
184 | // |
||
185 | // So to avoid clients |
||
186 | // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will |
||
187 | // instead drop the request entirely. |
||
188 | if (TryGetUserNames(uuid, names)) |
||
189 | client.SendNameReply(uuid, names[0], names[1]); |
||
190 | // else |
||
191 | // m_log.DebugFormat( |
||
192 | // "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}", |
||
193 | // uuid, client.Name); |
||
194 | }); |
||
195 | } |
||
196 | } |
||
197 | |||
198 | public void HandleAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query) |
||
199 | { |
||
200 | //EventManager.TriggerAvatarPickerRequest(); |
||
201 | |||
202 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); |
||
203 | |||
204 | List<UserData> users = GetUserData(query, 500, 1); |
||
205 | |||
206 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); |
||
207 | // TODO: don't create new blocks if recycling an old packet |
||
208 | |||
209 | AvatarPickerReplyPacket.DataBlock[] searchData = |
||
210 | new AvatarPickerReplyPacket.DataBlock[users.Count]; |
||
211 | AvatarPickerReplyPacket.AgentDataBlock agentData = new AvatarPickerReplyPacket.AgentDataBlock(); |
||
212 | |||
213 | agentData.AgentID = avatarID; |
||
214 | agentData.QueryID = RequestID; |
||
215 | replyPacket.AgentData = agentData; |
||
216 | //byte[] bytes = new byte[AvatarResponses.Count*32]; |
||
217 | |||
218 | int i = 0; |
||
219 | foreach (UserData item in users) |
||
220 | { |
||
221 | UUID translatedIDtem = item.Id; |
||
222 | searchData[i] = new AvatarPickerReplyPacket.DataBlock(); |
||
223 | searchData[i].AvatarID = translatedIDtem; |
||
224 | searchData[i].FirstName = Utils.StringToBytes((string)item.FirstName); |
||
225 | searchData[i].LastName = Utils.StringToBytes((string)item.LastName); |
||
226 | i++; |
||
227 | } |
||
228 | if (users.Count == 0) |
||
229 | { |
||
230 | searchData = new AvatarPickerReplyPacket.DataBlock[0]; |
||
231 | } |
||
232 | replyPacket.Data = searchData; |
||
233 | |||
234 | AvatarPickerReplyAgentDataArgs agent_data = new AvatarPickerReplyAgentDataArgs(); |
||
235 | agent_data.AgentID = replyPacket.AgentData.AgentID; |
||
236 | agent_data.QueryID = replyPacket.AgentData.QueryID; |
||
237 | |||
238 | List<AvatarPickerReplyDataArgs> data_args = new List<AvatarPickerReplyDataArgs>(); |
||
239 | for (i = 0; i < replyPacket.Data.Length; i++) |
||
240 | { |
||
241 | AvatarPickerReplyDataArgs data_arg = new AvatarPickerReplyDataArgs(); |
||
242 | data_arg.AvatarID = replyPacket.Data[i].AvatarID; |
||
243 | data_arg.FirstName = replyPacket.Data[i].FirstName; |
||
244 | data_arg.LastName = replyPacket.Data[i].LastName; |
||
245 | data_args.Add(data_arg); |
||
246 | } |
||
247 | client.SendAvatarPickerReply(agent_data, data_args); |
||
248 | } |
||
249 | |||
250 | protected virtual void AddAdditionalUsers(string query, List<UserData> users) |
||
251 | { |
||
252 | } |
||
253 | |||
254 | #endregion Event Handlers |
||
255 | |||
256 | #region IPeople |
||
257 | |||
258 | public List<UserData> GetUserData(string query, int page_size, int page_number) |
||
259 | { |
||
260 | // search the user accounts service |
||
261 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); |
||
262 | |||
263 | List<UserData> users = new List<UserData>(); |
||
264 | if (accs != null) |
||
265 | { |
||
266 | foreach (UserAccount acc in accs) |
||
267 | { |
||
268 | UserData ud = new UserData(); |
||
269 | ud.FirstName = acc.FirstName; |
||
270 | ud.LastName = acc.LastName; |
||
271 | ud.Id = acc.PrincipalID; |
||
272 | users.Add(ud); |
||
273 | } |
||
274 | } |
||
275 | |||
276 | // search the local cache |
||
277 | lock (m_UserCache) |
||
278 | { |
||
279 | foreach (UserData data in m_UserCache.Values) |
||
280 | { |
||
281 | if (data.Id != UUID.Zero && |
||
282 | users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && |
||
283 | (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) |
||
284 | users.Add(data); |
||
285 | } |
||
286 | } |
||
287 | |||
288 | AddAdditionalUsers(query, users); |
||
289 | |||
290 | return users; |
||
291 | |||
292 | } |
||
293 | |||
294 | #endregion IPeople |
||
295 | |||
296 | private void CacheCreators(SceneObjectGroup sog) |
||
297 | { |
||
298 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); |
||
299 | AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData); |
||
300 | |||
301 | foreach (SceneObjectPart sop in sog.Parts) |
||
302 | { |
||
303 | AddUser(sop.CreatorID, sop.CreatorData); |
||
304 | foreach (TaskInventoryItem item in sop.TaskInventory.Values) |
||
305 | AddUser(item.CreatorID, item.CreatorData); |
||
306 | } |
||
307 | } |
||
308 | |||
309 | /// <summary> |
||
310 | /// |
||
311 | /// </summary> |
||
312 | /// <param name="uuid"></param> |
||
313 | /// <param name="names">Caller please provide a properly instantiated array for names, string[2]</param> |
||
314 | /// <returns></returns> |
||
315 | private bool TryGetUserNames(UUID uuid, string[] names) |
||
316 | { |
||
317 | if (names == null) |
||
318 | names = new string[2]; |
||
319 | |||
320 | if (TryGetUserNamesFromCache(uuid, names)) |
||
321 | return true; |
||
322 | |||
323 | if (TryGetUserNamesFromServices(uuid, names)) |
||
324 | return true; |
||
325 | |||
326 | return false; |
||
327 | } |
||
328 | |||
329 | private bool TryGetUserNamesFromCache(UUID uuid, string[] names) |
||
330 | { |
||
331 | lock (m_UserCache) |
||
332 | { |
||
333 | if (m_UserCache.ContainsKey(uuid)) |
||
334 | { |
||
335 | names[0] = m_UserCache[uuid].FirstName; |
||
336 | names[1] = m_UserCache[uuid].LastName; |
||
337 | |||
338 | return true; |
||
339 | } |
||
340 | } |
||
341 | |||
342 | return false; |
||
343 | } |
||
344 | |||
345 | /// <summary> |
||
346 | /// Try to get the names bound to the given uuid, from the services. |
||
347 | /// </summary> |
||
348 | /// <returns>True if the name was found, false if not.</returns> |
||
349 | /// <param name='uuid'></param> |
||
350 | /// <param name='names'>The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User"</param> |
||
351 | private bool TryGetUserNamesFromServices(UUID uuid, string[] names) |
||
352 | { |
||
353 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); |
||
354 | |||
355 | if (account != null) |
||
356 | { |
||
357 | names[0] = account.FirstName; |
||
358 | names[1] = account.LastName; |
||
359 | |||
360 | UserData user = new UserData(); |
||
361 | user.FirstName = account.FirstName; |
||
362 | user.LastName = account.LastName; |
||
363 | |||
364 | lock (m_UserCache) |
||
365 | m_UserCache[uuid] = user; |
||
366 | |||
367 | return true; |
||
368 | } |
||
369 | else |
||
370 | { |
||
371 | // Let's try the GridUser service |
||
372 | GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString()); |
||
373 | if (uInfo != null) |
||
374 | { |
||
375 | string url, first, last, tmp; |
||
376 | UUID u; |
||
377 | if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp)) |
||
378 | { |
||
379 | AddUser(uuid, first, last, url); |
||
380 | |||
381 | if (m_UserCache.ContainsKey(uuid)) |
||
382 | { |
||
383 | names[0] = m_UserCache[uuid].FirstName; |
||
384 | names[1] = m_UserCache[uuid].LastName; |
||
385 | |||
386 | return true; |
||
387 | } |
||
388 | } |
||
389 | else |
||
390 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); |
||
391 | } |
||
392 | else |
||
393 | { |
||
394 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); |
||
395 | } |
||
396 | |||
397 | names[0] = "Unknown"; |
||
398 | names[1] = "UserUMMTGUN9"; |
||
399 | |||
400 | return false; |
||
401 | } |
||
402 | } |
||
403 | |||
404 | #region IUserManagement |
||
405 | |||
406 | public UUID GetUserIdByName(string name) |
||
407 | { |
||
408 | string[] parts = name.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); |
||
409 | if (parts.Length < 2) |
||
410 | throw new Exception("Name must have 2 components"); |
||
411 | |||
412 | return GetUserIdByName(parts[0], parts[1]); |
||
413 | } |
||
414 | |||
415 | public UUID GetUserIdByName(string firstName, string lastName) |
||
416 | { |
||
417 | // TODO: Optimize for reverse lookup if this gets used by non-console commands. |
||
418 | lock (m_UserCache) |
||
419 | { |
||
420 | foreach (UserData user in m_UserCache.Values) |
||
421 | { |
||
422 | if (user.FirstName == firstName && user.LastName == lastName) |
||
423 | return user.Id; |
||
424 | } |
||
425 | } |
||
426 | |||
427 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, firstName, lastName); |
||
428 | |||
429 | if (account != null) |
||
430 | return account.PrincipalID; |
||
431 | |||
432 | return UUID.Zero; |
||
433 | } |
||
434 | |||
435 | public string GetUserName(UUID uuid) |
||
436 | { |
||
437 | string[] names = new string[2]; |
||
438 | TryGetUserNames(uuid, names); |
||
439 | |||
440 | return names[0] + " " + names[1]; |
||
441 | |||
442 | } |
||
443 | |||
444 | public string GetUserHomeURL(UUID userID) |
||
445 | { |
||
446 | lock (m_UserCache) |
||
447 | { |
||
448 | if (m_UserCache.ContainsKey(userID)) |
||
449 | return m_UserCache[userID].HomeURL; |
||
450 | } |
||
451 | |||
452 | return string.Empty; |
||
453 | } |
||
454 | |||
455 | public string GetUserServerURL(UUID userID, string serverType) |
||
456 | { |
||
457 | UserData userdata; |
||
458 | lock (m_UserCache) |
||
459 | m_UserCache.TryGetValue(userID, out userdata); |
||
460 | |||
461 | if (userdata != null) |
||
462 | { |
||
463 | // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Requested url type {0} for {1}", serverType, userID); |
||
464 | |||
465 | if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) |
||
466 | { |
||
467 | return userdata.ServerURLs[serverType].ToString(); |
||
468 | } |
||
469 | |||
470 | if (!string.IsNullOrEmpty(userdata.HomeURL)) |
||
471 | { |
||
472 | //m_log.DebugFormat( |
||
473 | // "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}", |
||
474 | // serverType, userdata.HomeURL, userID); |
||
475 | |||
476 | UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL); |
||
477 | try |
||
478 | { |
||
479 | userdata.ServerURLs = uConn.GetServerURLs(userID); |
||
480 | } |
||
481 | catch (Exception e) |
||
482 | { |
||
483 | m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e); |
||
484 | userdata.ServerURLs = new Dictionary<string, object>(); |
||
485 | } |
||
486 | |||
487 | if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) |
||
488 | return userdata.ServerURLs[serverType].ToString(); |
||
489 | } |
||
490 | } |
||
491 | |||
492 | return string.Empty; |
||
493 | } |
||
494 | |||
495 | public string GetUserUUI(UUID userID) |
||
496 | { |
||
497 | UserData ud; |
||
498 | lock (m_UserCache) |
||
499 | m_UserCache.TryGetValue(userID, out ud); |
||
500 | |||
501 | if (ud == null) // It's not in the cache |
||
502 | { |
||
503 | string[] names = new string[2]; |
||
504 | // This will pull the data from either UserAccounts or GridUser |
||
505 | // and stick it into the cache |
||
506 | TryGetUserNamesFromServices(userID, names); |
||
507 | lock (m_UserCache) |
||
508 | m_UserCache.TryGetValue(userID, out ud); |
||
509 | } |
||
510 | |||
511 | if (ud != null) |
||
512 | { |
||
513 | string homeURL = ud.HomeURL; |
||
514 | string first = ud.FirstName, last = ud.LastName; |
||
515 | if (ud.LastName.StartsWith("@")) |
||
516 | { |
||
517 | string[] parts = ud.FirstName.Split('.'); |
||
518 | if (parts.Length >= 2) |
||
519 | { |
||
520 | first = parts[0]; |
||
521 | last = parts[1]; |
||
522 | } |
||
523 | return userID + ";" + homeURL + ";" + first + " " + last; |
||
524 | } |
||
525 | } |
||
526 | |||
527 | return userID.ToString(); |
||
528 | } |
||
529 | |||
530 | public void AddUser(UUID uuid, string first, string last) |
||
531 | { |
||
532 | lock (m_UserCache) |
||
533 | { |
||
534 | if (m_UserCache.ContainsKey(uuid)) |
||
535 | return; |
||
536 | } |
||
537 | |||
538 | UserData user = new UserData(); |
||
539 | user.Id = uuid; |
||
540 | user.FirstName = first; |
||
541 | user.LastName = last; |
||
542 | |||
543 | AddUserInternal(user); |
||
544 | } |
||
545 | |||
546 | public void AddUser(UUID uuid, string first, string last, string homeURL) |
||
547 | { |
||
548 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); |
||
549 | if (homeURL == string.Empty) |
||
550 | return; |
||
551 | |||
552 | AddUser(uuid, homeURL + ";" + first + " " + last); |
||
553 | } |
||
554 | |||
555 | public void AddUser(UUID id, string creatorData) |
||
556 | { |
||
557 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); |
||
558 | |||
559 | UserData oldUser; |
||
560 | lock (m_UserCache) |
||
561 | m_UserCache.TryGetValue(id, out oldUser); |
||
562 | |||
563 | if (oldUser != null) |
||
564 | { |
||
565 | if (string.IsNullOrEmpty(creatorData)) |
||
566 | { |
||
567 | //ignore updates without creator data |
||
568 | return; |
||
569 | } |
||
570 | |||
571 | //try update unknown users, but don't update anyone else |
||
572 | if (oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) |
||
573 | { |
||
574 | lock (m_UserCache) |
||
575 | m_UserCache.Remove(id); |
||
576 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); |
||
577 | } |
||
578 | else |
||
579 | { |
||
580 | //we have already a valid user within the cache |
||
581 | return; |
||
582 | } |
||
583 | } |
||
584 | |||
585 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); |
||
586 | |||
587 | if (account != null) |
||
588 | { |
||
589 | AddUser(id, account.FirstName, account.LastName); |
||
590 | } |
||
591 | else |
||
592 | { |
||
593 | UserData user = new UserData(); |
||
594 | user.Id = id; |
||
595 | |||
596 | if (!string.IsNullOrEmpty(creatorData)) |
||
597 | { |
||
598 | //creatorData = <endpoint>;<name> |
||
599 | |||
600 | string[] parts = creatorData.Split(';'); |
||
601 | if (parts.Length >= 1) |
||
602 | { |
||
603 | user.HomeURL = parts[0]; |
||
604 | try |
||
605 | { |
||
606 | Uri uri = new Uri(parts[0]); |
||
607 | user.LastName = "@" + uri.Authority; |
||
608 | } |
||
609 | catch (UriFormatException) |
||
610 | { |
||
611 | m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); |
||
612 | user.LastName = "@unknown"; |
||
613 | } |
||
614 | } |
||
615 | |||
616 | if (parts.Length >= 2) |
||
617 | user.FirstName = parts[1].Replace(' ', '.'); |
||
618 | } |
||
619 | else |
||
620 | { |
||
621 | // Temporarily add unknown user entries of this type into the cache so that we can distinguish |
||
622 | // this source from other recent (hopefully resolved) bugs that fail to retrieve a user name binding |
||
623 | // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or |
||
624 | // disappeared. |
||
625 | user.FirstName = "Unknown"; |
||
626 | user.LastName = "UserUMMAU4"; |
||
627 | } |
||
628 | |||
629 | AddUserInternal(user); |
||
630 | } |
||
631 | } |
||
632 | |||
633 | void AddUserInternal(UserData user) |
||
634 | { |
||
635 | lock (m_UserCache) |
||
636 | m_UserCache[user.Id] = user; |
||
637 | |||
638 | //m_log.DebugFormat( |
||
639 | // "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", |
||
640 | // user.Id, user.FirstName, user.LastName, user.HomeURL); |
||
641 | } |
||
642 | |||
643 | public bool IsLocalGridUser(UUID uuid) |
||
644 | { |
||
645 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid); |
||
646 | if (account == null || (account != null && !account.LocalToGrid)) |
||
647 | return false; |
||
648 | |||
649 | return true; |
||
650 | } |
||
651 | |||
652 | #endregion IUserManagement |
||
653 | |||
654 | protected void Init() |
||
655 | { |
||
656 | AddUser(UUID.Zero, "Unknown", "User"); |
||
657 | RegisterConsoleCmds(); |
||
658 | } |
||
659 | |||
660 | protected void RegisterConsoleCmds() |
||
661 | { |
||
662 | MainConsole.Instance.Commands.AddCommand("Users", true, |
||
663 | "show name", |
||
664 | "show name <uuid>", |
||
665 | "Show the bindings between a single user UUID and a user name", |
||
666 | String.Empty, |
||
667 | HandleShowUser); |
||
668 | |||
669 | MainConsole.Instance.Commands.AddCommand("Users", true, |
||
670 | "show names", |
||
671 | "show names", |
||
672 | "Show the bindings between user UUIDs and user names", |
||
673 | String.Empty, |
||
674 | HandleShowUsers); |
||
675 | } |
||
676 | |||
677 | private void HandleShowUser(string module, string[] cmd) |
||
678 | { |
||
679 | if (cmd.Length < 3) |
||
680 | { |
||
681 | MainConsole.Instance.OutputFormat("Usage: show name <uuid>"); |
||
682 | return; |
||
683 | } |
||
684 | |||
685 | UUID userId; |
||
686 | if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId)) |
||
687 | return; |
||
688 | |||
689 | UserData ud; |
||
690 | |||
691 | lock (m_UserCache) |
||
692 | { |
||
693 | if (!m_UserCache.TryGetValue(userId, out ud)) |
||
694 | { |
||
695 | MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId); |
||
696 | return; |
||
697 | } |
||
698 | } |
||
699 | |||
700 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); |
||
701 | cdt.AddColumn("UUID", 36); |
||
702 | cdt.AddColumn("Name", 30); |
||
703 | cdt.AddColumn("HomeURL", 40); |
||
704 | cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL); |
||
705 | |||
706 | MainConsole.Instance.Output(cdt.ToString()); |
||
707 | } |
||
708 | |||
709 | private void HandleShowUsers(string module, string[] cmd) |
||
710 | { |
||
711 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); |
||
712 | cdt.AddColumn("UUID", 36); |
||
713 | cdt.AddColumn("Name", 30); |
||
714 | cdt.AddColumn("HomeURL", 40); |
||
715 | |||
716 | lock (m_UserCache) |
||
717 | { |
||
718 | foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) |
||
719 | cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL); |
||
720 | } |
||
721 | |||
722 | MainConsole.Instance.Output(cdt.ToString()); |
||
723 | } |
||
724 | |||
725 | } |
||
726 | |||
727 | } |