SQLiteUserData.cs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  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 System.Data;
  30. using System.Reflection;
  31. using libsecondlife;
  32. using log4net;
  33. using Mono.Data.SqliteClient;
  34. using OpenSim.Framework;
  35. namespace OpenSim.Data.SQLite
  36. {
  37. /// <summary>
  38. /// A User storage interface for the SQLite database system
  39. /// </summary>
  40. public class SQLiteUserData : UserDataBase
  41. {
  42. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  43. /// <summary>
  44. /// The database manager
  45. /// </summary>
  46. /// <summary>
  47. /// Artificial constructor called upon plugin load
  48. /// </summary>
  49. private const string SelectUserByUUID = "select * from users where UUID=:UUID";
  50. private const string SelectUserByName = "select * from users where username=:username and surname=:surname";
  51. private const string SelectFriendsByUUID = "select a.friendID, a.friendPerms, b.friendPerms from userfriends as a, userfriends as b where a.ownerID=:ownerID and b.ownerID=a.friendID and b.friendID=a.ownerID";
  52. private const string userSelect = "select * from users";
  53. private const string userFriendsSelect = "select a.ownerID as ownerID,a.friendID as friendID,a.friendPerms as friendPerms,b.friendPerms as ownerperms, b.ownerID as fownerID, b.friendID as ffriendID from userfriends as a, userfriends as b";
  54. private const string AvatarPickerAndSQL = "select * from users where username like :username and surname like :surname";
  55. private const string AvatarPickerOrSQL = "select * from users where username like :username or surname like :surname";
  56. private Dictionary<LLUUID, AvatarAppearance> aplist = new Dictionary<LLUUID, AvatarAppearance>();
  57. private DataSet ds;
  58. private SqliteDataAdapter da;
  59. private SqliteDataAdapter daf;
  60. SqliteConnection g_conn;
  61. /// <summary>
  62. /// <list type="bullet">
  63. /// <item>Initialises User Interface</item>
  64. /// <item>Loads and initialises a new SQLite connection and maintains it.</item>
  65. /// <item>use default URI if connect string string is empty.</item>
  66. /// </list>
  67. /// </summary>
  68. /// <param name="connect">connect string</param>
  69. override public void Initialise(string connect)
  70. {
  71. // default to something sensible
  72. if (connect == "")
  73. connect = "URI=file:userprofiles.db,version=3";
  74. SqliteConnection conn = new SqliteConnection(connect);
  75. // This sucks, but It doesn't seem to work with the dataset Syncing :P
  76. g_conn = conn;
  77. g_conn.Open();
  78. Assembly assem = GetType().Assembly;
  79. Migration m = new Migration(g_conn, assem, "UserStore");
  80. // TODO: remove this after rev 6000
  81. TestTables(conn, m);
  82. m.Update();
  83. ds = new DataSet();
  84. da = new SqliteDataAdapter(new SqliteCommand(userSelect, conn));
  85. daf = new SqliteDataAdapter(new SqliteCommand(userFriendsSelect, conn));
  86. lock (ds)
  87. {
  88. ds.Tables.Add(createUsersTable());
  89. ds.Tables.Add(createUserAgentsTable());
  90. ds.Tables.Add(createUserFriendsTable());
  91. setupUserCommands(da, conn);
  92. da.Fill(ds.Tables["users"]);
  93. setupUserFriendsCommands(daf, conn);
  94. try
  95. {
  96. daf.Fill(ds.Tables["userfriends"]);
  97. }
  98. catch (SqliteSyntaxException)
  99. {
  100. m_log.Info("[USER DB]: userfriends table not found, creating.... ");
  101. InitDB(conn);
  102. daf.Fill(ds.Tables["userfriends"]);
  103. }
  104. }
  105. return;
  106. }
  107. /// <summary>
  108. /// see IUserData,
  109. /// Get user data profile by UUID
  110. /// </summary>
  111. /// <param name="uuid">User UUID</param>
  112. /// <returns>user profile data</returns>
  113. override public UserProfileData GetUserByUUID(LLUUID uuid)
  114. {
  115. lock (ds)
  116. {
  117. DataRow row = ds.Tables["users"].Rows.Find(Util.ToRawUuidString(uuid));
  118. if (row != null)
  119. {
  120. UserProfileData user = buildUserProfile(row);
  121. row = ds.Tables["useragents"].Rows.Find(Util.ToRawUuidString(uuid));
  122. if (row != null)
  123. {
  124. user.CurrentAgent = buildUserAgent(row);
  125. }
  126. return user;
  127. }
  128. else
  129. {
  130. return null;
  131. }
  132. }
  133. }
  134. /// <summary>
  135. /// see IUserData,
  136. /// Get user data profile by name
  137. /// </summary>
  138. /// <param name="fname">first name</param>
  139. /// <param name="lname">last name</param>
  140. /// <returns>user profile data</returns>
  141. override public UserProfileData GetUserByName(string fname, string lname)
  142. {
  143. string select = "surname = '" + lname + "' and username = '" + fname + "'";
  144. lock (ds)
  145. {
  146. DataRow[] rows = ds.Tables["users"].Select(select);
  147. if (rows.Length > 0)
  148. {
  149. UserProfileData user = buildUserProfile(rows[0]);
  150. DataRow row = ds.Tables["useragents"].Rows.Find(Util.ToRawUuidString(user.ID));
  151. if (row != null)
  152. {
  153. user.CurrentAgent = buildUserAgent(row);
  154. }
  155. return user;
  156. }
  157. else
  158. {
  159. return null;
  160. }
  161. }
  162. }
  163. #region User Friends List Data
  164. /// <summary>
  165. /// Add a new friend in the friendlist
  166. /// </summary>
  167. /// <param name="friendlistowner">UUID of the friendlist owner</param>
  168. /// <param name="friend">UUID of the friend to add</param>
  169. /// <param name="perms">permission flag</param>
  170. override public void AddNewUserFriend(LLUUID friendlistowner, LLUUID friend, uint perms)
  171. {
  172. string InsertFriends = "insert into userfriends(ownerID, friendID, friendPerms) values(:ownerID, :friendID, :perms)";
  173. using (SqliteCommand cmd = new SqliteCommand(InsertFriends, g_conn))
  174. {
  175. cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
  176. cmd.Parameters.Add(new SqliteParameter(":friendID", friend.UUID.ToString()));
  177. cmd.Parameters.Add(new SqliteParameter(":perms", perms));
  178. cmd.ExecuteNonQuery();
  179. }
  180. using (SqliteCommand cmd = new SqliteCommand(InsertFriends, g_conn))
  181. {
  182. cmd.Parameters.Add(new SqliteParameter(":ownerID", friend.UUID.ToString()));
  183. cmd.Parameters.Add(new SqliteParameter(":friendID", friendlistowner.UUID.ToString()));
  184. cmd.Parameters.Add(new SqliteParameter(":perms", perms));
  185. cmd.ExecuteNonQuery();
  186. }
  187. }
  188. /// <summary>
  189. /// Remove a user from the friendlist
  190. /// </summary>
  191. /// <param name="friendlistowner">UUID of the friendlist owner</param>
  192. /// <param name="friend">UUID of the friend to remove</param>
  193. override public void RemoveUserFriend(LLUUID friendlistowner, LLUUID friend)
  194. {
  195. string DeletePerms = "delete from friendlist where (ownerID=:ownerID and friendID=:friendID) or (ownerID=:friendID and friendID=:ownerID)";
  196. using (SqliteCommand cmd = new SqliteCommand(DeletePerms, g_conn))
  197. {
  198. cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
  199. cmd.Parameters.Add(new SqliteParameter(":friendID", friend.UUID.ToString()));
  200. cmd.ExecuteNonQuery();
  201. }
  202. }
  203. /// <summary>
  204. /// Update the friendlist permission
  205. /// </summary>
  206. /// <param name="friendlistowner">UUID of the friendlist owner</param>
  207. /// <param name="friend">UUID of the friend to modify</param>
  208. /// <param name="perms">updated permission flag</param>
  209. override public void UpdateUserFriendPerms(LLUUID friendlistowner, LLUUID friend, uint perms)
  210. {
  211. string UpdatePerms = "update friendlist set perms=:perms where ownerID=:ownerID and friendID=:friendID";
  212. using (SqliteCommand cmd = new SqliteCommand(UpdatePerms, g_conn))
  213. {
  214. cmd.Parameters.Add(new SqliteParameter(":perms", perms));
  215. cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
  216. cmd.Parameters.Add(new SqliteParameter(":friendID", friend.UUID.ToString()));
  217. cmd.ExecuteNonQuery();
  218. }
  219. }
  220. /// <summary>
  221. /// Get (fetch?) the friendlist for a user
  222. /// </summary>
  223. /// <param name="friendlistowner">UUID of the friendlist owner</param>
  224. /// <returns>The friendlist list</returns>
  225. override public List<FriendListItem> GetUserFriendList(LLUUID friendlistowner)
  226. {
  227. List<FriendListItem> returnlist = new List<FriendListItem>();
  228. using (SqliteCommand cmd = new SqliteCommand(SelectFriendsByUUID, g_conn))
  229. {
  230. cmd.Parameters.Add(new SqliteParameter(":ownerID", friendlistowner.UUID.ToString()));
  231. try
  232. {
  233. using (IDataReader reader = cmd.ExecuteReader())
  234. {
  235. while (reader.Read())
  236. {
  237. FriendListItem user = new FriendListItem();
  238. user.FriendListOwner = friendlistowner;
  239. user.Friend = new LLUUID((string)reader[0]);
  240. user.FriendPerms = Convert.ToUInt32(reader[1]);
  241. user.FriendListOwnerPerms = Convert.ToUInt32(reader[2]);
  242. returnlist.Add(user);
  243. }
  244. reader.Close();
  245. }
  246. }
  247. catch (Exception ex)
  248. {
  249. m_log.Error("[USER DB]: Exception getting friends list for user: " + ex.ToString());
  250. }
  251. }
  252. return returnlist;
  253. }
  254. #endregion
  255. /// <summary>
  256. /// STUB, Update the user's current region
  257. /// </summary>
  258. /// <param name="avatarid">UUID of the user</param>
  259. /// <param name="regionuuid">UUID of the region</param>
  260. /// <param name="regionhandle">region handle</param>
  261. /// <remarks>DO NOTHING</remarks>
  262. override public void UpdateUserCurrentRegion(LLUUID avatarid, LLUUID regionuuid, ulong regionhandle)
  263. {
  264. //m_log.Info("[USER DB]: Stub UpdateUserCUrrentRegion called");
  265. }
  266. /// <summary>
  267. ///
  268. /// </summary>
  269. /// <param name="queryID"></param>
  270. /// <param name="query"></param>
  271. /// <returns></returns>
  272. override public List<AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query)
  273. {
  274. List<AvatarPickerAvatar> returnlist = new List<AvatarPickerAvatar>();
  275. string[] querysplit;
  276. querysplit = query.Split(' ');
  277. if (querysplit.Length == 2)
  278. {
  279. using (SqliteCommand cmd = new SqliteCommand(AvatarPickerAndSQL, g_conn))
  280. {
  281. cmd.Parameters.Add(new SqliteParameter(":username", querysplit[0] + "%"));
  282. cmd.Parameters.Add(new SqliteParameter(":surname", querysplit[1] + "%"));
  283. using (IDataReader reader = cmd.ExecuteReader())
  284. {
  285. while (reader.Read())
  286. {
  287. AvatarPickerAvatar user = new AvatarPickerAvatar();
  288. user.AvatarID = new LLUUID((string) reader["UUID"]);
  289. user.firstName = (string) reader["username"];
  290. user.lastName = (string) reader["surname"];
  291. returnlist.Add(user);
  292. }
  293. reader.Close();
  294. }
  295. }
  296. }
  297. else if (querysplit.Length == 1)
  298. {
  299. using (SqliteCommand cmd = new SqliteCommand(AvatarPickerOrSQL, g_conn))
  300. {
  301. cmd.Parameters.Add(new SqliteParameter(":username", querysplit[0] + "%"));
  302. cmd.Parameters.Add(new SqliteParameter(":surname", querysplit[0] + "%"));
  303. using (IDataReader reader = cmd.ExecuteReader())
  304. {
  305. while (reader.Read())
  306. {
  307. AvatarPickerAvatar user = new AvatarPickerAvatar();
  308. user.AvatarID = new LLUUID((string) reader["UUID"]);
  309. user.firstName = (string) reader["username"];
  310. user.lastName = (string) reader["surname"];
  311. returnlist.Add(user);
  312. }
  313. reader.Close();
  314. }
  315. }
  316. }
  317. return returnlist;
  318. }
  319. /// <summary>
  320. /// Returns a user by UUID direct
  321. /// </summary>
  322. /// <param name="uuid">The user's account ID</param>
  323. /// <returns>A matching user profile</returns>
  324. override public UserAgentData GetAgentByUUID(LLUUID uuid)
  325. {
  326. try
  327. {
  328. return GetUserByUUID(uuid).CurrentAgent;
  329. }
  330. catch (Exception)
  331. {
  332. return null;
  333. }
  334. }
  335. /// <summary>
  336. /// Returns a session by account name
  337. /// </summary>
  338. /// <param name="name">The account name</param>
  339. /// <returns>The user's session agent</returns>
  340. override public UserAgentData GetAgentByName(string name)
  341. {
  342. return GetAgentByName(name.Split(' ')[0], name.Split(' ')[1]);
  343. }
  344. /// <summary>
  345. /// Returns a session by account name
  346. /// </summary>
  347. /// <param name="fname">The first part of the user's account name</param>
  348. /// <param name="lname">The second part of the user's account name</param>
  349. /// <returns>A user agent</returns>
  350. override public UserAgentData GetAgentByName(string fname, string lname)
  351. {
  352. try
  353. {
  354. return GetUserByName(fname, lname).CurrentAgent;
  355. }
  356. catch (Exception)
  357. {
  358. return null;
  359. }
  360. }
  361. /// <summary>
  362. /// DEPRECATED? Store the weblogin key
  363. /// </summary>
  364. /// <param name="AgentID">UUID of the user</param>
  365. /// <param name="WebLoginKey">UUID of the weblogin</param>
  366. override public void StoreWebLoginKey(LLUUID AgentID, LLUUID WebLoginKey)
  367. {
  368. DataTable users = ds.Tables["users"];
  369. lock (ds)
  370. {
  371. DataRow row = users.Rows.Find(Util.ToRawUuidString(AgentID));
  372. if (row == null)
  373. {
  374. m_log.Warn("[USER DB]: Unable to store new web login key for non-existant user");
  375. }
  376. else
  377. {
  378. UserProfileData user = GetUserByUUID(AgentID);
  379. user.WebLoginKey = WebLoginKey;
  380. fillUserRow(row, user);
  381. da.Update(ds, "users");
  382. }
  383. }
  384. }
  385. /// <summary>
  386. /// Creates a new user profile
  387. /// </summary>
  388. /// <param name="user">The profile to add to the database</param>
  389. override public void AddNewUserProfile(UserProfileData user)
  390. {
  391. DataTable users = ds.Tables["users"];
  392. lock (ds)
  393. {
  394. DataRow row = users.Rows.Find(Util.ToRawUuidString(user.ID));
  395. if (row == null)
  396. {
  397. row = users.NewRow();
  398. fillUserRow(row, user);
  399. users.Rows.Add(row);
  400. }
  401. else
  402. {
  403. fillUserRow(row, user);
  404. }
  405. // This is why we're getting the 'logins never log-off'.. because It isn't clearing the
  406. // useragents table once the useragent is null
  407. //
  408. // A database guy should look at this and figure out the best way to clear the useragents table.
  409. if (user.CurrentAgent != null)
  410. {
  411. DataTable ua = ds.Tables["useragents"];
  412. row = ua.Rows.Find(Util.ToRawUuidString(user.ID));
  413. if (row == null)
  414. {
  415. row = ua.NewRow();
  416. fillUserAgentRow(row, user.CurrentAgent);
  417. ua.Rows.Add(row);
  418. }
  419. else
  420. {
  421. fillUserAgentRow(row, user.CurrentAgent);
  422. }
  423. }
  424. else
  425. {
  426. // I just added this to help the standalone login situation.
  427. //It still needs to be looked at by a Database guy
  428. DataTable ua = ds.Tables["useragents"];
  429. row = ua.Rows.Find(Util.ToRawUuidString(user.ID));
  430. if (row == null)
  431. {
  432. // do nothing
  433. }
  434. else
  435. {
  436. row.Delete();
  437. ua.AcceptChanges();
  438. }
  439. }
  440. m_log.Info("[USER DB]: " +
  441. "Syncing user database: " + ds.Tables["users"].Rows.Count + " users stored");
  442. // save changes off to disk
  443. da.Update(ds, "users");
  444. }
  445. }
  446. /// <summary>
  447. /// Creates a new user profile
  448. /// </summary>
  449. /// <param name="user">The profile to add to the database</param>
  450. /// <returns>True on success, false on error</returns>
  451. override public bool UpdateUserProfile(UserProfileData user)
  452. {
  453. try
  454. {
  455. AddNewUserProfile(user);
  456. return true;
  457. }
  458. catch (Exception)
  459. {
  460. return false;
  461. }
  462. }
  463. /// <summary>
  464. /// Creates a new user agent
  465. /// </summary>
  466. /// <param name="agent">The agent to add to the database</param>
  467. override public void AddNewUserAgent(UserAgentData agent)
  468. {
  469. // Do nothing. yet.
  470. }
  471. /// <summary>
  472. /// Transfers money between two user accounts
  473. /// </summary>
  474. /// <param name="from">Starting account</param>
  475. /// <param name="to">End account</param>
  476. /// <param name="amount">The amount to move</param>
  477. /// <returns>Success?</returns>
  478. override public bool MoneyTransferRequest(LLUUID from, LLUUID to, uint amount)
  479. {
  480. return true;
  481. }
  482. /// <summary>
  483. /// Transfers inventory between two accounts
  484. /// </summary>
  485. /// <remarks>Move to inventory server</remarks>
  486. /// <param name="from">Senders account</param>
  487. /// <param name="to">Receivers account</param>
  488. /// <param name="item">Inventory item</param>
  489. /// <returns>Success?</returns>
  490. override public bool InventoryTransferRequest(LLUUID from, LLUUID to, LLUUID item)
  491. {
  492. return true;
  493. }
  494. /// <summary>
  495. /// Appearance.
  496. /// TODO: stubs for now to do in memory appearance.
  497. /// </summary>
  498. /// <param name="user">The user UUID</param>
  499. /// <returns>Avatar Appearence</returns>
  500. override public AvatarAppearance GetUserAppearance(LLUUID user)
  501. {
  502. AvatarAppearance aa = null;
  503. try {
  504. aa = aplist[user];
  505. m_log.Info("[APPEARANCE] Found appearance for " + user.ToString() + aa.ToString());
  506. } catch (System.Collections.Generic.KeyNotFoundException) {
  507. m_log.InfoFormat("[APPEARANCE] No appearance found for {0}", user.ToString());
  508. }
  509. return aa;
  510. }
  511. /// <summary>
  512. /// Update a user appearence
  513. /// </summary>
  514. /// <param name="user">the user UUID</param>
  515. /// <param name="appearance">appearence</param>
  516. override public void UpdateUserAppearance(LLUUID user, AvatarAppearance appearance)
  517. {
  518. appearance.Owner = user;
  519. aplist[user] = appearance;
  520. }
  521. /// <summary>
  522. /// Add an attachment item to an avatar
  523. /// </summary>
  524. /// <param name="user">the user UUID</param>
  525. /// <param name="item">the item UUID</param>
  526. /// <remarks>DO NOTHING ?</remarks>
  527. override public void AddAttachment(LLUUID user, LLUUID item)
  528. {
  529. return;
  530. }
  531. /// <summary>
  532. /// Remove an attachement item from an avatar
  533. /// </summary>
  534. /// <param name="user">the user UUID</param>
  535. /// <param name="item">the item UUID</param>
  536. /// <remarks>DO NOTHING ?</remarks>
  537. override public void RemoveAttachment(LLUUID user, LLUUID item)
  538. {
  539. return;
  540. }
  541. /// <summary>
  542. /// Get list of attached item
  543. /// </summary>
  544. /// <param name="user">the user UUID</param>
  545. /// <returns>List of attached item</returns>
  546. /// <remarks>DO NOTHING ?</remarks>
  547. override public List<LLUUID> GetAttachments(LLUUID user)
  548. {
  549. return new List<LLUUID>();
  550. }
  551. /// <summary>
  552. /// Returns the name of the storage provider
  553. /// </summary>
  554. /// <returns>Storage provider name</returns>
  555. override public string Name
  556. {
  557. get {return "Sqlite Userdata";}
  558. }
  559. /// <summary>
  560. /// Returns the version of the storage provider
  561. /// </summary>
  562. /// <returns>Storage provider version</returns>
  563. override public string Version
  564. {
  565. get {return "0.1";}
  566. }
  567. /***********************************************************************
  568. *
  569. * DataTable creation
  570. *
  571. **********************************************************************/
  572. /***********************************************************************
  573. *
  574. * Database Definition Functions
  575. *
  576. * This should be db agnostic as we define them in ADO.NET terms
  577. *
  578. **********************************************************************/
  579. /// <summary>
  580. /// Create the "users" table
  581. /// </summary>
  582. /// <returns>DataTable</returns>
  583. private static DataTable createUsersTable()
  584. {
  585. DataTable users = new DataTable("users");
  586. SQLiteUtil.createCol(users, "UUID", typeof (String));
  587. SQLiteUtil.createCol(users, "username", typeof (String));
  588. SQLiteUtil.createCol(users, "surname", typeof (String));
  589. SQLiteUtil.createCol(users, "passwordHash", typeof (String));
  590. SQLiteUtil.createCol(users, "passwordSalt", typeof (String));
  591. SQLiteUtil.createCol(users, "homeRegionX", typeof (Int32));
  592. SQLiteUtil.createCol(users, "homeRegionY", typeof (Int32));
  593. SQLiteUtil.createCol(users, "homeLocationX", typeof (Double));
  594. SQLiteUtil.createCol(users, "homeLocationY", typeof (Double));
  595. SQLiteUtil.createCol(users, "homeLocationZ", typeof (Double));
  596. SQLiteUtil.createCol(users, "homeLookAtX", typeof (Double));
  597. SQLiteUtil.createCol(users, "homeLookAtY", typeof (Double));
  598. SQLiteUtil.createCol(users, "homeLookAtZ", typeof (Double));
  599. SQLiteUtil.createCol(users, "created", typeof (Int32));
  600. SQLiteUtil.createCol(users, "lastLogin", typeof (Int32));
  601. SQLiteUtil.createCol(users, "rootInventoryFolderID", typeof (String));
  602. SQLiteUtil.createCol(users, "userInventoryURI", typeof (String));
  603. SQLiteUtil.createCol(users, "userAssetURI", typeof (String));
  604. SQLiteUtil.createCol(users, "profileCanDoMask", typeof (Int32));
  605. SQLiteUtil.createCol(users, "profileWantDoMask", typeof (Int32));
  606. SQLiteUtil.createCol(users, "profileAboutText", typeof (String));
  607. SQLiteUtil.createCol(users, "profileFirstText", typeof (String));
  608. SQLiteUtil.createCol(users, "profileImage", typeof (String));
  609. SQLiteUtil.createCol(users, "profileFirstImage", typeof (String));
  610. SQLiteUtil.createCol(users, "webLoginKey", typeof(String));
  611. // Add in contraints
  612. users.PrimaryKey = new DataColumn[] {users.Columns["UUID"]};
  613. return users;
  614. }
  615. /// <summary>
  616. /// Create the "useragents" table
  617. /// </summary>
  618. /// <returns>Data Table</returns>
  619. private static DataTable createUserAgentsTable()
  620. {
  621. DataTable ua = new DataTable("useragents");
  622. // this is the UUID of the user
  623. SQLiteUtil.createCol(ua, "UUID", typeof (String));
  624. SQLiteUtil.createCol(ua, "agentIP", typeof (String));
  625. SQLiteUtil.createCol(ua, "agentPort", typeof (Int32));
  626. SQLiteUtil.createCol(ua, "agentOnline", typeof (Boolean));
  627. SQLiteUtil.createCol(ua, "sessionID", typeof (String));
  628. SQLiteUtil.createCol(ua, "secureSessionID", typeof (String));
  629. SQLiteUtil.createCol(ua, "regionID", typeof (String));
  630. SQLiteUtil.createCol(ua, "loginTime", typeof (Int32));
  631. SQLiteUtil.createCol(ua, "logoutTime", typeof (Int32));
  632. SQLiteUtil.createCol(ua, "currentRegion", typeof (String));
  633. SQLiteUtil.createCol(ua, "currentHandle", typeof (String));
  634. // vectors
  635. SQLiteUtil.createCol(ua, "currentPosX", typeof (Double));
  636. SQLiteUtil.createCol(ua, "currentPosY", typeof (Double));
  637. SQLiteUtil.createCol(ua, "currentPosZ", typeof (Double));
  638. // constraints
  639. ua.PrimaryKey = new DataColumn[] {ua.Columns["UUID"]};
  640. return ua;
  641. }
  642. /// <summary>
  643. /// Create the "userfriends" table
  644. /// </summary>
  645. /// <returns>Data Table</returns>
  646. private static DataTable createUserFriendsTable()
  647. {
  648. DataTable ua = new DataTable("userfriends");
  649. // table contains user <----> user relationship with perms
  650. SQLiteUtil.createCol(ua, "ownerID", typeof(String));
  651. SQLiteUtil.createCol(ua, "friendID", typeof(String));
  652. SQLiteUtil.createCol(ua, "friendPerms", typeof(Int32));
  653. SQLiteUtil.createCol(ua, "ownerPerms", typeof(Int32));
  654. SQLiteUtil.createCol(ua, "datetimestamp", typeof(Int32));
  655. return ua;
  656. }
  657. /***********************************************************************
  658. *
  659. * Convert between ADO.NET <=> OpenSim Objects
  660. *
  661. * These should be database independant
  662. *
  663. **********************************************************************/
  664. /// <summary>
  665. /// TODO: this doesn't work yet because something more
  666. /// interesting has to be done to actually get these values
  667. /// back out. Not enough time to figure it out yet.
  668. /// </summary>
  669. /// <param name="row"></param>
  670. /// <returns></returns>
  671. private static UserProfileData buildUserProfile(DataRow row)
  672. {
  673. UserProfileData user = new UserProfileData();
  674. LLUUID tmp;
  675. LLUUID.TryParse((String)row["UUID"], out tmp);
  676. user.ID = tmp;
  677. user.FirstName = (String) row["username"];
  678. user.SurName = (String) row["surname"];
  679. user.PasswordHash = (String) row["passwordHash"];
  680. user.PasswordSalt = (String) row["passwordSalt"];
  681. user.HomeRegionX = Convert.ToUInt32(row["homeRegionX"]);
  682. user.HomeRegionY = Convert.ToUInt32(row["homeRegionY"]);
  683. user.HomeLocation = new LLVector3(
  684. Convert.ToSingle(row["homeLocationX"]),
  685. Convert.ToSingle(row["homeLocationY"]),
  686. Convert.ToSingle(row["homeLocationZ"])
  687. );
  688. user.HomeLookAt = new LLVector3(
  689. Convert.ToSingle(row["homeLookAtX"]),
  690. Convert.ToSingle(row["homeLookAtY"]),
  691. Convert.ToSingle(row["homeLookAtZ"])
  692. );
  693. user.Created = Convert.ToInt32(row["created"]);
  694. user.LastLogin = Convert.ToInt32(row["lastLogin"]);
  695. user.RootInventoryFolderID = new LLUUID((String) row["rootInventoryFolderID"]);
  696. user.UserInventoryURI = (String) row["userInventoryURI"];
  697. user.UserAssetURI = (String) row["userAssetURI"];
  698. user.CanDoMask = Convert.ToUInt32(row["profileCanDoMask"]);
  699. user.WantDoMask = Convert.ToUInt32(row["profileWantDoMask"]);
  700. user.AboutText = (String) row["profileAboutText"];
  701. user.FirstLifeAboutText = (String) row["profileFirstText"];
  702. LLUUID.TryParse((String)row["profileImage"], out tmp);
  703. user.Image = tmp;
  704. LLUUID.TryParse((String)row["profileFirstImage"], out tmp);
  705. user.FirstLifeImage = tmp;
  706. user.WebLoginKey = new LLUUID((String) row["webLoginKey"]);
  707. return user;
  708. }
  709. /// <summary>
  710. ///
  711. /// </summary>
  712. /// <param name="row"></param>
  713. /// <param name="user"></param>
  714. private void fillUserRow(DataRow row, UserProfileData user)
  715. {
  716. row["UUID"] = Util.ToRawUuidString(user.ID);
  717. row["username"] = user.FirstName;
  718. row["surname"] = user.SurName;
  719. row["passwordHash"] = user.PasswordHash;
  720. row["passwordSalt"] = user.PasswordSalt;
  721. row["homeRegionX"] = user.HomeRegionX;
  722. row["homeRegionY"] = user.HomeRegionY;
  723. row["homeLocationX"] = user.HomeLocation.X;
  724. row["homeLocationY"] = user.HomeLocation.Y;
  725. row["homeLocationZ"] = user.HomeLocation.Z;
  726. row["homeLookAtX"] = user.HomeLookAt.X;
  727. row["homeLookAtY"] = user.HomeLookAt.Y;
  728. row["homeLookAtZ"] = user.HomeLookAt.Z;
  729. row["created"] = user.Created;
  730. row["lastLogin"] = user.LastLogin;
  731. row["rootInventoryFolderID"] = user.RootInventoryFolderID;
  732. row["userInventoryURI"] = user.UserInventoryURI;
  733. row["userAssetURI"] = user.UserAssetURI;
  734. row["profileCanDoMask"] = user.CanDoMask;
  735. row["profileWantDoMask"] = user.WantDoMask;
  736. row["profileAboutText"] = user.AboutText;
  737. row["profileFirstText"] = user.FirstLifeAboutText;
  738. row["profileImage"] = user.Image;
  739. row["profileFirstImage"] = user.FirstLifeImage;
  740. row["webLoginKey"] = user.WebLoginKey;
  741. // ADO.NET doesn't handle NULL very well
  742. foreach (DataColumn col in ds.Tables["users"].Columns)
  743. {
  744. if (row[col] == null)
  745. {
  746. row[col] = String.Empty;
  747. }
  748. }
  749. }
  750. /// <summary>
  751. ///
  752. /// </summary>
  753. /// <param name="row"></param>
  754. /// <returns></returns>
  755. private static UserAgentData buildUserAgent(DataRow row)
  756. {
  757. UserAgentData ua = new UserAgentData();
  758. ua.ProfileID = new LLUUID((String) row["UUID"]);
  759. ua.AgentIP = (String) row["agentIP"];
  760. ua.AgentPort = Convert.ToUInt32(row["agentPort"]);
  761. ua.AgentOnline = Convert.ToBoolean(row["agentOnline"]);
  762. ua.SessionID = new LLUUID((String) row["sessionID"]);
  763. ua.SecureSessionID = new LLUUID((String) row["secureSessionID"]);
  764. ua.InitialRegion = new LLUUID((String) row["regionID"]);
  765. ua.LoginTime = Convert.ToInt32(row["loginTime"]);
  766. ua.LogoutTime = Convert.ToInt32(row["logoutTime"]);
  767. ua.Region = new LLUUID((String) row["currentRegion"]);
  768. ua.Handle = Convert.ToUInt64(row["currentHandle"]);
  769. ua.Position = new LLVector3(
  770. Convert.ToSingle(row["currentPosX"]),
  771. Convert.ToSingle(row["currentPosY"]),
  772. Convert.ToSingle(row["currentPosZ"])
  773. );
  774. return ua;
  775. }
  776. /// <summary>
  777. ///
  778. /// </summary>
  779. /// <param name="row"></param>
  780. /// <param name="ua"></param>
  781. private static void fillUserAgentRow(DataRow row, UserAgentData ua)
  782. {
  783. row["UUID"] = ua.ProfileID;
  784. row["agentIP"] = ua.AgentIP;
  785. row["agentPort"] = ua.AgentPort;
  786. row["agentOnline"] = ua.AgentOnline;
  787. row["sessionID"] = ua.SessionID;
  788. row["secureSessionID"] = ua.SecureSessionID;
  789. row["regionID"] = ua.InitialRegion;
  790. row["loginTime"] = ua.LoginTime;
  791. row["logoutTime"] = ua.LogoutTime;
  792. row["currentRegion"] = ua.Region;
  793. row["currentHandle"] = ua.Handle.ToString();
  794. // vectors
  795. row["currentPosX"] = ua.Position.X;
  796. row["currentPosY"] = ua.Position.Y;
  797. row["currentPosZ"] = ua.Position.Z;
  798. }
  799. /***********************************************************************
  800. *
  801. * Database Binding functions
  802. *
  803. * These will be db specific due to typing, and minor differences
  804. * in databases.
  805. *
  806. **********************************************************************/
  807. /// <summary>
  808. ///
  809. /// </summary>
  810. /// <param name="da"></param>
  811. /// <param name="conn"></param>
  812. private void setupUserCommands(SqliteDataAdapter da, SqliteConnection conn)
  813. {
  814. da.InsertCommand = SQLiteUtil.createInsertCommand("users", ds.Tables["users"]);
  815. da.InsertCommand.Connection = conn;
  816. da.UpdateCommand = SQLiteUtil.createUpdateCommand("users", "UUID=:UUID", ds.Tables["users"]);
  817. da.UpdateCommand.Connection = conn;
  818. SqliteCommand delete = new SqliteCommand("delete from users where UUID = :UUID");
  819. delete.Parameters.Add(SQLiteUtil.createSqliteParameter("UUID", typeof(String)));
  820. delete.Connection = conn;
  821. da.DeleteCommand = delete;
  822. }
  823. /// <summary>
  824. ///
  825. /// </summary>
  826. /// <param name="daf"></param>
  827. /// <param name="conn"></param>
  828. private void setupUserFriendsCommands(SqliteDataAdapter daf, SqliteConnection conn)
  829. {
  830. daf.InsertCommand = SQLiteUtil.createInsertCommand("userfriends", ds.Tables["userfriends"]);
  831. daf.InsertCommand.Connection = conn;
  832. daf.UpdateCommand = SQLiteUtil.createUpdateCommand("userfriends", "ownerID=:ownerID and friendID=:friendID", ds.Tables["userfriends"]);
  833. daf.UpdateCommand.Connection = conn;
  834. SqliteCommand delete = new SqliteCommand("delete from userfriends where ownerID=:ownerID and friendID=:friendID");
  835. delete.Parameters.Add(SQLiteUtil.createSqliteParameter("ownerID", typeof(String)));
  836. delete.Parameters.Add(SQLiteUtil.createSqliteParameter("friendID", typeof(String)));
  837. delete.Connection = conn;
  838. daf.DeleteCommand = delete;
  839. }
  840. /// <summary>
  841. ///
  842. /// </summary>
  843. /// <param name="conn"></param>
  844. private static void InitDB(SqliteConnection conn)
  845. {
  846. string createUsers = SQLiteUtil.defineTable(createUsersTable());
  847. string createFriends = SQLiteUtil.defineTable(createUserFriendsTable());
  848. SqliteCommand pcmd = new SqliteCommand(createUsers, conn);
  849. SqliteCommand fcmd = new SqliteCommand(createFriends, conn);
  850. conn.Open();
  851. try
  852. {
  853. pcmd.ExecuteNonQuery();
  854. }
  855. catch (Exception)
  856. {
  857. m_log.Info("[USER DB]: users table already exists");
  858. }
  859. try
  860. {
  861. fcmd.ExecuteNonQuery();
  862. }
  863. catch (Exception)
  864. {
  865. m_log.Info("[USER DB]: userfriends table already exists");
  866. }
  867. conn.Close();
  868. }
  869. /// <summary>
  870. ///
  871. /// </summary>
  872. /// <param name="conn"></param>
  873. /// <param name="m"></param>
  874. /// <returns></returns>
  875. private static bool TestTables(SqliteConnection conn, Migration m)
  876. {
  877. SqliteCommand cmd = new SqliteCommand(userSelect, conn);
  878. // SqliteCommand fcmd = new SqliteCommand(userFriendsSelect, conn);
  879. SqliteDataAdapter pDa = new SqliteDataAdapter(cmd);
  880. SqliteDataAdapter fDa = new SqliteDataAdapter(cmd);
  881. DataSet tmpDS = new DataSet();
  882. DataSet tmpDS2 = new DataSet();
  883. try
  884. {
  885. pDa.Fill(tmpDS, "users");
  886. fDa.Fill(tmpDS2, "userfriends");
  887. }
  888. catch (SqliteSyntaxException)
  889. {
  890. m_log.Info("[USER DB]: SQLite Database doesn't exist... creating");
  891. return false;
  892. }
  893. if (m.Version == 0)
  894. m.Version = 1;
  895. return true;
  896. // conn.Open();
  897. // try
  898. // {
  899. // cmd = new SqliteCommand("select webLoginKey from users limit 1;", conn);
  900. // cmd.ExecuteNonQuery();
  901. // }
  902. // catch (SqliteSyntaxException)
  903. // {
  904. // cmd = new SqliteCommand("alter table users add column webLoginKey text default '00000000-0000-0000-0000-000000000000';", conn);
  905. // cmd.ExecuteNonQuery();
  906. // pDa.Fill(tmpDS, "users");
  907. // }
  908. // finally
  909. // {
  910. // conn.Close();
  911. // }
  912. // return true;
  913. }
  914. }
  915. }