MySQLInventoryData.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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. using System;
  28. using System.Collections.Generic;
  29. using libsecondlife;
  30. using MySql.Data.MySqlClient;
  31. using OpenSim.Framework.Console;
  32. namespace OpenSim.Framework.Data.MySQL
  33. {
  34. /// <summary>
  35. /// A MySQL interface for the inventory server
  36. /// </summary>
  37. public class MySQLInventoryData : IInventoryData
  38. {
  39. private static readonly log4net.ILog m_log
  40. = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  41. /// <summary>
  42. /// The database manager
  43. /// </summary>
  44. private MySQLManager database;
  45. /// <summary>
  46. /// Loads and initialises this database plugin
  47. /// </summary>
  48. public void Initialise()
  49. {
  50. IniFile GridDataMySqlFile = new IniFile("mysql_connection.ini");
  51. string settingHostname = GridDataMySqlFile.ParseFileReadValue("hostname");
  52. string settingDatabase = GridDataMySqlFile.ParseFileReadValue("database");
  53. string settingUsername = GridDataMySqlFile.ParseFileReadValue("username");
  54. string settingPassword = GridDataMySqlFile.ParseFileReadValue("password");
  55. string settingPooling = GridDataMySqlFile.ParseFileReadValue("pooling");
  56. string settingPort = GridDataMySqlFile.ParseFileReadValue("port");
  57. database =
  58. new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, settingPooling,
  59. settingPort);
  60. TestTables(database.Connection);
  61. }
  62. #region Test and initialization code
  63. private void UpgradeFoldersTable(string oldVersion)
  64. {
  65. // null as the version, indicates that the table didn't exist
  66. if (oldVersion == null)
  67. {
  68. database.ExecuteResourceSql("CreateFoldersTable.sql");
  69. return;
  70. }
  71. // if the table is already at the current version, then we can exit immediately
  72. // if (oldVersion == "Rev. 2")
  73. // return;
  74. // database.ExecuteResourceSql("UpgradeFoldersTableToVersion2.sql");
  75. }
  76. private void UpgradeItemsTable(string oldVersion)
  77. {
  78. // null as the version, indicates that the table didn't exist
  79. if (oldVersion == null)
  80. {
  81. database.ExecuteResourceSql("CreateItemsTable.sql");
  82. return;
  83. }
  84. // if the table is already at the current version, then we can exit immediately
  85. // if (oldVersion == "Rev. 2")
  86. // return;
  87. // database.ExecuteResourceSql("UpgradeItemsTableToVersion2.sql");
  88. }
  89. private void TestTables(MySqlConnection conn)
  90. {
  91. Dictionary<string, string> tableList = new Dictionary<string, string>();
  92. tableList["inventoryfolders"] = null;
  93. tableList["inventoryitems"] = null;
  94. database.GetTableVersion(tableList);
  95. m_log.Info("[MYSQL]: Inventory Folder Version: " + tableList["inventoryfolders"]);
  96. m_log.Info("[MYSQL]: Inventory Items Version: " + tableList["inventoryitems"]);
  97. UpgradeFoldersTable(tableList["inventoryfolders"]);
  98. UpgradeItemsTable(tableList["inventoryitems"]);
  99. }
  100. #endregion
  101. /// <summary>
  102. /// The name of this DB provider
  103. /// </summary>
  104. /// <returns>Name of DB provider</returns>
  105. public string getName()
  106. {
  107. return "MySQL Inventory Data Interface";
  108. }
  109. /// <summary>
  110. /// Closes this DB provider
  111. /// </summary>
  112. public void Close()
  113. {
  114. // Do nothing.
  115. }
  116. /// <summary>
  117. /// Returns the version of this DB provider
  118. /// </summary>
  119. /// <returns>A string containing the DB provider</returns>
  120. public string getVersion()
  121. {
  122. return database.getVersion();
  123. }
  124. /// <summary>
  125. /// Returns a list of items in a specified folder
  126. /// </summary>
  127. /// <param name="folderID">The folder to search</param>
  128. /// <returns>A list containing inventory items</returns>
  129. public List<InventoryItemBase> getInventoryInFolder(LLUUID folderID)
  130. {
  131. try
  132. {
  133. lock (database)
  134. {
  135. List<InventoryItemBase> items = new List<InventoryItemBase>();
  136. MySqlCommand result =
  137. new MySqlCommand("SELECT * FROM inventoryitems WHERE parentFolderID = ?uuid",
  138. database.Connection);
  139. result.Parameters.AddWithValue("?uuid", folderID.ToString());
  140. MySqlDataReader reader = result.ExecuteReader();
  141. while (reader.Read())
  142. items.Add(readInventoryItem(reader));
  143. reader.Close();
  144. result.Dispose();
  145. return items;
  146. }
  147. }
  148. catch (Exception e)
  149. {
  150. database.Reconnect();
  151. m_log.Error(e.ToString());
  152. return null;
  153. }
  154. }
  155. /// <summary>
  156. /// Returns a list of the root folders within a users inventory
  157. /// </summary>
  158. /// <param name="user">The user whos inventory is to be searched</param>
  159. /// <returns>A list of folder objects</returns>
  160. public List<InventoryFolderBase> getUserRootFolders(LLUUID user)
  161. {
  162. try
  163. {
  164. lock (database)
  165. {
  166. MySqlCommand result =
  167. new MySqlCommand(
  168. "SELECT * FROM inventoryfolders WHERE parentFolderID = ?zero AND agentID = ?uuid",
  169. database.Connection);
  170. result.Parameters.AddWithValue("?uuid", user.ToString());
  171. result.Parameters.AddWithValue("?zero", LLUUID.Zero.ToString());
  172. MySqlDataReader reader = result.ExecuteReader();
  173. List<InventoryFolderBase> items = new List<InventoryFolderBase>();
  174. while (reader.Read())
  175. items.Add(readInventoryFolder(reader));
  176. reader.Close();
  177. result.Dispose();
  178. return items;
  179. }
  180. }
  181. catch (Exception e)
  182. {
  183. database.Reconnect();
  184. m_log.Error(e.ToString());
  185. return null;
  186. }
  187. }
  188. // see InventoryItemBase.getUserRootFolder
  189. public InventoryFolderBase getUserRootFolder(LLUUID user)
  190. {
  191. try
  192. {
  193. lock (database)
  194. {
  195. MySqlCommand result =
  196. new MySqlCommand(
  197. "SELECT * FROM inventoryfolders WHERE parentFolderID = ?zero AND agentID = ?uuid",
  198. database.Connection);
  199. result.Parameters.AddWithValue("?uuid", user.ToString());
  200. result.Parameters.AddWithValue("?zero", LLUUID.Zero.ToString());
  201. MySqlDataReader reader = result.ExecuteReader();
  202. List<InventoryFolderBase> items = new List<InventoryFolderBase>();
  203. while (reader.Read())
  204. items.Add(readInventoryFolder(reader));
  205. InventoryFolderBase rootFolder = null;
  206. // There should only ever be one root folder for a user. However, if there's more
  207. // than one we'll simply use the first one rather than failing. It would be even
  208. // nicer to print some message to this effect, but this feels like it's too low a
  209. // to put such a message out, and it's too minor right now to spare the time to
  210. // suitably refactor.
  211. if (items.Count > 0)
  212. {
  213. rootFolder = items[0];
  214. }
  215. reader.Close();
  216. result.Dispose();
  217. return rootFolder;
  218. }
  219. }
  220. catch (Exception e)
  221. {
  222. database.Reconnect();
  223. m_log.Error(e.ToString());
  224. return null;
  225. }
  226. }
  227. /// <summary>
  228. /// Return a list of folders in a users inventory contained within the specified folder.
  229. /// This method is only used in tests - in normal operation the user always have one,
  230. /// and only one, root folder.
  231. /// </summary>
  232. /// <param name="parentID">The folder to search</param>
  233. /// <returns>A list of inventory folders</returns>
  234. public List<InventoryFolderBase> getInventoryFolders(LLUUID parentID)
  235. {
  236. try
  237. {
  238. lock (database)
  239. {
  240. MySqlCommand result =
  241. new MySqlCommand("SELECT * FROM inventoryfolders WHERE parentFolderID = ?uuid",
  242. database.Connection);
  243. result.Parameters.AddWithValue("?uuid", parentID.ToString());
  244. MySqlDataReader reader = result.ExecuteReader();
  245. List<InventoryFolderBase> items = new List<InventoryFolderBase>();
  246. while (reader.Read())
  247. items.Add(readInventoryFolder(reader));
  248. reader.Close();
  249. result.Dispose();
  250. return items;
  251. }
  252. }
  253. catch (Exception e)
  254. {
  255. database.Reconnect();
  256. m_log.Error(e.ToString());
  257. return null;
  258. }
  259. }
  260. /// <summary>
  261. /// Reads a one item from an SQL result
  262. /// </summary>
  263. /// <param name="reader">The SQL Result</param>
  264. /// <returns>the item read</returns>
  265. private InventoryItemBase readInventoryItem(MySqlDataReader reader)
  266. {
  267. try
  268. {
  269. InventoryItemBase item = new InventoryItemBase();
  270. item.inventoryID = new LLUUID((string) reader["inventoryID"]);
  271. item.assetID = new LLUUID((string) reader["assetID"]);
  272. item.assetType = (int) reader["assetType"];
  273. item.parentFolderID = new LLUUID((string) reader["parentFolderID"]);
  274. item.avatarID = new LLUUID((string) reader["avatarID"]);
  275. item.inventoryName = (string) reader["inventoryName"];
  276. item.inventoryDescription = (string) reader["inventoryDescription"];
  277. item.inventoryNextPermissions = (uint) reader["inventoryNextPermissions"];
  278. item.inventoryCurrentPermissions = (uint) reader["inventoryCurrentPermissions"];
  279. item.invType = (int) reader["invType"];
  280. item.creatorsID = new LLUUID((string) reader["creatorID"]);
  281. item.inventoryBasePermissions = (uint) reader["inventoryBasePermissions"];
  282. item.inventoryEveryOnePermissions = (uint) reader["inventoryEveryOnePermissions"];
  283. return item;
  284. }
  285. catch (MySqlException e)
  286. {
  287. m_log.Error(e.ToString());
  288. }
  289. return null;
  290. }
  291. /// <summary>
  292. /// Returns a specified inventory item
  293. /// </summary>
  294. /// <param name="item">The item to return</param>
  295. /// <returns>An inventory item</returns>
  296. public InventoryItemBase getInventoryItem(LLUUID itemID)
  297. {
  298. try
  299. {
  300. lock (database)
  301. {
  302. Dictionary<string, string> param = new Dictionary<string, string>();
  303. MySqlCommand result =
  304. new MySqlCommand("SELECT * FROM inventoryitems WHERE inventoryID = ?uuid", database.Connection);
  305. result.Parameters.AddWithValue("?uuid", itemID.ToString());
  306. MySqlDataReader reader = result.ExecuteReader();
  307. InventoryItemBase item = null;
  308. if (reader.Read())
  309. item = readInventoryItem(reader);
  310. reader.Close();
  311. result.Dispose();
  312. return item;
  313. }
  314. }
  315. catch (Exception e)
  316. {
  317. database.Reconnect();
  318. m_log.Error(e.ToString());
  319. }
  320. return null;
  321. }
  322. /// <summary>
  323. /// Reads a list of inventory folders returned by a query.
  324. /// </summary>
  325. /// <param name="reader">A MySQL Data Reader</param>
  326. /// <returns>A List containing inventory folders</returns>
  327. protected InventoryFolderBase readInventoryFolder(MySqlDataReader reader)
  328. {
  329. try
  330. {
  331. InventoryFolderBase folder = new InventoryFolderBase();
  332. folder.agentID = new LLUUID((string) reader["agentID"]);
  333. folder.parentID = new LLUUID((string) reader["parentFolderID"]);
  334. folder.folderID = new LLUUID((string) reader["folderID"]);
  335. folder.name = (string) reader["folderName"];
  336. folder.type = (short) reader["type"];
  337. folder.version = (ushort) ((int) reader["version"]);
  338. return folder;
  339. }
  340. catch (Exception e)
  341. {
  342. m_log.Error(e.ToString());
  343. }
  344. return null;
  345. }
  346. /// <summary>
  347. /// Returns a specified inventory folder
  348. /// </summary>
  349. /// <param name="folder">The folder to return</param>
  350. /// <returns>A folder class</returns>
  351. public InventoryFolderBase getInventoryFolder(LLUUID folderID)
  352. {
  353. try
  354. {
  355. lock (database)
  356. {
  357. MySqlCommand result =
  358. new MySqlCommand("SELECT * FROM inventoryfolders WHERE folderID = ?uuid", database.Connection);
  359. result.Parameters.AddWithValue("?uuid", folderID.ToString());
  360. MySqlDataReader reader = result.ExecuteReader();
  361. reader.Read();
  362. InventoryFolderBase folder = readInventoryFolder(reader);
  363. reader.Close();
  364. result.Dispose();
  365. return folder;
  366. }
  367. }
  368. catch (Exception e)
  369. {
  370. database.Reconnect();
  371. m_log.Error(e.ToString());
  372. return null;
  373. }
  374. }
  375. /// <summary>
  376. /// Adds a specified item to the database
  377. /// </summary>
  378. /// <param name="item">The inventory item</param>
  379. public void addInventoryItem(InventoryItemBase item)
  380. {
  381. string sql =
  382. "REPLACE INTO inventoryitems (inventoryID, assetID, assetType, parentFolderID, avatarID, inventoryName, inventoryDescription, inventoryNextPermissions, inventoryCurrentPermissions, invType, creatorID, inventoryBasePermissions, inventoryEveryOnePermissions) VALUES ";
  383. sql +=
  384. "(?inventoryID, ?assetID, ?assetType, ?parentFolderID, ?avatarID, ?inventoryName, ?inventoryDescription, ?inventoryNextPermissions, ?inventoryCurrentPermissions, ?invType, ?creatorID, ?inventoryBasePermissions, ?inventoryEveryOnePermissions)";
  385. try
  386. {
  387. MySqlCommand result = new MySqlCommand(sql, database.Connection);
  388. result.Parameters.AddWithValue("?inventoryID", item.inventoryID.ToString());
  389. result.Parameters.AddWithValue("?assetID", item.assetID.ToString());
  390. result.Parameters.AddWithValue("?assetType", item.assetType.ToString());
  391. result.Parameters.AddWithValue("?parentFolderID", item.parentFolderID.ToString());
  392. result.Parameters.AddWithValue("?avatarID", item.avatarID.ToString());
  393. result.Parameters.AddWithValue("?inventoryName", item.inventoryName);
  394. result.Parameters.AddWithValue("?inventoryDescription", item.inventoryDescription);
  395. result.Parameters.AddWithValue("?inventoryNextPermissions", item.inventoryNextPermissions.ToString());
  396. result.Parameters.AddWithValue("?inventoryCurrentPermissions",
  397. item.inventoryCurrentPermissions.ToString());
  398. result.Parameters.AddWithValue("?invType", item.invType);
  399. result.Parameters.AddWithValue("?creatorID", item.creatorsID.ToString());
  400. result.Parameters.AddWithValue("?inventoryBasePermissions", item.inventoryBasePermissions);
  401. result.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.inventoryEveryOnePermissions);
  402. result.ExecuteNonQuery();
  403. result.Dispose();
  404. }
  405. catch (MySqlException e)
  406. {
  407. m_log.Error(e.ToString());
  408. }
  409. }
  410. /// <summary>
  411. /// Updates the specified inventory item
  412. /// </summary>
  413. /// <param name="item">Inventory item to update</param>
  414. public void updateInventoryItem(InventoryItemBase item)
  415. {
  416. addInventoryItem(item);
  417. }
  418. /// <summary>
  419. ///
  420. /// </summary>
  421. /// <param name="item"></param>
  422. public void deleteInventoryItem(LLUUID itemID)
  423. {
  424. try
  425. {
  426. MySqlCommand cmd =
  427. new MySqlCommand("DELETE FROM inventoryitems WHERE inventoryID=?uuid", database.Connection);
  428. cmd.Parameters.AddWithValue("?uuid", itemID.ToString());
  429. cmd.ExecuteNonQuery();
  430. }
  431. catch (MySqlException e)
  432. {
  433. database.Reconnect();
  434. m_log.Error(e.ToString());
  435. }
  436. }
  437. /// <summary>
  438. /// Creates a new inventory folder
  439. /// </summary>
  440. /// <param name="folder">Folder to create</param>
  441. public void addInventoryFolder(InventoryFolderBase folder)
  442. {
  443. string sql =
  444. "REPLACE INTO inventoryfolders (folderID, agentID, parentFolderID, folderName, type, version) VALUES ";
  445. sql += "(?folderID, ?agentID, ?parentFolderID, ?folderName, ?type, ?version)";
  446. MySqlCommand cmd = new MySqlCommand(sql, database.Connection);
  447. cmd.Parameters.AddWithValue("?folderID", folder.folderID.ToString());
  448. cmd.Parameters.AddWithValue("?agentID", folder.agentID.ToString());
  449. cmd.Parameters.AddWithValue("?parentFolderID", folder.parentID.ToString());
  450. cmd.Parameters.AddWithValue("?folderName", folder.name);
  451. cmd.Parameters.AddWithValue("?type", (short) folder.type);
  452. cmd.Parameters.AddWithValue("?version", folder.version);
  453. try
  454. {
  455. lock (database)
  456. {
  457. cmd.ExecuteNonQuery();
  458. }
  459. }
  460. catch (Exception e)
  461. {
  462. m_log.Error(e.ToString());
  463. }
  464. }
  465. /// <summary>
  466. /// Updates an inventory folder
  467. /// </summary>
  468. /// <param name="folder">Folder to update</param>
  469. public void updateInventoryFolder(InventoryFolderBase folder)
  470. {
  471. addInventoryFolder(folder);
  472. }
  473. /// Creates a new inventory folder
  474. /// </summary>
  475. /// <param name="folder">Folder to create</param>
  476. public void moveInventoryFolder(InventoryFolderBase folder)
  477. {
  478. string sql =
  479. "UPDATE inventoryfolders SET parentFolderID=?parentFolderID WHERE folderID=?folderID";
  480. MySqlCommand cmd = new MySqlCommand(sql, database.Connection);
  481. cmd.Parameters.AddWithValue("?folderID", folder.folderID.ToString());
  482. cmd.Parameters.AddWithValue("?parentFolderID", folder.parentID.ToString());
  483. try
  484. {
  485. lock (database)
  486. {
  487. cmd.ExecuteNonQuery();
  488. }
  489. }
  490. catch (Exception e)
  491. {
  492. m_log.Error(e.ToString());
  493. }
  494. }
  495. /// <summary>
  496. /// Append a list of all the child folders of a parent folder
  497. /// </summary>
  498. /// <param name="folders">list where folders will be appended</param>
  499. /// <param name="parentID">ID of parent</param>
  500. protected void getInventoryFolders(ref List<InventoryFolderBase> folders, LLUUID parentID)
  501. {
  502. List<InventoryFolderBase> subfolderList = getInventoryFolders(parentID);
  503. foreach (InventoryFolderBase f in subfolderList)
  504. folders.Add(f);
  505. }
  506. // See IInventoryData
  507. public List<InventoryFolderBase> getFolderHierarchy(LLUUID parentID)
  508. {
  509. List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
  510. getInventoryFolders(ref folders, parentID);
  511. for (int i = 0; i < folders.Count; i++)
  512. getInventoryFolders(ref folders, folders[i].folderID);
  513. return folders;
  514. }
  515. protected void deleteOneFolder(LLUUID folderID)
  516. {
  517. try
  518. {
  519. MySqlCommand cmd =
  520. new MySqlCommand("DELETE FROM inventoryfolders WHERE folderID=?uuid", database.Connection);
  521. cmd.Parameters.AddWithValue("?uuid", folderID.ToString());
  522. lock (database)
  523. {
  524. cmd.ExecuteNonQuery();
  525. }
  526. }
  527. catch (MySqlException e)
  528. {
  529. database.Reconnect();
  530. m_log.Error(e.ToString());
  531. }
  532. }
  533. protected void deleteItemsInFolder(LLUUID folderID)
  534. {
  535. try
  536. {
  537. MySqlCommand cmd =
  538. new MySqlCommand("DELETE FROM inventoryitems WHERE parentFolderID=?uuid", database.Connection);
  539. cmd.Parameters.AddWithValue("?uuid", folderID.ToString());
  540. lock (database)
  541. {
  542. cmd.ExecuteNonQuery();
  543. }
  544. }
  545. catch (MySqlException e)
  546. {
  547. database.Reconnect();
  548. m_log.Error(e.ToString());
  549. }
  550. }
  551. /// <summary>
  552. /// Delete an inventory folder
  553. /// </summary>
  554. /// <param name="folderId">Id of folder to delete</param>
  555. public void deleteInventoryFolder(LLUUID folderID)
  556. {
  557. List<InventoryFolderBase> subFolders = getFolderHierarchy(folderID);
  558. //Delete all sub-folders
  559. foreach (InventoryFolderBase f in subFolders)
  560. {
  561. deleteOneFolder(f.folderID);
  562. deleteItemsInFolder(f.folderID);
  563. }
  564. //Delete the actual row
  565. deleteOneFolder(folderID);
  566. deleteItemsInFolder(folderID);
  567. }
  568. }
  569. }