diff options
author | Dr Scofield | 2009-05-07 12:33:53 +0000 |
---|---|---|
committer | Dr Scofield | 2009-05-07 12:33:53 +0000 |
commit | 547f883f745ee17b4dbadc19bad6a4327672990d (patch) | |
tree | 18628ee779f533e58f55a16f01cd0977db9a86e1 /OpenSim/ApplicationPlugins/RemoteController | |
parent | Change avatar updates to be processed the same way object updates are, e.g. (diff) | |
download | opensim-SC-547f883f745ee17b4dbadc19bad6a4327672990d.zip opensim-SC-547f883f745ee17b4dbadc19bad6a4327672990d.tar.gz opensim-SC-547f883f745ee17b4dbadc19bad6a4327672990d.tar.bz2 opensim-SC-547f883f745ee17b4dbadc19bad6a4327672990d.tar.xz |
From: Alan M Webb <alan_webb@us.ibm.com>
This update implements support for creation of one or more
default avatars from information contained in a file
default_appearance.xml. Each avatar may have any number of
"outfits" with each outfit representing a different ensemble.
The default avatars get created the first time the RemoteAdmin
interface is used to define a user.
I've tested this quite a bit, but it will benefit from lost of
attention, I'm sure.
Diffstat (limited to 'OpenSim/ApplicationPlugins/RemoteController')
-rw-r--r-- | OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs | 779 |
1 files changed, 673 insertions, 106 deletions
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 1daa07f..b508c5c 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Xml; | ||
32 | using System.Net; | 33 | using System.Net; |
33 | using System.Reflection; | 34 | using System.Reflection; |
34 | using System.Timers; | 35 | using System.Timers; |
@@ -38,6 +39,7 @@ using Nwc.XmlRpc; | |||
38 | using OpenMetaverse; | 39 | using OpenMetaverse; |
39 | using OpenSim; | 40 | using OpenSim; |
40 | using OpenSim.Framework; | 41 | using OpenSim.Framework; |
42 | using OpenSim.Framework.Communications; | ||
41 | using OpenSim.Framework.Communications.Cache; | 43 | using OpenSim.Framework.Communications.Cache; |
42 | using OpenSim.Framework.Console; | 44 | using OpenSim.Framework.Console; |
43 | using OpenSim.Framework.Servers; | 45 | using OpenSim.Framework.Servers; |
@@ -52,6 +54,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
52 | { | 54 | { |
53 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 55 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
54 | 56 | ||
57 | private static bool daload = false; | ||
55 | private static Object rslock = new Object(); | 58 | private static Object rslock = new Object(); |
56 | 59 | ||
57 | private OpenSimBase m_app; | 60 | private OpenSimBase m_app; |
@@ -60,7 +63,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
60 | private IConfigSource m_configSource; | 63 | private IConfigSource m_configSource; |
61 | private string m_requiredPassword = String.Empty; | 64 | private string m_requiredPassword = String.Empty; |
62 | 65 | ||
63 | // TODO: required by IPlugin, but likely not at all right | ||
64 | private string m_name = "RemoteAdminPlugin"; | 66 | private string m_name = "RemoteAdminPlugin"; |
65 | private string m_version = "0.0"; | 67 | private string m_version = "0.0"; |
66 | 68 | ||
@@ -80,7 +82,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
80 | throw new PluginNotInitialisedException(Name); | 82 | throw new PluginNotInitialisedException(Name); |
81 | } | 83 | } |
82 | 84 | ||
83 | |||
84 | public void Initialise(OpenSimBase openSim) | 85 | public void Initialise(OpenSimBase openSim) |
85 | { | 86 | { |
86 | m_configSource = openSim.ConfigSource.Source; | 87 | m_configSource = openSim.ConfigSource.Source; |
@@ -387,52 +388,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
387 | m_app.Shutdown(); | 388 | m_app.Shutdown(); |
388 | } | 389 | } |
389 | 390 | ||
390 | |||
391 | private static void checkStringParameters(XmlRpcRequest request, string[] param) | ||
392 | { | ||
393 | Hashtable requestData = (Hashtable) request.Params[0]; | ||
394 | foreach (string p in param) | ||
395 | { | ||
396 | if (!requestData.Contains(p)) | ||
397 | throw new Exception(String.Format("missing string parameter {0}", p)); | ||
398 | if (String.IsNullOrEmpty((string) requestData[p])) | ||
399 | throw new Exception(String.Format("parameter {0} is empty", p)); | ||
400 | } | ||
401 | } | ||
402 | |||
403 | private static void checkIntegerParams(XmlRpcRequest request, string[] param) | ||
404 | { | ||
405 | Hashtable requestData = (Hashtable) request.Params[0]; | ||
406 | foreach (string p in param) | ||
407 | { | ||
408 | if (!requestData.Contains(p)) | ||
409 | throw new Exception(String.Format("missing integer parameter {0}", p)); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | private bool getBoolean(Hashtable requestData, string tag, bool defv) | ||
414 | { | ||
415 | // If an access value has been provided, apply it. | ||
416 | if (requestData.Contains(tag)) | ||
417 | { | ||
418 | switch (((string)requestData[tag]).ToLower()) | ||
419 | { | ||
420 | case "true" : | ||
421 | case "t" : | ||
422 | case "1" : | ||
423 | return true; | ||
424 | case "false" : | ||
425 | case "f" : | ||
426 | case "0" : | ||
427 | return false; | ||
428 | default : | ||
429 | return defv; | ||
430 | } | ||
431 | } | ||
432 | else | ||
433 | return defv; | ||
434 | } | ||
435 | |||
436 | /// <summary> | 391 | /// <summary> |
437 | /// Create a new region. | 392 | /// Create a new region. |
438 | /// <summary> | 393 | /// <summary> |
@@ -523,7 +478,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
523 | if (m_regionLimit != 0 && m_app.SceneManager.Scenes.Count >= m_regionLimit) | 478 | if (m_regionLimit != 0 && m_app.SceneManager.Scenes.Count >= m_regionLimit) |
524 | throw new Exception(String.Format("cannot instantiate new region, server capacity {0} already reached; delete regions first", | 479 | throw new Exception(String.Format("cannot instantiate new region, server capacity {0} already reached; delete regions first", |
525 | m_regionLimit)); | 480 | m_regionLimit)); |
526 | |||
527 | // extract or generate region ID now | 481 | // extract or generate region ID now |
528 | Scene scene = null; | 482 | Scene scene = null; |
529 | UUID regionID = UUID.Zero; | 483 | UUID regionID = UUID.Zero; |
@@ -949,31 +903,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
949 | throw new Exception(String.Format("failed to create new user {0} {1}", | 903 | throw new Exception(String.Format("failed to create new user {0} {1}", |
950 | firstname, lastname)); | 904 | firstname, lastname)); |
951 | 905 | ||
952 | // User has been created. Now establish gender and appearance. | 906 | // Establish the avatar's initial appearance |
953 | // Default appearance is 'Default Male'. Specifying gender can | ||
954 | // establish "Default Female". Specifying a specific model can | ||
955 | // establish a specific appearance without regard for gender. | ||
956 | |||
957 | try | ||
958 | { | ||
959 | string model = "Default Male"; | ||
960 | if (requestData.Contains("gender")) | ||
961 | if ((string)requestData["gender"] == "f") | ||
962 | model = "Default Female"; | ||
963 | |||
964 | if (requestData.Contains("model")) | ||
965 | model = (string)requestData["model"]; | ||
966 | |||
967 | string[] uname = model.Split(); | ||
968 | UserProfileData udata = m_app.CommunicationsManager.UserService.GetUserProfile(uname[0],uname[1]); | ||
969 | AvatarAppearance ava = m_app.CommunicationsManager.AvatarService.GetUserAppearance(udata.ID); | ||
970 | m_app.CommunicationsManager.AvatarService.UpdateUserAppearance(userID, ava); | ||
971 | 907 | ||
972 | } | 908 | updateUserAppearance(responseData, requestData, userID); |
973 | catch (Exception e) | ||
974 | { | ||
975 | m_log.ErrorFormat("[RADMIN] Error establishing initial appearance : {0}", e.Message); | ||
976 | } | ||
977 | 909 | ||
978 | responseData["success"] = "true"; | 910 | responseData["success"] = "true"; |
979 | responseData["avatar_uuid"] = userID.ToString(); | 911 | responseData["avatar_uuid"] = userID.ToString(); |
@@ -1110,6 +1042,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1110 | /// <description>error message if success is false</description></item> | 1042 | /// <description>error message if success is false</description></item> |
1111 | /// </list> | 1043 | /// </list> |
1112 | /// </remarks> | 1044 | /// </remarks> |
1045 | |||
1113 | public XmlRpcResponse XmlRpcUpdateUserAccountMethod(XmlRpcRequest request) | 1046 | public XmlRpcResponse XmlRpcUpdateUserAccountMethod(XmlRpcRequest request) |
1114 | { | 1047 | { |
1115 | m_log.Info("[RADMIN]: UpdateUserAccount: new request"); | 1048 | m_log.Info("[RADMIN]: UpdateUserAccount: new request"); |
@@ -1202,32 +1135,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1202 | // establish "Default Female". Specifying a specific model can | 1135 | // establish "Default Female". Specifying a specific model can |
1203 | // establish a specific appearance without regard for gender. | 1136 | // establish a specific appearance without regard for gender. |
1204 | 1137 | ||
1205 | try | 1138 | updateUserAppearance(responseData, requestData, userProfile.ID); |
1206 | { | ||
1207 | string model = "*none*"; | ||
1208 | if (requestData.Contains("gender")) | ||
1209 | { | ||
1210 | if ((string)requestData["gender"] == "f") | ||
1211 | model = "Default Female"; | ||
1212 | else | ||
1213 | model = "Default Male"; | ||
1214 | } | ||
1215 | |||
1216 | if (requestData.Contains("model")) | ||
1217 | model = (string)requestData["model"]; | ||
1218 | |||
1219 | if (model != "*none*") | ||
1220 | { | ||
1221 | string[] uname = model.Split(); | ||
1222 | UserProfileData udata = m_app.CommunicationsManager.UserService.GetUserProfile(uname[0],uname[1]); | ||
1223 | AvatarAppearance ava = m_app.CommunicationsManager.AvatarService.GetUserAppearance(udata.ID); | ||
1224 | m_app.CommunicationsManager.AvatarService.UpdateUserAppearance(userProfile.ID, ava); | ||
1225 | } | ||
1226 | } | ||
1227 | catch (Exception e) | ||
1228 | { | ||
1229 | m_log.ErrorFormat("[RADMIN] Error establishing initial appearance : {0}", e.Message); | ||
1230 | } | ||
1231 | 1139 | ||
1232 | if (!m_app.CommunicationsManager.UserService.UpdateUserProfile(userProfile)) | 1140 | if (!m_app.CommunicationsManager.UserService.UpdateUserProfile(userProfile)) |
1233 | throw new Exception("did not manage to update user profile"); | 1141 | throw new Exception("did not manage to update user profile"); |
@@ -1257,6 +1165,510 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1257 | } | 1165 | } |
1258 | 1166 | ||
1259 | /// <summary> | 1167 | /// <summary> |
1168 | /// This method is called by the user-create and user-modify methods to establish | ||
1169 | /// or change, the user's appearance. Default avatar names can be specified via | ||
1170 | /// the config file, but must correspond to avatars in the default appearance | ||
1171 | /// file, or pre-existing in the user database. | ||
1172 | /// This should probably get moved into somewhere more core eventually. | ||
1173 | /// </summary> | ||
1174 | |||
1175 | private void updateUserAppearance(Hashtable responseData, Hashtable requestData, UUID userid) | ||
1176 | { | ||
1177 | |||
1178 | m_log.DebugFormat("[RADMIN] updateUserAppearance"); | ||
1179 | |||
1180 | string dmale = m_config.GetString("default_male", "Default Male"); | ||
1181 | string dfemale = m_config.GetString("default_female", "Default Female"); | ||
1182 | string dneut = m_config.GetString("default_female", "Default Default"); | ||
1183 | string dmodel = dneut; | ||
1184 | string model = dneut; | ||
1185 | |||
1186 | // Has a gender preference been supplied? | ||
1187 | |||
1188 | if (requestData.Contains("gender")) | ||
1189 | { | ||
1190 | if ((string)requestData["gender"] == "f") | ||
1191 | dmodel = dmale; | ||
1192 | else | ||
1193 | dmodel = dfemale; | ||
1194 | } | ||
1195 | else | ||
1196 | dmodel = dneut; | ||
1197 | |||
1198 | // Has an explicit model been specified? | ||
1199 | |||
1200 | if (requestData.Contains("model")) | ||
1201 | model = (string)requestData["model"]; | ||
1202 | else | ||
1203 | model = dmodel; | ||
1204 | |||
1205 | m_log.DebugFormat("[RADMIN] Setting appearance for avatar {0}, using model {1}", userid, model); | ||
1206 | |||
1207 | string[] nomens = model.Split(); | ||
1208 | if (nomens.Length != 2) | ||
1209 | { | ||
1210 | m_log.WarnFormat("[RADMIN] User appearance not set for {0}. Invalid model name : <{1}>", | ||
1211 | userid, model); | ||
1212 | nomens = dmodel.Split(); | ||
1213 | } | ||
1214 | |||
1215 | UserProfileData mprof = m_app.CommunicationsManager.UserService.GetUserProfile(nomens[0], nomens[1]); | ||
1216 | |||
1217 | // Is this the first time one of the default models has been used? Create it if that is the case | ||
1218 | // otherwise default to male. | ||
1219 | |||
1220 | if (mprof == null) | ||
1221 | { | ||
1222 | if(model != dmale && model != dfemale) | ||
1223 | { | ||
1224 | m_log.WarnFormat("[RADMIN] Requested model ({0}) not found. Default appearance assumed", | ||
1225 | model); | ||
1226 | nomens = dmodel.Split(); | ||
1227 | } | ||
1228 | if (createDefaultAvatars()) | ||
1229 | { | ||
1230 | mprof = m_app.CommunicationsManager.UserService.GetUserProfile(nomens[0], nomens[1]); | ||
1231 | } | ||
1232 | } | ||
1233 | |||
1234 | if (mprof == null) | ||
1235 | { | ||
1236 | m_log.WarnFormat("[RADMIN] User appearance not set for {0}. Model avatar not found : <{1}>", | ||
1237 | userid, model); | ||
1238 | } | ||
1239 | else | ||
1240 | { | ||
1241 | |||
1242 | // Set current user's appearance. This bit is easy. The appearance structure is populated with | ||
1243 | // actual asset ids, however to complete the magic we need to populate the inventory with the | ||
1244 | // assets in question. | ||
1245 | |||
1246 | establishAppearance(userid, mprof.ID); | ||
1247 | |||
1248 | } | ||
1249 | |||
1250 | m_log.DebugFormat("[RADMIN] Finished setting appearance for avatar {0}, using model {1}", | ||
1251 | userid, model); | ||
1252 | |||
1253 | } | ||
1254 | |||
1255 | /// <summary> | ||
1256 | /// This method is called by updateAvatarAppearance once any specified model has been | ||
1257 | /// ratified, or an appropriate default value has been adopted. The intended prototype | ||
1258 | /// is known to exist, as is the target avatar. | ||
1259 | /// </summary> | ||
1260 | |||
1261 | private AvatarAppearance establishAppearance(UUID dest, UUID srca) | ||
1262 | { | ||
1263 | |||
1264 | m_log.DebugFormat("[RADMIN] Initializing inventory for {0} from {1}", dest, srca); | ||
1265 | |||
1266 | AvatarAppearance ava = m_app.CommunicationsManager.AvatarService.GetUserAppearance(srca); | ||
1267 | |||
1268 | // If the model has no associated appearance we're done. | ||
1269 | |||
1270 | if (ava == null) | ||
1271 | { | ||
1272 | return new AvatarAppearance(); | ||
1273 | } | ||
1274 | |||
1275 | UICallback sic = new UICallback(); | ||
1276 | UICallback dic = new UICallback(); | ||
1277 | IInventoryServices iserv = m_app.CommunicationsManager.InventoryService; | ||
1278 | |||
1279 | try | ||
1280 | { | ||
1281 | Dictionary<UUID,UUID> imap = new Dictionary<UUID,UUID>(); | ||
1282 | |||
1283 | iserv.RequestInventoryForUser(dest, dic.callback); | ||
1284 | iserv.RequestInventoryForUser(srca, sic.callback); | ||
1285 | |||
1286 | dic.GetInventory(); | ||
1287 | sic.GetInventory(); | ||
1288 | |||
1289 | if (sic.OK && dic.OK) | ||
1290 | { | ||
1291 | |||
1292 | InventoryFolderImpl efolder; | ||
1293 | InventoryFolderImpl srcf = sic.root.FindFolderForType(5); | ||
1294 | InventoryFolderImpl dstf = dic.root.FindFolderForType(5); | ||
1295 | |||
1296 | if (srcf == null || dstf == null) | ||
1297 | throw new Exception("Cannot locate clothing folder(s)"); | ||
1298 | |||
1299 | foreach (InventoryFolderImpl folder in sic.folders) | ||
1300 | { | ||
1301 | if (folder.ParentID == srcf.ID) | ||
1302 | { | ||
1303 | efolder = new InventoryFolderImpl(); | ||
1304 | efolder.ID = UUID.Random(); | ||
1305 | efolder.Name = folder.Name; | ||
1306 | efolder.Type = folder.Type; | ||
1307 | efolder.Version = folder.Version; | ||
1308 | efolder.Owner = dest; | ||
1309 | dstf.AddChildFolder(efolder); | ||
1310 | iserv.AddFolder(efolder); | ||
1311 | m_log.DebugFormat("[RADMIN] Added outfile folder {0} to folder {1}", efolder.ID, srcf.ID); | ||
1312 | foreach (InventoryItemBase item in sic.items) | ||
1313 | { | ||
1314 | if (item.Folder == folder.ID) | ||
1315 | { | ||
1316 | InventoryItemBase dsti = new InventoryItemBase(); | ||
1317 | dsti.ID = UUID.Random(); | ||
1318 | dsti.Name = item.Name; | ||
1319 | dsti.Description = item.Description; | ||
1320 | dsti.InvType = item.InvType; | ||
1321 | dsti.AssetType = item.AssetType; | ||
1322 | dsti.Flags = item.Flags; | ||
1323 | dsti.AssetID = item.AssetID; | ||
1324 | dsti.Folder = efolder.ID; | ||
1325 | dsti.Owner = dest; | ||
1326 | dsti.BasePermissions = item.BasePermissions; | ||
1327 | dsti.NextPermissions = item.NextPermissions; | ||
1328 | dsti.CurrentPermissions = item.CurrentPermissions; | ||
1329 | dsti.GroupPermissions = item.GroupPermissions; | ||
1330 | dsti.EveryOnePermissions = item.EveryOnePermissions; | ||
1331 | iserv.AddItem(dsti); | ||
1332 | imap.Add(item.ID, dsti.ID); | ||
1333 | m_log.DebugFormat("[RADMIN] Added item {0} to folder {1}", dsti.ID, efolder.ID); | ||
1334 | } | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1339 | // Update appearance tables | ||
1340 | AvatarWearable[] wearables = ava.Wearables; | ||
1341 | for (int i=0; i<wearables.Length; i++) | ||
1342 | { | ||
1343 | if (imap.ContainsKey(wearables[i].ItemID)) | ||
1344 | { | ||
1345 | AvatarWearable dw = new AvatarWearable(); | ||
1346 | dw.AssetID = wearables[i].AssetID; | ||
1347 | dw.ItemID = imap[wearables[i].ItemID]; | ||
1348 | ava.SetWearable(i, dw); | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | } | ||
1353 | else | ||
1354 | { | ||
1355 | throw new Exception("Unable to load both inventories"); | ||
1356 | } | ||
1357 | } | ||
1358 | catch (Exception e) | ||
1359 | { | ||
1360 | m_log.WarnFormat("[RADMIN] Error transferring inventory for {0} : {1}", | ||
1361 | dest, e.Message); | ||
1362 | return new AvatarAppearance(); | ||
1363 | } | ||
1364 | |||
1365 | m_app.CommunicationsManager.AvatarService.UpdateUserAppearance(dest, ava); | ||
1366 | return ava; | ||
1367 | |||
1368 | } | ||
1369 | |||
1370 | ///<summary> | ||
1371 | /// This method is called if a given model avatar name can not be found. If the external | ||
1372 | /// file has already been loaded once, then control returns immediately. If not, then it | ||
1373 | /// looks for a default appearance file. This file contains XML definitions of zero or more named | ||
1374 | /// avatars, each avatar can specify zero or more "outfits". Each outfit is a collection | ||
1375 | /// of items that together, define a particular ensemble for the avatar. Each avatar should | ||
1376 | /// indicate which outfit is the default, and this outfit will be automatically worn. The | ||
1377 | /// other outfits are provided to allow "real" avatars a way to easily change their outfits. | ||
1378 | /// </summary> | ||
1379 | |||
1380 | private bool createDefaultAvatars() | ||
1381 | { | ||
1382 | |||
1383 | m_log.DebugFormat("[RADMIN] Creating default avatar entries"); | ||
1384 | |||
1385 | // Only load once | ||
1386 | |||
1387 | if (daload) | ||
1388 | { | ||
1389 | return false; | ||
1390 | } | ||
1391 | |||
1392 | daload = true; | ||
1393 | |||
1394 | // Load processing starts here... | ||
1395 | |||
1396 | try | ||
1397 | { | ||
1398 | |||
1399 | string dafn = m_config.GetString("default_appearance", "default_appearance.xml"); | ||
1400 | |||
1401 | if (File.Exists(dafn)) | ||
1402 | { | ||
1403 | |||
1404 | XmlDocument doc = new XmlDocument(); | ||
1405 | string name = "*unknown*"; | ||
1406 | string email = "anon@anon"; | ||
1407 | uint regX = 1000; | ||
1408 | uint regY = 1000; | ||
1409 | string passwd = UUID.Random().ToString(); // No requirement to sign-in. | ||
1410 | CachedUserInfo UI; | ||
1411 | UUID ID = UUID.Zero; | ||
1412 | AvatarAppearance mava; | ||
1413 | XmlNodeList avatars; | ||
1414 | XmlNodeList assets; | ||
1415 | XmlNode perms = null; | ||
1416 | bool include = false; | ||
1417 | bool select = false; | ||
1418 | |||
1419 | UICallback uic; | ||
1420 | IInventoryServices iserv = m_app.CommunicationsManager.InventoryService; | ||
1421 | IAssetCache aserv = m_app.CommunicationsManager.AssetCache; | ||
1422 | |||
1423 | doc.LoadXml(File.ReadAllText(dafn)); | ||
1424 | |||
1425 | // Load up any included assets. Duplicates will be ignored | ||
1426 | assets = doc.GetElementsByTagName("RequiredAsset"); | ||
1427 | foreach(XmlNode asset in assets) | ||
1428 | { | ||
1429 | AssetBase rass = new AssetBase(); | ||
1430 | rass.FullID = UUID.Random(); | ||
1431 | rass.Name = GetStringAttribute(asset,"name",""); | ||
1432 | rass.Description = GetStringAttribute(asset,"desc",""); | ||
1433 | rass.Type = SByte.Parse(GetStringAttribute(asset,"type","")); | ||
1434 | rass.Local = Boolean.Parse(GetStringAttribute(asset,"local","")); | ||
1435 | rass.Temporary = Boolean.Parse(GetStringAttribute(asset,"temporary","")); | ||
1436 | rass.Data = Convert.FromBase64String(asset.InnerText); | ||
1437 | aserv.AddAsset(rass); | ||
1438 | } | ||
1439 | |||
1440 | avatars = doc.GetElementsByTagName("Avatar"); | ||
1441 | |||
1442 | // The document may contain multiple avatars | ||
1443 | |||
1444 | foreach (XmlElement avatar in avatars) | ||
1445 | { | ||
1446 | m_log.DebugFormat("[RADMIN] Loading appearance for {0}, gender = {1}", | ||
1447 | GetStringAttribute(avatar,"name","?"), GetStringAttribute(avatar,"gender","?")); | ||
1448 | |||
1449 | // Create the user identified by the avatar entry | ||
1450 | |||
1451 | try | ||
1452 | { | ||
1453 | // Only the name value is mandatory | ||
1454 | name = GetStringAttribute(avatar,"name",name); | ||
1455 | email = GetStringAttribute(avatar,"email",email); | ||
1456 | regX = GetUnsignedAttribute(avatar,"regx",regX); | ||
1457 | regY = GetUnsignedAttribute(avatar,"regy",regY); | ||
1458 | passwd = GetStringAttribute(avatar,"password",passwd); | ||
1459 | |||
1460 | string[] nomens = name.Split(); | ||
1461 | UI = m_app.CommunicationsManager.UserProfileCacheService.GetUserDetails(nomens[0], nomens[1]); | ||
1462 | if (null == UI) | ||
1463 | { | ||
1464 | ID = m_app.CommunicationsManager.UserAdminService.AddUser(nomens[0], nomens[1], | ||
1465 | passwd, email, regX, regY); | ||
1466 | if (ID == UUID.Zero) | ||
1467 | { | ||
1468 | m_log.ErrorFormat("[RADMIN] Avatar {0} {1} was not created", nomens[0], nomens[1]); | ||
1469 | return false; | ||
1470 | } | ||
1471 | } | ||
1472 | else | ||
1473 | { | ||
1474 | ID = UI.UserProfile.ID; | ||
1475 | } | ||
1476 | |||
1477 | m_log.DebugFormat("[RADMIN] User {0}[{1}] created or retrieved", name, ID); | ||
1478 | include = true; | ||
1479 | } | ||
1480 | catch (Exception e) | ||
1481 | { | ||
1482 | m_log.DebugFormat("[RADMIN] Error creating user {0} : {1}", name, e.Message); | ||
1483 | include = false; | ||
1484 | } | ||
1485 | |||
1486 | // OK, User has been created OK, now we can install the inventory. | ||
1487 | // First retrieve the current inventory (the user may already exist) | ||
1488 | // Note that althought he inventory is retrieved, the hierarchy has | ||
1489 | // not been interpreted at all. | ||
1490 | |||
1491 | if (include) | ||
1492 | { | ||
1493 | uic = new UICallback(); | ||
1494 | // Request the inventory | ||
1495 | iserv.RequestInventoryForUser(ID, uic.callback); | ||
1496 | |||
1497 | // While the inventory is being fetched, setup for appearance processing | ||
1498 | if ((mava = m_app.CommunicationsManager.AvatarService.GetUserAppearance(ID)) == null) | ||
1499 | { | ||
1500 | mava = new AvatarAppearance(); | ||
1501 | } | ||
1502 | |||
1503 | { | ||
1504 | AvatarWearable[] wearables = mava.Wearables; | ||
1505 | for (int i=0; i<wearables.Length; i++) | ||
1506 | { | ||
1507 | wearables[i] = new AvatarWearable(); | ||
1508 | } | ||
1509 | } | ||
1510 | |||
1511 | // Wait for the inventory to arrive | ||
1512 | uic.GetInventory(); | ||
1513 | |||
1514 | // We can only get dresssed if an inventory is forthcoming | ||
1515 | if (uic.OK) | ||
1516 | try | ||
1517 | { | ||
1518 | |||
1519 | m_log.DebugFormat("[RADMIN] {0} folders, {1} items in inventory", | ||
1520 | uic.folders.Count, uic.items.Count); | ||
1521 | |||
1522 | InventoryFolderImpl cfolder = uic.root.FindFolderForType(5); | ||
1523 | |||
1524 | // This should *never* be the case | ||
1525 | if (cfolder == null) | ||
1526 | { | ||
1527 | cfolder = new InventoryFolderImpl(); | ||
1528 | cfolder.Name = "Clothing"; | ||
1529 | cfolder.Type = 5; | ||
1530 | cfolder.Version = 1; | ||
1531 | cfolder.Owner = ID; | ||
1532 | uic.root.AddChildFolder(cfolder); // make connection | ||
1533 | iserv.AddFolder(cfolder); // store base record | ||
1534 | m_log.ErrorFormat("[RADMIN] Created clothing folder for {0}/{1}", name, ID); | ||
1535 | } | ||
1536 | |||
1537 | // OK, now we have an inventory for the user, read in the outfits from the | ||
1538 | // default appearance XMl file. | ||
1539 | |||
1540 | XmlNodeList outfits = avatar.GetElementsByTagName("Ensemble"); | ||
1541 | InventoryFolderImpl efolder; | ||
1542 | string oname; | ||
1543 | UUID assetid; | ||
1544 | |||
1545 | foreach (XmlElement outfit in outfits) | ||
1546 | { | ||
1547 | |||
1548 | m_log.DebugFormat("[RADMIN] Loading outfit {0} for {1}", | ||
1549 | GetStringAttribute(outfit,"name","?"), GetStringAttribute(avatar,"name","?")); | ||
1550 | |||
1551 | oname = GetStringAttribute(outfit,"name",""); | ||
1552 | select = (GetStringAttribute(outfit,"default","no") == "yes"); | ||
1553 | efolder = null; | ||
1554 | |||
1555 | // If the folder already exists, re-use it. The defaults may | ||
1556 | // change over time. Augment only. | ||
1557 | foreach (InventoryFolderImpl folder in uic.folders) | ||
1558 | { | ||
1559 | if (folder.Name == oname && folder.ParentID == cfolder.ID) | ||
1560 | { | ||
1561 | efolder = folder; | ||
1562 | break; | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | // Otherwise, we must create the folder. | ||
1567 | if (efolder == null) | ||
1568 | { | ||
1569 | m_log.DebugFormat("[RADMIN] Creating outfit folder {0} for {1}", oname, name); | ||
1570 | efolder = new InventoryFolderImpl(); | ||
1571 | efolder.ID = UUID.Random(); | ||
1572 | efolder.Name = oname; | ||
1573 | efolder.Type = 5; | ||
1574 | efolder.Version = 1; | ||
1575 | efolder.Owner = ID; | ||
1576 | cfolder.AddChildFolder(efolder); // make connection | ||
1577 | iserv.AddFolder(efolder); // store base record | ||
1578 | m_log.DebugFormat("[RADMIN] Adding outfile folder {0} to folder {1}", efolder.ID, cfolder.ID); | ||
1579 | } | ||
1580 | |||
1581 | // Now get the pieces that make up the outfit | ||
1582 | XmlNodeList items = outfit.GetElementsByTagName("Item"); | ||
1583 | |||
1584 | foreach (XmlElement item in items) | ||
1585 | { | ||
1586 | assetid = UUID.Zero; | ||
1587 | XmlNodeList children = item.ChildNodes; | ||
1588 | foreach (XmlNode child in children) | ||
1589 | { | ||
1590 | switch (child.Name) | ||
1591 | { | ||
1592 | case "Permissions" : | ||
1593 | m_log.DebugFormat("[RADMIN] Permissions specified"); | ||
1594 | perms = child; | ||
1595 | break; | ||
1596 | case "Asset" : | ||
1597 | assetid = new UUID(child.InnerText); | ||
1598 | break; | ||
1599 | } | ||
1600 | } | ||
1601 | |||
1602 | InventoryItemBase iitem = null; | ||
1603 | |||
1604 | if ((iitem = efolder.FindAsset(assetid)) == null) | ||
1605 | { | ||
1606 | iitem = new InventoryItemBase(); | ||
1607 | iitem.ID = UUID.Random(); | ||
1608 | iitem.Name = GetStringAttribute(item,"name",""); | ||
1609 | iitem.Description = GetStringAttribute(item,"desc",""); | ||
1610 | iitem.InvType = GetIntegerAttribute(item,"invtype",-1); | ||
1611 | iitem.AssetType = GetIntegerAttribute(item,"assettype",-1); | ||
1612 | iitem.Flags = GetUnsignedAttribute(item,"flags",0); | ||
1613 | iitem.AssetID = assetid; // associated asset | ||
1614 | iitem.Folder = efolder.ID; // Parent folder | ||
1615 | iitem.Owner = ID; // Agent ID | ||
1616 | iitem.BasePermissions = GetUnsignedAttribute(perms,"base",0x7fffffff); | ||
1617 | iitem.NextPermissions = GetUnsignedAttribute(perms,"next",0x7fffffff); | ||
1618 | iitem.CurrentPermissions = GetUnsignedAttribute(perms,"current",0x7fffffff); | ||
1619 | iitem.GroupPermissions = GetUnsignedAttribute(perms,"group",0x7fffffff); | ||
1620 | iitem.EveryOnePermissions = GetUnsignedAttribute(perms,"everyone",0x7fffffff); | ||
1621 | m_log.DebugFormat("[RADMIN] Adding item {0} to folder {1}", iitem.ID, efolder.ID); | ||
1622 | iserv.AddItem(iitem); | ||
1623 | } | ||
1624 | // Record whether or not the item is to be initially worn | ||
1625 | try | ||
1626 | { | ||
1627 | if (select && (GetStringAttribute(item, "wear", "false") == "true")) | ||
1628 | { | ||
1629 | mava.Wearables[iitem.Flags].ItemID = iitem.ID; | ||
1630 | mava.Wearables[iitem.Flags].AssetID = iitem.AssetID; | ||
1631 | } | ||
1632 | } | ||
1633 | catch {} | ||
1634 | } // foreach item in outfit | ||
1635 | m_log.DebugFormat("[RADMIN] Outfit {0} load completed", oname); | ||
1636 | } // foreach outfit | ||
1637 | m_log.DebugFormat("[RADMIN] Inventory update complete for {0}", name); | ||
1638 | m_app.CommunicationsManager.AvatarService.UpdateUserAppearance(ID, mava); | ||
1639 | } | ||
1640 | catch (Exception e) | ||
1641 | { | ||
1642 | m_log.WarnFormat("[RADMIN] Inventory processing incomplete for user {0} : {1}", | ||
1643 | name, e.Message); | ||
1644 | } | ||
1645 | else | ||
1646 | { | ||
1647 | m_log.WarnFormat("[RADMIN] Unable to retrieve inventory for {0}[{1}]", | ||
1648 | name, ID); | ||
1649 | // continue to next avatar | ||
1650 | } | ||
1651 | } // End of include | ||
1652 | } | ||
1653 | m_log.DebugFormat("[RADMIN] Default avatar loading complete"); | ||
1654 | } | ||
1655 | else | ||
1656 | { | ||
1657 | m_log.DebugFormat("[RADMIN] No default avatar information available"); | ||
1658 | return false; | ||
1659 | } | ||
1660 | } | ||
1661 | catch (Exception e) | ||
1662 | { | ||
1663 | m_log.WarnFormat("[RADMIN] Exception whilst loading default avatars ; {0}", e.Message); | ||
1664 | return false; | ||
1665 | } | ||
1666 | |||
1667 | return true; | ||
1668 | |||
1669 | } | ||
1670 | |||
1671 | /// <summary> | ||
1260 | /// Load an OAR file into a region.. | 1672 | /// Load an OAR file into a region.. |
1261 | /// <summary> | 1673 | /// <summary> |
1262 | /// <param name="request">incoming XML RPC request</param> | 1674 | /// <param name="request">incoming XML RPC request</param> |
@@ -1809,13 +2221,17 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1809 | Scene s = m_app.SceneManager.CurrentScene; | 2221 | Scene s = m_app.SceneManager.CurrentScene; |
1810 | Hashtable users = (Hashtable) requestData["users"]; | 2222 | Hashtable users = (Hashtable) requestData["users"]; |
1811 | List<UUID> uuids = new List<UUID>(); | 2223 | List<UUID> uuids = new List<UUID>(); |
1812 | foreach (string name in users.Values) | 2224 | foreach (string name in users.Values) |
1813 | { | 2225 | { |
1814 | string[] parts = name.Split(); | 2226 | string[] parts = name.Split(); |
1815 | uuids.Add(ups.GetUserDetails(parts[0],parts[1]).UserProfile.ID); | 2227 | CachedUserInfo udata = ups.GetUserDetails(parts[0],parts[1]); |
2228 | if (udata != null) | ||
2229 | { | ||
2230 | uuids.Add(udata.UserProfile.ID); | ||
2231 | } | ||
1816 | } | 2232 | } |
1817 | List<UUID> acl = new List<UUID>(s.RegionInfo.EstateSettings.EstateAccess); | 2233 | List<UUID> acl = new List<UUID>(s.RegionInfo.EstateSettings.EstateAccess); |
1818 | foreach (UUID uuid in uuids) | 2234 | foreach (UUID uuid in uuids) |
1819 | { | 2235 | { |
1820 | if (!acl.Contains(uuid)) | 2236 | if (!acl.Contains(uuid)) |
1821 | { | 2237 | { |
@@ -1891,7 +2307,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1891 | foreach (string name in users.Values) | 2307 | foreach (string name in users.Values) |
1892 | { | 2308 | { |
1893 | string[] parts = name.Split(); | 2309 | string[] parts = name.Split(); |
1894 | uuids.Add(ups.GetUserDetails(parts[0],parts[1]).UserProfile.ID); | 2310 | CachedUserInfo udata = ups.GetUserDetails(parts[0],parts[1]); |
2311 | if (udata != null) | ||
2312 | { | ||
2313 | uuids.Add(udata.UserProfile.ID); | ||
2314 | } | ||
1895 | } | 2315 | } |
1896 | List<UUID> acl = new List<UUID>(s.RegionInfo.EstateSettings.EstateAccess); | 2316 | List<UUID> acl = new List<UUID>(s.RegionInfo.EstateSettings.EstateAccess); |
1897 | foreach (UUID uuid in uuids) | 2317 | foreach (UUID uuid in uuids) |
@@ -1964,10 +2384,13 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1964 | UUID[] acl = s.RegionInfo.EstateSettings.EstateAccess; | 2384 | UUID[] acl = s.RegionInfo.EstateSettings.EstateAccess; |
1965 | Hashtable users = new Hashtable(); | 2385 | Hashtable users = new Hashtable(); |
1966 | 2386 | ||
1967 | foreach (UUID user in acl) | 2387 | foreach (UUID user in acl) |
1968 | { | 2388 | { |
1969 | users[user.ToString()] = | 2389 | CachedUserInfo udata = m_app.CommunicationsManager.UserProfileCacheService.GetUserDetails(user); |
1970 | m_app.CommunicationsManager.UserProfileCacheService.GetUserDetails(user).UserProfile.Name; | 2390 | if (udata != null) |
2391 | { | ||
2392 | users[user.ToString()] = udata.UserProfile.Name; | ||
2393 | } | ||
1971 | } | 2394 | } |
1972 | 2395 | ||
1973 | responseData["users"] = users; | 2396 | responseData["users"] = users; |
@@ -1990,9 +2413,153 @@ namespace OpenSim.ApplicationPlugins.RemoteController | |||
1990 | return response; | 2413 | return response; |
1991 | } | 2414 | } |
1992 | 2415 | ||
2416 | private static void checkStringParameters(XmlRpcRequest request, string[] param) | ||
2417 | { | ||
2418 | Hashtable requestData = (Hashtable) request.Params[0]; | ||
2419 | foreach (string p in param) | ||
2420 | { | ||
2421 | if (!requestData.Contains(p)) | ||
2422 | throw new Exception(String.Format("missing string parameter {0}", p)); | ||
2423 | if (String.IsNullOrEmpty((string) requestData[p])) | ||
2424 | throw new Exception(String.Format("parameter {0} is empty", p)); | ||
2425 | } | ||
2426 | } | ||
2427 | |||
2428 | private static void checkIntegerParams(XmlRpcRequest request, string[] param) | ||
2429 | { | ||
2430 | Hashtable requestData = (Hashtable) request.Params[0]; | ||
2431 | foreach (string p in param) | ||
2432 | { | ||
2433 | if (!requestData.Contains(p)) | ||
2434 | throw new Exception(String.Format("missing integer parameter {0}", p)); | ||
2435 | } | ||
2436 | } | ||
2437 | |||
2438 | private bool getBoolean(Hashtable requestData, string tag, bool defv) | ||
2439 | { | ||
2440 | // If an access value has been provided, apply it. | ||
2441 | if (requestData.Contains(tag)) | ||
2442 | { | ||
2443 | switch (((string)requestData[tag]).ToLower()) | ||
2444 | { | ||
2445 | case "true" : | ||
2446 | case "t" : | ||
2447 | case "1" : | ||
2448 | return true; | ||
2449 | case "false" : | ||
2450 | case "f" : | ||
2451 | case "0" : | ||
2452 | return false; | ||
2453 | default : | ||
2454 | return defv; | ||
2455 | } | ||
2456 | } | ||
2457 | else | ||
2458 | return defv; | ||
2459 | } | ||
2460 | |||
2461 | private int GetIntegerAttribute(XmlNode node, string attr, int dv) | ||
2462 | { | ||
2463 | try { return Convert.ToInt32(node.Attributes[attr].Value); } catch{} | ||
2464 | return dv; | ||
2465 | } | ||
2466 | |||
2467 | private uint GetUnsignedAttribute(XmlNode node, string attr, uint dv) | ||
2468 | { | ||
2469 | try { return Convert.ToUInt32(node.Attributes[attr].Value); } catch{} | ||
2470 | return dv; | ||
2471 | } | ||
2472 | |||
2473 | private string GetStringAttribute(XmlNode node, string attr, string dv) | ||
2474 | { | ||
2475 | try { return node.Attributes[attr].Value; } catch{} | ||
2476 | return dv; | ||
2477 | } | ||
2478 | |||
1993 | public void Dispose() | 2479 | public void Dispose() |
1994 | { | 2480 | { |
1995 | } | 2481 | } |
2482 | |||
2483 | } | ||
2484 | |||
2485 | class UICallback | ||
2486 | { | ||
2487 | |||
2488 | private Object uilock = new Object(); | ||
2489 | internal InventoryFolderImpl root = null; | ||
2490 | internal List<InventoryFolderImpl> folders; | ||
2491 | internal List<InventoryItemBase> items; | ||
2492 | internal bool OK = false; | ||
2493 | |||
2494 | public void callback(ICollection<InventoryFolderImpl> p_folders, ICollection<InventoryItemBase> p_items) | ||
2495 | { | ||
2496 | lock (uilock) | ||
2497 | { | ||
2498 | folders = (List<InventoryFolderImpl>) p_folders; | ||
2499 | items = (List<InventoryItemBase>) p_items; | ||
2500 | OK = true; | ||
2501 | System.Threading.Monitor.Pulse(uilock); | ||
2502 | } | ||
2503 | } | ||
2504 | |||
2505 | public void GetInventory() | ||
2506 | { | ||
2507 | |||
2508 | Dictionary<UUID, InventoryFolderImpl> fmap = new Dictionary<UUID, InventoryFolderImpl>(); | ||
2509 | |||
2510 | if (OK == false) | ||
2511 | { | ||
2512 | lock (uilock) | ||
2513 | { | ||
2514 | if (OK == false) | ||
2515 | System.Threading.Monitor.Wait(uilock); | ||
2516 | } | ||
2517 | } | ||
2518 | |||
2519 | // Got the inventory OK. So now merge the content of the default appearance | ||
2520 | // file with whatever we already have in-world. For convenience we initialize | ||
2521 | // the inventory hierarchy. | ||
2522 | |||
2523 | // Find root and build an index | ||
2524 | |||
2525 | foreach (InventoryFolderImpl folder in folders) | ||
2526 | { | ||
2527 | if (folder.ParentID == UUID.Zero) | ||
2528 | { | ||
2529 | if (root == null) | ||
2530 | { | ||
2531 | root = folder; | ||
2532 | } | ||
2533 | else | ||
2534 | { | ||
2535 | throw new Exception("Multiple root folders found"); | ||
2536 | } | ||
2537 | } | ||
2538 | fmap.Add(folder.ID, folder); | ||
2539 | } | ||
2540 | |||
2541 | // Hard to continue if the root folder is not there | ||
2542 | if (root == null) | ||
2543 | { | ||
2544 | throw new Exception("Root folder not found"); | ||
2545 | } | ||
2546 | |||
2547 | // Construct the folder hierarchy | ||
2548 | foreach (InventoryFolderImpl folder in folders) | ||
2549 | { | ||
2550 | if (folder.ID != root.ID) | ||
2551 | { | ||
2552 | fmap[folder.ParentID].AddChildFolder(folder); | ||
2553 | } | ||
2554 | } | ||
2555 | |||
2556 | // Find a home for every pre-existing item | ||
2557 | foreach (InventoryItemBase item in items) | ||
2558 | { | ||
2559 | fmap[item.Folder].Items.Add(item.ID, item); | ||
2560 | } | ||
2561 | |||
2562 | } | ||
1996 | } | 2563 | } |
1997 | 2564 | ||
1998 | } | 2565 | } |