diff options
Diffstat (limited to '')
-rw-r--r-- | Common/OpenGrid.Framework.UserManager/UserManagerBase.cs | 318 |
1 files changed, 119 insertions, 199 deletions
diff --git a/Common/OpenGrid.Framework.UserManager/UserManagerBase.cs b/Common/OpenGrid.Framework.UserManager/UserManagerBase.cs index eaa53dd..01fbf3a 100644 --- a/Common/OpenGrid.Framework.UserManager/UserManagerBase.cs +++ b/Common/OpenGrid.Framework.UserManager/UserManagerBase.cs | |||
@@ -79,37 +79,7 @@ namespace OpenGrid.Framework.UserManagement | |||
79 | pluginAssembly = null; | 79 | pluginAssembly = null; |
80 | } | 80 | } |
81 | 81 | ||
82 | /// <summary> | 82 | #region Get UserProfile |
83 | /// | ||
84 | /// </summary> | ||
85 | /// <param name="user"></param> | ||
86 | public void AddUserProfile(string firstName, string lastName, string pass, uint regX, uint regY) | ||
87 | { | ||
88 | UserProfileData user = new UserProfileData(); | ||
89 | user.homeLocation = new LLVector3(128, 128, 100); | ||
90 | user.UUID = LLUUID.Random(); | ||
91 | user.username = firstName; | ||
92 | user.surname = lastName; | ||
93 | user.passwordHash = pass; | ||
94 | user.passwordSalt = ""; | ||
95 | user.created = Util.UnixTimeSinceEpoch(); | ||
96 | user.homeLookAt = new LLVector3(100, 100, 100); | ||
97 | user.homeRegion = Util.UIntsToLong((regX * 256), (regY * 256)); | ||
98 | |||
99 | foreach (KeyValuePair<string, IUserData> plugin in _plugins) | ||
100 | { | ||
101 | try | ||
102 | { | ||
103 | plugin.Value.addNewUserProfile(user); | ||
104 | |||
105 | } | ||
106 | catch (Exception e) | ||
107 | { | ||
108 | OpenSim.Framework.Console.MainLog.Instance.Verbose( "Unable to find user via " + plugin.Key + "(" + e.ToString() + ")"); | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | /// <summary> | 83 | /// <summary> |
114 | /// Loads a user profile from a database by UUID | 84 | /// Loads a user profile from a database by UUID |
115 | /// </summary> | 85 | /// </summary> |
@@ -190,7 +160,9 @@ namespace OpenGrid.Framework.UserManagement | |||
190 | 160 | ||
191 | return null; | 161 | return null; |
192 | } | 162 | } |
163 | #endregion | ||
193 | 164 | ||
165 | #region Get UserAgent | ||
194 | /// <summary> | 166 | /// <summary> |
195 | /// Loads a user agent by uuid (not called directly) | 167 | /// Loads a user agent by uuid (not called directly) |
196 | /// </summary> | 168 | /// </summary> |
@@ -258,94 +230,9 @@ namespace OpenGrid.Framework.UserManagement | |||
258 | return null; | 230 | return null; |
259 | } | 231 | } |
260 | 232 | ||
261 | /// <summary> | 233 | #endregion |
262 | /// Creates a error response caused by invalid XML | ||
263 | /// </summary> | ||
264 | /// <returns>An XMLRPC response</returns> | ||
265 | private static XmlRpcResponse CreateErrorConnectingToGridResponse() | ||
266 | { | ||
267 | XmlRpcResponse response = new XmlRpcResponse(); | ||
268 | Hashtable ErrorRespData = new Hashtable(); | ||
269 | ErrorRespData["reason"] = "key"; | ||
270 | ErrorRespData["message"] = "Error connecting to grid. Could not percieve credentials from login XML."; | ||
271 | ErrorRespData["login"] = "false"; | ||
272 | response.Value = ErrorRespData; | ||
273 | return response; | ||
274 | } | ||
275 | |||
276 | /// <summary> | ||
277 | /// Creates an error response caused by bad login credentials | ||
278 | /// </summary> | ||
279 | /// <returns>An XMLRPC response</returns> | ||
280 | private static XmlRpcResponse CreateLoginErrorResponse() | ||
281 | { | ||
282 | XmlRpcResponse response = new XmlRpcResponse(); | ||
283 | Hashtable ErrorRespData = new Hashtable(); | ||
284 | ErrorRespData["reason"] = "key"; | ||
285 | ErrorRespData["message"] = "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist."; | ||
286 | ErrorRespData["login"] = "false"; | ||
287 | response.Value = ErrorRespData; | ||
288 | return response; | ||
289 | } | ||
290 | |||
291 | /// <summary> | ||
292 | /// Creates an error response caused by being logged in already | ||
293 | /// </summary> | ||
294 | /// <returns>An XMLRPC Response</returns> | ||
295 | private static XmlRpcResponse CreateAlreadyLoggedInResponse() | ||
296 | { | ||
297 | XmlRpcResponse response = new XmlRpcResponse(); | ||
298 | Hashtable PresenceErrorRespData = new Hashtable(); | ||
299 | PresenceErrorRespData["reason"] = "presence"; | ||
300 | PresenceErrorRespData["message"] = "You appear to be already logged in, if this is not the case please wait for your session to timeout, if this takes longer than a few minutes please contact the grid owner"; | ||
301 | PresenceErrorRespData["login"] = "false"; | ||
302 | response.Value = PresenceErrorRespData; | ||
303 | return response; | ||
304 | } | ||
305 | |||
306 | /// <summary> | ||
307 | /// Creates an error response caused by target region being down | ||
308 | /// </summary> | ||
309 | /// <returns>An XMLRPC Response</returns> | ||
310 | private static XmlRpcResponse CreateDeadRegionResponse() | ||
311 | { | ||
312 | XmlRpcResponse response = new XmlRpcResponse(); | ||
313 | Hashtable PresenceErrorRespData = new Hashtable(); | ||
314 | PresenceErrorRespData["reason"] = "key"; | ||
315 | PresenceErrorRespData["message"] = "The region you are attempting to log into is not responding. Please select another region and try again."; | ||
316 | PresenceErrorRespData["login"] = "false"; | ||
317 | response.Value = PresenceErrorRespData; | ||
318 | return response; | ||
319 | } | ||
320 | |||
321 | /// <summary> | ||
322 | /// Customises the login response and fills in missing values. | ||
323 | /// </summary> | ||
324 | /// <param name="response">The existing response</param> | ||
325 | /// <param name="theUser">The user profile</param> | ||
326 | public virtual void CustomiseResponse(ref Hashtable response, ref UserProfileData theUser) | ||
327 | { | ||
328 | |||
329 | } | ||
330 | |||
331 | /// <summary> | ||
332 | /// Checks a user against it's password hash | ||
333 | /// </summary> | ||
334 | /// <param name="profile">The users profile</param> | ||
335 | /// <param name="password">The supplied password</param> | ||
336 | /// <returns>Authenticated?</returns> | ||
337 | public bool AuthenticateUser(ref UserProfileData profile, string password) | ||
338 | { | ||
339 | OpenSim.Framework.Console.MainLog.Instance.Verbose( | ||
340 | "Authenticating " + profile.username + " " + profile.surname); | ||
341 | |||
342 | password = password.Remove(0, 3); //remove $1$ | ||
343 | |||
344 | string s = Util.Md5Hash(password + ":" + profile.passwordSalt); | ||
345 | |||
346 | return profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase); | ||
347 | } | ||
348 | 234 | ||
235 | #region CreateAgent | ||
349 | /// <summary> | 236 | /// <summary> |
350 | /// Creates and initialises a new user agent - make sure to use CommitAgent when done to submit to the DB | 237 | /// Creates and initialises a new user agent - make sure to use CommitAgent when done to submit to the DB |
351 | /// </summary> | 238 | /// </summary> |
@@ -390,7 +277,7 @@ namespace OpenGrid.Framework.UserManagement | |||
390 | { | 277 | { |
391 | string[] parts = startLoc.Remove(0, 4).Split('&'); | 278 | string[] parts = startLoc.Remove(0, 4).Split('&'); |
392 | string region = parts[0]; | 279 | string region = parts[0]; |
393 | 280 | ||
394 | //////////////////////////////////////////////////// | 281 | //////////////////////////////////////////////////// |
395 | //SimProfile SimInfo = new SimProfile(); | 282 | //SimProfile SimInfo = new SimProfile(); |
396 | //SimInfo = SimInfo.LoadFromGrid(theUser.currentAgent.currentHandle, _config.GridServerURL, _config.GridSendKey, _config.GridRecvKey); | 283 | //SimInfo = SimInfo.LoadFromGrid(theUser.currentAgent.currentHandle, _config.GridServerURL, _config.GridSendKey, _config.GridRecvKey); |
@@ -424,6 +311,58 @@ namespace OpenGrid.Framework.UserManagement | |||
424 | return true; | 311 | return true; |
425 | } | 312 | } |
426 | 313 | ||
314 | #endregion | ||
315 | |||
316 | /// <summary> | ||
317 | /// Checks a user against it's password hash | ||
318 | /// </summary> | ||
319 | /// <param name="profile">The users profile</param> | ||
320 | /// <param name="password">The supplied password</param> | ||
321 | /// <returns>Authenticated?</returns> | ||
322 | public virtual bool AuthenticateUser(ref UserProfileData profile, string password) | ||
323 | { | ||
324 | OpenSim.Framework.Console.MainLog.Instance.Verbose( | ||
325 | "Authenticating " + profile.username + " " + profile.surname); | ||
326 | |||
327 | password = password.Remove(0, 3); //remove $1$ | ||
328 | |||
329 | string s = Util.Md5Hash(password + ":" + profile.passwordSalt); | ||
330 | |||
331 | return profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase); | ||
332 | } | ||
333 | |||
334 | #region Xml Response | ||
335 | |||
336 | /// <summary> | ||
337 | /// | ||
338 | /// </summary> | ||
339 | /// <param name="firstname"></param> | ||
340 | /// <param name="lastname"></param> | ||
341 | /// <returns></returns> | ||
342 | public virtual UserProfileData GetTheUser(string firstname, string lastname) | ||
343 | { | ||
344 | return getUserProfile(firstname, lastname); | ||
345 | } | ||
346 | |||
347 | /// <summary> | ||
348 | /// | ||
349 | /// </summary> | ||
350 | /// <returns></returns> | ||
351 | public virtual string GetMessage() | ||
352 | { | ||
353 | return _config.DefaultStartupMsg; | ||
354 | } | ||
355 | |||
356 | /// <summary> | ||
357 | /// Customises the login response and fills in missing values. | ||
358 | /// </summary> | ||
359 | /// <param name="response">The existing response</param> | ||
360 | /// <param name="theUser">The user profile</param> | ||
361 | public virtual void CustomiseResponse(ref LoginResponse response, ref UserProfileData theUser) | ||
362 | { | ||
363 | |||
364 | } | ||
365 | |||
427 | /// <summary> | 366 | /// <summary> |
428 | /// Main user login function | 367 | /// Main user login function |
429 | /// </summary> | 368 | /// </summary> |
@@ -441,6 +380,7 @@ namespace OpenGrid.Framework.UserManagement | |||
441 | string passwd = ""; | 380 | string passwd = ""; |
442 | 381 | ||
443 | UserProfileData TheUser; | 382 | UserProfileData TheUser; |
383 | LoginResponse logResponse = new LoginResponse(); | ||
444 | 384 | ||
445 | if (GoodXML) | 385 | if (GoodXML) |
446 | { | 386 | { |
@@ -448,20 +388,20 @@ namespace OpenGrid.Framework.UserManagement | |||
448 | lastname = (string)requestData["last"]; | 388 | lastname = (string)requestData["last"]; |
449 | passwd = (string)requestData["passwd"]; | 389 | passwd = (string)requestData["passwd"]; |
450 | 390 | ||
451 | TheUser = getUserProfile(firstname, lastname); | 391 | TheUser = GetTheUser(firstname, lastname); |
452 | if (TheUser == null) | 392 | if (TheUser == null) |
453 | return CreateLoginErrorResponse(); | 393 | return logResponse.CreateLoginFailedResponse(); |
454 | 394 | ||
455 | GoodLogin = AuthenticateUser(ref TheUser, passwd); | 395 | GoodLogin = AuthenticateUser(ref TheUser, passwd); |
456 | } | 396 | } |
457 | else | 397 | else |
458 | { | 398 | { |
459 | return CreateErrorConnectingToGridResponse(); | 399 | return logResponse.CreateGridErrorResponse(); |
460 | } | 400 | } |
461 | 401 | ||
462 | if (!GoodLogin) | 402 | if (!GoodLogin) |
463 | { | 403 | { |
464 | return CreateLoginErrorResponse(); | 404 | return logResponse.CreateLoginFailedResponse(); |
465 | } | 405 | } |
466 | else | 406 | else |
467 | { | 407 | { |
@@ -469,7 +409,7 @@ namespace OpenGrid.Framework.UserManagement | |||
469 | if (TheUser.currentAgent != null && TheUser.currentAgent.agentOnline) | 409 | if (TheUser.currentAgent != null && TheUser.currentAgent.agentOnline) |
470 | { | 410 | { |
471 | // Reject the login | 411 | // Reject the login |
472 | return CreateAlreadyLoggedInResponse(); | 412 | return logResponse.CreateAlreadyLoggedInResponse(); |
473 | } | 413 | } |
474 | // Otherwise... | 414 | // Otherwise... |
475 | // Create a new agent session | 415 | // Create a new agent session |
@@ -477,39 +417,8 @@ namespace OpenGrid.Framework.UserManagement | |||
477 | 417 | ||
478 | try | 418 | try |
479 | { | 419 | { |
480 | Hashtable responseData = new Hashtable(); | ||
481 | 420 | ||
482 | LLUUID AgentID = TheUser.UUID; | 421 | LLUUID AgentID = TheUser.UUID; |
483 | |||
484 | // Global Texture Section | ||
485 | Hashtable GlobalT = new Hashtable(); | ||
486 | GlobalT["sun_texture_id"] = "cce0f112-878f-4586-a2e2-a8f104bba271"; | ||
487 | GlobalT["cloud_texture_id"] = "fc4b9f0b-d008-45c6-96a4-01dd947ac621"; | ||
488 | GlobalT["moon_texture_id"] = "fc4b9f0b-d008-45c6-96a4-01dd947ac621"; | ||
489 | ArrayList GlobalTextures = new ArrayList(); | ||
490 | GlobalTextures.Add(GlobalT); | ||
491 | |||
492 | // Login Flags Section | ||
493 | Hashtable LoginFlagsHash = new Hashtable(); | ||
494 | LoginFlagsHash["daylight_savings"] = "N"; | ||
495 | LoginFlagsHash["stipend_since_login"] = "N"; | ||
496 | LoginFlagsHash["gendered"] = "Y"; // Needs to be combined with below... | ||
497 | LoginFlagsHash["ever_logged_in"] = "Y"; // Should allow male/female av selection | ||
498 | ArrayList LoginFlags = new ArrayList(); | ||
499 | LoginFlags.Add(LoginFlagsHash); | ||
500 | |||
501 | // UI Customisation Section | ||
502 | Hashtable uiconfig = new Hashtable(); | ||
503 | uiconfig["allow_first_life"] = "Y"; | ||
504 | ArrayList ui_config = new ArrayList(); | ||
505 | ui_config.Add(uiconfig); | ||
506 | |||
507 | // Classified Categories Section | ||
508 | Hashtable ClassifiedCategoriesHash = new Hashtable(); | ||
509 | ClassifiedCategoriesHash["category_name"] = "Generic"; | ||
510 | ClassifiedCategoriesHash["category_id"] = (Int32)1; | ||
511 | ArrayList ClassifiedCategories = new ArrayList(); | ||
512 | ClassifiedCategories.Add(ClassifiedCategoriesHash); | ||
513 | 422 | ||
514 | // Inventory Library Section | 423 | // Inventory Library Section |
515 | ArrayList AgentInventoryArray = new ArrayList(); | 424 | ArrayList AgentInventoryArray = new ArrayList(); |
@@ -534,62 +443,37 @@ namespace OpenGrid.Framework.UserManagement | |||
534 | ArrayList InventoryRoot = new ArrayList(); | 443 | ArrayList InventoryRoot = new ArrayList(); |
535 | InventoryRoot.Add(InventoryRootHash); | 444 | InventoryRoot.Add(InventoryRootHash); |
536 | 445 | ||
537 | Hashtable InitialOutfitHash = new Hashtable(); | ||
538 | InitialOutfitHash["folder_name"] = "Nightclub Female"; | ||
539 | InitialOutfitHash["gender"] = "female"; | ||
540 | ArrayList InitialOutfit = new ArrayList(); | ||
541 | InitialOutfit.Add(InitialOutfitHash); | ||
542 | |||
543 | // Circuit Code | 446 | // Circuit Code |
544 | uint circode = (uint)(Util.RandomClass.Next()); | 447 | uint circode = (uint)(Util.RandomClass.Next()); |
545 | 448 | ||
546 | // Generics | 449 | logResponse.Lastname = TheUser.surname; |
547 | responseData["last_name"] = TheUser.surname; | 450 | logResponse.Firstname = TheUser.username; |
548 | responseData["ui-config"] = ui_config; | 451 | logResponse.AgentID = AgentID.ToStringHyphenated(); |
549 | responseData["sim_ip"] = "127.0.0.1"; //SimInfo.sim_ip.ToString(); | 452 | logResponse.SessionID = TheUser.currentAgent.sessionID.ToStringHyphenated(); |
550 | responseData["login-flags"] = LoginFlags; | 453 | logResponse.SecureSessionID = TheUser.currentAgent.secureSessionID.ToStringHyphenated(); |
551 | responseData["global-textures"] = GlobalTextures; | 454 | logResponse.InventoryRoot = InventoryRoot; |
552 | responseData["classified_categories"] = ClassifiedCategories; | 455 | logResponse.InventorySkeleton = AgentInventoryArray; |
553 | responseData["event_categories"] = new ArrayList(); | 456 | logResponse.CircuitCode = (Int32)circode; |
554 | responseData["inventory-skeleton"] = AgentInventoryArray; | 457 | logResponse.RegionX = 0; //overwritten |
555 | responseData["inventory-skel-lib"] = new ArrayList(); | 458 | logResponse.RegionY = 0; //overwritten |
556 | responseData["inventory-root"] = InventoryRoot; | 459 | logResponse.Home = "!!null temporary value {home}!!"; // Overwritten |
557 | responseData["event_notifications"] = new ArrayList(); | 460 | //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; |
558 | responseData["gestures"] = new ArrayList(); | 461 | logResponse.SimAddress = "127.0.0.1"; //overwritten |
559 | responseData["inventory-lib-owner"] = new ArrayList(); | 462 | logResponse.SimPort = 0; //overwritten |
560 | responseData["initial-outfit"] = InitialOutfit; | 463 | logResponse.Message = this.GetMessage(); |
561 | responseData["seconds_since_epoch"] = (Int32)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; | 464 | |
562 | responseData["start_location"] = "last"; | ||
563 | responseData["home"] = "!!null temporary value {home}!!"; // Overwritten | ||
564 | responseData["message"] = _config.DefaultStartupMsg; | ||
565 | responseData["first_name"] = TheUser.username; | ||
566 | responseData["circuit_code"] = (Int32)circode; | ||
567 | responseData["sim_port"] = 0; //(Int32)SimInfo.sim_port; | ||
568 | responseData["secure_session_id"] = TheUser.currentAgent.secureSessionID.ToStringHyphenated(); | ||
569 | responseData["look_at"] = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; | ||
570 | responseData["agent_id"] = AgentID.ToStringHyphenated(); | ||
571 | responseData["region_y"] = (Int32)0; // Overwritten | ||
572 | responseData["region_x"] = (Int32)0; // Overwritten | ||
573 | responseData["seed_capability"] = ""; | ||
574 | responseData["agent_access"] = "M"; | ||
575 | responseData["session_id"] = TheUser.currentAgent.sessionID.ToStringHyphenated(); | ||
576 | responseData["login"] = "true"; | ||
577 | |||
578 | try | 465 | try |
579 | { | 466 | { |
580 | this.CustomiseResponse(ref responseData, ref TheUser); | 467 | this.CustomiseResponse(ref logResponse, ref TheUser); |
581 | } | 468 | } |
582 | catch (Exception e) | 469 | catch (Exception e) |
583 | { | 470 | { |
584 | Console.WriteLine(e.ToString()); | 471 | Console.WriteLine(e.ToString()); |
585 | return CreateDeadRegionResponse(); | 472 | return logResponse.CreateDeadRegionResponse(); |
586 | } | 473 | } |
587 | |||
588 | CommitAgent(ref TheUser); | 474 | CommitAgent(ref TheUser); |
589 | 475 | ||
590 | response.Value = responseData; | 476 | return logResponse.ToXmlRpcResponse(); |
591 | // TheUser.SendDataToSim(SimInfo); | ||
592 | return response; | ||
593 | 477 | ||
594 | } | 478 | } |
595 | catch (Exception E) | 479 | catch (Exception E) |
@@ -602,6 +486,8 @@ namespace OpenGrid.Framework.UserManagement | |||
602 | 486 | ||
603 | } | 487 | } |
604 | 488 | ||
489 | #endregion | ||
490 | |||
605 | /// <summary> | 491 | /// <summary> |
606 | /// Deletes an active agent session | 492 | /// Deletes an active agent session |
607 | /// </summary> | 493 | /// </summary> |
@@ -617,6 +503,37 @@ namespace OpenGrid.Framework.UserManagement | |||
617 | } | 503 | } |
618 | 504 | ||
619 | /// <summary> | 505 | /// <summary> |
506 | /// | ||
507 | /// </summary> | ||
508 | /// <param name="user"></param> | ||
509 | public void AddUserProfile(string firstName, string lastName, string pass, uint regX, uint regY) | ||
510 | { | ||
511 | UserProfileData user = new UserProfileData(); | ||
512 | user.homeLocation = new LLVector3(128, 128, 100); | ||
513 | user.UUID = LLUUID.Random(); | ||
514 | user.username = firstName; | ||
515 | user.surname = lastName; | ||
516 | user.passwordHash = pass; | ||
517 | user.passwordSalt = ""; | ||
518 | user.created = Util.UnixTimeSinceEpoch(); | ||
519 | user.homeLookAt = new LLVector3(100, 100, 100); | ||
520 | user.homeRegion = Util.UIntsToLong((regX * 256), (regY * 256)); | ||
521 | |||
522 | foreach (KeyValuePair<string, IUserData> plugin in _plugins) | ||
523 | { | ||
524 | try | ||
525 | { | ||
526 | plugin.Value.addNewUserProfile(user); | ||
527 | |||
528 | } | ||
529 | catch (Exception e) | ||
530 | { | ||
531 | OpenSim.Framework.Console.MainLog.Instance.Verbose("Unable to add user via " + plugin.Key + "(" + e.ToString() + ")"); | ||
532 | } | ||
533 | } | ||
534 | } | ||
535 | |||
536 | /// <summary> | ||
620 | /// Returns an error message that the user could not be found in the database | 537 | /// Returns an error message that the user could not be found in the database |
621 | /// </summary> | 538 | /// </summary> |
622 | /// <returns>XML string consisting of a error element containing individual error(s)</returns> | 539 | /// <returns>XML string consisting of a error element containing individual error(s)</returns> |
@@ -693,6 +610,8 @@ namespace OpenGrid.Framework.UserManagement | |||
693 | return sw.ToString(); | 610 | return sw.ToString(); |
694 | } | 611 | } |
695 | 612 | ||
613 | #region REST Methods | ||
614 | //should most likely move out of here and into the grid's userserver sub class | ||
696 | public string RestGetUserMethodName(string request, string path, string param) | 615 | public string RestGetUserMethodName(string request, string path, string param) |
697 | { | 616 | { |
698 | UserProfileData userProfile = getUserProfile(param.Trim()); | 617 | UserProfileData userProfile = getUserProfile(param.Trim()); |
@@ -716,6 +635,7 @@ namespace OpenGrid.Framework.UserManagement | |||
716 | 635 | ||
717 | return ProfileToXml(userProfile); | 636 | return ProfileToXml(userProfile); |
718 | } | 637 | } |
638 | #endregion | ||
719 | 639 | ||
720 | } | 640 | } |
721 | } | 641 | } |