aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs')
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs432
1 files changed, 432 insertions, 0 deletions
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs
new file mode 100644
index 0000000..1e19982
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs
@@ -0,0 +1,432 @@
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.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces;
42
43namespace OpenSim.Services.Connectors.SimianGrid
44{
45 /// <summary>
46 /// Avatar profile flags
47 /// </summary>
48 [Flags]
49 public enum ProfileFlags : uint
50 {
51 AllowPublish = 1,
52 MaturePublish = 2,
53 Identified = 4,
54 Transacted = 8,
55 Online = 16
56 }
57
58 /// <summary>
59 /// Connects avatar profile and classified queries to the SimianGrid
60 /// backend
61 /// </summary>
62 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
63 public class SimianProfiles : INonSharedRegionModule
64 {
65 private static readonly ILog m_log =
66 LogManager.GetLogger(
67 MethodBase.GetCurrentMethod().DeclaringType);
68
69 private string m_serverUrl = String.Empty;
70
71 #region INonSharedRegionModule
72
73 public Type ReplaceableInterface { get { return null; } }
74 public void RegionLoaded(Scene scene) { }
75 public void Close() { }
76
77 public SimianProfiles() { }
78 public string Name { get { return "SimianProfiles"; } }
79 public void AddRegion(Scene scene) { CheckEstateManager(scene); scene.EventManager.OnClientConnect += ClientConnectHandler; }
80 public void RemoveRegion(Scene scene) { scene.EventManager.OnClientConnect -= ClientConnectHandler; }
81
82 #endregion INonSharedRegionModule
83
84 public SimianProfiles(IConfigSource source)
85 {
86 Initialise(source);
87 }
88
89 public void Initialise(IConfigSource source)
90 {
91 IConfig gridConfig = source.Configs["UserAccountService"];
92 if (gridConfig == null)
93 {
94 m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini");
95 throw new Exception("Profiles init error");
96 }
97
98 string serviceUrl = gridConfig.GetString("UserAccountServerURI");
99 if (String.IsNullOrEmpty(serviceUrl))
100 {
101 m_log.Error("[PROFILES]: No UserAccountServerURI in section UserAccountService");
102 throw new Exception("Profiles init error");
103 }
104
105 if (!serviceUrl.EndsWith("/"))
106 serviceUrl = serviceUrl + '/';
107
108 m_serverUrl = serviceUrl;
109 }
110
111 private void ClientConnectHandler(IClientCore clientCore)
112 {
113 if (clientCore is IClientAPI)
114 {
115 IClientAPI client = (IClientAPI)clientCore;
116
117 // Classifieds
118 client.AddGenericPacketHandler("avatarclassifiedsrequest", AvatarClassifiedsRequestHandler);
119 client.OnClassifiedInfoRequest += ClassifiedInfoRequestHandler;
120 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdateHandler;
121 client.OnClassifiedDelete += ClassifiedDeleteHandler;
122
123 // Picks
124 client.AddGenericPacketHandler("avatarpicksrequest", HandleAvatarPicksRequest);
125 client.AddGenericPacketHandler("pickinforequest", HandlePickInfoRequest);
126 client.OnPickInfoUpdate += PickInfoUpdateHandler;
127 client.OnPickDelete += PickDeleteHandler;
128
129 // Notes
130 client.AddGenericPacketHandler("avatarnotesrequest", HandleAvatarNotesRequest);
131 client.OnAvatarNotesUpdate += AvatarNotesUpdateHandler;
132
133 // Profiles
134 client.OnRequestAvatarProperties += RequestAvatarPropertiesHandler;
135 client.OnUpdateAvatarProperties += UpdateAvatarPropertiesHandler;
136 client.OnAvatarInterestUpdate += AvatarInterestUpdateHandler;
137 client.OnUserInfoRequest += UserInfoRequestHandler;
138 client.OnUpdateUserInfo += UpdateUserInfoHandler;
139 }
140 }
141
142 #region Classifieds
143
144 private void AvatarClassifiedsRequestHandler(Object sender, string method, List<String> args)
145 {
146 if (!(sender is IClientAPI))
147 return;
148 IClientAPI client = (IClientAPI)sender;
149
150 UUID targetAvatarID;
151 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
152 {
153 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
154 return;
155 }
156
157 // FIXME: Query the generic key/value store for classifieds
158 client.SendAvatarClassifiedReply(targetAvatarID, new Dictionary<UUID, string>(0));
159 }
160
161 private void ClassifiedInfoRequestHandler(UUID classifiedID, IClientAPI client)
162 {
163 // FIXME: Fetch this info
164 client.SendClassifiedInfoReply(classifiedID, UUID.Zero, 0, Utils.DateTimeToUnixTime(DateTime.UtcNow + TimeSpan.FromDays(1)),
165 0, String.Empty, String.Empty, UUID.Zero, 0, UUID.Zero, String.Empty, Vector3.Zero, String.Empty, 0, 0);
166 }
167
168 private void ClassifiedInfoUpdateHandler(UUID classifiedID, uint category, string name, string description,
169 UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price,
170 IClientAPI client)
171 {
172 // FIXME: Save this info
173 }
174
175 private void ClassifiedDeleteHandler(UUID classifiedID, IClientAPI client)
176 {
177 // FIXME: Delete the specified classified ad
178 }
179
180 #endregion Classifieds
181
182 #region Picks
183
184 private void HandleAvatarPicksRequest(Object sender, string method, List<String> args)
185 {
186 if (!(sender is IClientAPI))
187 return;
188 IClientAPI client = (IClientAPI)sender;
189
190 UUID targetAvatarID;
191 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
192 {
193 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
194 return;
195 }
196
197 // FIXME: Fetch these
198 client.SendAvatarPicksReply(targetAvatarID, new Dictionary<UUID, string>(0));
199 }
200
201 private void HandlePickInfoRequest(Object sender, string method, List<String> args)
202 {
203 if (!(sender is IClientAPI))
204 return;
205 IClientAPI client = (IClientAPI)sender;
206
207 UUID avatarID;
208 UUID pickID;
209 if (args.Count < 2 || !UUID.TryParse(args[0], out avatarID) || !UUID.TryParse(args[1], out pickID))
210 {
211 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
212 return;
213 }
214
215 // FIXME: Fetch this
216 client.SendPickInfoReply(pickID, avatarID, false, UUID.Zero, String.Empty, String.Empty, UUID.Zero, String.Empty,
217 String.Empty, String.Empty, Vector3.Zero, 0, false);
218 }
219
220 private void PickInfoUpdateHandler(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name,
221 string desc, UUID snapshotID, int sortOrder, bool enabled)
222 {
223 // FIXME: Save this
224 }
225
226 private void PickDeleteHandler(IClientAPI client, UUID pickID)
227 {
228 // FIXME: Delete
229 }
230
231 #endregion Picks
232
233 #region Notes
234
235 private void HandleAvatarNotesRequest(Object sender, string method, List<String> args)
236 {
237 if (!(sender is IClientAPI))
238 return;
239 IClientAPI client = (IClientAPI)sender;
240
241 UUID targetAvatarID;
242 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
243 {
244 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
245 return;
246 }
247
248 // FIXME: Fetch this
249 client.SendAvatarNotesReply(targetAvatarID, String.Empty);
250 }
251
252 private void AvatarNotesUpdateHandler(IClientAPI client, UUID targetID, string notes)
253 {
254 // FIXME: Save this
255 }
256
257 #endregion Notes
258
259 #region Profiles
260
261 private void RequestAvatarPropertiesHandler(IClientAPI client, UUID avatarID)
262 {
263 OSDMap user = FetchUserData(avatarID);
264
265 ProfileFlags flags = ProfileFlags.AllowPublish | ProfileFlags.MaturePublish;
266
267 if (user != null)
268 {
269 OSDMap about = null;
270 if (user.ContainsKey("LLAbout"))
271 {
272 try { about = OSDParser.DeserializeJson(user["LLAbout"].AsString()) as OSDMap; }
273 catch { }
274 }
275
276 if (about == null)
277 about = new OSDMap(0);
278
279 // Check if this user is a grid operator
280 byte[] charterMember;
281 if (user["AccessLevel"].AsInteger() >= 200)
282 charterMember = Utils.StringToBytes("Operator");
283 else
284 charterMember = Utils.EmptyBytes;
285
286 // Check if the user is online
287 if (client.Scene is Scene)
288 {
289 OpenSim.Services.Interfaces.PresenceInfo[] presences = ((Scene)client.Scene).PresenceService.GetAgents(new string[] { avatarID.ToString() });
290 if (presences != null && presences.Length > 0)
291 flags |= ProfileFlags.Online;
292 }
293
294 // Check if the user is identified
295 if (user["Identified"].AsBoolean())
296 flags |= ProfileFlags.Identified;
297
298 client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy",
299 System.Globalization.CultureInfo.InvariantCulture), charterMember, about["FLAbout"].AsString(), (uint)flags,
300 about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID());
301
302 }
303 else
304 {
305 m_log.Warn("[PROFILES]: Failed to fetch profile information for " + client.Name + ", returning default values");
306 client.SendAvatarProperties(avatarID, String.Empty, "1/1/1970", Utils.EmptyBytes,
307 String.Empty, (uint)flags, UUID.Zero, UUID.Zero, String.Empty, UUID.Zero);
308 }
309 }
310
311 private void UpdateAvatarPropertiesHandler(IClientAPI client, UserProfileData profileData)
312 {
313 OSDMap map = new OSDMap
314 {
315 { "About", OSD.FromString(profileData.AboutText) },
316 { "Image", OSD.FromUUID(profileData.Image) },
317 { "FLAbout", OSD.FromString(profileData.FirstLifeAboutText) },
318 { "FLImage", OSD.FromUUID(profileData.FirstLifeImage) },
319 { "URL", OSD.FromString(profileData.ProfileUrl) }
320 };
321
322 AddUserData(client.AgentId, "LLAbout", map);
323 }
324
325 private void AvatarInterestUpdateHandler(IClientAPI client, uint wantmask, string wanttext, uint skillsmask,
326 string skillstext, string languages)
327 {
328 OSDMap map = new OSDMap
329 {
330 { "WantMask", OSD.FromInteger(wantmask) },
331 { "WantText", OSD.FromString(wanttext) },
332 { "SkillsMask", OSD.FromInteger(skillsmask) },
333 { "SkillsText", OSD.FromString(skillstext) },
334 { "Languages", OSD.FromString(languages) }
335 };
336
337 AddUserData(client.AgentId, "LLInterests", map);
338 }
339
340 private void UserInfoRequestHandler(IClientAPI client)
341 {
342 m_log.Error("[PROFILES]: UserInfoRequestHandler");
343
344 // Fetch this user's e-mail address
345 NameValueCollection requestArgs = new NameValueCollection
346 {
347 { "RequestMethod", "GetUser" },
348 { "UserID", client.AgentId.ToString() }
349 };
350
351 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
352 string email = response["Email"].AsString();
353
354 if (!response["Success"].AsBoolean())
355 m_log.Warn("[PROFILES]: GetUser failed during a user info request for " + client.Name);
356
357 client.SendUserInfoReply(false, true, email);
358 }
359
360 private void UpdateUserInfoHandler(bool imViaEmail, bool visible, IClientAPI client)
361 {
362 m_log.Info("[PROFILES]: Ignoring user info update from " + client.Name);
363 }
364
365 #endregion Profiles
366
367 /// <summary>
368 /// Sanity checks regions for a valid estate owner at startup
369 /// </summary>
370 private void CheckEstateManager(Scene scene)
371 {
372 EstateSettings estate = scene.RegionInfo.EstateSettings;
373
374 if (estate.EstateOwner == UUID.Zero)
375 {
376 // Attempt to lookup the grid admin
377 UserAccount admin = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, UUID.Zero);
378 if (admin != null)
379 {
380 m_log.InfoFormat("[PROFILES]: Setting estate {0} (ID: {1}) owner to {2}", estate.EstateName,
381 estate.EstateID, admin.Name);
382
383 estate.EstateOwner = admin.PrincipalID;
384 estate.Save();
385 }
386 else
387 {
388 m_log.WarnFormat("[PROFILES]: Estate {0} (ID: {1}) does not have an owner", estate.EstateName, estate.EstateID);
389 }
390 }
391 }
392
393 private bool AddUserData(UUID userID, string key, OSDMap value)
394 {
395 NameValueCollection requestArgs = new NameValueCollection
396 {
397 { "RequestMethod", "AddUserData" },
398 { "UserID", userID.ToString() },
399 { key, OSDParser.SerializeJsonString(value) }
400 };
401
402 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
403 bool success = response["Success"].AsBoolean();
404
405 if (!success)
406 m_log.WarnFormat("[PROFILES]: Failed to add user data with key {0} for {1}: {2}", key, userID, response["Message"].AsString());
407
408 return success;
409 }
410
411 private OSDMap FetchUserData(UUID userID)
412 {
413 NameValueCollection requestArgs = new NameValueCollection
414 {
415 { "RequestMethod", "GetUser" },
416 { "UserID", userID.ToString() }
417 };
418
419 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
420 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
421 {
422 return (OSDMap)response["User"];
423 }
424 else
425 {
426 m_log.Error("[PROFILES]: Failed to fetch user data for " + userID + ": " + response["Message"].AsString());
427 }
428
429 return null;
430 }
431 }
432}