diff options
Diffstat (limited to 'OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs')
-rw-r--r-- | OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs new file mode 100644 index 0000000..cb686e2 --- /dev/null +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs | |||
@@ -0,0 +1,466 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using OpenMetaverse; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Services.Base; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenSim.Services.InventoryService; | ||
38 | using OpenSim.Data; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Server.Base; | ||
41 | |||
42 | namespace OpenSim.Services.HypergridService | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Hypergrid inventory service. It serves the IInventoryService interface, | ||
46 | /// but implements it in ways that are appropriate for inter-grid | ||
47 | /// inventory exchanges. Specifically, it does not performs deletions | ||
48 | /// and it responds to GetRootFolder requests with the ID of the | ||
49 | /// Suitcase folder, not the actual "My Inventory" folder. | ||
50 | /// </summary> | ||
51 | public class HGSuitcaseInventoryService : XInventoryService, IInventoryService | ||
52 | { | ||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger( | ||
55 | MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private string m_HomeURL; | ||
58 | private IUserAccountService m_UserAccountService; | ||
59 | |||
60 | private UserAccountCache m_Cache; | ||
61 | |||
62 | private ExpiringCache<UUID, List<XInventoryFolder>> m_SuitcaseTrees = new ExpiringCache<UUID,List<XInventoryFolder>>(); | ||
63 | |||
64 | public HGSuitcaseInventoryService(IConfigSource config, string configName) | ||
65 | : base(config, configName) | ||
66 | { | ||
67 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Starting with config name {0}", configName); | ||
68 | if (configName != string.Empty) | ||
69 | m_ConfigName = configName; | ||
70 | |||
71 | if (m_Database == null) | ||
72 | m_log.WarnFormat("[XXX]: m_Database is null!"); | ||
73 | |||
74 | // | ||
75 | // Try reading the [InventoryService] section, if it exists | ||
76 | // | ||
77 | IConfig invConfig = config.Configs[m_ConfigName]; | ||
78 | if (invConfig != null) | ||
79 | { | ||
80 | // realm = authConfig.GetString("Realm", realm); | ||
81 | string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty); | ||
82 | if (userAccountsDll == string.Empty) | ||
83 | throw new Exception("Please specify UserAccountsService in HGInventoryService configuration"); | ||
84 | |||
85 | Object[] args = new Object[] { config }; | ||
86 | m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args); | ||
87 | if (m_UserAccountService == null) | ||
88 | throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); | ||
89 | |||
90 | // legacy configuration [obsolete] | ||
91 | m_HomeURL = invConfig.GetString("ProfileServerURI", string.Empty); | ||
92 | // Preferred | ||
93 | m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL); | ||
94 | |||
95 | m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); | ||
96 | } | ||
97 | |||
98 | m_log.Debug("[HG SUITCASE INVENTORY SERVICE]: Starting..."); | ||
99 | } | ||
100 | |||
101 | public override bool CreateUserInventory(UUID principalID) | ||
102 | { | ||
103 | // NOGO | ||
104 | return false; | ||
105 | } | ||
106 | |||
107 | |||
108 | public override List<InventoryFolderBase> GetInventorySkeleton(UUID principalID) | ||
109 | { | ||
110 | // NOGO for this inventory service | ||
111 | return new List<InventoryFolderBase>(); | ||
112 | } | ||
113 | |||
114 | public override InventoryFolderBase GetRootFolder(UUID principalID) | ||
115 | { | ||
116 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetRootFolder for {0}", principalID); | ||
117 | if (m_Database == null) | ||
118 | m_log.ErrorFormat("[XXX]: m_Database is NULL!"); | ||
119 | |||
120 | // Let's find out the local root folder | ||
121 | XInventoryFolder root = GetRootXFolder(principalID); ; | ||
122 | if (root == null) | ||
123 | { | ||
124 | m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to retrieve local root folder for user {0}", principalID); | ||
125 | } | ||
126 | |||
127 | // Warp! Root folder for travelers is the suitcase folder | ||
128 | XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); | ||
129 | |||
130 | if (suitcase == null) | ||
131 | { | ||
132 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder. Creating it...", principalID); | ||
133 | // make one, and let's add it to the user's inventory as a direct child of the root folder | ||
134 | suitcase = CreateFolder(principalID, root.folderID, 100, "My Suitcase"); | ||
135 | if (suitcase == null) | ||
136 | m_log.ErrorFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to create suitcase folder"); | ||
137 | |||
138 | m_Database.StoreFolder(suitcase); | ||
139 | } | ||
140 | |||
141 | // Now let's change the folder ID to match that of the real root folder | ||
142 | SetAsRootFolder(suitcase, root.folderID); | ||
143 | |||
144 | return ConvertToOpenSim(suitcase); | ||
145 | } | ||
146 | |||
147 | public override InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) | ||
148 | { | ||
149 | //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type); | ||
150 | return GetRootFolder(principalID); | ||
151 | } | ||
152 | |||
153 | public override InventoryCollection GetFolderContent(UUID principalID, UUID folderID) | ||
154 | { | ||
155 | InventoryCollection coll = null; | ||
156 | XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); | ||
157 | XInventoryFolder root = GetRootXFolder(principalID); | ||
158 | |||
159 | if (!IsWithinSuitcaseTree(folderID, root, suitcase)) | ||
160 | return new InventoryCollection(); | ||
161 | |||
162 | if (folderID == root.folderID) // someone's asking for the root folder, we'll give them the suitcase | ||
163 | { | ||
164 | if (suitcase != null) | ||
165 | { | ||
166 | coll = base.GetFolderContent(principalID, suitcase.folderID); | ||
167 | foreach (InventoryFolderBase f in coll.Folders) | ||
168 | f.ParentID = root.folderID; | ||
169 | foreach (InventoryItemBase i in coll.Items) | ||
170 | i.Folder = root.folderID; | ||
171 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderContent for root folder returned content for suitcase folder"); | ||
172 | } | ||
173 | } | ||
174 | else | ||
175 | { | ||
176 | coll = base.GetFolderContent(principalID, folderID); | ||
177 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderContent for non-root folder {0}", folderID); | ||
178 | } | ||
179 | if (coll == null) | ||
180 | { | ||
181 | m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Something wrong with user {0}'s suitcase folder", principalID); | ||
182 | coll = new InventoryCollection(); | ||
183 | } | ||
184 | return coll; | ||
185 | } | ||
186 | |||
187 | public override List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) | ||
188 | { | ||
189 | // Let's do a bit of sanity checking, more than the base service does | ||
190 | // make sure the given folder exists under the suitcase tree of this user | ||
191 | XInventoryFolder root = GetRootXFolder(principalID); | ||
192 | XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); | ||
193 | |||
194 | if (!IsWithinSuitcaseTree(folderID, root, suitcase)) | ||
195 | return new List<InventoryItemBase>(); | ||
196 | |||
197 | return base.GetFolderItems(principalID, folderID); | ||
198 | } | ||
199 | |||
200 | public override bool AddFolder(InventoryFolderBase folder) | ||
201 | { | ||
202 | // Let's do a bit of sanity checking, more than the base service does | ||
203 | // make sure the given folder's parent folder exists under the suitcase tree of this user | ||
204 | XInventoryFolder root = GetRootXFolder(folder.Owner); | ||
205 | XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner); | ||
206 | |||
207 | if (!IsWithinSuitcaseTree(folder.ParentID, root, suitcase)) | ||
208 | return false; | ||
209 | |||
210 | // OK, it's legit | ||
211 | // Check if it's under the Root folder directly | ||
212 | if (folder.ParentID == root.folderID) | ||
213 | { | ||
214 | // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead | ||
215 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder for root folder for user {0}. Adding in suitcase instead", folder.Owner); | ||
216 | folder.ParentID = suitcase.folderID; | ||
217 | } | ||
218 | |||
219 | return base.AddFolder(folder); | ||
220 | } | ||
221 | |||
222 | public bool UpdateFolder(InventoryFolderBase folder) | ||
223 | { | ||
224 | XInventoryFolder root = GetRootXFolder(folder.Owner); | ||
225 | XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner); | ||
226 | |||
227 | if (!IsWithinSuitcaseTree(folder.ID, root, suitcase)) | ||
228 | return false; | ||
229 | |||
230 | return base.UpdateFolder(folder); | ||
231 | } | ||
232 | |||
233 | public override bool MoveFolder(InventoryFolderBase folder) | ||
234 | { | ||
235 | XInventoryFolder root = GetRootXFolder(folder.Owner); | ||
236 | XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner); | ||
237 | |||
238 | if (!IsWithinSuitcaseTree(folder.ID, root, suitcase) || !IsWithinSuitcaseTree(folder.ParentID, root, suitcase)) | ||
239 | return false; | ||
240 | |||
241 | if (folder.ParentID == root.folderID) | ||
242 | { | ||
243 | // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead | ||
244 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveFolder to root folder for user {0}. Moving it to suitcase instead", folder.Owner); | ||
245 | folder.ParentID = suitcase.folderID; | ||
246 | } | ||
247 | |||
248 | return base.MoveFolder(folder); | ||
249 | } | ||
250 | |||
251 | public override bool DeleteFolders(UUID principalID, List<UUID> folderIDs) | ||
252 | { | ||
253 | // NOGO | ||
254 | return false; | ||
255 | } | ||
256 | |||
257 | public override bool PurgeFolder(InventoryFolderBase folder) | ||
258 | { | ||
259 | // NOGO | ||
260 | return false; | ||
261 | } | ||
262 | |||
263 | public override bool AddItem(InventoryItemBase item) | ||
264 | { | ||
265 | // Let's do a bit of sanity checking, more than the base service does | ||
266 | // make sure the given folder's parent folder exists under the suitcase tree of this user | ||
267 | XInventoryFolder root = GetRootXFolder(item.Owner); | ||
268 | XInventoryFolder suitcase = GetSuitcaseXFolder(item.Owner); | ||
269 | |||
270 | if (!IsWithinSuitcaseTree(item.Folder, root, suitcase)) | ||
271 | return false; | ||
272 | |||
273 | // OK, it's legit | ||
274 | // Check if it's under the Root folder directly | ||
275 | if (item.Folder == root.folderID) | ||
276 | { | ||
277 | // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead | ||
278 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddItem for root folder for user {0}. Adding in suitcase instead", item.Owner); | ||
279 | item.Folder = suitcase.folderID; | ||
280 | } | ||
281 | |||
282 | return base.AddItem(item); | ||
283 | |||
284 | } | ||
285 | |||
286 | public override bool UpdateItem(InventoryItemBase item) | ||
287 | { | ||
288 | XInventoryFolder root = GetRootXFolder(item.Owner); | ||
289 | XInventoryFolder suitcase = GetSuitcaseXFolder(item.Owner); | ||
290 | |||
291 | if (!IsWithinSuitcaseTree(item.Folder, root, suitcase)) | ||
292 | return false; | ||
293 | |||
294 | return base.UpdateItem(item); | ||
295 | } | ||
296 | |||
297 | public override bool MoveItems(UUID principalID, List<InventoryItemBase> items) | ||
298 | { | ||
299 | // Principal is b0rked. *sigh* | ||
300 | |||
301 | XInventoryFolder root = GetRootXFolder(items[0].Owner); | ||
302 | XInventoryFolder suitcase = GetSuitcaseXFolder(items[0].Owner); | ||
303 | |||
304 | if (!IsWithinSuitcaseTree(items[0].Folder, root, suitcase)) | ||
305 | return false; | ||
306 | |||
307 | foreach (InventoryItemBase it in items) | ||
308 | if (it.Folder == root.folderID) | ||
309 | { | ||
310 | // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead | ||
311 | m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveItem to root folder for user {0}. Moving it to suitcase instead", it.Owner); | ||
312 | it.Folder = suitcase.folderID; | ||
313 | } | ||
314 | |||
315 | return base.MoveItems(principalID, items); | ||
316 | |||
317 | } | ||
318 | |||
319 | // Let these pass. Use inherited methods. | ||
320 | public override bool DeleteItems(UUID principalID, List<UUID> itemIDs) | ||
321 | { | ||
322 | return false; | ||
323 | } | ||
324 | |||
325 | public override InventoryItemBase GetItem(InventoryItemBase item) | ||
326 | { | ||
327 | InventoryItemBase it = base.GetItem(item); | ||
328 | XInventoryFolder root = GetRootXFolder(it.Owner); | ||
329 | XInventoryFolder suitcase = GetSuitcaseXFolder(it.Owner); | ||
330 | |||
331 | if (it != null) | ||
332 | { | ||
333 | if (!IsWithinSuitcaseTree(it.Folder, root, suitcase)) | ||
334 | return null; | ||
335 | |||
336 | if (it.Folder == suitcase.folderID) | ||
337 | it.Folder = root.folderID; | ||
338 | |||
339 | // UserAccount user = m_Cache.GetUser(it.CreatorId); | ||
340 | |||
341 | // // Adjust the creator data | ||
342 | // if (user != null && it != null && (it.CreatorData == null || it.CreatorData == string.Empty)) | ||
343 | // it.CreatorData = m_HomeURL + ";" + user.FirstName + " " + user.LastName; | ||
344 | //} | ||
345 | } | ||
346 | |||
347 | return it; | ||
348 | } | ||
349 | |||
350 | public override InventoryFolderBase GetFolder(InventoryFolderBase folder) | ||
351 | { | ||
352 | InventoryFolderBase f = base.GetFolder(folder); | ||
353 | XInventoryFolder root = GetRootXFolder(f.Owner); | ||
354 | XInventoryFolder suitcase = GetSuitcaseXFolder(f.Owner); | ||
355 | |||
356 | if (f != null) | ||
357 | { | ||
358 | if (!IsWithinSuitcaseTree(f.ID, root, suitcase)) | ||
359 | return null; | ||
360 | |||
361 | if (f.ParentID == suitcase.folderID) | ||
362 | f.ParentID = root.folderID; | ||
363 | } | ||
364 | |||
365 | return f; | ||
366 | } | ||
367 | |||
368 | //public List<InventoryItemBase> GetActiveGestures(UUID principalID) | ||
369 | //{ | ||
370 | //} | ||
371 | |||
372 | //public int GetAssetPermissions(UUID principalID, UUID assetID) | ||
373 | //{ | ||
374 | //} | ||
375 | |||
376 | #region Auxiliary functions | ||
377 | private XInventoryFolder GetXFolder(UUID userID, UUID folderID) | ||
378 | { | ||
379 | XInventoryFolder[] folders = m_Database.GetFolders( | ||
380 | new string[] { "agentID", "folderID" }, | ||
381 | new string[] { userID.ToString(), folderID.ToString() }); | ||
382 | |||
383 | if (folders.Length == 0) | ||
384 | return null; | ||
385 | |||
386 | return folders[0]; | ||
387 | } | ||
388 | |||
389 | private XInventoryFolder GetRootXFolder(UUID principalID) | ||
390 | { | ||
391 | XInventoryFolder[] folders = m_Database.GetFolders( | ||
392 | new string[] { "agentID", "folderName", "type" }, | ||
393 | new string[] { principalID.ToString(), "My Inventory", ((int)AssetType.RootFolder).ToString() }); | ||
394 | |||
395 | if (folders != null && folders.Length > 0) | ||
396 | return folders[0]; | ||
397 | return null; | ||
398 | } | ||
399 | |||
400 | private XInventoryFolder GetSuitcaseXFolder(UUID principalID) | ||
401 | { | ||
402 | // Warp! Root folder for travelers | ||
403 | XInventoryFolder[] folders = m_Database.GetFolders( | ||
404 | new string[] { "agentID", "type" }, | ||
405 | new string[] { principalID.ToString(), "100" }); // This is a special folder type... | ||
406 | |||
407 | if (folders != null && folders.Length > 0) | ||
408 | return folders[0]; | ||
409 | return null; | ||
410 | } | ||
411 | |||
412 | private void SetAsRootFolder(XInventoryFolder suitcase, UUID rootID) | ||
413 | { | ||
414 | suitcase.folderID = rootID; | ||
415 | suitcase.parentFolderID = UUID.Zero; | ||
416 | } | ||
417 | |||
418 | private List<XInventoryFolder> GetFolderTree(UUID root) | ||
419 | { | ||
420 | List<XInventoryFolder> t = null; | ||
421 | if (m_SuitcaseTrees.TryGetValue(root, out t)) | ||
422 | return t; | ||
423 | |||
424 | t = GetFolderTreeRecursive(root); | ||
425 | m_SuitcaseTrees.AddOrUpdate(root, t, 120); | ||
426 | return t; | ||
427 | } | ||
428 | |||
429 | private List<XInventoryFolder> GetFolderTreeRecursive(UUID root) | ||
430 | { | ||
431 | List<XInventoryFolder> tree = new List<XInventoryFolder>(); | ||
432 | XInventoryFolder[] folders = m_Database.GetFolders( | ||
433 | new string[] { "parentFolderID" }, | ||
434 | new string[] { root.ToString() }); | ||
435 | |||
436 | if (folders == null || (folders != null && folders.Length == 0)) | ||
437 | return tree; // empty tree | ||
438 | else | ||
439 | { | ||
440 | foreach (XInventoryFolder f in folders) | ||
441 | { | ||
442 | tree.Add(f); | ||
443 | tree.AddRange(GetFolderTreeRecursive(f.folderID)); | ||
444 | } | ||
445 | return tree; | ||
446 | } | ||
447 | |||
448 | } | ||
449 | |||
450 | private bool IsWithinSuitcaseTree(UUID folderID, XInventoryFolder root, XInventoryFolder suitcase) | ||
451 | { | ||
452 | List<XInventoryFolder> tree = new List<XInventoryFolder>(); | ||
453 | tree.Add(root); // Warp! the tree is the real root folder plus the children of the suitcase folder | ||
454 | tree.AddRange(GetFolderTree(suitcase.folderID)); | ||
455 | XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl) | ||
456 | { | ||
457 | if (fl.folderID == folderID) return true; | ||
458 | else return false; | ||
459 | }); | ||
460 | |||
461 | if (f == null) return false; | ||
462 | else return true; | ||
463 | } | ||
464 | #endregion | ||
465 | } | ||
466 | } | ||