SQLiteUserData.cs 35 KB

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