aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Communications/Services
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Communications/Services')
-rw-r--r--OpenSim/Framework/Communications/Services/GridInfoService.cs172
-rw-r--r--OpenSim/Framework/Communications/Services/HGInventoryService.cs33
-rw-r--r--OpenSim/Framework/Communications/Services/LoginResponse.cs812
-rw-r--r--OpenSim/Framework/Communications/Services/LoginService.cs1093
4 files changed, 2104 insertions, 6 deletions
diff --git a/OpenSim/Framework/Communications/Services/GridInfoService.cs b/OpenSim/Framework/Communications/Services/GridInfoService.cs
new file mode 100644
index 0000000..96fe0d8
--- /dev/null
+++ b/OpenSim/Framework/Communications/Services/GridInfoService.cs
@@ -0,0 +1,172 @@
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 OpenSim 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;
30using System.IO;
31using System.Reflection;
32using System.Text;
33using log4net;
34using Nini.Config;
35using Nwc.XmlRpc;
36using OpenSim.Framework.Servers;
37
38namespace OpenSim.Framework.Communications.Services
39{
40 public class GridInfoService
41 {
42 private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private Hashtable _info = new Hashtable();
45
46 /// <summary>
47 /// Instantiate a GridInfoService object.
48 /// </summary>
49 /// <param name="configPath">path to config path containing
50 /// grid information</param>
51 /// <remarks>
52 /// GridInfoService uses the [GridInfo] section of the
53 /// standard OpenSim.ini file --- which is not optimal, but
54 /// anything else requires a general redesign of the config
55 /// system.
56 /// </remarks>
57 public GridInfoService(IConfigSource configSource)
58 {
59 loadGridInfo(configSource);
60 }
61
62 /// <summary>
63 /// Default constructor, uses OpenSim.ini.
64 /// </summary>
65 public GridInfoService()
66 {
67 try
68 {
69 IConfigSource configSource = new IniConfigSource(Path.Combine(Util.configDir(), "OpenSim.ini"));
70 loadGridInfo(configSource);
71 }
72 catch (FileNotFoundException)
73 {
74 _log.Warn("[GridInfoService] no OpenSim.ini file found --- GridInfoServices WILL NOT BE AVAILABLE to your users");
75 }
76 }
77
78 private void loadGridInfo(IConfigSource configSource)
79 {
80 _info["platform"] = "OpenSim";
81 try
82 {
83 IConfig startupCfg = configSource.Configs["Startup"];
84 IConfig gridCfg = configSource.Configs["GridInfo"];
85 IConfig netCfg = configSource.Configs["Network"];
86
87 bool grid = startupCfg.GetBoolean("gridmode", false);
88
89 if (grid)
90 _info["mode"] = "grid";
91 else
92 _info["mode"] = "standalone";
93
94
95 if (null != gridCfg)
96 {
97 foreach (string k in gridCfg.GetKeys())
98 {
99 _info[k] = gridCfg.GetString(k);
100 }
101 }
102 else if (null != netCfg)
103 {
104 if (grid)
105 _info["login"]
106 = netCfg.GetString(
107 "user_server_url", "http://127.0.0.1:" + UserConfig.DefaultHttpPort.ToString());
108 else
109 _info["login"]
110 = String.Format(
111 "http://127.0.0.1:{0}/",
112 netCfg.GetString(
113 "http_listener_port", NetworkServersInfo.DefaultHttpListenerPort.ToString()));
114
115 IssueWarning();
116 }
117 else
118 {
119 _info["login"] = "http://127.0.0.1:9000/";
120 IssueWarning();
121 }
122 }
123 catch (Exception)
124 {
125 _log.Debug("[GridInfoService] cannot get grid info from config source, using minimal defaults");
126 }
127 _log.InfoFormat("[GridInfoService] Grid info service initialized with {0} keys", _info.Count);
128
129 }
130
131 private void IssueWarning()
132 {
133 _log.Warn("[GridInfoService] found no [GridInfo] section in your OpenSim.ini");
134 _log.Warn("[GridInfoService] trying to guess sensible defaults, you might want to provide better ones:");
135 foreach (string k in _info.Keys)
136 {
137 _log.WarnFormat("[GridInfoService] {0}: {1}", k, _info[k]);
138 }
139 }
140
141 public XmlRpcResponse XmlRpcGridInfoMethod(XmlRpcRequest request)
142 {
143 XmlRpcResponse response = new XmlRpcResponse();
144 Hashtable responseData = new Hashtable();
145
146 _log.Info("[GridInfo]: Request for grid info");
147
148 foreach (string k in _info.Keys)
149 {
150 responseData[k] = _info[k];
151 }
152 response.Value = responseData;
153
154 return response;
155 }
156
157 public string RestGetGridInfoMethod(string request, string path, string param,
158 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
159 {
160 StringBuilder sb = new StringBuilder();
161
162 sb.Append("<gridinfo>\n");
163 foreach (string k in _info.Keys)
164 {
165 sb.AppendFormat("<{0}>{1}</{0}>\n", k, _info[k]);
166 }
167 sb.Append("</gridinfo>\n");
168
169 return sb.ToString();
170 }
171 }
172}
diff --git a/OpenSim/Framework/Communications/Services/HGInventoryService.cs b/OpenSim/Framework/Communications/Services/HGInventoryService.cs
index f0b2259..33d7722 100644
--- a/OpenSim/Framework/Communications/Services/HGInventoryService.cs
+++ b/OpenSim/Framework/Communications/Services/HGInventoryService.cs
@@ -52,19 +52,41 @@ namespace OpenSim.Framework.Communications.Services
52 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 private InventoryServiceBase m_inventoryService; 54 private InventoryServiceBase m_inventoryService;
55 private UserManagerBase m_userService;
56 IAssetDataPlugin m_assetProvider;
57 IHttpServer httpServer; 55 IHttpServer httpServer;
58 private string m_thisInventoryUrl = "http://localhost:9000"; 56 private string m_thisInventoryUrl = "http://localhost:9000";
59 private string m_thisHostname = "127.0.0.1"; 57 private string m_thisHostname = "127.0.0.1";
60 private uint m_thisPort = 9000; 58 private uint m_thisPort = 9000;
61 59
60 // These two used for local access, standalone mode
61 private UserManagerBase m_userService = null;
62 IAssetDataPlugin m_assetProvider = null;
62 63
63 public HGInventoryService(InventoryServiceBase invService, IAssetDataPlugin assetService, UserManagerBase userService, IHttpServer httpserver, string url) 64 // These two used for remote access
65 string m_UserServerURL = string.Empty;
66 string m_AssetServerURL = string.Empty;
67
68 // Constructor for grid inventory server
69 public HGInventoryService(InventoryServiceBase invService, string assetServiceURL, string userServiceURL, IHttpServer httpserver, string thisurl)
70 {
71 m_UserServerURL = userServiceURL;
72 m_AssetServerURL = assetServiceURL;
73
74 Init(invService, thisurl, httpserver);
75 }
76
77 // Constructor for standalone mode
78 public HGInventoryService(InventoryServiceBase invService, IAssetDataPlugin assetService, UserManagerBase userService, IHttpServer httpserver, string thisurl)
64 { 79 {
65 m_inventoryService = invService;
66 m_userService = userService; 80 m_userService = userService;
67 m_thisInventoryUrl = url; 81 m_assetProvider = assetService;
82
83 Init(invService, thisurl, httpserver);
84 }
85
86 private void Init(InventoryServiceBase invService, string thisurl, IHttpServer httpserver)
87 {
88 m_inventoryService = invService;
89 m_thisInventoryUrl = thisurl;
68 if (!m_thisInventoryUrl.EndsWith("/")) 90 if (!m_thisInventoryUrl.EndsWith("/"))
69 m_thisInventoryUrl += "/"; 91 m_thisInventoryUrl += "/";
70 92
@@ -75,7 +97,6 @@ namespace OpenSim.Framework.Communications.Services
75 m_thisPort = (uint)uri.Port; 97 m_thisPort = (uint)uri.Port;
76 } 98 }
77 99
78 m_assetProvider = assetService;
79 httpServer = httpserver; 100 httpServer = httpserver;
80 101
81 AddHttpHandlers(); 102 AddHttpHandlers();
diff --git a/OpenSim/Framework/Communications/Services/LoginResponse.cs b/OpenSim/Framework/Communications/Services/LoginResponse.cs
new file mode 100644
index 0000000..82515e0
--- /dev/null
+++ b/OpenSim/Framework/Communications/Services/LoginResponse.cs
@@ -0,0 +1,812 @@
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 OpenSim 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;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nwc.XmlRpc;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36
37namespace OpenSim.Framework.Communications.Services
38{
39 /// <summary>
40 /// A temp class to handle login response.
41 /// Should make use of UserProfileManager where possible.
42 /// </summary>
43 public class LoginResponse
44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 private Hashtable loginFlagsHash;
48 private Hashtable globalTexturesHash;
49 private Hashtable loginError;
50 private Hashtable uiConfigHash;
51
52 private ArrayList loginFlags;
53 private ArrayList globalTextures;
54 private ArrayList eventCategories;
55 private ArrayList uiConfig;
56 private ArrayList classifiedCategories;
57 private ArrayList inventoryRoot;
58 private ArrayList initialOutfit;
59 private ArrayList agentInventory;
60 private ArrayList inventoryLibraryOwner;
61 private ArrayList inventoryLibRoot;
62 private ArrayList inventoryLibrary;
63 private ArrayList activeGestures;
64
65 private UserInfo userProfile;
66
67 private UUID agentID;
68 private UUID sessionID;
69 private UUID secureSessionID;
70
71 // Login Flags
72 private string dst;
73 private string stipendSinceLogin;
74 private string gendered;
75 private string everLoggedIn;
76 private string login;
77 private uint simPort;
78 private uint simHttpPort;
79 private string simAddress;
80 private string agentAccess;
81 private Int32 circuitCode;
82 private uint regionX;
83 private uint regionY;
84
85 // Login
86 private string firstname;
87 private string lastname;
88
89 // Global Textures
90 private string sunTexture;
91 private string cloudTexture;
92 private string moonTexture;
93
94 // Error Flags
95 private string errorReason;
96 private string errorMessage;
97
98 // Response
99 private XmlRpcResponse xmlRpcResponse;
100 // private XmlRpcResponse defaultXmlRpcResponse;
101
102 private string welcomeMessage;
103 private string startLocation;
104 private string allowFirstLife;
105 private string home;
106 private string seedCapability;
107 private string lookAt;
108
109 private BuddyList m_buddyList = null;
110
111 public LoginResponse()
112 {
113 loginFlags = new ArrayList();
114 globalTextures = new ArrayList();
115 eventCategories = new ArrayList();
116 uiConfig = new ArrayList();
117 classifiedCategories = new ArrayList();
118
119 loginError = new Hashtable();
120 uiConfigHash = new Hashtable();
121
122 // defaultXmlRpcResponse = new XmlRpcResponse();
123 userProfile = new UserInfo();
124 inventoryRoot = new ArrayList();
125 initialOutfit = new ArrayList();
126 agentInventory = new ArrayList();
127 inventoryLibrary = new ArrayList();
128 inventoryLibraryOwner = new ArrayList();
129 activeGestures = new ArrayList();
130
131 xmlRpcResponse = new XmlRpcResponse();
132 // defaultXmlRpcResponse = new XmlRpcResponse();
133
134 SetDefaultValues();
135 }
136
137 private void SetDefaultValues()
138 {
139 DST = "N";
140 StipendSinceLogin = "N";
141 Gendered = "Y";
142 EverLoggedIn = "Y";
143 login = "false";
144 firstname = "Test";
145 lastname = "User";
146 agentAccess = "M";
147 startLocation = "last";
148 allowFirstLife = "Y";
149
150 SunTexture = "cce0f112-878f-4586-a2e2-a8f104bba271";
151 CloudTexture = "dc4b9f0b-d008-45c6-96a4-01dd947ac621";
152 MoonTexture = "ec4b9f0b-d008-45c6-96a4-01dd947ac621";
153
154 ErrorMessage = "You have entered an invalid name/password combination. Check Caps/lock.";
155 ErrorReason = "key";
156 welcomeMessage = "Welcome to OpenSim!";
157 seedCapability = String.Empty;
158 home = "{'region_handle':[r" + (1000*Constants.RegionSize).ToString() + ",r" + (1000*Constants.RegionSize).ToString() + "], 'position':[r" +
159 userProfile.homepos.X.ToString() + ",r" + userProfile.homepos.Y.ToString() + ",r" +
160 userProfile.homepos.Z.ToString() + "], 'look_at':[r" + userProfile.homelookat.X.ToString() + ",r" +
161 userProfile.homelookat.Y.ToString() + ",r" + userProfile.homelookat.Z.ToString() + "]}";
162 lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]";
163 RegionX = (uint) 255232;
164 RegionY = (uint) 254976;
165
166 // Classifieds;
167 AddClassifiedCategory((Int32) 1, "Shopping");
168 AddClassifiedCategory((Int32) 2, "Land Rental");
169 AddClassifiedCategory((Int32) 3, "Property Rental");
170 AddClassifiedCategory((Int32) 4, "Special Attraction");
171 AddClassifiedCategory((Int32) 5, "New Products");
172 AddClassifiedCategory((Int32) 6, "Employment");
173 AddClassifiedCategory((Int32) 7, "Wanted");
174 AddClassifiedCategory((Int32) 8, "Service");
175 AddClassifiedCategory((Int32) 9, "Personal");
176
177 SessionID = UUID.Random();
178 SecureSessionID = UUID.Random();
179 AgentID = UUID.Random();
180
181 Hashtable InitialOutfitHash = new Hashtable();
182 InitialOutfitHash["folder_name"] = "Nightclub Female";
183 InitialOutfitHash["gender"] = "female";
184 initialOutfit.Add(InitialOutfitHash);
185 }
186
187 #region Login Failure Methods
188
189 public XmlRpcResponse GenerateFailureResponse(string reason, string message, string login)
190 {
191 // Overwrite any default values;
192 xmlRpcResponse = new XmlRpcResponse();
193
194 // Ensure Login Failed message/reason;
195 ErrorMessage = message;
196 ErrorReason = reason;
197
198 loginError["reason"] = ErrorReason;
199 loginError["message"] = ErrorMessage;
200 loginError["login"] = login;
201 xmlRpcResponse.Value = loginError;
202 return (xmlRpcResponse);
203 }
204
205 public OSD GenerateFailureResponseLLSD(string reason, string message, string login)
206 {
207 OSDMap map = new OSDMap();
208
209 // Ensure Login Failed message/reason;
210 ErrorMessage = message;
211 ErrorReason = reason;
212
213 map["reason"] = OSD.FromString(ErrorReason);
214 map["message"] = OSD.FromString(ErrorMessage);
215 map["login"] = OSD.FromString(login);
216
217 return map;
218 }
219
220 public XmlRpcResponse CreateFailedResponse()
221 {
222 return (CreateLoginFailedResponse());
223 }
224
225 public OSD CreateFailedResponseLLSD()
226 {
227 return CreateLoginFailedResponseLLSD();
228 }
229
230 public XmlRpcResponse CreateLoginFailedResponse()
231 {
232 return
233 (GenerateFailureResponse("key",
234 "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist.",
235 "false"));
236 }
237
238 public OSD CreateLoginFailedResponseLLSD()
239 {
240 return GenerateFailureResponseLLSD(
241 "key",
242 "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist.",
243 "false");
244 }
245
246 /// <summary>
247 /// Response to indicate that login failed because the agent's inventory was not available.
248 /// </summary>
249 /// <returns></returns>
250 public XmlRpcResponse CreateLoginInventoryFailedResponse()
251 {
252 return GenerateFailureResponse(
253 "key",
254 "The avatar inventory service is not responding. Please notify your login region operator.",
255 "false");
256 }
257
258 public XmlRpcResponse CreateAlreadyLoggedInResponse()
259 {
260 return
261 (GenerateFailureResponse("presence",
262 "You appear to be already logged in. " +
263 "If this is not the case please wait for your session to timeout. " +
264 "If this takes longer than a few minutes please contact the grid owner. " +
265 "Please wait 5 minutes if you are going to connect to a region nearby to the region you were at previously.",
266 "false"));
267 }
268
269 public OSD CreateAlreadyLoggedInResponseLLSD()
270 {
271 return GenerateFailureResponseLLSD(
272 "presence",
273 "You appear to be already logged in. " +
274 "If this is not the case please wait for your session to timeout. " +
275 "If this takes longer than a few minutes please contact the grid owner",
276 "false");
277 }
278
279 public XmlRpcResponse CreateLoginBlockedResponse()
280 {
281 return
282 (GenerateFailureResponse("presence",
283 "Logins are currently restricted. Please try again later",
284 "false"));
285 }
286
287 public OSD CreateLoginBlockedResponseLLSD()
288 {
289 return GenerateFailureResponseLLSD(
290 "presence",
291 "Logins are currently restricted. Please try again later",
292 "false");
293 }
294
295 public XmlRpcResponse CreateDeadRegionResponse()
296 {
297 return
298 (GenerateFailureResponse("key",
299 "The region you are attempting to log into is not responding. Please select another region and try again.",
300 "false"));
301 }
302
303 public OSD CreateDeadRegionResponseLLSD()
304 {
305 return GenerateFailureResponseLLSD(
306 "key",
307 "The region you are attempting to log into is not responding. Please select another region and try again.",
308 "false");
309 }
310
311 public XmlRpcResponse CreateGridErrorResponse()
312 {
313 return
314 (GenerateFailureResponse("key",
315 "Error connecting to grid. Could not percieve credentials from login XML.",
316 "false"));
317 }
318
319 public OSD CreateGridErrorResponseLLSD()
320 {
321 return GenerateFailureResponseLLSD(
322 "key",
323 "Error connecting to grid. Could not percieve credentials from login XML.",
324 "false");
325 }
326
327 #endregion
328
329 public virtual XmlRpcResponse ToXmlRpcResponse()
330 {
331 try
332 {
333 Hashtable responseData = new Hashtable();
334
335 loginFlagsHash = new Hashtable();
336 loginFlagsHash["daylight_savings"] = DST;
337 loginFlagsHash["stipend_since_login"] = StipendSinceLogin;
338 loginFlagsHash["gendered"] = Gendered;
339 loginFlagsHash["ever_logged_in"] = EverLoggedIn;
340 loginFlags.Add(loginFlagsHash);
341
342 responseData["first_name"] = Firstname;
343 responseData["last_name"] = Lastname;
344 responseData["agent_access"] = agentAccess;
345
346 globalTexturesHash = new Hashtable();
347 globalTexturesHash["sun_texture_id"] = SunTexture;
348 globalTexturesHash["cloud_texture_id"] = CloudTexture;
349 globalTexturesHash["moon_texture_id"] = MoonTexture;
350 globalTextures.Add(globalTexturesHash);
351 // this.eventCategories.Add(this.eventCategoriesHash);
352
353 AddToUIConfig("allow_first_life", allowFirstLife);
354 uiConfig.Add(uiConfigHash);
355
356 responseData["sim_port"] = (Int32) SimPort;
357 responseData["sim_ip"] = SimAddress;
358 responseData["http_port"] = (Int32)SimHttpPort;
359
360 responseData["agent_id"] = AgentID.ToString();
361 responseData["session_id"] = SessionID.ToString();
362 responseData["secure_session_id"] = SecureSessionID.ToString();
363 responseData["circuit_code"] = CircuitCode;
364 responseData["seconds_since_epoch"] = (Int32) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
365 responseData["login-flags"] = loginFlags;
366 responseData["global-textures"] = globalTextures;
367 responseData["seed_capability"] = seedCapability;
368
369 responseData["event_categories"] = eventCategories;
370 responseData["event_notifications"] = new ArrayList(); // todo
371 responseData["classified_categories"] = classifiedCategories;
372 responseData["ui-config"] = uiConfig;
373
374 responseData["inventory-skeleton"] = agentInventory;
375 responseData["inventory-skel-lib"] = inventoryLibrary;
376 responseData["inventory-root"] = inventoryRoot;
377 responseData["inventory-lib-root"] = inventoryLibRoot;
378 responseData["gestures"] = activeGestures;
379 responseData["inventory-lib-owner"] = inventoryLibraryOwner;
380 responseData["initial-outfit"] = initialOutfit;
381 responseData["start_location"] = startLocation;
382 responseData["seed_capability"] = seedCapability;
383 responseData["home"] = home;
384 responseData["look_at"] = lookAt;
385 responseData["message"] = welcomeMessage;
386 responseData["region_x"] = (Int32)(RegionX * Constants.RegionSize);
387 responseData["region_y"] = (Int32)(RegionY * Constants.RegionSize);
388
389 //responseData["inventory-lib-root"] = new ArrayList(); // todo
390
391 if (m_buddyList != null)
392 {
393 responseData["buddy-list"] = m_buddyList.ToArray();
394 }
395
396 responseData["login"] = "true";
397 xmlRpcResponse.Value = responseData;
398
399 return (xmlRpcResponse);
400 }
401 catch (Exception e)
402 {
403 m_log.Warn("[CLIENT]: LoginResponse: Error creating XML-RPC Response: " + e.Message);
404
405 return (GenerateFailureResponse("Internal Error", "Error generating Login Response", "false"));
406 }
407 }
408
409 public OSD ToLLSDResponse()
410 {
411 try
412 {
413 OSDMap map = new OSDMap();
414
415 map["first_name"] = OSD.FromString(Firstname);
416 map["last_name"] = OSD.FromString(Lastname);
417 map["agent_access"] = OSD.FromString(agentAccess);
418
419 map["sim_port"] = OSD.FromInteger(SimPort);
420 map["sim_ip"] = OSD.FromString(SimAddress);
421
422 map["agent_id"] = OSD.FromUUID(AgentID);
423 map["session_id"] = OSD.FromUUID(SessionID);
424 map["secure_session_id"] = OSD.FromUUID(SecureSessionID);
425 map["circuit_code"] = OSD.FromInteger(CircuitCode);
426 map["seconds_since_epoch"] = OSD.FromInteger((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds);
427
428 #region Login Flags
429
430 OSDMap loginFlagsLLSD = new OSDMap();
431 loginFlagsLLSD["daylight_savings"] = OSD.FromString(DST);
432 loginFlagsLLSD["stipend_since_login"] = OSD.FromString(StipendSinceLogin);
433 loginFlagsLLSD["gendered"] = OSD.FromString(Gendered);
434 loginFlagsLLSD["ever_logged_in"] = OSD.FromString(EverLoggedIn);
435 map["login-flags"] = WrapOSDMap(loginFlagsLLSD);
436
437 #endregion Login Flags
438
439 #region Global Textures
440
441 OSDMap globalTexturesLLSD = new OSDMap();
442 globalTexturesLLSD["sun_texture_id"] = OSD.FromString(SunTexture);
443 globalTexturesLLSD["cloud_texture_id"] = OSD.FromString(CloudTexture);
444 globalTexturesLLSD["moon_texture_id"] = OSD.FromString(MoonTexture);
445
446 map["global-textures"] = WrapOSDMap(globalTexturesLLSD);
447
448 #endregion Global Textures
449
450 map["seed_capability"] = OSD.FromString(seedCapability);
451
452 map["event_categories"] = ArrayListToOSDArray(eventCategories);
453 //map["event_notifications"] = new OSDArray(); // todo
454 map["classified_categories"] = ArrayListToOSDArray(classifiedCategories);
455
456 #region UI Config
457
458 OSDMap uiConfigLLSD = new OSDMap();
459 uiConfigLLSD["allow_first_life"] = OSD.FromString(allowFirstLife);
460 map["ui-config"] = WrapOSDMap(uiConfigLLSD);
461
462 #endregion UI Config
463
464 #region Inventory
465
466 map["inventory-skeleton"] = ArrayListToOSDArray(agentInventory);
467
468 map["inventory-skel-lib"] = ArrayListToOSDArray(inventoryLibrary);
469 map["inventory-root"] = ArrayListToOSDArray(inventoryRoot); ;
470 map["inventory-lib-root"] = ArrayListToOSDArray(inventoryLibRoot);
471 map["inventory-lib-owner"] = ArrayListToOSDArray(inventoryLibraryOwner);
472
473 #endregion Inventory
474
475 map["gestures"] = ArrayListToOSDArray(activeGestures);
476
477 map["initial-outfit"] = ArrayListToOSDArray(initialOutfit);
478 map["start_location"] = OSD.FromString(startLocation);
479
480 map["seed_capability"] = OSD.FromString(seedCapability);
481 map["home"] = OSD.FromString(home);
482 map["look_at"] = OSD.FromString(lookAt);
483 map["message"] = OSD.FromString(welcomeMessage);
484 map["region_x"] = OSD.FromInteger(RegionX * Constants.RegionSize);
485 map["region_y"] = OSD.FromInteger(RegionY * Constants.RegionSize);
486
487 if (m_buddyList != null)
488 {
489 map["buddy-list"] = ArrayListToOSDArray(m_buddyList.ToArray());
490 }
491
492 map["login"] = OSD.FromString("true");
493
494 return map;
495 }
496 catch (Exception e)
497 {
498 m_log.Warn("[CLIENT]: LoginResponse: Error creating LLSD Response: " + e.Message);
499
500 return GenerateFailureResponseLLSD("Internal Error", "Error generating Login Response", "false");
501 }
502 }
503
504 public OSDArray ArrayListToOSDArray(ArrayList arrlst)
505 {
506 OSDArray llsdBack = new OSDArray();
507 foreach (Hashtable ht in arrlst)
508 {
509 OSDMap mp = new OSDMap();
510 foreach (DictionaryEntry deHt in ht)
511 {
512 mp.Add((string)deHt.Key, OSDString.FromObject(deHt.Value));
513 }
514 llsdBack.Add(mp);
515 }
516 return llsdBack;
517 }
518
519 private static OSDArray WrapOSDMap(OSDMap wrapMe)
520 {
521 OSDArray array = new OSDArray();
522 array.Add(wrapMe);
523 return array;
524 }
525
526 public void SetEventCategories(string category, string value)
527 {
528 // this.eventCategoriesHash[category] = value;
529 //TODO
530 }
531
532 public void AddToUIConfig(string itemName, string item)
533 {
534 uiConfigHash[itemName] = item;
535 }
536
537 public void AddClassifiedCategory(Int32 ID, string categoryName)
538 {
539 Hashtable hash = new Hashtable();
540 hash["category_name"] = categoryName;
541 hash["category_id"] = ID;
542 classifiedCategories.Add(hash);
543 // this.classifiedCategoriesHash.Clear();
544 }
545
546 #region Properties
547
548 public string Login
549 {
550 get { return login; }
551 set { login = value; }
552 }
553
554 public string DST
555 {
556 get { return dst; }
557 set { dst = value; }
558 }
559
560 public string StipendSinceLogin
561 {
562 get { return stipendSinceLogin; }
563 set { stipendSinceLogin = value; }
564 }
565
566 public string Gendered
567 {
568 get { return gendered; }
569 set { gendered = value; }
570 }
571
572 public string EverLoggedIn
573 {
574 get { return everLoggedIn; }
575 set { everLoggedIn = value; }
576 }
577
578 public uint SimPort
579 {
580 get { return simPort; }
581 set { simPort = value; }
582 }
583
584 public uint SimHttpPort
585 {
586 get { return simHttpPort; }
587 set { simHttpPort = value; }
588 }
589
590 public string SimAddress
591 {
592 get { return simAddress; }
593 set { simAddress = value; }
594 }
595
596 public UUID AgentID
597 {
598 get { return agentID; }
599 set { agentID = value; }
600 }
601
602 public UUID SessionID
603 {
604 get { return sessionID; }
605 set { sessionID = value; }
606 }
607
608 public UUID SecureSessionID
609 {
610 get { return secureSessionID; }
611 set { secureSessionID = value; }
612 }
613
614 public Int32 CircuitCode
615 {
616 get { return circuitCode; }
617 set { circuitCode = value; }
618 }
619
620 public uint RegionX
621 {
622 get { return regionX; }
623 set { regionX = value; }
624 }
625
626 public uint RegionY
627 {
628 get { return regionY; }
629 set { regionY = value; }
630 }
631
632 public string SunTexture
633 {
634 get { return sunTexture; }
635 set { sunTexture = value; }
636 }
637
638 public string CloudTexture
639 {
640 get { return cloudTexture; }
641 set { cloudTexture = value; }
642 }
643
644 public string MoonTexture
645 {
646 get { return moonTexture; }
647 set { moonTexture = value; }
648 }
649
650 public string Firstname
651 {
652 get { return firstname; }
653 set { firstname = value; }
654 }
655
656 public string Lastname
657 {
658 get { return lastname; }
659 set { lastname = value; }
660 }
661
662 public string AgentAccess
663 {
664 get { return agentAccess; }
665 set { agentAccess = value; }
666 }
667
668 public string StartLocation
669 {
670 get { return startLocation; }
671 set { startLocation = value; }
672 }
673
674 public string LookAt
675 {
676 get { return lookAt; }
677 set { lookAt = value; }
678 }
679
680 public string SeedCapability
681 {
682 get { return seedCapability; }
683 set { seedCapability = value; }
684 }
685
686 public string ErrorReason
687 {
688 get { return errorReason; }
689 set { errorReason = value; }
690 }
691
692 public string ErrorMessage
693 {
694 get { return errorMessage; }
695 set { errorMessage = value; }
696 }
697
698 public ArrayList InventoryRoot
699 {
700 get { return inventoryRoot; }
701 set { inventoryRoot = value; }
702 }
703
704 public ArrayList InventorySkeleton
705 {
706 get { return agentInventory; }
707 set { agentInventory = value; }
708 }
709
710 public ArrayList InventoryLibrary
711 {
712 get { return inventoryLibrary; }
713 set { inventoryLibrary = value; }
714 }
715
716 public ArrayList InventoryLibraryOwner
717 {
718 get { return inventoryLibraryOwner; }
719 set { inventoryLibraryOwner = value; }
720 }
721
722 public ArrayList InventoryLibRoot
723 {
724 get { return inventoryLibRoot; }
725 set { inventoryLibRoot = value; }
726 }
727
728 public ArrayList ActiveGestures
729 {
730 get { return activeGestures; }
731 set { activeGestures = value; }
732 }
733
734 public string Home
735 {
736 get { return home; }
737 set { home = value; }
738 }
739
740 public string Message
741 {
742 get { return welcomeMessage; }
743 set { welcomeMessage = value; }
744 }
745
746 public BuddyList BuddList
747 {
748 get { return m_buddyList; }
749 set { m_buddyList = value; }
750 }
751
752 #endregion
753
754 public class UserInfo
755 {
756 public string firstname;
757 public string lastname;
758 public ulong homeregionhandle;
759 public Vector3 homepos;
760 public Vector3 homelookat;
761 }
762
763 public class BuddyList
764 {
765 public List<BuddyInfo> Buddies = new List<BuddyInfo>();
766
767 public void AddNewBuddy(BuddyInfo buddy)
768 {
769 if (!Buddies.Contains(buddy))
770 {
771 Buddies.Add(buddy);
772 }
773 }
774
775 public ArrayList ToArray()
776 {
777 ArrayList buddyArray = new ArrayList();
778 foreach (BuddyInfo buddy in Buddies)
779 {
780 buddyArray.Add(buddy.ToHashTable());
781 }
782 return buddyArray;
783 }
784
785 public class BuddyInfo
786 {
787 public int BuddyRightsHave = 1;
788 public int BuddyRightsGiven = 1;
789 public UUID BuddyID;
790
791 public BuddyInfo(string buddyID)
792 {
793 BuddyID = new UUID(buddyID);
794 }
795
796 public BuddyInfo(UUID buddyID)
797 {
798 BuddyID = buddyID;
799 }
800
801 public Hashtable ToHashTable()
802 {
803 Hashtable hTable = new Hashtable();
804 hTable["buddy_rights_has"] = BuddyRightsHave;
805 hTable["buddy_rights_given"] = BuddyRightsGiven;
806 hTable["buddy_id"] = BuddyID.ToString();
807 return hTable;
808 }
809 }
810 }
811 }
812}
diff --git a/OpenSim/Framework/Communications/Services/LoginService.cs b/OpenSim/Framework/Communications/Services/LoginService.cs
new file mode 100644
index 0000000..51158c9
--- /dev/null
+++ b/OpenSim/Framework/Communications/Services/LoginService.cs
@@ -0,0 +1,1093 @@
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 OpenSim 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;
30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using System.Threading;
35using System.Web;
36using log4net;
37using Nwc.XmlRpc;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenSim.Framework.Communications.Cache;
41using OpenSim.Framework.Statistics;
42
43namespace OpenSim.Framework.Communications.Services
44{
45 public abstract class LoginService
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 protected string m_welcomeMessage = "Welcome to OpenSim";
50 protected int m_minLoginLevel = 0;
51 protected UserManagerBase m_userManager = null;
52 protected Mutex m_loginMutex = new Mutex(false);
53
54 /// <summary>
55 /// Used during login to send the skeleton of the OpenSim Library to the client.
56 /// </summary>
57 protected LibraryRootFolder m_libraryRootFolder;
58
59 protected uint m_defaultHomeX;
60 protected uint m_defaultHomeY;
61
62 /// <summary>
63 /// Used by the login service to make requests to the inventory service.
64 /// </summary>
65 protected IInterServiceInventoryServices m_inventoryService;
66
67 /// <summary>
68 /// Constructor
69 /// </summary>
70 /// <param name="userManager"></param>
71 /// <param name="libraryRootFolder"></param>
72 /// <param name="welcomeMess"></param>
73 public LoginService(UserManagerBase userManager, LibraryRootFolder libraryRootFolder,
74 string welcomeMess)
75 {
76 m_userManager = userManager;
77 m_libraryRootFolder = libraryRootFolder;
78
79 if (welcomeMess != String.Empty)
80 {
81 m_welcomeMessage = welcomeMess;
82 }
83 }
84
85 /// <summary>
86 /// If the user is already logged in, try to notify the region that the user they've got is dead.
87 /// </summary>
88 /// <param name="theUser"></param>
89 public virtual void LogOffUser(UserProfileData theUser, string message)
90 {
91 }
92
93
94 /// <summary>
95 /// Called when we receive the client's initial XMLRPC login_to_simulator request message
96 /// </summary>
97 /// <param name="request">The XMLRPC request</param>
98 /// <returns>The response to send</returns>
99 public virtual XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request)
100 {
101 // Temporary fix
102 m_loginMutex.WaitOne();
103
104 try
105 {
106 //CFK: CustomizeResponse contains sufficient strings to alleviate the need for this.
107 //CKF: m_log.Info("[LOGIN]: Attempting login now...");
108 XmlRpcResponse response = new XmlRpcResponse();
109 Hashtable requestData = (Hashtable)request.Params[0];
110
111 SniffLoginKey((Uri)request.Params[2], requestData);
112
113 bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") &&
114 (requestData.Contains("passwd") || requestData.Contains("web_login_key")));
115
116 string startLocationRequest = "last";
117
118 UserProfileData userProfile;
119 LoginResponse logResponse = new LoginResponse();
120
121 string firstname;
122 string lastname;
123
124 if (GoodXML)
125 {
126 if (requestData.Contains("start"))
127 {
128 startLocationRequest = (string)requestData["start"];
129 }
130
131 firstname = (string)requestData["first"];
132 lastname = (string)requestData["last"];
133
134 m_log.InfoFormat(
135 "[LOGIN BEGIN]: XMLRPC Received login request message from user '{0}' '{1}'",
136 firstname, lastname);
137
138 string clientVersion = "Unknown";
139
140 if (requestData.Contains("version"))
141 {
142 clientVersion = (string)requestData["version"];
143 }
144
145 m_log.DebugFormat(
146 "[LOGIN]: XMLRPC Client is {0}, start location is {1}", clientVersion, startLocationRequest);
147
148 if (!TryAuthenticateXmlRpcLogin(request, firstname, lastname, out userProfile))
149 {
150 return logResponse.CreateLoginFailedResponse();
151 }
152 }
153 else
154 {
155 m_log.Info(
156 "[LOGIN END]: XMLRPC login_to_simulator login message did not contain all the required data");
157
158 return logResponse.CreateGridErrorResponse();
159 }
160
161 if (userProfile.GodLevel < m_minLoginLevel)
162 {
163 return logResponse.CreateLoginBlockedResponse();
164 }
165 else
166 {
167 // If we already have a session...
168 if (userProfile.CurrentAgent != null && userProfile.CurrentAgent.AgentOnline)
169 {
170 //TODO: The following statements can cause trouble:
171 // If agentOnline could not turn from true back to false normally
172 // because of some problem, for instance, the crashment of server or client,
173 // the user cannot log in any longer.
174 userProfile.CurrentAgent.AgentOnline = false;
175
176 m_userManager.CommitAgent(ref userProfile);
177
178 // try to tell the region that their user is dead.
179 LogOffUser(userProfile, " XMLRPC You were logged off because you logged in from another location");
180
181 // Reject the login
182
183 m_log.InfoFormat(
184 "[LOGIN END]: XMLRPC Notifying user {0} {1} that they are already logged in",
185 firstname, lastname);
186
187 return logResponse.CreateAlreadyLoggedInResponse();
188 }
189
190 // Otherwise...
191 // Create a new agent session
192
193 m_userManager.ResetAttachments(userProfile.ID);
194
195 CreateAgent(userProfile, request);
196
197 try
198 {
199 UUID agentID = userProfile.ID;
200 InventoryData inventData;
201
202 try
203 {
204 inventData = GetInventorySkeleton(agentID);
205 }
206 catch (Exception e)
207 {
208 m_log.ErrorFormat(
209 "[LOGIN END]: Error retrieving inventory skeleton of agent {0} - {1}",
210 agentID, e);
211
212 return logResponse.CreateLoginInventoryFailedResponse();
213 }
214
215 ArrayList AgentInventoryArray = inventData.InventoryArray;
216
217 Hashtable InventoryRootHash = new Hashtable();
218 InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString();
219 ArrayList InventoryRoot = new ArrayList();
220 InventoryRoot.Add(InventoryRootHash);
221 userProfile.RootInventoryFolderID = inventData.RootFolderID;
222
223 // Inventory Library Section
224 Hashtable InventoryLibRootHash = new Hashtable();
225 InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000";
226 ArrayList InventoryLibRoot = new ArrayList();
227 InventoryLibRoot.Add(InventoryLibRootHash);
228
229 logResponse.InventoryLibRoot = InventoryLibRoot;
230 logResponse.InventoryLibraryOwner = GetLibraryOwner();
231 logResponse.InventoryRoot = InventoryRoot;
232 logResponse.InventorySkeleton = AgentInventoryArray;
233 logResponse.InventoryLibrary = GetInventoryLibrary();
234
235 logResponse.CircuitCode = Util.RandomClass.Next();
236 logResponse.Lastname = userProfile.SurName;
237 logResponse.Firstname = userProfile.FirstName;
238 logResponse.AgentID = agentID;
239 logResponse.SessionID = userProfile.CurrentAgent.SessionID;
240 logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID;
241 logResponse.Message = GetMessage();
242 logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID));
243 logResponse.StartLocation = startLocationRequest;
244
245 if (CustomiseResponse(logResponse, userProfile, startLocationRequest))
246 {
247 userProfile.LastLogin = userProfile.CurrentAgent.LoginTime;
248 CommitAgent(ref userProfile);
249
250 // If we reach this point, then the login has successfully logged onto the grid
251 if (StatsManager.UserStats != null)
252 StatsManager.UserStats.AddSuccessfulLogin();
253
254 m_log.DebugFormat(
255 "[LOGIN END]: XMLRPC Authentication of user {0} {1} successful. Sending response to client.",
256 firstname, lastname);
257
258 return logResponse.ToXmlRpcResponse();
259 }
260 else
261 {
262 m_log.ErrorFormat("[LOGIN END]: XMLRPC informing user {0} {1} that login failed due to an unavailable region", firstname, lastname);
263 return logResponse.CreateDeadRegionResponse();
264 }
265 }
266 catch (Exception e)
267 {
268 m_log.Error("[LOGIN END]: XMLRPC Login failed, " + e);
269 m_log.Error(e.StackTrace);
270 }
271 }
272
273 m_log.Info("[LOGIN END]: XMLRPC Login failed. Sending back blank XMLRPC response");
274 return response;
275 }
276 finally
277 {
278 m_loginMutex.ReleaseMutex();
279 }
280 }
281
282 protected virtual bool TryAuthenticateXmlRpcLogin(XmlRpcRequest request, string firstname, string lastname, out UserProfileData userProfile)
283 {
284 Hashtable requestData = (Hashtable)request.Params[0];
285
286 bool GoodLogin = false;
287
288 userProfile = GetTheUser(firstname, lastname);
289 if (userProfile == null)
290 {
291 m_log.Info("[LOGIN END]: XMLRPC Could not find a profile for " + firstname + " " + lastname);
292 }
293 else
294 {
295 if (requestData.Contains("passwd"))
296 {
297 string passwd = (string)requestData["passwd"];
298 GoodLogin = AuthenticateUser(userProfile, passwd);
299 }
300 if (!GoodLogin && (requestData.Contains("web_login_key")))
301 {
302 try
303 {
304 UUID webloginkey = new UUID((string)requestData["web_login_key"]);
305 GoodLogin = AuthenticateUser(userProfile, webloginkey);
306 }
307 catch (Exception e)
308 {
309 m_log.InfoFormat(
310 "[LOGIN END]: XMLRPC Bad web_login_key: {0} for user {1} {2}, exception {3}",
311 requestData["web_login_key"], firstname, lastname, e);
312 }
313 }
314 }
315
316 return GoodLogin;
317 }
318
319 protected virtual bool TryAuthenticateLLSDLogin(string firstname, string lastname, string passwd, out UserProfileData userProfile)
320 {
321 bool GoodLogin = false;
322 userProfile = GetTheUser(firstname, lastname);
323 if (userProfile == null)
324 {
325 m_log.Info("[LOGIN]: LLSD Could not find a profile for " + firstname + " " + lastname);
326
327 return false;
328 }
329
330 GoodLogin = AuthenticateUser(userProfile, passwd);
331 return GoodLogin;
332 }
333
334 /// <summary>
335 /// Called when we receive the client's initial LLSD login_to_simulator request message
336 /// </summary>
337 /// <param name="request">The LLSD request</param>
338 /// <returns>The response to send</returns>
339 public OSD LLSDLoginMethod(OSD request)
340 {
341 // Temporary fix
342 m_loginMutex.WaitOne();
343
344 try
345 {
346 // bool GoodLogin = false;
347
348 string startLocationRequest = "last";
349
350 UserProfileData userProfile = null;
351 LoginResponse logResponse = new LoginResponse();
352
353 if (request.Type == OSDType.Map)
354 {
355 OSDMap map = (OSDMap)request;
356
357 if (map.ContainsKey("first") && map.ContainsKey("last") && map.ContainsKey("passwd"))
358 {
359 string firstname = map["first"].AsString();
360 string lastname = map["last"].AsString();
361 string passwd = map["passwd"].AsString();
362
363 if (map.ContainsKey("start"))
364 {
365 m_log.Info("[LOGIN]: LLSD StartLocation Requested: " + map["start"].AsString());
366 startLocationRequest = map["start"].AsString();
367 }
368 m_log.Info("[LOGIN]: LLSD Login Requested for: '" + firstname + "' '" + lastname + "' / " + passwd);
369
370 if (!TryAuthenticateLLSDLogin(firstname, lastname, passwd, out userProfile))
371 {
372 return logResponse.CreateLoginFailedResponseLLSD();
373 }
374 }
375 else
376 return logResponse.CreateLoginFailedResponseLLSD();
377 }
378 else
379 return logResponse.CreateLoginFailedResponseLLSD();
380
381
382 if (userProfile.GodLevel < m_minLoginLevel)
383 {
384 return logResponse.CreateLoginBlockedResponseLLSD();
385 }
386 else
387 {
388 // If we already have a session...
389 if (userProfile.CurrentAgent != null && userProfile.CurrentAgent.AgentOnline)
390 {
391 userProfile.CurrentAgent.AgentOnline = false;
392
393 m_userManager.CommitAgent(ref userProfile);
394 // try to tell the region that their user is dead.
395 LogOffUser(userProfile, " LLSD You were logged off because you logged in from another location");
396
397 // Reject the login
398
399 m_log.InfoFormat(
400 "[LOGIN END]: LLSD Notifying user {0} {1} that they are already logged in",
401 userProfile.FirstName, userProfile.SurName);
402
403 userProfile.CurrentAgent = null;
404 return logResponse.CreateAlreadyLoggedInResponseLLSD();
405 }
406
407 // Otherwise...
408 // Create a new agent session
409
410 m_userManager.ResetAttachments(userProfile.ID);
411
412 CreateAgent(userProfile, request);
413
414 try
415 {
416 UUID agentID = userProfile.ID;
417
418 //InventoryData inventData = GetInventorySkeleton(agentID);
419 InventoryData inventData = null;
420
421 try
422 {
423 inventData = GetInventorySkeleton(agentID);
424 }
425 catch (Exception e)
426 {
427 m_log.ErrorFormat(
428 "[LOGIN END]: LLSD Error retrieving inventory skeleton of agent {0}, {1} - {2}",
429 agentID, e.GetType(), e.Message);
430
431 return logResponse.CreateLoginFailedResponseLLSD();// .CreateLoginInventoryFailedResponseLLSD ();
432 }
433
434
435 ArrayList AgentInventoryArray = inventData.InventoryArray;
436
437 Hashtable InventoryRootHash = new Hashtable();
438 InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString();
439 ArrayList InventoryRoot = new ArrayList();
440 InventoryRoot.Add(InventoryRootHash);
441 userProfile.RootInventoryFolderID = inventData.RootFolderID;
442
443
444 // Inventory Library Section
445 Hashtable InventoryLibRootHash = new Hashtable();
446 InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000";
447 ArrayList InventoryLibRoot = new ArrayList();
448 InventoryLibRoot.Add(InventoryLibRootHash);
449
450 logResponse.InventoryLibRoot = InventoryLibRoot;
451 logResponse.InventoryLibraryOwner = GetLibraryOwner();
452 logResponse.InventoryRoot = InventoryRoot;
453 logResponse.InventorySkeleton = AgentInventoryArray;
454 logResponse.InventoryLibrary = GetInventoryLibrary();
455
456 logResponse.CircuitCode = (Int32)Util.RandomClass.Next();
457 logResponse.Lastname = userProfile.SurName;
458 logResponse.Firstname = userProfile.FirstName;
459 logResponse.AgentID = agentID;
460 logResponse.SessionID = userProfile.CurrentAgent.SessionID;
461 logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID;
462 logResponse.Message = GetMessage();
463 logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID));
464 logResponse.StartLocation = startLocationRequest;
465
466 try
467 {
468 CustomiseResponse(logResponse, userProfile, startLocationRequest);
469 }
470 catch (Exception ex)
471 {
472 m_log.Info("[LOGIN]: LLSD " + ex.ToString());
473 return logResponse.CreateDeadRegionResponseLLSD();
474 }
475
476 userProfile.LastLogin = userProfile.CurrentAgent.LoginTime;
477 CommitAgent(ref userProfile);
478
479 // If we reach this point, then the login has successfully logged onto the grid
480 if (StatsManager.UserStats != null)
481 StatsManager.UserStats.AddSuccessfulLogin();
482
483 m_log.DebugFormat(
484 "[LOGIN END]: LLSD Authentication of user {0} {1} successful. Sending response to client.",
485 userProfile.FirstName, userProfile.SurName);
486
487 return logResponse.ToLLSDResponse();
488 }
489 catch (Exception ex)
490 {
491 m_log.Info("[LOGIN]: LLSD " + ex.ToString());
492 return logResponse.CreateFailedResponseLLSD();
493 }
494 }
495 }
496 finally
497 {
498 m_loginMutex.ReleaseMutex();
499 }
500 }
501
502 public Hashtable ProcessHTMLLogin(Hashtable keysvals)
503 {
504 // Matches all unspecified characters
505 // Currently specified,; lowercase letters, upper case letters, numbers, underline
506 // period, space, parens, and dash.
507
508 Regex wfcut = new Regex("[^a-zA-Z0-9_\\.\\$ \\(\\)\\-]");
509
510 Hashtable returnactions = new Hashtable();
511 int statuscode = 200;
512
513 string firstname = String.Empty;
514 string lastname = String.Empty;
515 string location = String.Empty;
516 string region = String.Empty;
517 string grid = String.Empty;
518 string channel = String.Empty;
519 string version = String.Empty;
520 string lang = String.Empty;
521 string password = String.Empty;
522 string errormessages = String.Empty;
523
524 // the client requires the HTML form field be named 'username'
525 // however, the data it sends when it loads the first time is 'firstname'
526 // another one of those little nuances.
527
528 if (keysvals.Contains("firstname"))
529 firstname = wfcut.Replace((string)keysvals["firstname"], String.Empty, 99999);
530
531 if (keysvals.Contains("username"))
532 firstname = wfcut.Replace((string)keysvals["username"], String.Empty, 99999);
533
534 if (keysvals.Contains("lastname"))
535 lastname = wfcut.Replace((string)keysvals["lastname"], String.Empty, 99999);
536
537 if (keysvals.Contains("location"))
538 location = wfcut.Replace((string)keysvals["location"], String.Empty, 99999);
539
540 if (keysvals.Contains("region"))
541 region = wfcut.Replace((string)keysvals["region"], String.Empty, 99999);
542
543 if (keysvals.Contains("grid"))
544 grid = wfcut.Replace((string)keysvals["grid"], String.Empty, 99999);
545
546 if (keysvals.Contains("channel"))
547 channel = wfcut.Replace((string)keysvals["channel"], String.Empty, 99999);
548
549 if (keysvals.Contains("version"))
550 version = wfcut.Replace((string)keysvals["version"], String.Empty, 99999);
551
552 if (keysvals.Contains("lang"))
553 lang = wfcut.Replace((string)keysvals["lang"], String.Empty, 99999);
554
555 if (keysvals.Contains("password"))
556 password = wfcut.Replace((string)keysvals["password"], String.Empty, 99999);
557
558 // load our login form.
559 string loginform = GetLoginForm(firstname, lastname, location, region, grid, channel, version, lang, password, errormessages);
560
561 if (keysvals.ContainsKey("show_login_form"))
562 {
563 UserProfileData user = GetTheUser(firstname, lastname);
564 bool goodweblogin = false;
565
566 if (user != null)
567 goodweblogin = AuthenticateUser(user, password);
568
569 if (goodweblogin)
570 {
571 UUID webloginkey = UUID.Random();
572 m_userManager.StoreWebLoginKey(user.ID, webloginkey);
573 //statuscode = 301;
574
575 // string redirectURL = "about:blank?redirect-http-hack=" +
576 // HttpUtility.UrlEncode("secondlife:///app/login?first_name=" + firstname + "&last_name=" +
577 // lastname +
578 // "&location=" + location + "&grid=Other&web_login_key=" + webloginkey.ToString());
579 //m_log.Info("[WEB]: R:" + redirectURL);
580 returnactions["int_response_code"] = statuscode;
581 //returnactions["str_redirect_location"] = redirectURL;
582 //returnactions["str_response_string"] = "<HTML><BODY>GoodLogin</BODY></HTML>";
583 returnactions["str_response_string"] = webloginkey.ToString();
584 }
585 else
586 {
587 errormessages = "The Username and password supplied did not match our records. Check your caps lock and try again";
588
589 loginform = GetLoginForm(firstname, lastname, location, region, grid, channel, version, lang, password, errormessages);
590 returnactions["int_response_code"] = statuscode;
591 returnactions["str_response_string"] = loginform;
592 }
593 }
594 else
595 {
596 returnactions["int_response_code"] = statuscode;
597 returnactions["str_response_string"] = loginform;
598 }
599 return returnactions;
600 }
601
602 public string GetLoginForm(string firstname, string lastname, string location, string region,
603 string grid, string channel, string version, string lang,
604 string password, string errormessages)
605 {
606 // inject our values in the form at the markers
607
608 string loginform = String.Empty;
609 string file = Path.Combine(Util.configDir(), "http_loginform.html");
610 if (!File.Exists(file))
611 {
612 loginform = GetDefaultLoginForm();
613 }
614 else
615 {
616 StreamReader sr = File.OpenText(file);
617 loginform = sr.ReadToEnd();
618 sr.Close();
619 }
620
621 loginform = loginform.Replace("[$firstname]", firstname);
622 loginform = loginform.Replace("[$lastname]", lastname);
623 loginform = loginform.Replace("[$location]", location);
624 loginform = loginform.Replace("[$region]", region);
625 loginform = loginform.Replace("[$grid]", grid);
626 loginform = loginform.Replace("[$channel]", channel);
627 loginform = loginform.Replace("[$version]", version);
628 loginform = loginform.Replace("[$lang]", lang);
629 loginform = loginform.Replace("[$password]", password);
630 loginform = loginform.Replace("[$errors]", errormessages);
631
632 return loginform;
633 }
634
635 public string GetDefaultLoginForm()
636 {
637 string responseString =
638 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
639 responseString += "<html xmlns=\"http://www.w3.org/1999/xhtml\">";
640 responseString += "<head>";
641 responseString += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />";
642 responseString += "<meta http-equiv=\"cache-control\" content=\"no-cache\">";
643 responseString += "<meta http-equiv=\"Pragma\" content=\"no-cache\">";
644 responseString += "<title>OpenSim Login</title>";
645 responseString += "<body><br />";
646 responseString += "<div id=\"login_box\">";
647
648 responseString += "<form action=\"/go.cgi\" method=\"GET\" id=\"login-form\">";
649
650 responseString += "<div id=\"message\">[$errors]</div>";
651 responseString += "<fieldset id=\"firstname\">";
652 responseString += "<legend>First Name:</legend>";
653 responseString += "<input type=\"text\" id=\"firstname_input\" size=\"15\" maxlength=\"100\" name=\"username\" value=\"[$firstname]\" />";
654 responseString += "</fieldset>";
655 responseString += "<fieldset id=\"lastname\">";
656 responseString += "<legend>Last Name:</legend>";
657 responseString += "<input type=\"text\" size=\"15\" maxlength=\"100\" name=\"lastname\" value=\"[$lastname]\" />";
658 responseString += "</fieldset>";
659 responseString += "<fieldset id=\"password\">";
660 responseString += "<legend>Password:</legend>";
661 responseString += "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">";
662 responseString += "<tr>";
663 responseString += "<td colspan=\"2\"><input type=\"password\" size=\"15\" maxlength=\"100\" name=\"password\" value=\"[$password]\" /></td>";
664 responseString += "</tr>";
665 responseString += "<tr>";
666 responseString += "<td valign=\"middle\"><input type=\"checkbox\" name=\"remember_password\" id=\"remember_password\" [$remember_password] style=\"margin-left:0px;\"/></td>";
667 responseString += "<td><label for=\"remember_password\">Remember password</label></td>";
668 responseString += "</tr>";
669 responseString += "</table>";
670 responseString += "</fieldset>";
671 responseString += "<input type=\"hidden\" name=\"show_login_form\" value=\"FALSE\" />";
672 responseString += "<input type=\"hidden\" name=\"method\" value=\"login\" />";
673 responseString += "<input type=\"hidden\" id=\"grid\" name=\"grid\" value=\"[$grid]\" />";
674 responseString += "<input type=\"hidden\" id=\"region\" name=\"region\" value=\"[$region]\" />";
675 responseString += "<input type=\"hidden\" id=\"location\" name=\"location\" value=\"[$location]\" />";
676 responseString += "<input type=\"hidden\" id=\"channel\" name=\"channel\" value=\"[$channel]\" />";
677 responseString += "<input type=\"hidden\" id=\"version\" name=\"version\" value=\"[$version]\" />";
678 responseString += "<input type=\"hidden\" id=\"lang\" name=\"lang\" value=\"[$lang]\" />";
679 responseString += "<div id=\"submitbtn\">";
680 responseString += "<input class=\"input_over\" type=\"submit\" value=\"Connect\" />";
681 responseString += "</div>";
682 responseString += "<div id=\"connecting\" style=\"visibility:hidden\"> Connecting...</div>";
683
684 responseString += "<div id=\"helplinks\"><!---";
685 responseString += "<a href=\"#join now link\" target=\"_blank\"></a> | ";
686 responseString += "<a href=\"#forgot password link\" target=\"_blank\"></a>";
687 responseString += "---></div>";
688
689 responseString += "<div id=\"channelinfo\"> [$channel] | [$version]=[$lang]</div>";
690 responseString += "</form>";
691 responseString += "<script language=\"JavaScript\">";
692 responseString += "document.getElementById('firstname_input').focus();";
693 responseString += "</script>";
694 responseString += "</div>";
695 responseString += "</div>";
696 responseString += "</body>";
697 responseString += "</html>";
698
699 return responseString;
700 }
701
702 /// <summary>
703 /// Saves a target agent to the database
704 /// </summary>
705 /// <param name="profile">The users profile</param>
706 /// <returns>Successful?</returns>
707 public bool CommitAgent(ref UserProfileData profile)
708 {
709 return m_userManager.CommitAgent(ref profile);
710 }
711
712 /// <summary>
713 /// Checks a user against it's password hash
714 /// </summary>
715 /// <param name="profile">The users profile</param>
716 /// <param name="password">The supplied password</param>
717 /// <returns>Authenticated?</returns>
718 public virtual bool AuthenticateUser(UserProfileData profile, string password)
719 {
720 bool passwordSuccess = false;
721 //m_log.InfoFormat("[LOGIN]: Authenticating {0} {1} ({2})", profile.FirstName, profile.SurName, profile.ID);
722
723 // Web Login method seems to also occasionally send the hashed password itself
724
725 // we do this to get our hash in a form that the server password code can consume
726 // when the web-login-form submits the password in the clear (supposed to be over SSL!)
727 if (!password.StartsWith("$1$"))
728 password = "$1$" + Util.Md5Hash(password);
729
730 password = password.Remove(0, 3); //remove $1$
731
732 string s = Util.Md5Hash(password + ":" + profile.PasswordSalt);
733 // Testing...
734 //m_log.Info("[LOGIN]: SubHash:" + s + " userprofile:" + profile.passwordHash);
735 //m_log.Info("[LOGIN]: userprofile:" + profile.passwordHash + " SubCT:" + password);
736
737 passwordSuccess = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
738 || profile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase));
739
740 return passwordSuccess;
741 }
742
743 public virtual bool AuthenticateUser(UserProfileData profile, UUID webloginkey)
744 {
745 bool passwordSuccess = false;
746 m_log.InfoFormat("[LOGIN]: Authenticating {0} {1} ({2})", profile.FirstName, profile.SurName, profile.ID);
747
748 // Match web login key unless it's the default weblogin key UUID.Zero
749 passwordSuccess = ((profile.WebLoginKey == webloginkey) && profile.WebLoginKey != UUID.Zero);
750
751 return passwordSuccess;
752 }
753
754 /// <summary>
755 ///
756 /// </summary>
757 /// <param name="profile"></param>
758 /// <param name="request"></param>
759 public void CreateAgent(UserProfileData profile, XmlRpcRequest request)
760 {
761 m_userManager.CreateAgent(profile, request);
762 }
763
764 public void CreateAgent(UserProfileData profile, OSD request)
765 {
766 m_userManager.CreateAgent(profile, request);
767 }
768
769 /// <summary>
770 ///
771 /// </summary>
772 /// <param name="firstname"></param>
773 /// <param name="lastname"></param>
774 /// <returns></returns>
775 public virtual UserProfileData GetTheUser(string firstname, string lastname)
776 {
777 return m_userManager.GetUserProfile(firstname, lastname);
778 }
779
780 /// <summary>
781 ///
782 /// </summary>
783 /// <returns></returns>
784 public virtual string GetMessage()
785 {
786 return m_welcomeMessage;
787 }
788
789 private static LoginResponse.BuddyList ConvertFriendListItem(List<FriendListItem> LFL)
790 {
791 LoginResponse.BuddyList buddylistreturn = new LoginResponse.BuddyList();
792 foreach (FriendListItem fl in LFL)
793 {
794 LoginResponse.BuddyList.BuddyInfo buddyitem = new LoginResponse.BuddyList.BuddyInfo(fl.Friend);
795 buddyitem.BuddyID = fl.Friend;
796 buddyitem.BuddyRightsHave = (int)fl.FriendListOwnerPerms;
797 buddyitem.BuddyRightsGiven = (int)fl.FriendPerms;
798 buddylistreturn.AddNewBuddy(buddyitem);
799 }
800 return buddylistreturn;
801 }
802
803 /// <summary>
804 /// Converts the inventory library skeleton into the form required by the rpc request.
805 /// </summary>
806 /// <returns></returns>
807 protected virtual ArrayList GetInventoryLibrary()
808 {
809 Dictionary<UUID, InventoryFolderImpl> rootFolders
810 = m_libraryRootFolder.RequestSelfAndDescendentFolders();
811 ArrayList folderHashes = new ArrayList();
812
813 foreach (InventoryFolderBase folder in rootFolders.Values)
814 {
815 Hashtable TempHash = new Hashtable();
816 TempHash["name"] = folder.Name;
817 TempHash["parent_id"] = folder.ParentID.ToString();
818 TempHash["version"] = (Int32)folder.Version;
819 TempHash["type_default"] = (Int32)folder.Type;
820 TempHash["folder_id"] = folder.ID.ToString();
821 folderHashes.Add(TempHash);
822 }
823
824 return folderHashes;
825 }
826
827 /// <summary>
828 ///
829 /// </summary>
830 /// <returns></returns>
831 protected virtual ArrayList GetLibraryOwner()
832 {
833 //for now create random inventory library owner
834 Hashtable TempHash = new Hashtable();
835 TempHash["agent_id"] = "11111111-1111-0000-0000-000100bba000";
836 ArrayList inventoryLibOwner = new ArrayList();
837 inventoryLibOwner.Add(TempHash);
838 return inventoryLibOwner;
839 }
840
841 public class InventoryData
842 {
843 public ArrayList InventoryArray = null;
844 public UUID RootFolderID = UUID.Zero;
845
846 public InventoryData(ArrayList invList, UUID rootID)
847 {
848 InventoryArray = invList;
849 RootFolderID = rootID;
850 }
851 }
852
853 protected void SniffLoginKey(Uri uri, Hashtable requestData)
854 {
855 string uri_str = uri.ToString();
856 string[] parts = uri_str.Split(new char[] { '=' });
857 if (parts.Length > 1)
858 {
859 string web_login_key = parts[1];
860 requestData.Add("web_login_key", web_login_key);
861 m_log.InfoFormat("[LOGIN]: Login with web_login_key {0}", web_login_key);
862 }
863 }
864
865 /// <summary>
866 /// Customises the login response and fills in missing values. This method also tells the login region to
867 /// expect a client connection.
868 /// </summary>
869 /// <param name="response">The existing response</param>
870 /// <param name="theUser">The user profile</param>
871 /// <param name="startLocationRequest">The requested start location</param>
872 /// <returns>true on success, false if the region was not successfully told to expect a user connection</returns>
873 public bool CustomiseResponse(LoginResponse response, UserProfileData theUser, string startLocationRequest)
874 {
875 // add active gestures to login-response
876 AddActiveGestures(response, theUser);
877
878 // HomeLocation
879 RegionInfo homeInfo = null;
880
881 // use the homeRegionID if it is stored already. If not, use the regionHandle as before
882 UUID homeRegionId = theUser.HomeRegionID;
883 ulong homeRegionHandle = theUser.HomeRegion;
884 if (homeRegionId != UUID.Zero)
885 {
886 homeInfo = GetRegionInfo(homeRegionId);
887 }
888 else
889 {
890 homeInfo = GetRegionInfo(homeRegionHandle);
891 }
892
893 if (homeInfo != null)
894 {
895 response.Home =
896 string.Format(
897 "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}",
898 (homeInfo.RegionLocX * Constants.RegionSize),
899 (homeInfo.RegionLocY * Constants.RegionSize),
900 theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z,
901 theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z);
902 }
903 else
904 {
905 m_log.InfoFormat("not found the region at {0} {1}", theUser.HomeRegionX, theUser.HomeRegionY);
906 // Emergency mode: Home-region isn't available, so we can't request the region info.
907 // Use the stored home regionHandle instead.
908 // NOTE: If the home-region moves, this will be wrong until the users update their user-profile again
909 ulong regionX = homeRegionHandle >> 32;
910 ulong regionY = homeRegionHandle & 0xffffffff;
911 response.Home =
912 string.Format(
913 "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}",
914 regionX, regionY,
915 theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z,
916 theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z);
917
918 m_log.InfoFormat("[LOGIN] Home region of user {0} {1} is not available; using computed region position {2} {3}",
919 theUser.FirstName, theUser.SurName,
920 regionX, regionY);
921 }
922
923 // StartLocation
924 RegionInfo regionInfo = null;
925 if (startLocationRequest == "home")
926 {
927 regionInfo = homeInfo;
928 theUser.CurrentAgent.Position = theUser.HomeLocation;
929 response.LookAt = "[r" + theUser.HomeLookAt.X.ToString() + ",r" + theUser.HomeLookAt.Y.ToString() + ",r" + theUser.HomeLookAt.Z.ToString() + "]";
930 }
931 else if (startLocationRequest == "last")
932 {
933 UUID lastRegion = theUser.CurrentAgent.Region;
934 regionInfo = GetRegionInfo(lastRegion);
935 response.LookAt = "[r" + theUser.CurrentAgent.LookAt.X.ToString() + ",r" + theUser.CurrentAgent.LookAt.Y.ToString() + ",r" + theUser.CurrentAgent.LookAt.Z.ToString() + "]";
936 }
937 else
938 {
939 Regex reURI = new Regex(@"^uri:(?<region>[^&]+)&(?<x>\d+)&(?<y>\d+)&(?<z>\d+)$");
940 Match uriMatch = reURI.Match(startLocationRequest);
941 if (uriMatch == null)
942 {
943 m_log.InfoFormat("[LOGIN]: Got Custom Login URL {0}, but can't process it", startLocationRequest);
944 }
945 else
946 {
947 string region = uriMatch.Groups["region"].ToString();
948 regionInfo = RequestClosestRegion(region);
949 if (regionInfo == null)
950 {
951 m_log.InfoFormat("[LOGIN]: Got Custom Login URL {0}, can't locate region {1}", startLocationRequest, region);
952 }
953 else
954 {
955 theUser.CurrentAgent.Position = new Vector3(float.Parse(uriMatch.Groups["x"].Value),
956 float.Parse(uriMatch.Groups["y"].Value), float.Parse(uriMatch.Groups["z"].Value));
957 }
958 }
959 response.LookAt = "[r0,r1,r0]";
960 // can be: last, home, safe, url
961 response.StartLocation = "url";
962 }
963
964 if ((regionInfo != null) && (PrepareLoginToRegion(regionInfo, theUser, response)))
965 {
966 return true;
967 }
968
969 // StartLocation not available, send him to a nearby region instead
970 // regionInfo = m_gridService.RequestClosestRegion("");
971 //m_log.InfoFormat("[LOGIN]: StartLocation not available sending to region {0}", regionInfo.regionName);
972
973 // Send him to default region instead
974 ulong defaultHandle = (((ulong)m_defaultHomeX * Constants.RegionSize) << 32) |
975 ((ulong)m_defaultHomeY * Constants.RegionSize);
976
977 if ((regionInfo != null) && (defaultHandle == regionInfo.RegionHandle))
978 {
979 m_log.ErrorFormat("[LOGIN]: Not trying the default region since this is the same as the selected region");
980 return false;
981 }
982
983 m_log.Error("[LOGIN]: Sending user to default region " + defaultHandle + " instead");
984 regionInfo = GetRegionInfo(defaultHandle);
985
986 if (regionInfo == null)
987 {
988 m_log.ErrorFormat("[LOGIN]: No default region available. Aborting.");
989 return false;
990 }
991
992 theUser.CurrentAgent.Position = new Vector3(128, 128, 0);
993 response.StartLocation = "safe";
994
995 return PrepareLoginToRegion(regionInfo, theUser, response);
996 }
997
998 protected abstract RegionInfo RequestClosestRegion(string region);
999 protected abstract RegionInfo GetRegionInfo(ulong homeRegionHandle);
1000 protected abstract RegionInfo GetRegionInfo(UUID homeRegionId);
1001 protected abstract bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response);
1002
1003 /// <summary>
1004 /// Add active gestures of the user to the login response.
1005 /// </summary>
1006 /// <param name="response">
1007 /// A <see cref="LoginResponse"/>
1008 /// </param>
1009 /// <param name="theUser">
1010 /// A <see cref="UserProfileData"/>
1011 /// </param>
1012 protected void AddActiveGestures(LoginResponse response, UserProfileData theUser)
1013 {
1014 List<InventoryItemBase> gestures = m_inventoryService.GetActiveGestures(theUser.ID);
1015 //m_log.DebugFormat("[LOGIN]: AddActiveGestures, found {0}", gestures == null ? 0 : gestures.Count);
1016 ArrayList list = new ArrayList();
1017 if (gestures != null)
1018 {
1019 foreach (InventoryItemBase gesture in gestures)
1020 {
1021 Hashtable item = new Hashtable();
1022 item["item_id"] = gesture.ID.ToString();
1023 item["asset_id"] = gesture.AssetID.ToString();
1024 list.Add(item);
1025 }
1026 }
1027 response.ActiveGestures = list;
1028 }
1029
1030 /// <summary>
1031 /// Get the initial login inventory skeleton (in other words, the folder structure) for the given user.
1032 /// </summary>
1033 /// <param name="userID"></param>
1034 /// <returns></returns>
1035 /// <exception cref='System.Exception'>This will be thrown if there is a problem with the inventory service</exception>
1036 protected InventoryData GetInventorySkeleton(UUID userID)
1037 {
1038 List<InventoryFolderBase> folders = m_inventoryService.GetInventorySkeleton(userID);
1039
1040 // If we have user auth but no inventory folders for some reason, create a new set of folders.
1041 if (folders == null || folders.Count == 0)
1042 {
1043 m_log.InfoFormat(
1044 "[LOGIN]: A root inventory folder for user {0} was not found. Requesting creation.", userID);
1045
1046 // Although the create user function creates a new agent inventory along with a new user profile, some
1047 // tools are creating the user profile directly in the database without creating the inventory. At
1048 // this time we'll accomodate them by lazily creating the user inventory now if it doesn't already
1049 // exist.
1050 if (!m_inventoryService.CreateNewUserInventory(userID))
1051 {
1052 throw new Exception(
1053 String.Format(
1054 "The inventory creation request for user {0} did not succeed."
1055 + " Please contact your inventory service provider for more information.",
1056 userID));
1057 }
1058
1059 m_log.InfoFormat("[LOGIN]: A new inventory skeleton was successfully created for user {0}", userID);
1060
1061 folders = m_inventoryService.GetInventorySkeleton(userID);
1062
1063 if (folders == null || folders.Count == 0)
1064 {
1065 throw new Exception(
1066 String.Format(
1067 "A root inventory folder for user {0} could not be retrieved from the inventory service",
1068 userID));
1069 }
1070 }
1071
1072 UUID rootID = UUID.Zero;
1073 ArrayList AgentInventoryArray = new ArrayList();
1074 Hashtable TempHash;
1075 foreach (InventoryFolderBase InvFolder in folders)
1076 {
1077 if (InvFolder.ParentID == UUID.Zero)
1078 {
1079 rootID = InvFolder.ID;
1080 }
1081 TempHash = new Hashtable();
1082 TempHash["name"] = InvFolder.Name;
1083 TempHash["parent_id"] = InvFolder.ParentID.ToString();
1084 TempHash["version"] = (Int32)InvFolder.Version;
1085 TempHash["type_default"] = (Int32)InvFolder.Type;
1086 TempHash["folder_id"] = InvFolder.ID.ToString();
1087 AgentInventoryArray.Add(TempHash);
1088 }
1089
1090 return new InventoryData(AgentInventoryArray, rootID);
1091 }
1092 }
1093}