SQLiteUserData.cs 42 KB

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