diff --git a/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/IMoneyManager.cs b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/IMoneyManager.cs new file mode 100644 index 0000000..f807ecb --- /dev/null +++ b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/IMoneyManager.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public interface IMoneyManager + { + int getBalance(string userID); + + //int getBalanceStatus(string userID); + + //bool updateBalanceStatus(string userID,int status); + + bool withdrawMoney(UUID transactionID, string senderID, int amount); + + bool giveMoney(UUID transactionID, string receiverID, int amount); + + bool addTransaction(TransactionData transaction); + + bool updateTransactionStatus(UUID transactionID, int status, string description); + + TransactionData FetchTransaction(UUID transactionID); + + TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index, uint retNum); + + int getTransactionNum(string userID, int startTime, int endTime); + + bool addUser(string userID, int balance, int status, int type); + + bool SetTransExpired(int deadTime); + + bool ValidateTransfer(string secureCode, UUID transactionID); + + bool addUserInfo(UserInfo user); + + UserInfo fetchUserInfo(string userID); + + bool updateUserInfo(UserInfo user); + + } +} diff --git a/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLMoneyManager.cs b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLMoneyManager.cs new file mode 100644 index 0000000..d260035 --- /dev/null +++ b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLMoneyManager.cs @@ -0,0 +1,1627 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Data; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using log4net; +using MySql.Data.MySqlClient; +using OpenMetaverse; + + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public class MySQLMoneyManager:IMoneyManager + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string Table_of_Balances = "balances"; + private string Table_of_Transactions = "transactions"; + private string Table_of_TotalSales = "totalsales"; + private string Table_of_UserInfo = "userinfo"; + private int balances_rev = 0; + private int userinfo_rev = 0; + + private string connectString; + private MySqlConnection dbcon; + + + public MySQLMoneyManager(string hostname,string database,string username ,string password,string cpooling, string port) + { + string s = "Server=" + hostname + ";Port=" + port + ";Database=" + database + + ";User ID=" + username + ";Password=" + password + ";Pooling=" + cpooling + ";"; + Initialise(s); + } + + + public MySQLMoneyManager(string connect) + { + Initialise(connect); + } + + + private void Initialise(string connect) + { + try { + connectString = connect; + dbcon = new MySqlConnection(connectString); + try { + dbcon.Open(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Connection error while using connection string ["+connectString+"]", e); + } + //m_log.Info("[MONEY MANAGER]: Connection established"); + } + + catch(Exception e) { + throw new Exception("[MONEY MANAGER]: Error initialising MySql Database: " + e.ToString()); + } + + try { + Dictionary tableList = new Dictionary(); + tableList = CheckTables(); + + // + // Balances Table + if (!tableList.ContainsKey(Table_of_Balances)) { + try { + CreateBalancesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating balances table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_Balances].Trim(); + int nVer = getTableVersionNum(version); + balances_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateBalancesTable1(); + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 2: //Rev.2 + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 3: //Rev.3 + UpdateBalancesTable3(); + break; + } + } + + // + // UserInfo Table + if (!tableList.ContainsKey(Table_of_UserInfo)) { + try { + CreateUserInfoTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating userinfo table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_UserInfo].Trim(); + int nVer = getTableVersionNum(version); + userinfo_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateUserInfoTable1(); + UpdateUserInfoTable2(); + break; + case 2: //Rev.2 + UpdateUserInfoTable2(); + break; + } + } + + // + // Transactions Table + if (!tableList.ContainsKey(Table_of_Transactions)) { + try { + CreateTransactionsTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating transactions table: " + e.ToString()); + } + } + // check transactions table version + else { + string version = tableList[Table_of_Transactions].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 2: //Rev.2 + UpdateTransactionsTable2(); + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 3: //Rev.3 + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 4: //Rev.4 + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 5: //Rev.5 + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 6: //Rev.6 + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 7: //Rev.7 + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 8: //Rev.8 + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 9: //Rev.9 + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 10: //Rev.10 + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 11: //Rev.11 + UpdateTransactionsTable11(); + break; + } + } + + // + // TotalSales Table + if (!tableList.ContainsKey(Table_of_TotalSales)) { + try { + CreateTotalSalesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating totalsales table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_TotalSales].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 1: //Rev.1 + UpdateTotalSalesTable1(); + UpdateTotalSalesTable2(); + break; + case 2: //Rev.2 + UpdateTotalSalesTable2(); + break; + } + } + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + throw new Exception("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + } + } + + + private int getTableVersionNum(string version) + { + int nVer = 0; + + Regex _commentPattenRegex = new Regex(@"\w+\.(?\d+)"); + Match m = _commentPattenRegex.Match(version); + if (m.Success) { + string ver = m.Groups["ver"].Value; + nVer = Convert.ToInt32(ver); + } + return nVer; + } + + + + /////////////////////////////////////////////////////////////////////// + // create Tables + + private void CreateBalancesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Balances + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`balance` int(10) NOT NULL,"; + sql += "`status` tinyint(2) DEFAULT NULL,"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.4';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateUserInfoTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_UserInfo + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`simip` varchar(64) NOT NULL,"; + sql += "`avatar` varchar(50) NOT NULL,"; + sql += "`pass` varchar(36) NOT NULL DEFAULT '',"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`class` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`serverurl` varchar(255) NOT NULL DEFAULT '',"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTransactionsTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Transactions + "`("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`sender` varchar(36) NOT NULL,"; + sql += "`receiver` varchar(36) NOT NULL,"; + sql += "`amount` int(10) NOT NULL,"; + sql += "`senderBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`receiverBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`objectUUID` varchar(36) DEFAULT NULL,"; + sql += "`objectName` varchar(255) DEFAULT NULL,"; + sql += "`regionHandle` varchar(36) NOT NULL,"; + sql += "`regionUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`time` int(11) NOT NULL,"; + sql += "`secure` varchar(36) NOT NULL,"; + sql += "`status` tinyint(1) NOT NULL,"; + sql += "`commonName` varchar(128) NOT NULL,"; + sql += "`description` varchar(255) DEFAULT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.12';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTotalSalesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_TotalSales + "` ("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`objectUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`TotalCount` int(10) NOT NULL DEFAULT 0,"; + sql += "`TotalAmount` int(10) NOT NULL DEFAULT 0,"; + sql += "`time` int(11) NOT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + initTotalSalesTable(); + } + + + + /////////////////////////////////////////////////////////////////////// + // update Balances Table + + private void UpdateBalancesTable1() + { + m_log.Info("[MONEY MANAGER]: Converting Balance Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Balances; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT * FROM " + Table_of_Balances; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i=0) { + amount += balance; + updatedb = updateBalance(uuid, amount); + } + else { + updatedb = addUser(uuid, amount, int.Parse(row[i,2]), 0); + } + if (!updatedb) break; + } + } + + // Delete + if (updatedb) { + for (int i=0; i uuid, url, name, pass + bool updatedb = true; + for (int i=0; i + /// update transactions table from Rev.2 to Rev.3 + /// + private void UpdateTransactionsTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`objectUUID` varchar(36) DEFAULT NULL AFTER `amount`),"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.3 to Rev.4 + /// + private void UpdateTransactionsTable3() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`secure` varchar(36) NOT NULL AFTER `time`),"; + sql += "COMMENT = 'Rev.4';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.4 to Rev.5 + /// + private void UpdateTransactionsTable4() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`regionHandle` varchar(36) NOT NULL AFTER `objectUUID`),"; + sql += "COMMENT = 'Rev.5';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.5 to Rev.6 + /// + private void UpdateTransactionsTable5() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`commonName` varchar(128) NOT NULL AFTER `status`),"; + sql += "COMMENT = 'Rev.6';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.6 to Rev.7 + /// + private void UpdateTransactionsTable6() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Transactions; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT UUID,sender,receiver FROM " + Table_of_Transactions; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i + /// update transactions table from Rev.7 to Rev.8 + /// + private void UpdateTransactionsTable7() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `objectName` varchar(255) DEFAULT NULL AFTER `objectUUID`,"; + sql += "COMMENT = 'Rev.8';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.8 to Rev.9 + /// + private void UpdateTransactionsTable8() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `senderBalance` int(10) NOT NULL DEFAULT -1 AFTER `amount`,"; + sql += "ADD `receiverBalance` int(10) NOT NULL DEFAULT -1 AFTER `senderBalance`,"; + sql += "COMMENT = 'Rev.9';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.9 to Rev.10 + /// + private void UpdateTransactionsTable9() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "MODIFY COLUMN `sender` varchar(36) NOT NULL,"; + sql += "MODIFY COLUMN `receiver` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.10';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.10 to Rev.11 + /// change type of BirthGift from 1000 to 900 + /// + private void UpdateTransactionsTable10() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM `" + Table_of_Transactions + "` WHERE type=1000"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + if (resultCount>0) { + sql = "SELECT UUID FROM `" + Table_of_Transactions + "` WHERE type=1000"; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[] row = new string[resultCount]; + while (dbReader.Read()) { + row[l] = dbReader.GetString(0); + l++; + } + dbReader.Close(); + cmd.Dispose(); + + sql = "UPDATE `" + Table_of_Transactions + "` SET type=900 WHERE UUID=?uuid"; + for (int i=0; i + /// update transactions table from Rev.11 to Rev.12 + /// + private void UpdateTransactionsTable11() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `regionUUID` varchar(36) NOT NULL AFTER `regionHandle`,"; + sql += "COMMENT = 'Rev.12';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + // update Total Sales Table + + private void UpdateTotalSalesTable1() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "ADD `time` int(11) NOT NULL AFTER `TotalAmount`,"; + sql += "COMMENT = 'Rev.2';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + deleteTotalSalesTable(); + initTotalSalesTable(); + } + + + private void UpdateTotalSalesTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "MODIFY COLUMN `user` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + // + + private Dictionary CheckTables() + { + Dictionary tableDic = new Dictionary(); + + lock (dbcon) { + string sql = string.Empty; + + sql = "SELECT TABLE_NAME,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?dbname"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?dbname", dbcon.Database); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + while (r.Read()) { + try { + string tableName = (string)r["TABLE_NAME"]; + string comment = (string)r["TABLE_COMMENT"]; + tableDic.Add(tableName, comment); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error checking tables" + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return tableDic; + } + } + + + /// + /// Reconnect to the database + /// + public void Reconnect() + { + m_log.Info("[MONEY MANAGER]: Reconnecting database"); + lock (dbcon) { + try { + dbcon.Close(); + dbcon = new MySqlConnection(connectString); + dbcon.Open(); + m_log.Info("[MONEY MANAGER]: Reconnected database"); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to reconnect to database: " + e.ToString()); + } + } + } + + + + /////////////////////////////////////////////////////////////////////// + // + // balances + // + + /// + /// Get balance from database. returns -1 if failed. + /// + /// + /// + public int getBalance(string userID) + { + if (userID==UUID.Zero.ToString()) return 999999999; // System + + int retValue = -1; + string sql = string.Empty; + + sql = "SELECT balance FROM " + Table_of_Balances + " WHERE user = ?userid"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userid", userID); + + using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { + try { + if (dbReader.Read()) { + retValue = Convert.ToInt32(dbReader["balance"]); + } + } +#pragma warning disable CS0168 // The variable 'e' is declared but never +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception e) { + m_log.ErrorFormat("[MoneyDB]: MySql failed to fetch balance {0}.", userID); + retValue = -2; + } +#pragma warning restore CA1031 // Do not catch general exception types +#pragma warning restore CS0168 // The variable 'e' is declared but never + + dbReader.Close(); + } + cmd.Dispose(); + + return retValue; + } + + + public bool updateBalance(string userID, int amount) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Balances + " SET balance = ?amount WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userID", userID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool addUser(string userID, int balance, int status, int type) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + if (balances_rev>=4) { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`,`type`) VALUES "; + sql += " (?userID,?balance,?status,?type);"; + } + else { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`) VALUES "; + sql += " (?userID,?balance,?status);"; + } + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userID", userID); + cmd.Parameters.AddWithValue("?balance", balance); + cmd.Parameters.AddWithValue("?status", status); + if (balances_rev>=4) { + cmd.Parameters.AddWithValue("?type", type); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + + return bRet; + } + + + /// + /// Here we'll make a withdraw from the sender and update transaction status + /// + /// + /// + /// + /// + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + bool bRet = false; + string sql = string.Empty; + MySqlCommand cmd = null; + + // System + if (senderID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET senderBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET senderBalance = balance - ?amount, "+ Table_of_Transactions + ".status = ?status, balance = balance - ?amount "; + sql += " WHERE UUID = ?tranid AND user = sender AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", senderID); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Give money to the receiver and change the transaction status to success. + /// + /// + /// + /// + /// + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + string sql = string.Empty; + bool bRet = false; + MySqlCommand cmd = null; + + // System + if (receiverID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET receiverBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET receiverBalance = balance + ?amount, " + Table_of_Transactions + ".status = ?status, balance = balance + ?amount "; + sql += " WHERE UUID = ?tranid AND user = receiver AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", receiverID); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // totalsales + // + private void initTotalSalesTable() + { + m_log.Info("[MONEY MANAGER]: Initailising TotalSales Table..."); + string sql = string.Empty; + + sql = "SELECT SQL_CALC_FOUND_ROWS receiver,objectUUID,type,COUNT(*),SUM(amount),MIN(time) FROM "+ Table_of_Transactions; + sql += " WHERE sender != receiver AND status = ?status AND sender != ?system"; + sql += " GROUP BY receiver,objectUUID,type;"; + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); + cmd.Parameters.AddWithValue("?system", UUID.Zero.ToString()); + cmd.ExecuteNonQuery(); + + MySqlCommand cmd2 = new MySqlCommand("SELECT FOUND_ROWS();", dbcon); + int lineCount = int.Parse(cmd2.ExecuteScalar().ToString()); + cmd2.Dispose(); + + if (lineCount<=0) { + cmd.Dispose(); + return; + } + + MySqlDataReader r = cmd.ExecuteReader(); + int l = 0; + string[,] row = new string[lineCount, r.FieldCount]; + while (r.Read()) { + for (int i=0; i 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTotalSale(UUID saleUUID, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_TotalSales; + sql += " SET TotalCount = TotalCount + ?count, TotalAmount = TotalAmount + ?amount, time = ?time "; + sql += " WHERE UUID = ?uuid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?uuid", saleUUID.ToString()); + cmd.Parameters.AddWithValue("?count", count); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?time", tmstamp); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + + } + + + public bool setTotalSale(string userUUID, string objectUUID, int type, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + string uuid = string.Empty; + int dbtm = 0; + + sql = "SELECT UUID,time FROM " + Table_of_TotalSales; + sql += " WHERE user = ?userid AND objectUUID = ?objID AND type = ?type;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userid", userUUID); + cmd.Parameters.AddWithValue("?objID", objectUUID); + cmd.Parameters.AddWithValue("?type", type); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + uuid = (string)r["UUID"]; + dbtm = Convert.ToInt32(r["time"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get sale data from DB failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return false; + } + } + r.Close(); + } + + if (uuid!=string.Empty) { + UUID saleUUID = UUID.Zero; + UUID.TryParse(uuid, out saleUUID); + if (dbtm 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions + " SET status = ?status,description = ?desc WHERE UUID = ?tranid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", status); + cmd.Parameters.AddWithValue("?desc", description); + cmd.Parameters.AddWithValue("?tranid", transactionID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool SetTransExpired(int deadTime) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions; + sql += " SET status = ?failedstatus,description = ?desc WHERE time <= ?deadTime AND status = ?pendingstatus;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?failedstatus", (int)Status.FAILED_STATUS); + cmd.Parameters.AddWithValue("?desc", "expired"); + cmd.Parameters.AddWithValue("?deadTime", deadTime); + cmd.Parameters.AddWithValue("?pendingstatus", (int)Status.PENDING_STATUS); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Validate if the transacion is legal + /// + /// + /// + /// + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + bool bRet = false; + string secure = string.Empty; + string sql = string.Empty; + + sql = "SELECT secure FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + secure = (string)r["secure"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get transaction from DB failed: " + e.ToString()); + } + if (secureCode == secure) bRet = true; + else bRet = false; + } + r.Close(); + } + + cmd.Dispose(); + return bRet; + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + TransactionData transactionData = new TransactionData(); + transactionData.TransUUID = transactionID; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 1: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + + } + r.Close(); + } + + cmd.Dispose(); + return transactionData; + } + + + public TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index, uint retNum) + { + List rows = new List(); + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user) ORDER BY time ASC LIMIT ?index,?num;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + cmd.Parameters.AddWithValue("?index", index); + cmd.Parameters.AddWithValue("?num", retNum); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + for (int i = 0; i < retNum; i++) { + if (r.Read()) { + try { + TransactionData transactionData = new TransactionData(); + string uuid = (string)r["UUID"]; + UUID transUUID; + UUID.TryParse(uuid,out transUUID); + + transactionData.TransUUID = transUUID; + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + // + rows.Add(transactionData); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 2: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + } + r.Close(); + } + + cmd.Dispose(); + return rows.ToArray(); + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + int iRet = -1; + string sql = string.Empty; + + sql = "SELECT COUNT(*) AS number FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user);"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + iRet = Convert.ToInt32(r["number"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to get transaction info: " + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return iRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // userinfo + // + public bool addUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Adding UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + if (userInfo.Avatar==null) return false; + + if (userinfo_rev>=3) { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`,`type`,`class`,`serverurl`) VALUES"; + sql += "(?user,?simip,?avatar,?password,?type,?class,?serverurl);"; + } + else { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`) VALUES"; + sql += "(?user,?simip,?avatar,?password);"; + } + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?avatar", userInfo.Avatar); + cmd.Parameters.AddWithValue("?password", userInfo.PswHash); + if (userinfo_rev>=3) { + cmd.Parameters.AddWithValue("?type", userInfo.Type); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + } + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public UserInfo fetchUserInfo(string userID) + { + //m_log.Error("[MONEY MANAGER]: Fetching UserInfo: " + userID); + + UserInfo userInfo = new UserInfo(); + userInfo.UserID = null; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_UserInfo + " WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userID", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + userInfo.UserID = (string)r["user"]; + userInfo.SimIP = (string)r["simip"]; + userInfo.Avatar = (string)r["avatar"]; + userInfo.PswHash = (string)r["pass"]; + userInfo.Type = Convert.ToInt32(r["type"]); + userInfo.Class = Convert.ToInt32(r["class"]); + userInfo.ServerURL = (string)r["serverurl"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching UserInfo failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + r.Close(); + } + cmd.Dispose(); + + if (userInfo.UserID!=userID) return null; + return userInfo; + } + + + public bool updateUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Updating UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_UserInfo + " SET simip=?simip,pass=?pass,class=?class,serverurl=?serverurl WHERE user=?user;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?pass", userInfo.PswHash); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + } +} diff --git a/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs new file mode 100644 index 0000000..26974c8 --- /dev/null +++ b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs @@ -0,0 +1,53 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + // This bit of code is from OpenSim.Data.MySQLSuperManager + public class MySQLSuperManager + { + public bool Locked; + private readonly Mutex m_lock = new Mutex(false); + public MySQLMoneyManager Manager; + public string Running; + + public void GetLock() + { + Locked = true; + m_lock.WaitOne(); + } + + public void Release() + { + m_lock.ReleaseMutex(); + Locked = false; + } + } +} diff --git a/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f4a2a82 --- /dev/null +++ b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("03f4a266-2e30-47e4-b785-ff02cdb4bbb9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs new file mode 100644 index 0000000..abb0fd1 --- /dev/null +++ b/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs @@ -0,0 +1,237 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public class TransactionData + { + UUID m_uuid; + string m_sender = string.Empty; + string m_receiver = string.Empty; + int m_amount; + int m_senderBalance; + int m_receiverBalance; + int m_type; + int m_time; + int m_status; + string m_objectID = UUID.Zero.ToString(); +// string m_objectID = "00000000-0000-0000-0000-000000000000"; + string m_objectName = string.Empty; + string m_regionHandle = string.Empty; + string m_regionUUID = string.Empty; + string m_secureCode = string.Empty; + string m_commonName = string.Empty; + string m_description = string.Empty; + +/* + public TransactionData(string uuid, string sender, string receiver, + int amount, int time, int status, string description) + { + this.m_uuid = uuid; + this.m_sender = sender; + this.m_receiver = receiver; + this.m_amount = amount; + } +*/ + + public UUID TransUUID + { + get { return m_uuid; } + set { m_uuid = value; } + } + + public string Sender + { + get { return m_sender; } + set { m_sender = value; } + } + + public string Receiver + { + get { return m_receiver; } + set { m_receiver = value; } + } + + public int Amount + { + get { return m_amount; } + set { m_amount = value; } + } + + public int SenderBalance + { + get { return m_senderBalance; } + set { m_senderBalance = value; } + } + + public int ReceiverBalance + { + get { return m_receiverBalance; } + set { m_receiverBalance = value; } + } + + public int Type + { + get { return m_type; } + set { m_type = value; } + } + + public int Time + { + get { return m_time; } + set { m_time = value; } + } + + public int Status + { + get { return m_status; } + set { m_status = value; } + } + + public string Description + { + get { return m_description; } + set { m_description = value; } + } + + public string ObjectUUID + { + get { return m_objectID; } + set { m_objectID = value; } + } + + public string ObjectName + { + get { return m_objectName; } + set { m_objectName = value; } + } + + public string RegionHandle + { + get { return m_regionHandle; } + set { m_regionHandle = value; } + } + + public string RegionUUID + { + get { return m_regionUUID; } + set { m_regionUUID = value; } + } + + public string SecureCode + { + get { return m_secureCode; } + set { m_secureCode = value; } + } + + public string CommonName + { + get { return m_commonName; } + set { m_commonName = value; } + } + } + + + public enum Status + { + SUCCESS_STATUS = 0, + PENDING_STATUS = 1, + FAILED_STATUS = 2, + ERROR_STATUS = 9 + } + + + public enum AvatarType + { + LOCAL_AVATAR = 0, + HG_AVATAR = 1, + NPC_AVATAR = 2, + GUEST_AVATAR = 3, + FOREIGN_AVATAR = 8, + UNKNOWN_AVATAR = 9 + } + + + public class UserInfo + { + string m_userID = string.Empty; + string m_simIP = string.Empty; + string m_avatarName = string.Empty; + string m_passwordHash = string.Empty; + int m_avatarType = (int)AvatarType.LOCAL_AVATAR; + int m_avatarClass = (int)AvatarType.LOCAL_AVATAR; + string m_serverURL = string.Empty; + + public string UserID + { + get { return m_userID; } + set { m_userID = value; } + } + + public string SimIP + { + get { return m_simIP; } + set { m_simIP = value; } + } + + public string Avatar + { + get { return m_avatarName; } + set { m_avatarName = value; } + } + + public string PswHash + { + get { return m_passwordHash; } + set { m_passwordHash = value; } + } + + public int Type + { + get { return m_avatarType; } + set { m_avatarType = value; } + } + + public int Class + { + get { return m_avatarClass; } + set { m_avatarClass = value; } + } + + public string ServerURL + { + get { return m_serverURL; } + set { m_serverURL = value; } + } + } +} diff --git a/OpenSim.Grid.MoneyServer/IMoneyDBService.cs b/OpenSim.Grid.MoneyServer/IMoneyDBService.cs new file mode 100644 index 0000000..2043719 --- /dev/null +++ b/OpenSim.Grid.MoneyServer/IMoneyDBService.cs @@ -0,0 +1,77 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma warning disable IDE1006 + +#pragma warning disable S1128 // Unused "using" should be removed +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +#pragma warning restore S1128 // Unused "using" should be removed + + +namespace OpenSim.Grid.MoneyServer +{ + /// + /// IMoney DB Service + /// + public interface IMoneyDBService + { + int getBalance(string userID); + + bool withdrawMoney(UUID transactionID, string senderID, int amount); + + bool giveMoney(UUID transactionID, string receiverID, int amount); + + bool addTransaction(TransactionData transaction); + + bool addUser(string userID, int balance, int status, int type); + + bool updateTransactionStatus(UUID transactionID, int status, string description); + + bool SetTransExpired(int deadTime); + + bool ValidateTransfer(string secureCode, UUID transactionID); + + TransactionData FetchTransaction(UUID transactionID); + + TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex); + + int getTransactionNum(string userID, int startTime, int endTime); + + bool DoTransfer(UUID transactionUUID); + + bool DoAddMoney(UUID transactionUUID); // Added by Fumi.Iseki + + bool TryAddUserInfo(UserInfo user); + + UserInfo FetchUserInfo(string userID); + + } +} diff --git a/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs b/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs new file mode 100644 index 0000000..7f84903 --- /dev/null +++ b/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; + +using Nini.Config; + + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyServiceCore + { + BaseHttpServer GetHttpServer(); + Dictionary GetSessionDic(); + Dictionary GetSecureSessionDic(); + Dictionary GetWebSessionDic(); + + // + IConfig GetServerConfig(); + IConfig GetCertConfig(); + bool IsCheckClientCert(); + } +} diff --git a/OpenSim.Grid.MoneyServer/MoneyDBService.cs b/OpenSim.Grid.MoneyServer/MoneyDBService.cs new file mode 100644 index 0000000..103647e --- /dev/null +++ b/OpenSim.Grid.MoneyServer/MoneyDBService.cs @@ -0,0 +1,584 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using log4net; +using System.Reflection; +using OpenMetaverse; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyDBService: IMoneyDBService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string m_connect; + //private MySQLMoneyManager m_moneyManager; + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + // DB manager pool + protected Dictionary m_dbconnections = new Dictionary(); // with Lock + private int m_maxConnections; + + public int m_lastConnect = 0; + + + public MoneyDBService(string connect) + { + m_connect = connect; + Initialise(m_connect,10); + } + + + public MoneyDBService() + { + } + + + public void Initialise(string connectionString, int maxDBConnections) + { + m_connect = connectionString; + m_maxConnections = maxDBConnections; + if (connectionString != string.Empty) { + //m_moneyManager = new MySQLMoneyManager(connectionString); + + //m_log.Info("Creating " + m_maxConnections + " DB connections..."); + for (int i=0; im_maxConnections) { + lockedCons = 0; + System.Threading.Thread.Sleep(1000); // Wait some time before searching them again. + m_log.Debug("WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound."); + } + } + } + + + public int getBalance(string userID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getBalance(userID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.getBalance(userID); + } + catch(Exception e) { + m_log.Error(e.ToString()); + return 0; + } + finally { + dbm.Release(); + } + } + + + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool setTotalSale(TransactionData transaction) + { + if (transaction.Receiver==transaction.Sender) return false; + if (transaction.Sender==UUID.Zero.ToString()) return false; + + MySQLSuperManager dbm = GetLockedConnection(); + + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addTransaction(TransactionData transaction) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.addTransaction(transaction); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.addTransaction(transaction); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addUser(string userID, int balance, int status, int type) + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = UUID.Random(); + transaction.Sender = UUID.Zero.ToString(); + transaction.Receiver = userID; + transaction.Amount = balance; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.ObjectName = string.Empty; + transaction.RegionHandle = string.Empty; + transaction.Type = (int)TransactionType.BirthGift; + transaction.Time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);; + transaction.Status = (int)Status.PENDING_STATUS; + transaction.SecureCode = UUID.Random().ToString(); + transaction.CommonName = string.Empty; + transaction.Description = "addUser " + DateTime.UtcNow.ToString(); + + bool ret = addTransaction(transaction); + if (!ret) return false; + + // + MySQLSuperManager dbm = GetLockedConnection(); + + try { + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + + // + if (ret) ret = giveMoney(transaction.TransUUID, userID, balance); + return ret; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool SetTransExpired(int deadTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.SetTransExpired(deadTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.SetTransExpired(deadTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.FetchTransaction(transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.FetchTransaction(transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex) + { + MySQLSuperManager dbm = GetLockedConnection(); + TransactionData[] arrTransaction; + + uint index = 0; + if (lastIndex>=0) index = Convert.ToUInt32(lastIndex) + 1; + + try { + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + + // + if (arrTransaction.Length > 0) { + return arrTransaction[0]; + } + else { + return null; + } + } + + + public bool DoTransfer(UUID transactionUUID) + { + bool do_trans = false; + + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction != null && transaction.Status == (int)Status.PENDING_STATUS) { + int balance = getBalance(transaction.Sender); + + //check the amount + if (transaction.Amount >= 0 && balance >= transaction.Amount) { + if (withdrawMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver) == -1) { + m_log.ErrorFormat("[MONEY DB]: DoTransfer: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + do_trans = true; + } + else { // give money to receiver failed. Refund Processing + m_log.ErrorFormat("[MONEY DB]: Give money to receiver {0} failed", transaction.Receiver); + //Return money to sender + if (giveMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + m_log.ErrorFormat("[MONEY DB]: give money to receiver {0} failed but return it to sender {1} successfully", + transaction.Receiver, transaction.Sender); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "give money to receiver failed but return it to sender successfully"); + } + else { + m_log.ErrorFormat("[MONEY DB]: FATAL ERROR: Money withdrawn from sender: {0}, but failed to be given to receiver {1}", + transaction.Sender, transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.ERROR_STATUS, "give money to receiver failed, and return it to sender unsuccessfully!!!"); + } + } + } + else { // withdraw money failed + m_log.ErrorFormat("[MONEY DB]: Withdraw money from sender {0} failed", transaction.Sender); + } + } + else { // not enough balance to finish the transaction + m_log.ErrorFormat("[MONEY DB]: Not enough balance for user: {0} to apply the transaction.", transaction.Sender); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + // + if (do_trans) { + setTotalSale(transaction); + } + + return do_trans; + } + + + // by Fumi.Iseki + public bool DoAddMoney(UUID transactionUUID) + { + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction!=null && transaction.Status==(int)Status.PENDING_STATUS) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver)==-1) { + m_log.ErrorFormat("[MONEY DB]: DoAddMoney: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + // + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + setTotalSale(transaction); + return true; + } + else { // give money to receiver failed. + m_log.ErrorFormat("[MONEY DB]: Add money to receiver {0} failed", transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "add money to receiver failed"); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + return false; + } + + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // userinfo + // + + public bool TryAddUserInfo(UserInfo user) + { + MySQLSuperManager dbm = GetLockedConnection(); + + UserInfo userInfo = null; + + try { + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + dbm.Release(); + return false; + } + + try { + if (userInfo!=null) { + //m_log.InfoFormat("[MONEY DB]: Found user \"{0}\", now update information", user.Avatar); + if (dbm.Manager.updateUserInfo(user)) return true; + } + else if (dbm.Manager.addUserInfo(user)) { + //m_log.InfoFormat("[MONEY DB]: Unable to find user \"{0}\", add it to DB successfully", user.Avatar); + return true; + } + m_log.InfoFormat("[MONEY DB]: WARNNING: TryAddUserInfo: Unable to TryAddUserInfo."); + return false; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public UserInfo FetchUserInfo(string userID) + { + UserInfo userInfo = null; + MySQLSuperManager dbm = GetLockedConnection(); + + try { + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return -1; + } + finally { + dbm.Release(); + } + } + } +} diff --git a/OpenSim.Grid.MoneyServer/MoneyServerBase.cs b/OpenSim.Grid.MoneyServer/MoneyServerBase.cs new file mode 100644 index 0000000..deddd76 --- /dev/null +++ b/OpenSim.Grid.MoneyServer/MoneyServerBase.cs @@ -0,0 +1,407 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma warning disable S1128 // Unused "using" should be removed +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Net; +using System.Net.Security; +using System.Reflection; +using System.Timers; +using OpenSim.Framework.Servers.HttpServer; +using Nini.Config; +using log4net; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Data; +using NSL.Certificate.Tools; + +using System.Threading; +using System.Security.Cryptography.X509Certificates; +using log4net.Appender; +using log4net.Core; +using log4net.Repository; +using OpenMetaverse; +using Timer = System.Timers.Timer; +#pragma warning restore S1128 // Unused "using" should be removed + + +/// +/// OpenSim Grid MoneyServer +/// +namespace OpenSim.Grid.MoneyServer +{ + /// + /// class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore + /// Manni internal class + /// + internal class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string connectionString = string.Empty; + private uint m_moneyServerPort = 8008; // 8008 is default server port + + private string m_certFilename = ""; + private string m_certPassword = ""; + private string m_cacertFilename = ""; + private string m_clcrlFilename = ""; + private bool m_checkClientCert = false; + + private int DEAD_TIME = 120; + private int MAX_DB_CONNECTION = 10; + +#pragma warning disable S1450 // Private fields only used as local variables in methods should become local variables + private MoneyXmlRpcModule m_moneyXmlRpcModule; +#pragma warning restore S1450 // Private fields only used as local variables in methods should become local variables + private MoneyDBService m_moneyDBService; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // Client Certificate + +#pragma warning disable S2933 // Fields that are only assigned in the constructor should be "readonly" + private Dictionary m_sessionDic = new Dictionary(); + private Dictionary m_secureSessionDic = new Dictionary(); + private Dictionary m_webSessionDic = new Dictionary(); +#pragma warning restore S2933 // Fields that are only assigned in the constructor should be "readonly" + + IConfig m_server_config; + IConfig m_cert_config; + + + /// + /// Money Server Base + /// + public MoneyServerBase() + { + m_console = new LocalConsole("MoneyServer "); + MainConsole.Instance = m_console; + } + + + /// + /// Work + /// + public void Work() + { + //The timer checks the transactions table every 60 seconds + Timer checkTimer = new Timer + { + Interval = 60 * 1000, + Enabled = true + }; + checkTimer.Elapsed += new ElapsedEventHandler(CheckTransaction); + checkTimer.Start(); + + while (true) { + m_console.Prompt(); + } + } + + + /// + /// Check the transactions table, set expired transaction state to failed + /// + private void CheckTransaction(object sender, ElapsedEventArgs e) + { + long ticksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + int unixEpochTime = (int)((DateTime.UtcNow.Ticks - ticksToEpoch)/10000000); + int deadTime = unixEpochTime - DEAD_TIME; + m_moneyDBService.SetTransExpired(deadTime); + } + + + /// + /// Startup Specific + /// + protected override void StartupSpecific() + { + m_log.Info("[MONEY SERVER]: Setup HTTP Server process"); + + ReadIniConfig(); + + try { + if (m_certFilename != "") { + m_httpServer = new BaseHttpServer(m_moneyServerPort, true, m_certFilename, m_certPassword); + m_httpServer.CertificateValidationCallback = null; + // + if (m_checkClientCert) { + m_httpServer.CertificateValidationCallback = (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate; + m_log.Info("[MONEY SERVER]: Set RemoteCertificateValidationCallback"); + + /* + Type typeBaseHttpServer = typeof(BaseHttpServer); // BaseHttpServer.cs にパッチがあたっていない場合のため + PropertyInfo pinfo = typeBaseHttpServer.GetProperty("CertificateValidationCallback"); + + if (pinfo!=null) { + pinfo.SetValue(m_httpServer, (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate, null); + m_log.Info ("[MONEY SERVER]: Set RemoteCertificateValidationCallback"); + } + else { + m_log.Error("[MONEY SERVER]: StartupSpecific: CheckClientCert is true. But this MoneyServer does not support CheckClientCert!!"); + } + */ + } + } + else { + m_httpServer = new BaseHttpServer(m_moneyServerPort); + } + + SetupMoneyServices(); + m_httpServer.Start(); + base.StartupSpecific(); // OpenSim/Framework/Servers/BaseOpenSimServer.cs + } + + catch (Exception e) { + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Fail to start HTTPS process"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Please Check Certificate File or Password. Exit"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: {0}", e); + Environment.Exit(1); + } + } + + + /// + /// Read Ini Config + /// + protected void ReadIniConfig() + { + MoneyServerConfigSource moneyConfig = new MoneyServerConfigSource(); + Config = moneyConfig.m_config; + + try { + // [Startup] + IConfig st_config = moneyConfig.m_config.Configs["Startup"]; + string PIDFile = st_config.GetString("PIDFile", ""); + if (PIDFile != "") Create_PIDFile(PIDFile); + + // [MySql] + IConfig db_config = moneyConfig.m_config.Configs["MySql"]; + string sqlserver = db_config.GetString("hostname", "localhost"); + string database = db_config.GetString("database", "OpenSim"); + string username = db_config.GetString("username", "root"); + string password = db_config.GetString("password", "password"); + string pooling = db_config.GetString("pooling", "false"); + string port = db_config.GetString("port", "3306"); + MAX_DB_CONNECTION = db_config.GetInt ("MaxConnection", MAX_DB_CONNECTION); + + connectionString = "Server=" + sqlserver + ";Port=" + port + ";Database=" + database + ";User ID=" + + username + ";Password=" + password + ";Pooling=" + pooling + ";"; + + // [MoneyServer] + m_server_config = moneyConfig.m_config.Configs["MoneyServer"]; + DEAD_TIME = m_server_config.GetInt("ExpiredTime", DEAD_TIME); + m_moneyServerPort = (uint)m_server_config.GetInt("ServerPort", (int)m_moneyServerPort); + + // + // [Certificate] + m_cert_config = moneyConfig.m_config.Configs["Certificate"]; + if (m_cert_config == null) { + m_log.Info("[MONEY SERVER]: [Certificate] section is not found. Using [MoneyServer] section instead"); + m_cert_config = m_server_config; + } + + // HTTPS Server Cert (Server Mode) // サーバ証明書 + m_certFilename = m_cert_config.GetString("ServerCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ServerCertPassword", m_certPassword); + if (m_certFilename != "") { + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute HTTPS comunication. Server Cert file is " + m_certFilename); + } + + // Client Certificate + m_checkClientCert = m_cert_config.GetBoolean("CheckClientCert", m_checkClientCert); + m_cacertFilename = m_cert_config.GetString ("CACertFilename", m_cacertFilename); + m_clcrlFilename = m_cert_config.GetString ("ClientCrlFilename", m_clcrlFilename); + // + if (m_checkClientCert && (m_cacertFilename != "")) { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CA file is " + m_cacertFilename); + } + else { + m_checkClientCert = false; + } + + if (m_checkClientCert) { + if (m_clcrlFilename != "") { + m_certVerify.SetPrivateCRL(m_clcrlFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CRL file is " + m_clcrlFilename); + } + } + } + + catch (Exception) + { + m_log.Error("[MONEY SERVER]: ReadIniConfig: Fail to setup configure. Please check MoneyServer.ini. Exit"); + Environment.Exit(1); + } + } + + + /// + /// Create PID File added by skidz + /// + protected void Create_PIDFile(string path) + { + try { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + m_pidFile = path; + } +#pragma warning disable S2486 // Generic exceptions should not be ignored +#pragma warning disable CA1031 // Do not catch general exception types +#pragma warning disable S108 // Nested blocks of code should not be left empty + catch (Exception) { } +#pragma warning restore S108 // Nested blocks of code should not be left empty +#pragma warning restore CA1031 // Do not catch general exception types +#pragma warning restore S2486 // Generic exceptions should not be ignored + } + + + /// + /// Setup Money Services + /// + protected virtual void SetupMoneyServices() + { + m_log.Info("[MONEY SERVER]: Connecting to Money Storage Server"); + + m_moneyDBService = new MoneyDBService(); + m_moneyDBService.Initialise(connectionString, MAX_DB_CONNECTION); + + m_moneyXmlRpcModule = new MoneyXmlRpcModule(); + m_moneyXmlRpcModule.Initialise(m_version, m_moneyDBService, this); + m_moneyXmlRpcModule.PostInitialise(); + } + + + /// + /// Is Check Client Cert + /// + public bool IsCheckClientCert() + { + return m_checkClientCert; + } + + + /// + /// Get Server Config + /// + public IConfig GetServerConfig() + { + return m_server_config; + } + + + /// + /// Get Cert Config + /// + public IConfig GetCertConfig() + { + return m_cert_config; + } + + + /// + /// Get Http Server + /// + public BaseHttpServer GetHttpServer() + { + return m_httpServer; + } + + + /// + /// Get Session Dic + /// + public Dictionary GetSessionDic() + { + return m_sessionDic; + } + + /// + /// Get Secure Session Dic + /// + public Dictionary GetSecureSessionDic() + { + return m_secureSessionDic; + } + + + /// + /// Get Web Session Dic + /// + public Dictionary GetWebSessionDic() + { + return m_webSessionDic; + } + + } + + + + /// + /// class Money Server Config Source + /// + class MoneyServerConfigSource + { + /// + /// Ini Config Source + /// + public IniConfigSource m_config; + + /// + /// Money Server Config Source + /// + public MoneyServerConfigSource() + { + string configPath = Path.Combine(Directory.GetCurrentDirectory(), "MoneyServer.ini"); + if (File.Exists(configPath)) + { + m_config = new IniConfigSource(configPath); + } +#pragma warning disable S108 // Nested blocks of code should not be left empty + else { } +#pragma warning restore S108 // Nested blocks of code should not be left empty + } + + + /// + /// Save config + /// + public void Save(string path) + { + m_config.Save(path); + } + + } +} diff --git a/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs b/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs new file mode 100644 index 0000000..bb957cb --- /dev/null +++ b/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs @@ -0,0 +1,1807 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Collections; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using OpenSim.Region.Framework.Scenes; + +using NSL.Network.XmlRpc; +using NSL.Certificate.Tools; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyXmlRpcModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private int m_defaultBalance = 1000; + // + private bool m_forceTransfer = false; + private string m_bankerAvatar = ""; + + private bool m_scriptSendMoney = false; + private string m_scriptAccessKey = ""; + private string m_scriptIPaddress = "127.0.0.1"; + + private bool m_hg_enable = false; + private bool m_gst_enable = false; + private int m_hg_defaultBalance = 0; + private int m_gst_defaultBalance = 0; + + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + + private string m_certFilename = ""; + private string m_certPassword = ""; + //private X509Certificate2 m_clientCert = null; + + private string m_sslCommonName = ""; + + /// + /// For server authentication + /// + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); + + /// + /// Update Balance Messages + /// + private string m_BalanceMessageLandSale = "Paid the Money L${0} for Land."; + private string m_BalanceMessageRcvLandSale = ""; + private string m_BalanceMessageSendGift = "Sent Gift L${0} to {1}."; + private string m_BalanceMessageReceiveGift = "Received Gift L${0} from {1}."; + private string m_BalanceMessagePayCharge = ""; + private string m_BalanceMessageBuyObject = "Bought the Object {2} from {1} by L${0}."; + private string m_BalanceMessageSellObject = "{1} bought the Object {2} by L${0}."; + private string m_BalanceMessageGetMoney = "Got the Money L${0} from {1}."; + private string m_BalanceMessageBuyMoney = "Bought the Money L${0}."; + private string m_BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}."; + private string m_BalanceMessageSendMoney = "Paid the Money L${0} to {1}."; + private string m_BalanceMessageReceiveMoney = "Received L${0} from {1}."; + + private bool m_enableAmountZero = false; + + const int MONEYMODULE_REQUEST_TIMEOUT = 30 * 1000; //30 seconds + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + private IMoneyDBService m_moneyDBService; + private IMoneyServiceCore m_moneyCore; + + protected IConfig m_server_config; + protected IConfig m_cert_config; + + /// + /// Used to notify old regions as to which OpenSim version to upgrade to + /// + //private string m_opensimVersion; + + private Dictionary m_sessionDic; + private Dictionary m_secureSessionDic; + private Dictionary m_webSessionDic; + + protected BaseHttpServer m_httpServer; + + + public MoneyXmlRpcModule() + { + } + + + public void Initialise(string opensimVersion, IMoneyDBService moneyDBService, IMoneyServiceCore moneyCore) + { + //m_opensimVersion = opensimVersion; + m_moneyDBService = moneyDBService; + m_moneyCore = moneyCore; + m_server_config = m_moneyCore.GetServerConfig(); // [MoneyServer] Section + m_cert_config = m_moneyCore.GetCertConfig(); // [Certificate] Section + + //////////////////////////////////////////////////////////////////////// + // [MoneyServer] Section + m_defaultBalance = m_server_config.GetInt("DefaultBalance", m_defaultBalance); + + m_forceTransfer = m_server_config.GetBoolean("EnableForceTransfer", m_forceTransfer); + + string banker = m_server_config.GetString("BankerAvatar", m_bankerAvatar); + m_bankerAvatar = banker.ToLower(); + + m_enableAmountZero = m_server_config.GetBoolean("EnableAmountZero", m_enableAmountZero); + m_scriptSendMoney = m_server_config.GetBoolean("EnableScriptSendMoney", m_scriptSendMoney); + m_scriptAccessKey = m_server_config.GetString ("MoneyScriptAccessKey", m_scriptAccessKey); + m_scriptIPaddress = m_server_config.GetString ("MoneyScriptIPaddress", m_scriptIPaddress); + + // Hyper Grid Avatar + m_hg_enable = m_server_config.GetBoolean("EnableHGAvatar", m_hg_enable); + m_gst_enable = m_server_config.GetBoolean("EnableGuestAvatar", m_gst_enable); + m_hg_defaultBalance = m_server_config.GetInt("HGAvatarDefaultBalance", m_hg_defaultBalance); + m_gst_defaultBalance = m_server_config.GetInt("GuestAvatarDefaultBalance", m_gst_defaultBalance); + + // Update Balance Messages + m_BalanceMessageLandSale = m_server_config.GetString("BalanceMessageLandSale", m_BalanceMessageLandSale); + m_BalanceMessageRcvLandSale = m_server_config.GetString("BalanceMessageRcvLandSale", m_BalanceMessageRcvLandSale); + m_BalanceMessageSendGift = m_server_config.GetString("BalanceMessageSendGift", m_BalanceMessageSendGift); + m_BalanceMessageReceiveGift = m_server_config.GetString("BalanceMessageReceiveGift", m_BalanceMessageReceiveGift); + m_BalanceMessagePayCharge = m_server_config.GetString("BalanceMessagePayCharge", m_BalanceMessagePayCharge); + m_BalanceMessageBuyObject = m_server_config.GetString("BalanceMessageBuyObject", m_BalanceMessageBuyObject); + m_BalanceMessageSellObject = m_server_config.GetString("BalanceMessageSellObject", m_BalanceMessageSellObject); + m_BalanceMessageGetMoney = m_server_config.GetString("BalanceMessageGetMoney", m_BalanceMessageGetMoney); + m_BalanceMessageBuyMoney = m_server_config.GetString("BalanceMessageBuyMoney", m_BalanceMessageBuyMoney); + m_BalanceMessageRollBack = m_server_config.GetString("BalanceMessageRollBack", m_BalanceMessageRollBack); + m_BalanceMessageSendMoney = m_server_config.GetString("BalanceMessageSendMoney", m_BalanceMessageSendMoney); + m_BalanceMessageReceiveMoney = m_server_config.GetString("BalanceMessageReceiveMoney", m_BalanceMessageReceiveMoney); + + //////////////////////////////////////////////////////////////////////// + // [Certificate] Section + + // XML RPC to Region Server (Client Mode) + // Client Certificate + m_certFilename = m_cert_config.GetString("ClientCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename != "") { + m_certVerify.SetPrivateCert(m_certFilename, m_certPassword); + //m_clientCert = new X509Certificate2(m_certFilename, m_certPassword); + //m_clientCert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.Info("[MONEY XMLRPC]: Initialise: Issue Authentication of Client. Cert file is " + m_certFilename); + } + + // Server Authentication + // CA : MoneyServer が XMLRPC のWebサーバのサーバ証明書をチェックするための設定 + m_checkServerCert = m_cert_config.GetBoolean("CheckServerCert", m_checkServerCert); + m_cacertFilename = m_cert_config.GetString ("CACertFilename", m_cacertFilename); + + if (m_cacertFilename != "") { + m_certVerify.SetPrivateCA(m_cacertFilename); + } + else { + m_checkServerCert = false; + } + + if (m_checkServerCert) { + m_log.Info("[MONEY XMLRPC]: Initialise: Execute Authentication of Server. CA file is " + m_cacertFilename); + } + else { + m_log.Info("[MONEY XMLRPC]: Initialise: No check XMLRPC Server or CACertFilename is empty. CheckServerCert is false."); + } + + //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + //ServicePointManager.UseNagleAlgorithm = false; + //ServicePointManager.Expect100Continue = false; + + m_sessionDic = m_moneyCore.GetSessionDic(); + m_secureSessionDic = m_moneyCore.GetSecureSessionDic(); + m_webSessionDic = m_moneyCore.GetWebSessionDic(); + RegisterHandlers(); + } + + + public void PostInitialise() + { + } + + + public void RegisterHandlers() + { + m_httpServer = m_moneyCore.GetHttpServer(); + m_httpServer.AddXmlRPCHandler("ClientLogin", handleClientLogin); + m_httpServer.AddXmlRPCHandler("ClientLogout", handleClientLogout); + m_httpServer.AddXmlRPCHandler("GetBalance", handleGetBalance); + m_httpServer.AddXmlRPCHandler("GetTransaction", handleGetTransaction); + + m_httpServer.AddXmlRPCHandler("CancelTransfer", handleCancelTransfer); + m_httpServer.AddXmlRPCHandler("TransferMoney", handleTransaction); + m_httpServer.AddXmlRPCHandler("ForceTransferMoney", handleForceTransaction); // added + m_httpServer.AddXmlRPCHandler("PayMoneyCharge", handlePayMoneyCharge); // added + m_httpServer.AddXmlRPCHandler("AddBankerMoney", handleAddBankerMoney); // added + m_httpServer.AddXmlRPCHandler("SendMoney", handleScriptTransaction); // added + m_httpServer.AddXmlRPCHandler("MoveMoney", handleScriptTransaction); // added + + // this is from original DTL. not check yet. + m_httpServer.AddXmlRPCHandler("WebLogin", handleWebLogin); + m_httpServer.AddXmlRPCHandler("WebLogout", handleWebLogout); + m_httpServer.AddXmlRPCHandler("WebGetBalance", handleWebGetBalance); + m_httpServer.AddXmlRPCHandler("WebGetTransaction", handleWebGetTransaction); + m_httpServer.AddXmlRPCHandler("WebGetTransactionNum", handleWebGetTransactionNum); + + // Land Buy Test + m_httpServer.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func); + m_httpServer.AddXmlRPCHandler("buyLandPrep", landBuy_func); + + // Currency Buy Test + m_httpServer.AddXmlRPCHandler("getCurrencyQuote", quote_func); + m_httpServer.AddXmlRPCHandler("buyCurrency", buy_func); + } + + + private XmlRpcResponse buy_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient buyCurrency."); + throw new NotImplementedException(); + } + + + private XmlRpcResponse quote_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient getCurrencyQuote."); + throw new NotImplementedException(); + } + + + private XmlRpcResponse landBuy_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient buyLandPrep."); + throw new NotImplementedException(); + } + + + private XmlRpcResponse preflightBuyLandPrep_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient preflightBuyLandPrep."); + throw new NotImplementedException(); + } + + + // + public string GetSSLCommonName(XmlRpcRequest request) + { + if (request.Params.Count>5) { + m_sslCommonName = (string)request.Params[5]; + } + else if (request.Params.Count==5) { + m_sslCommonName = (string)request.Params[4]; + if (m_sslCommonName=="gridproxy") m_sslCommonName = ""; + } + else { + m_sslCommonName = ""; + } + return m_sslCommonName; + } + + + // + public string GetSSLCommonName() + { + return m_sslCommonName; + } + + + /// + /// Get the user balance when user entering a parcel. + /// + /// + /// + public XmlRpcResponse handleClientLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogin: Start."); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + responseData["success"] = false; + responseData["clientBalance"] = 0; + + // Check Client Cert + if (m_moneyCore.IsCheckClientCert()) { + string commonName = GetSSLCommonName(); + if (commonName=="") { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Warnning: Check Client Cert is set, but SSL Common Name is empty."); + responseData["success"] = false; + responseData["description"] = "SSL Common Name is empty"; + return response; + } + else { + if (commonName=="SSLCN:unknownName") { + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogin: SSL Common Name is \"{0}\", but this name is ignored.", commonName); + } + else { + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogin: SSL Common Name is \"{0}\"", commonName); + } + } + } + + string universalID = string.Empty; + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string simIP = string.Empty; + string userName = string.Empty; + int balance = 0; + int avatarType = (int)AvatarType.UNKNOWN_AVATAR; + int avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + if (requestData.ContainsKey("universalID")) universalID = (string)requestData["universalID"]; + if (requestData.ContainsKey("userName")) userName = (string)requestData["userName"]; + if (requestData.ContainsKey("openSimServIP")) simIP = (string)requestData["openSimServIP"]; + if (requestData.ContainsKey("avatarType")) avatarType = Convert.ToInt32(requestData["avatarType"]); + if (requestData.ContainsKey("avatarClass")) avatarClass = Convert.ToInt32(requestData["avatarClass"]); + + // + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + string securePsw = string.Empty; + // + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out securePsw); + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // Information from DB + UserInfo userInfo = m_moneyDBService.FetchUserInfo(clientUUID); + if (userInfo!=null) { + avatarType = userInfo.Type; // Avatar Type is not updated + if (avatarType ==(int)AvatarType.LOCAL_AVATAR) avatarClass = (int)AvatarType.LOCAL_AVATAR; + if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) avatarClass = userInfo.Class; + if (String.IsNullOrEmpty(userName)) userName = userInfo.Avatar; + } + // + if (avatarType==(int)AvatarType.UNKNOWN_AVATAR) avatarType = avatarClass; + if (String.IsNullOrEmpty(serverURL)) avatarClass = (int)AvatarType.NPC_AVATAR; + + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: Avatar {0} ({1}) is logged on.", userName, clientUUID); + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: Avatar Type is {0} and Avatar Class is {1}", avatarType, avatarClass); + + //if (String.IsNullOrEmpty(serverURL)) { + // responseData["description"] = "Server URL is empty. Avatar is a NPC?"; + // m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + // return response; + //} + + // + // Check Avatar + if (avatarClass==(int)AvatarType.GUEST_AVATAR && !m_gst_enable) { + responseData["description"] = "Avatar is a Guest avatar. But this Money Server does not support Guest avatars."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.HG_AVATAR && !m_hg_enable) { + responseData["description"] = "Avatar is a HG avatar. But this Money Server does not support HG avatars."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.FOREIGN_AVATAR) { + responseData["description"] = "Avatar is a Foreign avatar."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) { + responseData["description"] = "Avatar is a Unknown avatar."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + // NPC + else if (avatarClass==(int)AvatarType.NPC_AVATAR) { + responseData["success"] = true; + responseData["clientBalance"] = 0; + responseData["description"] = "Avatar is a NPC."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + + // + //Update the session and secure session dictionary + lock (m_sessionDic) { + if (!m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Add(clientUUID, sessionID); + } + else m_sessionDic[clientUUID] = sessionID; + } + lock (m_secureSessionDic) { + if (!m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Add(clientUUID, secureID); + } + else m_secureSessionDic[clientUUID] = secureID; + } + + // + try { + if (userInfo==null) userInfo = new UserInfo(); + userInfo.UserID = clientUUID; + userInfo.SimIP = simIP; + userInfo.Avatar = userName; + userInfo.PswHash = UUID.Zero.ToString(); + userInfo.Type = avatarType; + userInfo.Class = avatarClass; + userInfo.ServerURL = serverURL; + if (!String.IsNullOrEmpty(securePsw)) userInfo.PswHash = securePsw; + + if (!m_moneyDBService.TryAddUserInfo(userInfo)) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Unable to refresh information for user \"{0}\" in DB.", userName); + responseData["success"] = true; // for FireStorm + responseData["description"] = "Update or add user information to db failed"; + return response; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Can't update userinfo for user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + return response; + } + + // + try { + balance = m_moneyDBService.getBalance(clientUUID); + + //add user to balances table if not exist. (if balance is -1, it means avatar is not exist at balances table) + if (balance==-1) { + int default_balance = m_defaultBalance; + if (avatarClass==(int)AvatarType.HG_AVATAR) default_balance = m_hg_defaultBalance; + if (avatarClass==(int)AvatarType.GUEST_AVATAR) default_balance = m_gst_defaultBalance; + + if (m_moneyDBService.addUser(clientUUID, default_balance, 0, avatarType)) { + responseData["success"] = true; + responseData["description"] = "add user successfully"; + responseData["clientBalance"] = default_balance; + } + else { + responseData["description"] = "add user failed"; + } + } + //Success + else if (balance >= 0) { + responseData["success"] = true; + responseData["description"] = "get user balance successfully"; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Can't get balance of user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + } + + return response; + } + + + // + public XmlRpcResponse handleClientLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogout:"); + + //GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogout: User {0} is logging off.", clientUUID); + try { + lock (m_sessionDic) { + if (m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Remove(clientUUID); + } + } + + lock (m_secureSessionDic) { + if (m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Remove(clientUUID); + } + } + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleClientLogout: Failed to delete user session: " + e.ToString() ); + responseData["success"] = false; + return response; + } + + responseData["success"] = true; + return response; + } + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + /// + /// handle incoming transaction + /// + /// + /// + public XmlRpcResponse handleTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction: Transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction: Object ID = {0}, Object Name = {1}", objectID, objectName); + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction: Transfering money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleTransaction: Receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + rcv_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleTransaction: Add transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleTransaction: Exception occurred while adding transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handleTransaction: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle incoming force transaction. no check senderSessionID and senderSecureSessionID + /// + /// + /// + public XmlRpcResponse handleForceTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleForceTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + // + if (!m_forceTransfer) { + m_log.Error("[MONEY XMLRPC]: handleForceTransaction: Not allowed force transfer of Money."); + m_log.Error("[MONEY XMLRPC]: handleForceTransaction: Set enableForceTransfer at [MoneyServer] to true in MoneyServer.ini"); + responseData["message"] = "not allowed force transfer of Money!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleForceTransaction: Force transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY XMLRPC]: handleForceTransaction: Object ID = {0}, Object Name = {1}", objectID, objectName); + + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleForceTransaction: Force receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + snd_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleForceTransaction: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleForceTransaction: Exception occurred while adding force transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle scripted sending money transaction. + /// + /// + /// + public XmlRpcResponse handleScriptTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string receiverID = UUID.Zero.ToString(); + string clientIP = remoteClient.Address.ToString(); + string secretCode = string.Empty; + string description = "Scripted Send Money from/to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (!m_scriptSendMoney || m_scriptAccessKey=="") { + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Set enableScriptSendMoney and MoneyScriptAccessKey at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed set money to avatar!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("transactionType")) transactionType= Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + if (requestData.ContainsKey("secretAccessCode")) secretCode = (string)requestData["secretAccessCode"]; + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(m_scriptAccessKey + "_" + clientIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(hash + "_" + m_scriptIPaddress)); + hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + + if (secretCode.ToLower()!=hash) { + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Not match Script Access Key."); + responseData["message"] = "not allowed send money to avatar! not match Script Key"; + return response; + } + + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: Send money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle= "0"; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo senderInfo = null; + UserInfo receiverInfo = null; + if (transaction.Sender !=UUID.Zero.ToString()) senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (transaction.Receiver!=UUID.Zero.ToString()) receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + + if (senderInfo==null && receiverInfo==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleScriptTransaction: Sender and Receiver are not yet in DB, or both of them are System: {0}, {1}", + transaction.Sender, transaction.Receiver); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: ScriptTransaction money finished successfully, now update balance {0}", + transactionUUID.ToString()); + string message = string.Empty; + if (senderInfo!=null) { + if (receiverInfo==null) message = string.Format(m_BalanceMessageSendMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageSendMoney, amount, receiverInfo.Avatar, ""); + UpdateBalance(transaction.Sender, message); + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Sender, message); + } + if (receiverInfo!=null) { + if (senderInfo==null) message = string.Format(m_BalanceMessageReceiveMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageReceiveMoney, amount, senderInfo.Avatar, ""); + UpdateBalance(transaction.Receiver, message); + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Receiver, message); + } + + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleScriptTransaction: Add force transaction for user {0} failed.", transaction.Sender); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle adding money transaction. + /// + /// + /// + public XmlRpcResponse handleAddBankerMoney(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleAddBankerMoney:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string bankerID = string.Empty; + string regionHandle = "0"; + string regionUUID = UUID.Zero.ToString(); + string description = "Add Money to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("bankerID")) bankerID = (string)requestData["bankerID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + // Check Banker Avatar + if (m_bankerAvatar!=UUID.Zero.ToString() && m_bankerAvatar!=bankerID) { + m_log.Error("[MONEY XMLRPC]: handleAddBankerMoney: Not allowed add money to avatar!!"); + m_log.Error("[MONEY XMLRPC]: handleAddBankerMoney: Set BankerAvatar at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed add money to avatar!"; + responseData["banker"] = false; + return response; + } + responseData["banker"] = true; + + m_log.InfoFormat("[MONEY XMLRPC]: handleAddBankerMoney: Add money to avatar {0}", bankerID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = bankerID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(bankerID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleAddBankerMoney: Avatar is not yet in DB {0}", bankerID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoAddMoney(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY XMLRPC]: handleAddBankerMoney: Adding money finished successfully, now update balance: {0}", + transactionUUID.ToString()); + string message = string.Format(m_BalanceMessageBuyMoney, amount, "SYSTEM", ""); + UpdateBalance(transaction.Receiver, message); + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleAddBankerMoney: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleAddBankerMoney: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle pay charge transaction. no check receiver information. + /// + /// + /// + public XmlRpcResponse handlePayMoneyCharge(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = UUID.Zero.ToString(); + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = UUID.Zero.ToString(); + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Pay Charge on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Object ID = {0}, Object Name = {1}", objectID, objectName); + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Pay from {0}", senderID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string message = string.Format(m_BalanceMessagePayCharge, amount, "SYSTEM", ""); + responseData["success"] = NotifyTransfer(transactionUUID, message, "", ""); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Pay money transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handlePayMoneyCharge: Exception occurred while pay money transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handlePayMoneyCharge: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + // added by Fumi.Iseki + // + /// + /// Continue transaction with no confirm. + /// + /// + /// + public bool NotifyTransfer(UUID transactionUUID, string msg2sender, string msg2receiver, string objectName) + { + //m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: User has accepted the transaction, now continue with the transaction"); + + try { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction Type = {0}", transaction.Type); + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Payment finished successfully, now update balance {0}", transactionUUID.ToString()); + + bool updateSender = true; + bool updateReceiv = true; + if (transaction.Sender==transaction.Receiver) updateSender = false; + //if (transaction.Type==(int)TransactionType.UploadCharge) return true; + if (transaction.Type==(int)TransactionType.UploadCharge) updateReceiv = false; + + if (updateSender) { + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string receiverName = "unknown user"; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + string snd_message = string.Format(msg2sender, transaction.Amount, receiverName, objectName); + UpdateBalance(transaction.Sender, snd_message); + } + if (updateReceiv) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + string senderName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + string rcv_message = string.Format(msg2receiver, transaction.Amount, senderName, objectName); + UpdateBalance(transaction.Receiver, rcv_message); + } + + // Notify to sender + if (transaction.Type==(int)TransactionType.PayObject) { + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Now notify opensim to give object to customer {0} ", transaction.Sender); + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = transaction.Sender; + requestTable["receiverUUID"] = transaction.Receiver; + + if(m_sessionDic.ContainsKey(transaction.Sender)&&m_secureSessionDic.ContainsKey(transaction.Sender)) { + requestTable["clientSessionID"] = m_sessionDic[transaction.Sender]; + requestTable["clientSecureSessionID"] = m_secureSessionDic[transaction.Sender]; + } + else { + requestTable["clientSessionID"] = UUID.Zero.ToString(); + requestTable["clientSecureSessionID"] = UUID.Zero.ToString(); + } + requestTable["transactionType"] = transaction.Type; + requestTable["amount"] = transaction.Amount; + requestTable["objectID"] = transaction.ObjectUUID; + requestTable["objectName"] = transaction.ObjectName; + requestTable["regionHandle"] = transaction.RegionHandle; + + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (user!=null) { + Hashtable responseTable = genericCurrencyXMLRPCRequest(requestTable, "OnMoneyTransfered", user.SimIP); + + if (responseTable!=null && responseTable.ContainsKey("success")) { + //User not online or failed to get object ? + if (!(bool)responseTable["success"]) { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: User {0} can't get the object, rolling back.", transaction.Sender); + if (RollBackTransaction(transaction)) { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} failed but roll back succeeded.", transactionUUID.ToString()); + } + else { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} failed and roll back failed as well.", + transactionUUID.ToString()); + } + } + else { + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} finished successfully.", transactionUUID.ToString()); + return true; + } + } + } + return false; + } + return true; + } + } + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} failed.", transactionUUID.ToString()); + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: exception occurred when transaction {0}: {1}", transactionUUID.ToString(), e.ToString()); + } + + return false; + } + + + /// + /// Get the user balance. + /// + /// + /// + public XmlRpcResponse handleGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + int balance; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleGetBalance: Getting balance for user {0}", clientUUID); + + if (m_sessionDic.ContainsKey(clientUUID) && m_secureSessionDic.ContainsKey(clientUUID)) { + if (m_sessionDic[clientUUID]==sessionID && m_secureSessionDic[clientUUID]==secureID) { + try { + balance = m_moneyDBService.getBalance(clientUUID); + if (balance==-1) // User not found + { + responseData["description"] = "user not found"; + responseData["clientBalance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleGetBalance: Can't get balance for user {0}, Exception {1}", clientUUID, e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handleGetBalance: Session authentication failed when getting balance for user " + clientUUID); + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method, string uri) + { + //m_log.InfoFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: to {0}", uri); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!uri.StartsWith("https://")) { + m_log.InfoFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file."); + //return null; + } + } + else { + if (!uri.StartsWith("https://") && !uri.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: Invalid Region Server URL: {0}", uri); + return null; + } + } + + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + //moneyServResp = moneyModuleReq.certSend(uri, m_clientCert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + moneyServResp = moneyModuleReq.certSend(uri, m_certVerify, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: Unable to connect to Region Server {0}", uri); + m_log.ErrorFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: {0}", ex.ToString()); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + /// + /// Update the client balance.We don't care about the result. + /// + /// + private void UpdateBalance(string userID, string message) + { + //m_log.InfoFormat("[MONEY XMLRPC]: UpdateBalance: ID = {0}, Message = {1}", userID, message); + + string sessionID = string.Empty; + string secureID = string.Empty; + + if (m_sessionDic.ContainsKey(userID) && m_secureSessionDic.ContainsKey(userID)) { + sessionID = m_sessionDic[userID]; + secureID = m_secureSessionDic[userID]; + + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = userID; + requestTable["clientSessionID"] = sessionID; + requestTable["clientSecureSessionID"] = secureID; + requestTable["Balance"] = m_moneyDBService.getBalance(userID); + if (message!="") requestTable["Message"] = message; + + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + genericCurrencyXMLRPCRequest(requestTable, "UpdateBalance", user.SimIP); + m_log.InfoFormat("[MONEY XMLRPC]: UpdateBalance: Sended UpdateBalance Request to {0}", user.SimIP.ToString()); + } + } + } + + + /// + /// RollBack the transaction if user failed to get the object paid + /// + /// + /// + protected bool RollBackTransaction(TransactionData transaction) + { + //m_log.InfoFormat("[MONEY XMLRPC]: RollBackTransaction:"); + + if(m_moneyDBService.withdrawMoney(transaction.TransUUID, transaction.Receiver, transaction.Amount)) { + if(m_moneyDBService.giveMoney(transaction.TransUUID, transaction.Sender, transaction.Amount)) { + m_log.InfoFormat("[MONEY XMLRPC]: RollBackTransaction: Transaction {0} is successfully.", transaction.TransUUID.ToString()); + m_moneyDBService.updateTransactionStatus(transaction.TransUUID, (int)Status.FAILED_STATUS, + "The buyer failed to get the object, roll back the transaction"); + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string senderName = "unknown user"; + string receiverName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + + string snd_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, receiverName, transaction.ObjectName); + string rcv_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, senderName, transaction.ObjectName); + + if (transaction.Sender!=transaction.Receiver) UpdateBalance(transaction.Sender, snd_message); + UpdateBalance(transaction.Receiver, rcv_message); + return true; + } + } + return false; + } + + + // + public XmlRpcResponse handleCancelTransfer(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleCancelTransfer:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string secureCode = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("secureCode")) secureCode = (string)requestData["secureCode"]; + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (string.IsNullOrEmpty(secureCode) || string.IsNullOrEmpty(transactionID)) { + m_log.Error("[MONEY XMLRPC]: handleCancelTransfer: secureCode and/or transactionID are empty."); + return response; + } + + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + + try { + m_log.InfoFormat("[MONEY XMLRPC]: handleCancelTransfer: User {0} wanted to cancel the transaction.", user.Avatar); + if (m_moneyDBService.ValidateTransfer(secureCode, transactionUUID)) { + m_log.InfoFormat("[MONEY XMLRPC]: handleCancelTransfer: User {0} has canceled the transaction {1}", user.Avatar, transactionID); + m_moneyDBService.updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, + "User canceled the transaction on " + DateTime.UtcNow.ToString()); + responseData["success"] = true; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleCancelTransfer: Exception occurred when transaction {0}: {1}", transactionID, e.ToString()); + } + return response; + } + + + // + public XmlRpcResponse handleGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (m_sessionDic.ContainsKey(clientID) && m_secureSessionDic.ContainsKey(clientID)) { + if (m_sessionDic[clientID]==sessionID && m_secureSessionDic[clientID]==secureID) { + // + if (string.IsNullOrEmpty(transactionID)) { + responseData["description"] = "TransactionID is empty"; + m_log.Error("[MONEY XMLRPC]: handleGetTransaction: TransactionID is empty."); + return response; + } + + try { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null) { + responseData["success"] = true; + responseData["amount"] = transaction.Amount; + responseData["time"] = transaction.Time; + responseData["type"] = transaction.Type; + responseData["sender"] = transaction.Sender.ToString(); + responseData["receiver"] = transaction.Receiver.ToString(); + responseData["description"] = transaction.Description; + } + else { + responseData["description"] = "Invalid Transaction UUID"; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleGetTransaction: {0}", e.ToString()); + m_log.ErrorFormat("[MONEY XMLRPC]: handleGetTransaction: Can't get transaction information for {0}", transactionUUID.ToString()); + } + return response; + } + } + + responseData["success"] = false; + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // In development + // + + public XmlRpcResponse handleWebLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogin: Start."); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, login failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (!m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Add(userID, webSessionID); + } + else m_webSessionDic[userID] = webSessionID; + } + + m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogin: User {0} has logged in from web.", userID); + responseData["success"] = true; + return response; + } + + + // + public XmlRpcResponse handleWebLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, log out failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Remove(userID); + } + } + + m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogout: User {0} has logged out from web.", userID); + responseData["success"] = true; + return response; + } + + + /// + /// Get balance method for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int balance = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetBalance: Getting balance for user {0}", userID); + + //perform session check + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + balance = m_moneyDBService.getBalance(userID); + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + responseData["userName"] = user.Avatar; + } + else { + responseData["userName"] = "unknown user"; + } + // + // User not found + if (balance==-1) { + responseData["errorMessage"] = "User not found"; + responseData["balance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["balance"] = balance; + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleWebGetBalance: Can't get balance for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting balance"; + return response; + } + } + } + + m_log.Error("[MONEY XMLRPC]: handleWebLogout: Session authentication failed when getting balance for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get transaction for web pages + /// + /// + /// + public XmlRpcResponse handleWebGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int lastIndex = -1; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + if (requestData.ContainsKey("lastIndex")) lastIndex = (int)requestData["lastIndex"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + int total = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + TransactionData tran = null; + m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransaction: Getting transation[{0}] for user {1}", lastIndex + 1, userID); + if (total > lastIndex + 2) { + responseData["isEnd"] = false; + } + else { + responseData["isEnd"] = true; + } + + tran = m_moneyDBService.FetchTransaction(userID, startTime, endTime, lastIndex); + if (tran!=null) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(tran.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(tran.Receiver); + if (senderInfo!=null && receiverInfo!=null) { + responseData["senderName"] = senderInfo.Avatar; + responseData["receiverName"] = receiverInfo.Avatar; + } + else { + responseData["senderName"] = "unknown user"; + responseData["receiverName"] = "unknown user"; + } + responseData["success"] = true; + responseData["transactionIndex"] = lastIndex + 1; + responseData["transactionUUID"] = tran.TransUUID.ToString(); + responseData["senderID"] = tran.Sender; + responseData["receiverID"] = tran.Receiver; + responseData["amount"] = tran.Amount; + responseData["type"] = tran.Type; + responseData["time"] = tran.Time; + responseData["status"] = tran.Status; + responseData["description"] = tran.Description; + } + else { + responseData["errorMessage"] = string.Format("Unable to fetch transaction data with the index {0}", lastIndex + 1); + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleWebGetTransaction: Can't get transaction for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting transaction"; + return response; + } + } + } + + m_log.Error("[MONEY XMLRPC]: handleWebGetTransaction: Session authentication failed when getting transaction for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get total number of transactions for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetTransactionNum(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransactionNum:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + int it = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + if (it>=0) { + m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransactionNum: Get {0} transactions for user {1}", it, userID); + responseData["success"] = true; + responseData["number"] = it; + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handleWebGetTransactionNum: Session authentication failed when getting transaction number for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + } + +} + diff --git a/OpenSim.Grid.MoneyServer/Program.cs b/OpenSim.Grid.MoneyServer/Program.cs new file mode 100644 index 0000000..3fbd12d --- /dev/null +++ b/OpenSim.Grid.MoneyServer/Program.cs @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net.Config; + +namespace OpenSim.Grid.MoneyServer +{ + class Program + { + public static void Main(string[] args) + { + XmlConfigurator.Configure(); + MoneyServerBase app = new MoneyServerBase(); + app.Startup(); + app.Work(); + } + } +} diff --git a/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs b/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..407ecee --- /dev/null +++ b/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Grid.MoneyServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("OpenSim.Grid.MoneyServer")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f554c84a-d8c7-41ea-833d-2483cde29e0f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs b/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs new file mode 100644 index 0000000..9bfca89 --- /dev/null +++ b/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs @@ -0,0 +1,1920 @@ +// * Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp +// * +// * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ +// * See CONTRIBUTORS.TXT for a full list of copyright holders. +// * +// * Redistribution and use in source and binary forms, with or without +// * modification, are permitted provided that the following conditions are met: +// * * Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * * Redistributions in binary form must reproduce the above copyright +// * notice, this list of conditions and the following disclaimer in the +// * documentation and/or other materials provided with the distribution. +// * * Neither the name of the OpenSim Project nor the +// * names of its contributors may be used to endorse or promote products +// * derived from this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +// * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES +// * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using Mono.Addins; + +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using NSL.Certificate.Tools; +using NSL.Network.XmlRpc; + + + +[assembly: Addin("DTLNSLMoneyModule", "1.0")] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] + + + +namespace OpenSim.Modules.Currency +{ + /// + /// Transaction Type + /// + public enum TransactionType : int + { + None = 0, + // Extend + BirthGift = 900, + AwardPoints = 901, + // One-Time Charges + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + // Recurrent Charges + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + ScheduledFee = 2900, + // Inventory Transactions + GiveInventory = 3000, + // Transfers Between Users + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InvntorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + BuyMoney = 5010, + MoveMoney = 5011, + SendMoney = 5012, + // Group Transactions + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + // Stipend Credits + StipendBasic = 10000 + } + + +/* + // Refer to OpenMetaverse + public enum OpenMetaverse.MoneyTransactionType : int + { + None = 0, + FailSimulatorTimeout = 1, + FailDataserverTimeout = 2, + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + ObjectPublicClaim = 1003, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + GiveInventory = 3000, + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InventorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + ObjectRelease = 8000, + LandRelease = 8001, + ObjectDelete = 8002, + ObjectPublicDecay = 8003, + ObjectPublicDelete = 8004, + LindenAdjustment = 9000, + LindenGrant = 9001, + LindenPenalty = 9002, + EventFee = 9003, + EventPrize = 9004, + StipendBasic = 10000, + StipendDeveloper = 10001, + StipendAlways = 10002, + StipendDaily = 10003, + StipendRating = 10004, + StipendDelta = 10005 + } +*/ + + + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")] + public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule + { + #region Constant numbers and members. + + // Constant memebers + private const int MONEYMODULE_REQUEST_TIMEOUT = 10000; + + // Private data members. + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + //private bool m_enabled = true; + private bool m_sellEnabled = false; + private bool m_enable_server = true; // enable Money Server + + private IConfigSource m_config; + + private string m_moneyServURL = string.Empty; + public BaseHttpServer HttpServer; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + //private X509Certificate2 m_cert = null; + + private bool m_use_web_settle = false; + private string m_settle_url = ""; + private string m_settle_message = ""; + private bool m_settle_user = false; + + private int m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // For server authentication + + + /// + /// Scene dictionary indexed by Region Handle + /// + private Dictionary m_sceneList = new Dictionary(); + + /// + /// To cache the balance data while the money server is not available. + /// + private Dictionary m_moneyServer = new Dictionary(); + + // Events + public event ObjectPaid OnObjectPaid; + + // Price + private int ObjectCount = 0; + private int PriceEnergyUnit = 100; + private int PriceObjectClaim = 10; + private int PricePublicObjectDecay = 4; + private int PricePublicObjectDelete = 4; + private int PriceParcelClaim = 1; + private float PriceParcelClaimFactor = 1.0f; + private int PriceUpload = 0; + private int PriceRentLight = 5; + private float PriceObjectRent = 1.0f; + private float PriceObjectScaleFactor = 10.0f; + private int PriceParcelRent = 1; + private int PriceGroupCreate = 0; + private int TeleportMinPrice = 2; + private float TeleportPriceExponent = 2.0f; + private float EnergyEfficiency = 1.0f; + + #endregion + + + /// + /// Initialise + /// + /// + /// + public void Initialise(Scene scene, IConfigSource source) + { + Initialise(source); + if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false; + // + AddRegion(scene); + } + + + #region ISharedRegionModule interface + + public void Initialise(IConfigSource source) + { + //m_log.InfoFormat("[MONEY MODULE]: Initialise:"); + + // Handle the parameters errors. + if (source==null) return; + + try { + m_config = source; + + // [Economy] section + IConfig economyConfig = m_config.Configs["Economy"]; + + if (economyConfig.GetString("EconomyModule")!=Name && economyConfig.GetString("economymodule")!=Name) { + //m_enabled = false; + m_log.InfoFormat("[MONEY MODULE]: Initialise: The DTL/NSL MoneyModule is disabled"); + return; + } + else { + m_log.InfoFormat("[MONEY MODULE]: Initialise: The DTL/NSL MoneyModule is enabled"); + } + + m_sellEnabled = economyConfig.GetBoolean("SellEnabled", m_sellEnabled); + m_moneyServURL = economyConfig.GetString("CurrencyServer", m_moneyServURL); + + // Client Certification // クライアント証明書 + m_certFilename = economyConfig.GetString("ClientCertFilename", m_certFilename); + m_certPassword = economyConfig.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename!="") { + m_certVerify.SetPrivateCert(m_certFilename, m_certPassword); + //m_cert = new X509Certificate2(m_certFilename, m_certPassword); + //m_cert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.Info("[MONEY MODULE]: Initialise: Issue Authentication of Client. Cert File is " + m_certFilename); + } + + // Server Authentication // MoneyServer のサーバ証明書のチェック + m_checkServerCert = economyConfig.GetBoolean("CheckServerCert", m_checkServerCert); + m_cacertFilename = economyConfig.GetString ("CACertFilename", m_cacertFilename); + + if (m_cacertFilename != "") { + m_certVerify.SetPrivateCA(m_cacertFilename); + } + else { + m_checkServerCert = false; + } + + if (m_checkServerCert) { + m_log.Info("[MONEY MODULE]: Initialise: Execute Authentication of Server. CA Cert File is " + m_cacertFilename); + } + else { + m_log.Info("[MONEY MODULE]: Initialise: No check Money Server or CACertFilename is empty. CheckServerCert is false."); + } + + //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + //ServicePointManager.UseNagleAlgorithm = false; + //ServicePointManager.Expect100Continue = false; + + // Settlement + m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", m_use_web_settle); + m_settle_url = economyConfig.GetString ("SettlementURL", m_settle_url); + m_settle_message = economyConfig.GetString ("SettlementMessage", m_settle_message); + + // Price + PriceEnergyUnit = economyConfig.GetInt ("PriceEnergyUnit", PriceEnergyUnit); + PriceObjectClaim = economyConfig.GetInt ("PriceObjectClaim", PriceObjectClaim); + PricePublicObjectDecay = economyConfig.GetInt ("PricePublicObjectDecay", PricePublicObjectDecay); + PricePublicObjectDelete = economyConfig.GetInt ("PricePublicObjectDelete", PricePublicObjectDelete); + PriceParcelClaim = economyConfig.GetInt ("PriceParcelClaim", PriceParcelClaim); + PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", PriceParcelClaimFactor); + PriceUpload = economyConfig.GetInt ("PriceUpload", PriceUpload); + PriceRentLight = economyConfig.GetInt ("PriceRentLight", PriceRentLight); + PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", PriceObjectRent); + PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", PriceObjectScaleFactor); + PriceParcelRent = economyConfig.GetInt ("PriceParcelRent", PriceParcelRent); + PriceGroupCreate = economyConfig.GetInt ("PriceGroupCreate", PriceGroupCreate); + TeleportMinPrice = economyConfig.GetInt ("TeleportMinPrice", TeleportMinPrice); + TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", TeleportPriceExponent); + EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", EnergyEfficiency); + + // for HG Avatar + string avatar_class = economyConfig.GetString("HGAvatarAs", "HGAvatar").ToLower(); + if (avatar_class=="localavatar") m_hg_avatarClass = (int)AvatarType.LOCAL_AVATAR; + else if (avatar_class=="guestavatar") m_hg_avatarClass = (int)AvatarType.GUEST_AVATAR; + else if (avatar_class=="hgavatar") m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + else if (avatar_class=="foreignavatar") m_hg_avatarClass = (int)AvatarType.FOREIGN_AVATAR; + else m_hg_avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + } + catch { + m_log.ErrorFormat("[MONEY MODULE]: Initialise: Faile to read configuration file"); + } + } + + + public void AddRegion(Scene scene) + { + //m_log.InfoFormat("[MONEY MODULE]: AddRegion:"); + + if (scene==null) return; + + scene.RegisterModuleInterface(this); // 競合するモジュールの排除 + + lock (m_sceneList) { + if (m_sceneList.Count==0) { + if (m_enable_server) { + HttpServer = new BaseHttpServer(9000); + HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo)); + + HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler); + HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + HttpServer.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + HttpServer.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + + MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler); + MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + } + } + + if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle)) { + m_sceneList[scene.RegionInfo.RegionHandle] = scene; + } + else { + m_sceneList.Add(scene.RegionInfo.RegionHandle, scene); + } + } + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer += MoneyTransferAction; + scene.EventManager.OnValidateLandBuy += ValidateLandBuy; + scene.EventManager.OnLandBuy += processLandBuy; + } + + + public void RemoveRegion(Scene scene) + { + if (scene==null) return; + + lock (m_sceneList) { + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent -= MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer -= MoneyTransferAction; + scene.EventManager.OnValidateLandBuy -= ValidateLandBuy; + scene.EventManager.OnLandBuy -= processLandBuy; + } + } + + + public void RegionLoaded(Scene scene) + { + //m_log.InfoFormat("[MONEY MODULE]: RegionLoaded:"); + } + + + public Type ReplaceableInterface + { + //get { return typeof(IMoneyModule); } + get { return null; } + } + + + public bool IsSharedModule + { + get { return true; } + } + + + public string Name + { + get { return "DTLNSLMoneyModule"; } + } + + + public void PostInitialise() + { + //m_log.InfoFormat("[MONEY MODULE]: PostInitialise:"); + } + + + public void Close() + { + //m_log.InfoFormat("[MONEY MODULE]: Close:"); + } + + #endregion + + + #region IMoneyModule interface. + + // for LSL llGiveMoney() function + public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result) + { + //m_log.InfoFormat("[MONEY MODULE]: ObjectGiveMoney: LSL ObjectGiveMoney. UUID = {0}", objectID.ToString()); + + result = string.Empty; + if (!m_sellEnabled) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + + string objName = string.Empty; + string avatarName = string.Empty; + + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + objName = sceneObj.Name; + + Scene scene = GetLocateScene(toID); + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID); + if (account!=null) { + avatarName = account.FirstName + " " + account.LastName; + } + } + + bool ret = false; + string description = String.Format("Object {0} pays {1}", objName, avatarName); + + if (sceneObj.OwnerID==fromID) { + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + if (GetLocateClient(fromID)!=null) { + ret = TransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + else { + ret = ForceTransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + } + + if (!ret) result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return ret; + } + + + // + public int UploadCharge + { + get { return PriceUpload; } + } + + + // + public int GroupCreationCharge + { + get { return PriceGroupCreate; } + } + + + public int GetBalance(UUID agentID) + { + IClientAPI client = GetLocateClient(agentID); + return QueryBalanceFromMoneyServer(client); + } + + + public bool UploadCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public bool AmountCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public void ApplyUploadCharge(UUID agentID, int amount, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)TransactionType.UploadCharge, regionHandle, regionUUID, text); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type) + { + ApplyCharge(agentID, amount, type, string.Empty); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)type, regionHandle, regionUUID, text); + } + + + public bool Transfer(UUID fromID, UUID toID, int regionHandle, int amount, MoneyTransactionType type, string text) + { + return TransferMoney(fromID, toID, amount, (int)type, UUID.Zero, (ulong)regionHandle, UUID.Zero, text); + } + + + public bool Transfer(UUID fromID, UUID toID, UUID objectID, int amount, MoneyTransactionType type, string text) + { + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) return false; + + ulong regionHandle = sceneObj.ParentGroup.Scene.RegionInfo.RegionHandle; + UUID regionUUID = sceneObj.ParentGroup.Scene.RegionInfo.RegionID; + return TransferMoney(fromID, toID, amount, (int)type, objectID, (ulong)regionHandle, regionUUID, text); + } + + + // for 0.8.3 over + public void MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, string text) + { + ForceTransferMoney(fromAgentID, toAgentID, amount, (int)TransactionType.MoveMoney, UUID.Zero, (ulong)0, UUID.Zero, text); + } + + // for 0.9.1 over + public bool MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, MoneyTransactionType type, string text) + { + bool ret = ForceTransferMoney(fromAgentID, toAgentID, amount, (int)type, UUID.Zero, (ulong)0, UUID.Zero, text); + return ret; + } + + #endregion + + + #region MoneyModule event handlers + + // + private void OnNewClient(IClientAPI client) + { + //m_log.InfoFormat("[MONEY MODULE]: OnNewClient"); + + client.OnEconomyDataRequest += OnEconomyDataRequest; + client.OnLogout += ClientClosed; + + client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + client.OnRequestPayPrice += OnRequestPayPrice; + client.OnObjectBuy += OnObjectBuy; + } + + + public void OnMakeRootAgent(ScenePresence agent) + { + //m_log.InfoFormat("[MONEY MODULE]: OnMakeRootAgent:"); + + int balance = 0; + IClientAPI client = agent.ControllingClient; + + m_enable_server = LoginMoneyServer(agent, out balance); + client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + + //client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + //client.OnRequestPayPrice += OnRequestPayPrice; + //client.OnObjectBuy += OnObjectBuy; + } + + + // for OnClientClosed event + private void ClientClosed(IClientAPI client) + { + //m_log.InfoFormat("[MONEY MODULE]: ClientClosed:"); + + if (m_enable_server && client!=null) { + LogoffMoneyServer(client); + } + } + + + // for OnMakeChildAgent event + private void MakeChildAgent(ScenePresence avatar) + { + //m_log.InfoFormat("[MONEY MODULE]: MakeChildAgent:"); + } + + + // for OnMoneyTransfer event + private void MoneyTransferAction(Object sender, EventManager.MoneyTransferArgs moneyEvent) + { + //m_log.InfoFormat("[MONEY MODULE]: MoneyTransferAction: type = {0}", moneyEvent.transactiontype); + + if (!m_sellEnabled) return; + + // Check the money transaction is necessary. + if (moneyEvent.sender==moneyEvent.receiver) { + return; + } + + UUID receiver = moneyEvent.receiver; + // Pay for the object. + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + SceneObjectPart sceneObj = GetLocatePrim(moneyEvent.receiver); + if (sceneObj!=null) { + receiver = sceneObj.OwnerID; + } + else { + return; + } + } + + // Before paying for the object, save the object local ID for current transaction. + UUID objectID = UUID.Zero; + ulong regionHandle = 0; + UUID regionUUID = UUID.Zero; + + if (sender is Scene) { + Scene scene = (Scene)sender; + regionHandle = scene.RegionInfo.RegionHandle; + regionUUID = scene.RegionInfo.RegionID; + + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + objectID = scene.GetSceneObjectPart(moneyEvent.receiver).UUID; + } + } + + TransferMoney(moneyEvent.sender, receiver, moneyEvent.amount, moneyEvent.transactiontype, objectID, regionHandle, regionUUID, "OnMoneyTransfer event"); + return; + } + + + // for OnValidateLandBuy event + private void ValidateLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY MODULE]: ValidateLandBuy:"); + + IClientAPI senderClient = GetLocateClient(landBuyEvent.agentId); + if (senderClient!=null) { + int balance = QueryBalanceFromMoneyServer(senderClient); + if (balance >= landBuyEvent.parcelPrice) { + lock(landBuyEvent) { + landBuyEvent.economyValidated = true; + } + } + } + return; + } + + + // for LandBuy even + private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY MODULE]: processLandBuy:"); + + if (!m_sellEnabled) return; + + lock(landBuyEvent) { + if (landBuyEvent.economyValidated==true && landBuyEvent.transactionID==0) { + landBuyEvent.transactionID = Util.UnixTimeSinceEpoch(); + + ulong parcelID = (ulong)landBuyEvent.parcelLocalID; + UUID regionUUID = UUID.Zero; + if (sender is Scene) regionUUID = ((Scene)sender).RegionInfo.RegionID; + + if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID, + landBuyEvent.parcelPrice, (int)TransactionType.LandSale, regionUUID, parcelID, regionUUID, "Land Purchase")) { + landBuyEvent.amountDebited = landBuyEvent.parcelPrice; + } + } + } + return; + } + + + // for OnObjectBuy event + public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID, + UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice) + { + m_log.InfoFormat("[MONEY MODULE]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId); + + // Handle the parameters error. + if (!m_sellEnabled) return; + if (remoteClient==null || salePrice<0) return; + + // Get the balance from money server. + int balance = QueryBalanceFromMoneyServer(remoteClient); + if (balance(); + if (mod!=null) { + UUID receiverId = sceneObj.OwnerID; + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + bool ret = false; + // + if (salePrice>=0) { + if (!string.IsNullOrEmpty(m_moneyServURL)) { + ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice, + (int)TransactionType.PayObject, sceneObj.UUID, regionHandle, regionUUID, "Object Buy"); + } + else if (salePrice==0) { // amount is 0 with No Money Server + ret = true; + } + } + if (ret) { + mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); + } + } + } + else { + remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false); + return; + } + } + return; + } + + + /// + /// Sends the the stored money balance to the client + /// + /// + /// + /// + /// + private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID) + { + m_log.InfoFormat("[MONEY MODULE]: OnMoneyBalanceRequest:"); + + if (client.AgentId==agentID && client.SessionId==SessionID) { + int balance = 0; + // + if (m_enable_server) { + balance = QueryBalanceFromMoneyServer(client); + } + + client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + } + else { + client.SendAlertMessage("Unable to send your money balance"); + } + } + + + private void OnRequestPayPrice(IClientAPI client, UUID objectID) + { + m_log.InfoFormat("[MONEY MODULE]: OnRequestPayPrice:"); + + Scene scene = GetLocateScene(client.AgentId); + if (scene==null) return; + SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID); + if (sceneObj==null) return; + SceneObjectGroup group = sceneObj.ParentGroup; + SceneObjectPart root = group.RootPart; + + client.SendPayPrice(objectID, root.PayPrice); + } + + + // + //private void OnEconomyDataRequest(UUID agentId) + private void OnEconomyDataRequest(IClientAPI user) + { + //m_log.InfoFormat("[MONEY MODULE]: OnEconomyDataRequest:"); + //IClientAPI user = GetLocateClient(agentId); + + if (user!=null) { + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + //Scene s = GetLocateScene(user.AgentId); + Scene s = (Scene)user.Scene; + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, + PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, + PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, + TeleportMinPrice, TeleportPriceExponent); + } + } + } + + #endregion + + + #region MoneyModule XML-RPC Handler + + // "OnMoneyTransfered" RPC from MoneyServer + public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + m_log.InfoFormat("[MONEY MODULE]: OnMoneyTransferedHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("transactionType") && requestParam.Contains("objectID") && requestParam.Contains("amount")) { + //m_log.InfoFormat("[MONEY MODULE]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]); + + // Pay for the object. + if ((int)requestParam["transactionType"]==(int)TransactionType.PayObject) { + // Send notify to the client(viewer) for Money Event Trigger. + ObjectPaid handlerOnObjectPaid = OnObjectPaid; + if (handlerOnObjectPaid!=null) { + UUID objectID = UUID.Zero; + UUID.TryParse((string)requestParam["objectID"], out objectID); + handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money() + } + ret = true; + } + } + } + } + } + } + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY MODULE]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UpdateBalance" RPC from MoneyServer or Script + public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: BalanceUpdateHandler:"); + + bool ret = false; + + #region Update the balance from money server. + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + // + if (requestParam.Contains("Balance")) { + // Send notify to the client. + string msg = ""; + if (requestParam.Contains("Message")) msg = (string)requestParam["Message"]; + client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"], + 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + // Dialog + if (msg!="") { + Scene scene = (Scene)client.Scene; + IDialogModule dlg = scene.RequestModuleInterface(); + dlg.SendAlertToUser(client.AgentId, msg); + } + ret = true; + } + } + } + } + } + + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY MODULE]: BalanceUpdateHandler: Cannot update client balance from MoneyServer"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UserAlert" RPC from Script + public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: UserAlertHandler:"); + + bool ret = false; + + #region confirm the request and show the notice from money server. + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("Description")) + { + string description = (string)requestParam["Description"]; + // Show the notice dialog with money server message. + GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()), + (byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3()); + client.SendInstantMessage(gridMsg); + ret = true; + } + } + } + } + } + // + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + return resp; + } + + + // "GetBalance" RPC from Script + public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: GetBalanceHandler:"); + + bool ret = false; + int balance = -1; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + balance = QueryBalanceFromMoneyServer(client); + } + } + } + } + + // Send the response to caller. + if (balance<0) { + m_log.ErrorFormat("[MONEY MODULE]: GetBalanceHandler: GetBalance transaction is failed"); + ret = false; + } + + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + paramTable["balance"] = balance; + resp.Value = paramTable; + + return resp; + } + + + // "AddBankerMoney" RPC from Script + public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: AddBankerMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID bankerUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID); + // + if (bankerUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(bankerUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("amount")) + { + Scene scene = (Scene)client.Scene; + int amount = (int)requestParam["amount"]; + ulong regionHandle = scene.RegionInfo.RegionHandle; + UUID regionUUID = scene.RegionInfo.RegionID; + ret = AddBankerMoney(bankerUUID, amount, regionHandle, regionUUID); + + if (m_use_web_settle && m_settle_user) { + ret = true; + IDialogModule dlg = scene.RequestModuleInterface(); + if (dlg!=null) { + dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url); + } + } + } + } + } + } + } + + if (!ret) m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoneyHandler: Add Banker Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["settle"] = false; + paramTable["success"] = ret; + + if (m_use_web_settle && m_settle_user) paramTable["settle"] = true; + resp.Value = paramTable; + + return resp; + } + + + // "SendMoney" RPC from Script + public XmlRpcResponse SendMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: SendMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("agentUUID") && requestParam.Contains("secretAccessCode")) { + UUID agentUUID = UUID.Zero; + UUID.TryParse((string)requestParam["agentUUID"], out agentUUID); + + if (agentUUID!=UUID.Zero) { + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + int type = -1; + if (requestParam.Contains("type")) type = (int)requestParam["type"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY MODULE]: SendMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = SendMoneyTo(agentUUID, amount, type, hash); + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("agentUUID")) { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: agentUUID is missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: Send Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + + // "MoveMoney" RPC from Script + public XmlRpcResponse MoveMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: MoveMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if ((requestParam.Contains("fromUUID") || requestParam.Contains("toUUID")) && requestParam.Contains("secretAccessCode")) { + UUID fromUUID = UUID.Zero; + UUID toUUID = UUID.Zero; // UUID.Zero means System + if (requestParam.Contains("fromUUID")) UUID.TryParse((string)requestParam["fromUUID"], out fromUUID); + if (requestParam.Contains("toUUID")) UUID.TryParse((string)requestParam["toUUID"], out toUUID); + + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY MODULE]: MoveMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = MoveMoneyFromTo(fromUUID, toUUID, amount, hash); + } + else { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("fromUUID") && !requestParam.Contains("toUUID")) { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: fromUUID and toUUID are missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: Move Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + #endregion + + + #region MoneyModule private help functions + + /// + /// Transfer the money from one user to another. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY MODULE]: TransferMoney:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY MODULE]: TransferMoney: Client {0} not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Force transfer the money from one user to another. + /// This function does not check sender login. + /// Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY MODULE]: ForceTransferMoney:"); + + bool ret = false; + + #region Force send transaction request to money server and parse the resultes. + + if (m_enable_server) { + string objName = string.Empty; + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj!=null)objName = sceneObj.Name; + + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = sender.ToString(); + paramTable["receiverID"] = receiver.ToString(); + paramTable["transactionType"] = type; + paramTable["objectID"] = objectID.ToString(); + paramTable["objectName"] = objName; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["amount"] = amount; + paramTable["description"] = description; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + else m_log.ErrorFormat("[MONEY MODULE]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString()); + } + //else m_log.ErrorFormat("[MONEY MODULE]: ForceTransferMoney: Money Server is not available!!"); + + #endregion + + return ret; + } + + + /// + /// Send the money to avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool SendMoneyTo(UUID avatarID, int amount, int type, string secretCode) + { + //m_log.InfoFormat("[MONEY MODULE]: SendMoneyTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + if (type<0) type = (int)TransactionType.ReferBonus; + Hashtable paramTable = new Hashtable(); + paramTable["receiverID"] = avatarID.ToString(); + paramTable["transactionType"] = type; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Bonus to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Move the money from avatar to other avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool MoveMoneyFromTo(UUID senderID, UUID receiverID, int amount, string secretCode) + { + //m_log.InfoFormat("[MONEY MODULE]: MoveMoneyFromTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = senderID.ToString(); + paramTable["receiverID"] = receiverID.ToString(); + paramTable["transactionType"] = (int)TransactionType.MoveMoney; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Move Money"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "MoveMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Add the money to banker avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle, UUID regionUUID) + { + //m_log.InfoFormat("[MONEY MODULE]: AddBankerMoney:"); + + bool ret = false; + m_settle_user = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["bankerID"] = bankerID.ToString(); + paramTable["transactionType"] = (int)TransactionType.BuyMoney; + paramTable["amount"] = amount; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["description"] = "Add Money to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null) { + if (resultTable.Contains("success") && (bool)resultTable["success"]==true) { + ret = true; + } + else { + if (resultTable.Contains("banker")) { + m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used. + if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used."); + } + else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Fail Message {0}", resultTable["message"]); + } + } + else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Money Server is not available!!"); + + return ret; + } + + + /// + /// Pay the money of charge. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY MODULE]: PayMoneyCharge:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY MODULE]: PayMoneyCharge: Client {0} is not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Login the money server when the new client login. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LoginMoneyServer(ScenePresence avatar, out int balance) + { + //m_log.InfoFormat("[MONEY MODULE]: LoginMoneyServer:"); + + balance = 0; + bool ret = false; + bool isNpc = avatar.IsNPC; + + IClientAPI client = avatar.ControllingClient; + + #region Send money server the client info for login. + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + Scene scene = (Scene)client.Scene; + string userName = string.Empty; + + // Get the username for the login user. + if (client.Scene is Scene) { + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId); + if (account!=null) { + userName = account.FirstName + " " + account.LastName; + } + } + } + + ////////////////////////////////////////////////////////////// + // User Universal Identifer for Grid Avatar, HG Avatar or NPC + string universalID = string.Empty; + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + int avatarType = (int)AvatarType.LOCAL_AVATAR; + int avatarClass = (int)AvatarType.LOCAL_AVATAR; + + AgentCircuitData agent = scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); + + if (agent!=null) { + universalID = Util.ProduceUserUniversalIdentifier(agent); + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + string tmp; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out tmp); + } + // if serverURL is empty, avatar is a NPC + if (isNpc || String.IsNullOrEmpty(serverURL)) { + avatarType = (int)AvatarType.NPC_AVATAR; + } + // + if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin)!=0 || String.IsNullOrEmpty(userName)) { + avatarType = (int)AvatarType.HG_AVATAR; + } + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // + avatarClass = avatarType; + if (avatarType==(int)AvatarType.NPC_AVATAR) return false; + if (avatarType==(int)AvatarType.HG_AVATAR) avatarClass = m_hg_avatarClass; + + // + // Login the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(), + scene.RegionInfo.HttpPort.ToString()); + paramTable["avatarType"] = avatarType.ToString(); + paramTable["avatarClass"] = avatarClass.ToString(); + paramTable["userName"] = userName; + paramTable["universalID"] = universalID; + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + balance = (int)resultTable["clientBalance"]; + m_log.InfoFormat("[MONEY MODULE]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL); + ret = true; + } + } + else m_log.ErrorFormat("[MONEY MODULE]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString()); + } + else m_log.ErrorFormat("[MONEY MODULE]: LoginMoneyServer: Money Server is not available!! Server URL is Null or empty!!"); + + #endregion + + // Viewerへ設定を通知する. + if (ret || string.IsNullOrEmpty(m_moneyServURL)) { + OnEconomyDataRequest(client); + } + + return ret; + } + + + /// + /// Log off from the money server. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LogoffMoneyServer(IClientAPI client) + { + //m_log.InfoFormat("[MONEY MODULE]: LogoffMoneyServer:"); + + bool ret = false; + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + // Log off from the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout"); + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + } + + return ret; + } + + + // + private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID) + { + //m_log.InfoFormat("[MONEY MODULE]: GetTransactionInfo:"); + + EventManager.MoneyTransferArgs args = null; + + if (m_enable_server) { + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + paramTable["transactionID"] = transactionID; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + int amount = (int)resultTable["amount"]; + int type = (int)resultTable["type"]; + string desc = (string)resultTable["description"]; + UUID sender = UUID.Zero; + UUID recver = UUID.Zero; + UUID.TryParse((string)resultTable["sender"], out sender); + UUID.TryParse((string)resultTable["receiver"], out recver); + args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc); + } + else { + m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]); + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: Invalid Response"); + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: Invalid Money Server URL"); + } + + return args; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method) + { + //m_log.InfoFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest:"); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!m_moneyServURL.StartsWith("https://")) { + m_log.InfoFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file"); + //return null; + } + } + else { + if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL); + return null; + } + } + + // + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + //moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_certVerify, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL); + m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: {0}", ex); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /// Locates a IClientAPI for the client specified + /// + /// + /// + private IClientAPI GetLocateClient(UUID AgentID) + { + IClientAPI client = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID); + if (tPresence!=null && !tPresence.IsChildAgent) { + IClientAPI rclient = tPresence.ControllingClient; + if (rclient!=null) { + client = rclient; + break; + } + } + } + } + } + + return client; + } + + + private Scene GetLocateScene(UUID AgentId) + { + Scene scene = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId); + if (tPresence!=null && !tPresence.IsChildAgent) { + scene = _scene; + break; + } + } + } + } + + return scene; + } + + + private SceneObjectPart GetLocatePrim(UUID objectID) + { + SceneObjectPart sceneObj = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID); + if (part!=null) { + sceneObj = part; + break; + } + } + } + } + + return sceneObj; + } + + #endregion + } + +} diff --git a/OpenSim.Modules.Currency/NSLCertificateTools.cs b/OpenSim.Modules.Currency/NSLCertificateTools.cs new file mode 100644 index 0000000..b0c3034 --- /dev/null +++ b/OpenSim.Modules.Currency/NSLCertificateTools.cs @@ -0,0 +1,291 @@ +/* + * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp + * + */ + +#pragma warning disable S1128 // Unused "using" should be removed +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Net; +using System.Net.Security; +using System.Text; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using log4net; +#pragma warning restore S1128 // Unused "using" should be removed + + +namespace NSL.Certificate.Tools +{ + /// + /// class NSL Certificate Verify + /// + public class NSLCertificateVerify + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private X509Chain m_chain = null; + private X509Certificate2 m_cacert = null; + private X509Certificate2 m_mycert = null; + + private Mono.Security.X509.X509Crl m_clientcrl = null; + + + /// + /// NSL Certificate Verify + /// + public NSLCertificateVerify() + { + m_chain = null; + m_cacert = null; + m_clientcrl = null; + } + + + /// + /// NSL Certificate Verify + /// + /// + public NSLCertificateVerify(string certfile) + { + SetPrivateCA(certfile); + } + + + /// + /// NSL Certificate Verify + /// + /// + /// + public NSLCertificateVerify(string certfile, string crlfile) + { + SetPrivateCA (certfile); + SetPrivateCRL(crlfile); + } + + + /// + /// Set Private Certificate + /// + /// + /// + public void SetPrivateCert(string certfile, string passwd) + { + try { + m_mycert = new X509Certificate2(certfile, passwd); + } + catch (Exception ex) { + m_mycert = null; + m_log.ErrorFormat("[SET PRIVATE CERT]: Cert File setting error [{0}]. {1}", certfile, ex); + } + } + + + /// + /// Get Private Certificate + /// + public X509Certificate2 GetPrivateCert() + { + return m_mycert; + } + + + /// + /// Set Private CA + /// + /// + public void SetPrivateCA(string certfile) + { + try { + m_cacert = new X509Certificate2(certfile); + } + catch (Exception ex) { + m_cacert = null; + m_log.ErrorFormat("[SET PRIVATE CA]: CA File reading error [{0}]. {1}", certfile, ex); + } + + if (m_cacert!=null) { + m_chain = new X509Chain(); + m_chain.ChainPolicy.ExtraStore.Add(m_cacert); + m_chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + m_chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; + } + } + + + // + public void SetPrivateCRL(string crlfile) + { + try { + m_clientcrl = Mono.Security.X509.X509Crl.CreateFromFile(crlfile); + } + catch (Exception ex) { + m_clientcrl = null; + m_log.ErrorFormat("[SET PRIVATE CRL]: CRL File reading error [{0}]. {1}", crlfile, ex); + } + } + + + /// + /// Check Private Chain + /// + /// + /// + public bool CheckPrivateChain(X509Certificate2 cert) + { + if (m_chain==null || m_cacert==null) { + return false; + } + + bool ret = m_chain.Build((X509Certificate2)cert); + if (ret) { + return true; + } + + for (int i=0; i + /// Validate Server Certificate Callback Function + /// + /// + /// + /// + /// + /// + public bool ValidateServerCertificate(object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Policy is ({0})", sslPolicyErrors); + + if (obj is HttpWebRequest) { + HttpWebRequest Request = (HttpWebRequest)obj; + string noVerify = Request.Headers.Get("NoVerifyCert"); + if ((noVerify != null) && (noVerify.ToLower() == "true")) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: No Verify Server Certificate."); + return true; + } + } + + X509Certificate2 certificate2 = new X509Certificate2(certificate); + string commonname = certificate2.GetNameInfo(X509NameType.SimpleName, false); + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Common Name is \"{0}\"", commonname); + + /* + // RemoteCertificateNotAvailableはエラーとする. + if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable)==SslPolicyErrors.RemoteCertificateNotAvailable) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Policy Error! {0}", sslPolicyErrors); + return false; + } + */ + + // None, ChainErrors Error except for. // None, ChainErrors 以外は全てエラーとする. + if ((sslPolicyErrors != SslPolicyErrors.None) && (sslPolicyErrors != SslPolicyErrors.RemoteCertificateChainErrors)) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Policy Error! {0}", sslPolicyErrors); + return false; + } + + bool valid = CheckPrivateChain(certificate2); + if (valid) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Valid Server Certification for \"{0}\"", commonname); + } + else { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Failed to Verify Server Certification for \"{0}\"", commonname); + } + return valid; + } + + + /// + /// Validate Client Certificate Callback Function + /// + /// + /// + /// + /// + /// + public bool ValidateClientCertificate(object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Start."); + + if (certificate==null) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Client does not have a Certificate!"); + return false; + } + + X509Certificate2 certificate2 = new X509Certificate2(certificate); + string commonname = certificate2.GetNameInfo(X509NameType.SimpleName, false); + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Common Name is \"{0}\"", commonname); + + // None, ChainErrors 以外は全てエラーとする. + if (sslPolicyErrors!=SslPolicyErrors.None && sslPolicyErrors!=SslPolicyErrors.RemoteCertificateChainErrors) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Policy Error! {0}", sslPolicyErrors); + return false; + } + + // check CRL + if (m_clientcrl!=null) { + Mono.Security.X509.X509Certificate monocert = new Mono.Security.X509.X509Certificate(certificate.GetRawCertData()); + Mono.Security.X509.X509Crl.X509CrlEntry entry = m_clientcrl.GetCrlEntry(monocert); + if (entry!=null) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: Common Name \"{0}\" was revoked at {1}", commonname, entry.RevocationDate.ToString()); + return false; + } + } + + bool valid = CheckPrivateChain(certificate2); + if (valid) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: Valid Client Certification for \"{0}\"", commonname); + } + else { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: Failed to Verify Client Certification for \"{0}\"", commonname); + } + return valid; + } + } + + +/* + /// + /// class NSL Certificate Policy + /// + public class NSLCertificatePolicy : ICertificatePolicy + { + /// + /// Check Validation Result + /// + /// + /// + /// + /// + /// + public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) + { + if (certificateProblem == 0 || // normal // 正常 + certificateProblem == -2146762487 || // Not trusted // 信頼されてない + certificateProblem == -2146762495 || // Expired // 期限切れ + certificateProblem == -2146762481) { // Incorrect name // 名前不正 + return true; + } + else { + return false; + } + } + } +*/ +} diff --git a/OpenSim.Modules.Currency/NSLXmlRpc.cs b/OpenSim.Modules.Currency/NSLXmlRpc.cs new file mode 100644 index 0000000..025236a --- /dev/null +++ b/OpenSim.Modules.Currency/NSLXmlRpc.cs @@ -0,0 +1,115 @@ +/* + * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp + * + */ + + +using System; +using System.Collections; +using System.IO; +using System.Xml; +using System.Net; +using System.Text; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using log4net; +using Nwc.XmlRpc; + +using System.Net.Security; +using NSL.Certificate.Tools; + + +namespace NSL.Network.XmlRpc +{ + public class NSLXmlRpcRequest : XmlRpcRequest + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Encoding _encoding = new UTF8Encoding(); + private XmlRpcRequestSerializer _serializer = new XmlRpcRequestSerializer(); + private XmlRpcResponseDeserializer _deserializer = new XmlRpcResponseDeserializer(); + + + public NSLXmlRpcRequest() + { + _params = new ArrayList(); + } + + + public NSLXmlRpcRequest(String methodName, IList parameters) + { + MethodName = methodName; + _params = parameters; + } + + + //public XmlRpcResponse certSend(String url, X509Certificate2 myClientCert, bool checkServerCert, Int32 timeout) + public XmlRpcResponse certSend(String url, NSLCertificateVerify certVerify, bool checkServerCert, Int32 timeout) + { + m_log.InfoFormat("[MONEY NSL XMLRPC]: XmlRpcResponse certSend: connect to {0}", url); + +//#pragma warning disable SYSLIB0014 // Use HttpClient instead of WebRequest.Create. + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); +//#pragma warning restore SYSLIB0014 + if (request==null) { + throw new XmlRpcException(XmlRpcErrorCodes.TRANSPORT_ERROR, XmlRpcErrorCodes.TRANSPORT_ERROR_MSG +": Could not create request with " + url); + } + + X509Certificate2 clientCert = null; + + request.Method = "POST"; + request.ContentType = "text/xml"; + request.AllowWriteStreamBuffering = true; + request.Timeout = timeout; + request.UserAgent = "NSLXmlRpcRequest"; + + if (certVerify != null) { + clientCert = certVerify.GetPrivateCert(); + if (clientCert != null) request.ClientCertificates.Add(clientCert); // Own certificate // 自身の証明書 + request.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(certVerify.ValidateServerCertificate); + } + else { + checkServerCert = false; + } + // + if (!checkServerCert) { + request.Headers.Add("NoVerifyCert", "true"); // Do not verify the certificate of the other party // 相手の証明書を検証しない + } + + // + Stream stream = null; + try { + stream = request.GetRequestStream(); + } +#pragma warning disable CS0168 + catch (Exception ex) { +#pragma warning restore CS0168 + m_log.ErrorFormat("[MONEY NSL XMLRPC]: GetRequestStream Error: {0}", ex); + stream = null; + } + if (stream==null) return null; + + // + XmlTextWriter xml = new XmlTextWriter(stream, _encoding); + _serializer.Serialize(xml, this); + xml.Flush(); + xml.Close(); + + HttpWebResponse response = null; + try { + response = (HttpWebResponse)request.GetResponse(); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY NSL XMLRPC]: XmlRpcResponse certSend: GetResponse Error: {0}", ex.ToString()); + } + StreamReader input = new StreamReader(response.GetResponseStream()); + + string inputXml = input.ReadToEnd(); + XmlRpcResponse resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); + + input.Close(); + response.Close(); + return resp; + } + } +} diff --git a/OpenSim.Modules.Currency/Properties/AssemblyInfo.cs b/OpenSim.Modules.Currency/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..59897cb --- /dev/null +++ b/OpenSim.Modules.Currency/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Modules.Currency")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("DTL/NSL Group")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2363e3c9-7be0-4b9b-84ac-82923d5021f4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/README b/README new file mode 100644 index 0000000..f01d4f4 --- /dev/null +++ b/README @@ -0,0 +1,127 @@ + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// DTL/NSL Secure Money Server for Linux/Unix +// by Fumi.Iseki and NSL +// http://www.nsl.tuis.ac.jp + +0. Outline + + This Money Server is modified version of DTL Currency Processing. + As for this, some bug fixes and some functionality expansions are done. And this can be operated by OpenSim 0.9.x. + But, Web Monitor function (ASP.NET) is removed from original DTL Currency. So, this version is less secure than original + version!! Please use this at Your Own Risk!! + +Attention) + Client(SIM) certification causes an error in mono-5.16 and above. + + +1. Install + +1) Compile Opensim or Prepare compiled binary Opensim + +2) When you use mono + # cd opensim + # svn co http://www.nsl.tuis.ac.jp/svn/opensim/opensim.currency/trunk opensim.currency + # cd opensim.currensy + # ./build.sh + +3) When you use dotnet + # cd opensim + # svn co http://www.nsl.tuis.ac.jp/svn/opensim/opensim.currency/trunk opensim.currency + # cd opensim.currensy + # ./build.net.sh + + +2. Setting + +2-1. Money Server + + # cd opensim-0.9.x-source + # vi bin/MoneyServer.ini + + - Plese set hostname, database, username and password of MySQL at [MySql] section. + - If you use Banker Avatar, please set UUID of Banker Avatar to "BankerAvatar" in MoneyServer.ini. + Banker Avatar can buy money from system with no cost. + When 00000000-0000-0000-0000-000000000000 is specified as UUID, all avatars can get money from system. + - If you want to normally use llGiveMoney() function even when payer doesn't login to OpenSim, + you must set "true" to "enableForceTransfer" in MoneyServer.ini. + - If you want to send money to anotger avatar by PHP script, you must set "true" to "enableScriptSendMoney" + And please set "MoneyScriptAccessKey" and "MoneyScriptIPaddress", too. + "MoneyScriptAccessKey" is Secret key of Helper Script. Specify same key in include/config.php or WI(XoopenSim/Modlos) + "MoneyScriptIPaddress" is IP address of server that Helper Script execute at. Not specify 127.0.0.1. + - If you want to change Update Balance Messages (blue dialog), pleaase enable and rewrite "BalanceMessage..." valiables. + - Please see also: http://www.nsl.tuis.ac.jp/xoops/modules/xpwiki/?OpenSim%2FMoneyServer%2FMoneyServer.ini + + +2-2. Region Server + + # cd opensim-0.9.x-source + # vi bin/OpenSim.ini + + [Economy] + SellEnabled = "true" + CurrencyServer = "https://(MoneyServer's Name or IP):8008/" + UserServer = "http://(UserServer's Name or IP):8002/" + EconomyModule = DTLNSLMoneyModule + + ;; Money Unit fee to upload textures, animations etc + PriceUpload = 10 + + ;; Money Unit fee to create groups + PriceGroupCreate = 100 + + + Attention) + - Module name was changed from DTLMoneyModule to DTLNSLMoneyModule + - Not use 127.0.0.1 or localhost for UserServer's address and CurrencyServer's address. + This address is used for identification of user on Money Server. + - Please see also: http://www.nsl.tuis.ac.jp/xoops/modules/xpwiki/?OpenSim%2FMoneyServer%2FOpenSim.ini + + +2-3. Helper Script + + - If you do not use XoopenSim or Modlos (Web Interface), you should setup helper scripts by manual. + - Please copy Scripts/* to any Web contents directory, and execute setup_sripts.sh shell script. + And next, edit include/config.php to rewrite ENV_HELPER_URL, ENV_HELPER_PATH, DB information, and etc.etc. + - Please see also: http://www.nsl.tuis.ac.jp/xoops/modules/xpwiki/?OpenSim%2FMoneyServer%2FHelper%20Script + + ex.) + # mkdir /var/www/currency + # cp -Rpd Scripts/* /var/www/currency + # cd /var/www/currency + # ./setup_sripts.sh + # chown -R www-data.www-data . + # vi include/config.php + + - Please execute viewer with "-helperuri [ENV_HELPER_URL/]" option. + Here, ENV_HELPER_URL is helper directory url in include/config.php. + - ex.) -helperuri http://localhost/currency/helper/ need last '/' + + +5. License. + + MIT License + + +6. Attention. + + This is unofficial software. Please do not inquire to OpenSim development team or DTL Currency Processing + development team about this software. + + +7. Exemption from responsibility. + + This software is not guaranteed at all. The author doesn't assume the responsibility for the + problem that occurs along with use, remodeling, and the re-distribution of this software at all. + Please use everything by the self-responsibility. + + +8. Address of thanks. + + This Money Server is modified version of DTL Currency Processing. + + About this project, Milo did a lot of advice and donation to us. + + Thank you very much!! + diff --git a/README.jp b/README.jp new file mode 100644 index 0000000..5e8d305 --- /dev/null +++ b/README.jp @@ -0,0 +1,138 @@ + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// OpenSim DTL/NSL Secure Money Server for Linux/Unix +// by Fumi.Iseki and NSL +// http://www.nsl.tuis.ac.jp + +0. はじめに + + これは DTL Currency Processing Project から Web Monitor を取り外して,いくつかのバグフィックスと +0.9.xで動作するようにパッチを充てた物です. + また幾つかの機能拡張も行っています.Web Monitor を取り外したのは,我々のターゲットが主に +Linuxであるのに対して,この機能 ASP.NETで作動しており,Linux上で動作させるのが困難だったためです. + + 従って,セキュリティ的には本来の DTL Money Serverよりも低下していると思われます.実際,この +Money Serverを誤魔化すことも不可能ではありません.つまり,このシステムについては厳密に仮想通貨 +を取り扱いたい環境での使用はお勧めできません.本システムを使用する場合は,あくまでも自己責任で +お使いください. + + +1. インストール + +1) OpenSim をコンパイルするか,コンポいる済みの OpenSim を用意します. + +2) Mono を使用する場合 + # cd opensim + # svn co http://www.nsl.tuis.ac.jp/svn/opensim/opensim.currency/trunk opensim.currency + # cd opensim.currensy + # ./build.sh + +2) dotnet を使用する場合 + # cd opensim + # svn co http://www.nsl.tuis.ac.jp/svn/opensim/opensim.currency/trunk opensim.currency + # cd opensim.currensy + # ./build.net.sh + + +2. 設定 + +2-1. Money Server + + bin/MoneyServer.ini の [MySql] に MySQLサーバにアクセスするための情報を追加する + + # cd opensim-0.9.x-source + # vi bin/MoneyServer.ini + + 1. [MySql]セクションの hostname, database, username, password を設定する. + OpenSim のMySQLの設定と同じものを指定すれば良い. + 2. バンカーアバター(システムから対価無しにMoneyを購入することが可能なアバター)を有効にするには + [MoneyServer]セクションの "BankerAvatar" にバンカーアバターとなるアバターのUUIDを指定する. + UUIDとして 00000000-0000-0000-0000-000000000000を指定した場合は,全てのアバターがバンカーアバターとなる. + 3. 支払い者がログインしていない状態でも,llGiveMoney()を正常に動かす場合は + [MoneyServer]セクションの "enableForceTransfer" を trueにする. + 4. PHPスクリプトの send_money() を使用して,お金をアバターに振り込む場合は "enableScriptSendMoney" を trueにする. + また,"MoneyScriptAccessKey", "MoneyScriptIPaddress" も設定が必要である. + "MoneyScriptAccessKey" はスクリプトへのアクセスキーであり,include/config.php または WI(XoopenSim/Modlos) と同じものを設定する. + "MoneyScriptIPaddress" にはスクリプトが動作するサーバのIPアドレスを記述する.127.0.0.1は使用しないこと. + 5. 所持金のアップデートのメッセージ(青いダイアログ)を変更することが可能である.メッセージを変更したい場合は各 "BalanceMessage..." + を有効にし内容を書き換える. + + 参考: http://www.nsl.tuis.ac.jp/xoops/modules/xpwiki/?OpenSim%2FMoneyServer%2FMoneyServer.ini + + +2-2. Region Server + + bin/OpenSim.ini に MoneyServerに接続するための設定を行う.Money Serverには HTTPS +を使用して接続を行う.この際に使用するポート番号は 8008である. + + # cd opensim-0.9.x-source + # vi bin/OpenSim.ini + + [Economy] + SellEnabled = "true" + CurrencyServer = "https://(MoneyServer's Name or IP):8008/" + UserServer = "http://(UserServer's Name or IP):8002" + EconomyModule = DTLNSLMoneyModule + + ;; Money Unit fee to upload textures, animations etc + PriceUpload = 10 ;; テクスチャなどのアップロードのコスト + + ;; Money Unit fee to create groups + PriceGroupCreate = 100 ;; グループ作成のコスト + + + 注)モジュールの名前が DTLNSLMoneyModule に変更になりました. + なお,UserServer と CurrencyServer のアドレスに localhost (127.0.0.1)を使用しないこと. + これは,アドレスが,Monet Server内でのユーザのアカウント識別に利用されるためである. + + 参考: http://www.nsl.tuis.ac.jp/xoops/modules/xpwiki/?OpenSim%2FMoneyServer%2FOpenSim.ini + + +2-3. Helper スクリプト + + Webインターフェイスの XoopenSimまたは Modlosを使用しない場合,ヘルパースクリプトを手動で設置 +なければならない.ヘルパースクリプトは Scriptsディレクトリにあるので,これを適当なディレクトリ +にコピーし,inculde/helper.php の内容(主に ENV_HELPER_URL, ENV_HELPER_PATH, DB関連)をシステム +に合わせて変更する. + + コマンド例) + # mkdir /var/www/currency + # cp -Rpd Scripts/* /var/www/currency + # cd /var/www/currency + # ./setup_scripts.sh + # chown -R www-data.www-data . + # vi include/config.php + + Viewerは "-helperuri [ENV_HELPER_URL/]" オプション付きで起動しなければならない.ここで ENV_HELPER_URL +ヘルパースクリプトの helperディレクトリのURLである. + 例) -helperuri http://localhost/currency/helper/ 最後の / は必ず必要!! + + 参考: http://www.nsl.tuis.ac.jp/xoops/modules/xpwiki/?OpenSim%2FMoneyServer%2FHelper%20Script + + +3. ライセンス + + MIT License + + +4. 注意事項 + + このソフトウェアはNSLで改造された非公式のソフトウェアです.このソフトウェアに関して OpenSimの開発チームや + DTL Currency Processingの開発チームへのお問い合わせは行わないでください. + + +5. 免責 + + このソフトウェアは全くの無保証です.このソフトウェアの使用・改造・再配布に伴い発生する問題に関して,作者は一切の + 責任を負いません.全て自己責任でご使用ください. + + +6. 謝辞 + + このプログラムは DTL Curremcy Processing を改造したものです. + + このプロジェクトに関して,Miloから沢山のアドバイスと寄付をいただきました. + + ありがとうございました. + diff --git a/Release.txt b/Release.txt new file mode 100644 index 0000000..cbeb0ad --- /dev/null +++ b/Release.txt @@ -0,0 +1,16 @@ + +DTL/NSL Money Server v0.9.3.0 (2023 8/11) + for .Net6 + +DTL/NSL Money Server v0.9.2.2 (2023 6/2) + for Client Certificate + +DTL/NSL Money Server v0.9.1r01 (2020 4/11) + Fix NPC Bug, Variable Port No. of Server + +DTL/NSL Money Server v0.9.1 (2019 11/5) + Suport of OpenSim v0.9.1 + +DTL/NSL Money Server v0.9.0 (2018 4/22) + Suport of OpenSim v0.9.0 + diff --git a/bin/net6.0/MoneyServer b/bin/net6.0/MoneyServer new file mode 100755 index 0000000..690bd3a Binary files /dev/null and b/bin/net6.0/MoneyServer differ diff --git a/bin/net6.0/MoneyServer.dll b/bin/net6.0/MoneyServer.dll new file mode 100644 index 0000000..4b706b4 Binary files /dev/null and b/bin/net6.0/MoneyServer.dll differ diff --git a/bin/net6.0/MoneyServer.runtimeconfig.json b/bin/net6.0/MoneyServer.runtimeconfig.json new file mode 100644 index 0000000..9adb78a --- /dev/null +++ b/bin/net6.0/MoneyServer.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net6.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "6.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.TieredCompilation.QuickJit": false + } + } +} \ No newline at end of file diff --git a/bin/net6.0/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll b/bin/net6.0/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll new file mode 100644 index 0000000..3453be0 Binary files /dev/null and b/bin/net6.0/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll differ diff --git a/bin/net6.0/OpenSim.Modules.Currency.dll b/bin/net6.0/OpenSim.Modules.Currency.dll new file mode 100644 index 0000000..64e01b2 Binary files /dev/null and b/bin/net6.0/OpenSim.Modules.Currency.dll differ diff --git a/build.net.sh b/build.net.sh new file mode 100755 index 0000000..0e7ce95 --- /dev/null +++ b/build.net.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +CONFIGPATH=./config +OPNSIMPATH=../bin +DOTNETVER=6.0 + +echo "===================" +echo "DTL/NSL_CURRENCY" +echo "===================" + +./clean.sh +./runprebuild.net.sh +dotnet build -c Release OpenSim.Currency.sln || exit 1 + +echo +cp -f bin/net${DOTNETVER}/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll $OPNSIMPATH +cp -f bin/net${DOTNETVER}/OpenSim.Modules.Currency.dll $OPNSIMPATH +cp -f bin/net${DOTNETVER}/MoneyServer.dll $OPNSIMPATH +cp -f bin/net${DOTNETVER}/MoneyServer $OPNSIMPATH +cp -f bin/net${DOTNETVER}/MoneyServer.runtimeconfig.json $OPNSIMPATH + +# +rm -f $OPNSIMPATH/OpenSim.Forge.Currency.dll + +if [ ! -f $OPNSIMPATH/MoneyServer.ini ]; then + cp $CONFIGPATH/MoneyServer.ini $OPNSIMPATH +else + cp $CONFIGPATH/MoneyServer.ini $OPNSIMPATH/MoneyServer.ini.example +fi + +if [ ! -f $OPNSIMPATH/MoneyServer.dll.config ]; then + cp $CONFIGPATH/MoneyServer.exe.config $OPNSIMPATH/MoneyServer.dll.config +fi + +# Sample Server Cert file 1 for MoneyServer.exe +if [ ! -f $OPNSIMPATH/SineWaveCert.pfx ]; then + cp $CONFIGPATH/SineWaveCert.pfx $OPNSIMPATH +fi + +# Sample Server Cert file 2 (JOGRID.NET) for MoneyServer.exe. No password +if [ ! -f $OPNSIMPATH/server_cert.p12 ]; then + cp $CONFIGPATH/server_cert.p12 $OPNSIMPATH +fi + + diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..f862b0b --- /dev/null +++ b/build.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +CONFIGPATH=./config +OPNSIMPATH=../bin + +echo "===================" +echo "DTL/NSL_CURRENCY" +echo "===================" + +./clean.sh +./runprebuild.sh +xbuild /target:CLean || exit 1 +#xbuild || exit 1 +xbuild /p:Configuration=Release || exit 1 + +echo +cp -f bin/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll $OPNSIMPATH +cp -f bin/OpenSim.Modules.Currency.dll $OPNSIMPATH +cp -f bin/MoneyServer.exe $OPNSIMPATH + +# +rm -f $OPNSIMPATH/OpenSim.Forge.Currency.dll + +if [ ! -f $OPNSIMPATH/MoneyServer.ini ]; then + cp $CONFIGPATH/MoneyServer.ini $OPNSIMPATH +else + cp $CONFIGPATH/MoneyServer.ini $OPNSIMPATH/MoneyServer.ini.example +fi + +if [ ! -f $OPNSIMPATH/MoneyServer.exe.config ]; then + cp $CONFIGPATH/MoneyServer.exe.config $OPNSIMPATH +fi + +# Sample Server Cert file 1 for MoneyServer.exe +if [ ! -f $OPNSIMPATH/SineWaveCert.pfx ]; then + cp $CONFIGPATH/SineWaveCert.pfx $OPNSIMPATH +fi + +# Sample Server Cert file 2 (JOGRID.NET) for MoneyServer.exe. No password +if [ ! -f $OPNSIMPATH/server_cert.p12 ]; then + cp $CONFIGPATH/server_cert.p12 $OPNSIMPATH +fi + diff --git a/build_opensim.sh b/build_opensim.sh new file mode 100755 index 0000000..e5ea40a --- /dev/null +++ b/build_opensim.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +CONFIGPATH=./config +OPNSIMPATH=../bin + + +echo "==============================================" +echo "Rebuild OpenSim for Secure DTL/NSL_CURRENCY" +echo "==============================================" + + +function xbuild_opensim() +{ + ./runprebuild.sh vs2010 + xbuild /target:CLean + xbuild || return 1 + + cd opensim.currency + ./build.sh + cd .. + + if [ -d opensim.modules ]; then + cd opensim.modules + ./build.sh || return 1 + cd .. + fi +} + + + + +if [ "$1" != '-R' ]; then + # + if [ ! -f ../bin/HttpServer_OpenSim.dll.orig ]; then + mv ../bin/HttpServer_OpenSim.dll ../bin/HttpServer_OpenSim.dll.orig + fi + cp -f HttpServer_OpenSim/bin/HttpServer_OpenSim.dll ../bin + + cd .. + + PCHK=`grep "request.IHttpClientContext.SSLCommonName" OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs` + + if [ "$PCHK" = "" ]; then + patch -p1 < ./opensim.currency/patch/opensim.patch || exit 1 + fi + xbuild_opensim || exit 1 + # +else + # + if [ -f ../bin/HttpServer_OpenSim.dll.orig ]; then + rm -f ../bin/HttpServer_OpenSim.dll + mv ../bin/HttpServer_OpenSim.dll.orig ../bin/HttpServer_OpenSim.dll + fi + + cd .. + patch -p1 -R < ./opensim.currency/patch/opensim.patch || exit 1 + xbuild_opensim || exit 1 + # +fi + diff --git a/clean.sh b/clean.sh new file mode 100755 index 0000000..c978be6 --- /dev/null +++ b/clean.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +rm -rf OpenSim.Currency.sln +rm -rf bin/* +rm -rf OpenSim.*/obj/* + +rm -f OpenSim.*/*.csproj +rm -f OpenSim.*/*.csproj.user diff --git a/config/MoneyServer.exe.config b/config/MoneyServer.exe.config new file mode 100644 index 0000000..1f31302 --- /dev/null +++ b/config/MoneyServer.exe.config @@ -0,0 +1,29 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/MoneyServer.ini b/config/MoneyServer.ini new file mode 100644 index 0000000..99cce6d --- /dev/null +++ b/config/MoneyServer.ini @@ -0,0 +1,105 @@ +[Startup] +; +; Place to create a PID file +PIDFile = "/var/run/MoneyServer.pid" + +NoVerifyCertChain = true +NoVerifyCertHostname = true + + +[MySql] +; +;Connection parameters of MySQL +hostname = localhost ; Name of MySQL Server +database = opensim_db +username = opensim_user +password = opensim_pass + +pooling = false +port = 3306 + +; +; Max DB connections kept by money server. +MaxConnection = 10 + + +[MoneyServer] +; Port No. of this Server +;ServerPort = 8008 + +; +; If the user is not found in database,he/she will be created with the default balance. +DefaultBalance = 1000 + +; +; Is amount==0 transaction enable? Default is false. +;EnableAmountZero = false + +; +; If "00000000-0000-0000-0000-000000000000" is specified, all avatars can get money from system. +; If "" is specified, nobody can get money. +BankerAvatar = "" + +; +; If you want to use llGiveMoney() function normally even when payer doesn't login to OpenSim, +; please set true to this valiable +EnableForceTransfer = true + +; +; Send/Move money to/from avatar by Money Script +;EnableScriptSendMoney = false +;MoneyScriptAccessKey = "123456789" ;; Specify same secret key in include/config.php or WI(XoopenSim/Modlos) +;MoneyScriptIPaddress = "202.26.159.139" ;; Not use 127.0.0.1. This is used to generate Script key + +; +; for HG/Guest Avatar. Foreign Avatar is always false +;EnableHGAvatar = false +;EnableGuestAvatar = false +;HGAvatarDefaultBalance = 0 +;GuestAvatarDefaultBalance = 0 + +; +; Message that displayed in blue dialog, when balance is updated. +; If "" is specified, blue dialog is not displayed. +; You can use {0} and {1} in message string. +; {0} means amount and {1} means avatar name or object owner name. +;BalanceMessageSendGift = "Sent Gift L${0} to {1}." ;; for send gift to other avatar +;BalanceMessageReceiveGift = "Received Gift L${0} from {1}." ;; for receieve gift from other avatar +;BalanceMessagePayCharge = "" ;; for upload and group creation charge +;BalanceMessageBuyObject = "Bought the Object {2} from {1} by L${0}." ;; for buy the object +;BalanceMessageSellObject = "{1} bought the Object {2} by L${0}." ;; for sell the object +;BalanceMessageLandSale = "Paid the Money L${0} for Land." ;; for buy the land +;BalanceMessageScvLandSale = "" ;; for get the money of the sold land +;BalanceMessageGetMoney = "Got the Money L${0} from {1}." ;; for get the money from object by llGiveMoney() +;BalanceMessageBuyMoney = "Bought the Money L${0}." ;; for buy the money from system +;BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}.";; when roll back ocuurred +;BalanceMessageSendMoney = "Paid the Money L${0} to {1}." ;; for sender of sending the money +;BalanceMessageReceiveMoney = "Received L${0} from {1}." ;; for receive the money + + +[Certificate] +; +; Certification Configuration +; + +; CA Cert to check Client/Server Cert +;CACertFilename = "cacert.crt" + +; +; HTTPS Server Cert (Server Mode) +;ServerCertFilename = "SineWaveCert.pfx" +;ServerCertPassword = "123" +ServerCertFilename = "server_cert.p12" +ServerCertPassword = "" + +; Client Authentication from Region Server +;CheckClientCert = false ;; check Region Server +;ClientCrlFilename = "clcrl.crt" + + +; +; XML RPC to Region Server (Client Mode) +;;CheckServerCert = false ;; check Region Server +;;ClientCertFilename = "client_cert.p12" +;;ClientCertPassword = "" + diff --git a/config/OpenSim.ini.sample b/config/OpenSim.ini.sample new file mode 100644 index 0000000..1f7e7f5 --- /dev/null +++ b/config/OpenSim.ini.sample @@ -0,0 +1,43 @@ +[Economy] + + ;; Enables selling things for $0. Default is true. + SellEnabled = true + + ;CurrencyServer = "" ;; ex.) "https://jogrid.net:8008/" Default is "" + EconomyModule = DTLNSLMoneyModule + + ; + ;; CA + ;CheckServerCert = false + ;CACertFilename = "cacert.crt" + + ; + ;; Client Cert + ;ClientCertFilename = "region_cert.p12" + ;ClientCertPassword = "" + + ; + ;; Money Unit fee to upload textures, animations etc. Default is 0. + PriceUpload = 10 + + ;; Mesh upload factors + ;MeshModelUploadCostFactor = 0.0 + ;MeshModelUploadTextureCostFactor = 1.0 + ;MeshModelMinCostFactor = 0.0 + + ;; Money Unit fee to create groups. Default is 0. + PriceGroupCreate = 10 + + ; + ;; Avatar Class for HG Avatar + ;; {ForeignAvatar, HGAvatar, GuestAvatar, LocalAvatar} HGAvatar + ;; HG Avatar is assumed as a specified avatar class. Default is HGAvatar + ;; Processing for each avatar class is dependent on Money Server settings. + ;HGAvatarAs = "HGAvatar" + + ; + ;; in development + ;SettlementByWeb = false + ;SettlementURL = "http://www.jogrid.net" + ;SettlementMessage = "Goto the settlement of accounts Web page. (Testing now)" + diff --git a/config/ResetDB_to_0.8.2.sql b/config/ResetDB_to_0.8.2.sql new file mode 100644 index 0000000..ec2bdbf --- /dev/null +++ b/config/ResetDB_to_0.8.2.sql @@ -0,0 +1,7 @@ +alter table userinfo drop type; +alter table userinfo drop class; +alter table userinfo drop serverurl; +alter table userinfo COMMENT='Rev.2'; +alter table balances COMMENT='Rev.2'; +alter table totalsales COMMENT='Rev.2'; +alter table transactions COMMENT='Rev.9'; diff --git a/config/SineWaveCert.pfx b/config/SineWaveCert.pfx new file mode 100644 index 0000000..11c8ae5 Binary files /dev/null and b/config/SineWaveCert.pfx differ diff --git a/config/opensim_money.net.service b/config/opensim_money.net.service new file mode 100644 index 0000000..6427722 --- /dev/null +++ b/config/opensim_money.net.service @@ -0,0 +1,30 @@ +# /usr/lib/systemd/system/opensim_money.net.service +# +# v.0.2 by Fumi.Iseki +# + +[Unit] +Description = MoneyServer for OpenSimulator +After = opensim_robust.net.service + +[Service] +Environment = OPENSIM_DIR=/usr/local/opensim_server +Environment = OPENSIM_COM=MoneyServer +Environment = OPENSIM_DLL=MoneyServer.dll +Environment = EXEC_COM=/usr/bin/dotnet +Environment = TMUX_OS_ID=opensim_money +#Environment = WAIT_STOP_TM=5 + +Type = forking +User = root +LimitSTACK = infinity + +WorkingDirectory = ${OPENSIM_DIR}/bin + +ExecStart = /usr/bin/tmux new -d -s ${TMUX_OS_ID} -c ${OPENSIM_DIR}/bin ${OPENSIM_DIR}/bin/${OPENSIM_COM} +#ExecStop = /usr/bin/tmux send-keys -t ${TMUX_OS_ID} C-m "quit" C-m ; /usr/bin/sleep ${WAIT_STOP_TM} + +Restart = always + +[Install] +WantedBy = multi-user.target diff --git a/config/server_cert.p12 b/config/server_cert.p12 new file mode 100644 index 0000000..16adb01 Binary files /dev/null and b/config/server_cert.p12 differ diff --git a/old/HttpServer_OpenSim/original/source/HttpClientContext.cs b/old/HttpServer_OpenSim/original/source/HttpClientContext.cs new file mode 100644 index 0000000..b85f436 --- /dev/null +++ b/old/HttpServer_OpenSim/original/source/HttpClientContext.cs @@ -0,0 +1,578 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using HttpServer.Exceptions; +using HttpServer.Parser; + +namespace HttpServer +{ + /// + /// Contains a connection to a browser/client. + /// + /// + /// Remember to after you have hooked the event. + /// + /// TODO: Maybe this class should be broken up into HttpClientChannel and HttpClientContext? + public class HttpClientContext : IHttpClientContext ,IDisposable + { + private readonly byte[] _buffer; + private int _bytesLeft; + private ILogWriter _log; + private readonly IHttpRequestParser _parser; + private readonly int _bufferSize; + private IHttpRequest _currentRequest; + private Socket _sock; + + public bool Available = true; + private bool _endWhenDone = false; + public bool StreamPassedOff = false; + public int MonitorStartMS = 0; + public int MonitorKeepaliveMS = 0; + public bool TriggerKeepalive = false; + public int TimeoutFirstLine = 70000; // 70 seconds + public int TimeoutRequestReceived = 180000; // 180 seconds + + // The difference between this and request received is on POST more time is needed before we get the full request. + public int TimeoutFullRequestProcessed = 1200000; // 20 minutes + public int TimeoutKeepAlive = 400000; // 400 seconds before keepalive timeout + + public bool FirstRequestLineReceived; + public bool FullRequestReceived; + public bool FullRequestProcessed; + + public bool StopMonitoring; + /// + /// This context have been cleaned, which means that it can be reused. + /// + public event EventHandler Cleaned = delegate { }; + + /// + /// Context have been started (a new client have connected) + /// + public event EventHandler Started = delegate { }; + + /// + /// Initializes a new instance of the class. + /// + /// true if the connection is secured (SSL/TLS) + /// client that connected. + /// Stream used for communication + /// Used to create a . + /// Size of buffer to use when reading data. Must be at least 4096 bytes. + /// If fails + /// Stream must be writable and readable. + public HttpClientContext(bool secured, IPEndPoint remoteEndPoint, + Stream stream, IRequestParserFactory parserFactory, int bufferSize, Socket sock) + { + Check.Require(remoteEndPoint, "remoteEndPoint"); + Check.NotEmpty(remoteEndPoint.Address.ToString(), "remoteEndPoint.Address"); + Check.Require(stream, "stream"); + Check.Require(parserFactory, "parser"); + Check.Min(4096, bufferSize, "bufferSize"); + Check.Require(sock, "socket"); + + if (!stream.CanWrite || !stream.CanRead) + throw new ArgumentException("Stream must be writable and readable."); + + _bufferSize = bufferSize; + RemoteAddress = remoteEndPoint.Address.ToString(); + RemotePort = remoteEndPoint.Port.ToString(); + _log = NullLogWriter.Instance; + _parser = parserFactory.CreateParser(_log); + _parser.RequestCompleted += OnRequestCompleted; + _parser.RequestLineReceived += OnRequestLine; + _parser.HeaderReceived += OnHeaderReceived; + _parser.BodyBytesReceived += OnBodyBytesReceived; + _currentRequest = new HttpRequest(); + Available = false; + IsSecured = secured; + _stream = stream; + _sock = sock; + _buffer = new byte[bufferSize]; + + } + + public bool EndWhenDone + { + get { return _endWhenDone; } + set { _endWhenDone = value;} + } + + /// + /// Process incoming body bytes. + /// + /// + /// Bytes + protected virtual void OnBodyBytesReceived(object sender, BodyEventArgs e) + { + _currentRequest.AddToBody(e.Buffer, e.Offset, e.Count); + } + + /// + /// + /// + /// + /// + protected virtual void OnHeaderReceived(object sender, HeaderEventArgs e) + { + if (string.Compare(e.Name, "expect", true) == 0 && e.Value.Contains("100-continue")) + { + Respond("HTTP/1.0", HttpStatusCode.Continue, "Please continue mate."); + } + + _currentRequest.AddHeader(e.Name, e.Value); + } + + private void OnRequestLine(object sender, RequestLineEventArgs e) + { + _currentRequest.Method = e.HttpMethod; + _currentRequest.HttpVersion = e.HttpVersion; + _currentRequest.UriPath = e.UriPath; + FirstRequestLineReceived = true; + } + + /// + /// Overload to specify own type. + /// + /// + /// Must be specified before the context is being used. + /// + protected IHttpRequest CurrentRequest + { get { return _currentRequest; } set { _currentRequest = value; } } + + /// + /// Start reading content. + /// + /// + /// Make sure to call base.Start() if you override this method. + /// + public virtual void Start() + { + try + { + _stream.BeginRead(_buffer, 0, _bufferSize, OnReceive, null); + } + catch (IOException err) + { + LogWriter.Write(this, LogPrio.Debug, err.ToString()); + } + + Started(this, EventArgs.Empty); + } + + /// + /// Clean up context. + /// + /// + /// Make sure to call base.Cleanup() if you override the method. + /// + public virtual void Cleanup() + { + if (Stream == null) + return; + if (StreamPassedOff) + return; + _sock = null; + + Stream.Dispose(); + Stream = null; + _currentRequest.Clear(); + _bytesLeft = 0; + + FirstRequestLineReceived = false; + FullRequestReceived = false; + FullRequestProcessed = false; + MonitorStartMS = 0; + StopMonitoring = false; + MonitorKeepaliveMS = 0; + TriggerKeepalive = false; + + Cleaned(this, EventArgs.Empty); + _parser.Clear(); + } + + public void Close() + { + if (StreamPassedOff) + return; + Cleanup(); + Available = true; + } + + /// + /// Using SSL or other encryption method. + /// + [Obsolete("Use IsSecured instead.")] + public bool Secured + { + get { return IsSecured; } + } + + /// + /// Using SSL or other encryption method. + /// + public bool IsSecured { get; internal set; } + + /// + /// Specify which logger to use. + /// + public ILogWriter LogWriter + { + get { return _log; } + set + { + _log = value ?? NullLogWriter.Instance; + _parser.LogWriter = _log; + } + } + + private Stream _stream; + + /// + /// Gets or sets the network stream. + /// + internal Stream Stream + { + get { return _stream; } + set { _stream = value; } + } + + /// + /// Gets or sets IP address that the client connected from. + /// + internal string RemoteAddress { get; set; } + + /// + /// Gets or sets port that the client connected from. + /// + internal string RemotePort { get; set; } + + /// + /// Disconnect from client + /// + /// error to report in the event. + public void Disconnect(SocketError error) + { + // disconnect may not throw any exceptions + try + { + //_sock.Disconnect(true); + if (error == SocketError.Success) + { + if (Stream is ReusableSocketNetworkStream) + ((NetworkStream)Stream).Flush(); + if (_currentRequest.Connection == ConnectionType.Close) + _sock = null; + + } + if (error == SocketError.TimedOut) + { + try + { + if (Stream != null) + Stream.Close(); + _sock = null; + } + catch {} // Best Try + } + //Stream.Close(); + Disconnected(this, new DisconnectedEventArgs(error)); + } + catch (Exception err) + { + LogWriter.Write(this, LogPrio.Error, "Disconnect threw an exception: " + err); + } + } + + private void OnReceive(IAsyncResult ar) + { + try + { + int bytesRead = 0; + + try + { + bytesRead = Stream.EndRead(ar); + } + catch (NullReferenceException) + { + Disconnect(SocketError.ConnectionReset); + return; + } + + if (bytesRead == 0) + { + Disconnect(SocketError.ConnectionReset); + return; + } + _bytesLeft += bytesRead; + if (_bytesLeft > _buffer.Length) + { +#if DEBUG + throw new BadRequestException("Too large HTTP header: " + Encoding.UTF8.GetString(_buffer, 0, bytesRead)); +#else + throw new BadRequestException("Too large HTTP header: " + _bytesLeft); +#endif + } + +#if DEBUG +#pragma warning disable 219 + string temp = Encoding.ASCII.GetString(_buffer, 0, _bytesLeft); + LogWriter.Write(this, LogPrio.Trace, "Received: " + temp); +#pragma warning restore 219 +#endif + int offset = _parser.Parse(_buffer, 0, _bytesLeft); + if (Stream == null) + return; // "Connection: Close" in effect. + + // try again to see if we can parse another message (check parser to see if it is looking for a new message) + int oldOffset = offset; + while (_parser.CurrentState == RequestParserState.FirstLine && offset != 0 && _bytesLeft - offset > 0) + { +#if DEBUG + temp = Encoding.ASCII.GetString(_buffer, offset, _bytesLeft - offset); + LogWriter.Write(this, LogPrio.Trace, "Processing: " + temp); +#endif + offset = _parser.Parse(_buffer, offset, _bytesLeft - offset); + if (Stream == null) + return; // "Connection: Close" in effect. + } + + // need to be able to move prev bytes, so restore offset. + if (offset == 0) + offset = oldOffset; + + // copy unused bytes to the beginning of the array + if (offset > 0 && _bytesLeft > offset) + Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bytesLeft - offset); + + _bytesLeft -= offset; + if (Stream != null && Stream.CanRead && !StreamPassedOff) + Stream.BeginRead(_buffer, _bytesLeft, _buffer.Length - _bytesLeft, OnReceive, null); + else + { + _log.Write(this, LogPrio.Warning, "Could not read any more from the socket."); + Disconnect(SocketError.Success); + } + } + catch (BadRequestException err) + { + LogWriter.Write(this, LogPrio.Warning, "Bad request, responding with it. Error: " + err); + try + { + Respond("HTTP/1.0", HttpStatusCode.BadRequest, err.Message); + } + catch(Exception err2) + { + LogWriter.Write(this, LogPrio.Fatal, "Failed to reply to a bad request. " + err2); + } + Disconnect(SocketError.NoRecovery); + } + catch (IOException err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive: " + err.Message); + if (err.InnerException is SocketException) + Disconnect((SocketError) ((SocketException) err.InnerException).ErrorCode); + else + Disconnect(SocketError.ConnectionReset); + } + catch (ObjectDisposedException err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive : " + err.Message); + Disconnect(SocketError.NotSocket); + } + catch (NullReferenceException err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive : NullRef: " + err.Message); + Disconnect(SocketError.NoRecovery); + } + catch (Exception err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive: " + err.Message); + Disconnect(SocketError.NoRecovery); + } + } + + private void OnRequestCompleted(object source, EventArgs args) + { + _currentRequest.AddHeader("remote_addr", RemoteAddress); + _currentRequest.AddHeader("remote_port", RemotePort); + + // load cookies if they exist + RequestCookies cookies = _currentRequest.Headers["cookie"] != null + ? new RequestCookies(_currentRequest.Headers["cookie"]) + : new RequestCookies(String.Empty); + _currentRequest.SetCookies(cookies); + + _currentRequest.Body.Seek(0, SeekOrigin.Begin); + RequestReceived(this, new RequestEventArgs(_currentRequest)); + + FullRequestReceived = true; + + if (_currentRequest.Connection == ConnectionType.Close) + _sock = null; + else + TriggerKeepalive = true; + + if (!StreamPassedOff) + _currentRequest.Clear(); + } + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + /// HTML body contents, can be null or empty. + /// A content type to return the body as, i.e. 'text/html' or 'text/plain', defaults to 'text/html' if null or empty + /// If is invalid. + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) + { + if (string.IsNullOrEmpty(contentType)) + contentType = "text/html"; + + if (string.IsNullOrEmpty(httpVersion) || !httpVersion.StartsWith("HTTP/1")) + throw new ArgumentException("Invalid HTTP version"); + + if (string.IsNullOrEmpty(reason)) + reason = statusCode.ToString(); + + string response = string.IsNullOrEmpty(body) + ? httpVersion + " " + (int) statusCode + " " + reason + "\r\n\r\n" + : string.Format("{0} {1} {2}\r\nContent-Type: {5}\r\nContent-Length: {3}\r\n\r\n{4}", + httpVersion, (int) statusCode, reason ?? statusCode.ToString(), + body.Length, body, contentType); + byte[] buffer = Encoding.ASCII.GetBytes(response); + + Send(buffer); + if (_currentRequest.Connection == ConnectionType.Close) + FullRequestProcessed = true; + + } + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) + { + Respond(httpVersion, statusCode, reason, null, null); + } + + /// + /// Send a response. + /// + /// + public void Respond(string body) + { + if (body == null) + throw new ArgumentNullException("body"); + Respond("HTTP/1.1", HttpStatusCode.OK, HttpStatusCode.OK.ToString(), body, null); + } + + /// + /// send a whole buffer + /// + /// buffer to send + /// + public void Send(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + Send(buffer, 0, buffer.Length); + } + + /// + /// Send data using the stream + /// + /// Contains data to send + /// Start position in buffer + /// number of bytes to send + /// + /// + public void Send(byte[] buffer, int offset, int size) + { + + if (offset + size > buffer.Length) + throw new ArgumentOutOfRangeException("offset", offset, "offset + size is beyond end of buffer."); + + if (Stream != null && Stream.CanWrite) + { + try + { + Stream.Write(buffer, offset, size); + } + catch (IOException) + { + + } + } + + } + + /// + /// The context have been disconnected. + /// + /// + /// Event can be used to clean up a context, or to reuse it. + /// + public event EventHandler Disconnected = delegate{}; + /// + /// A request have been received in the context. + /// + public event EventHandler RequestReceived = delegate{}; + + public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing() + { + _endWhenDone = true; + StreamPassedOff = true; + _parser.RequestCompleted -= OnRequestCompleted; + _parser.RequestLineReceived -= OnRequestLine; + _parser.HeaderReceived -= OnHeaderReceived; + _parser.BodyBytesReceived -= OnBodyBytesReceived; + _parser.Clear(); + + return new HTTPNetworkContext() { Socket = _sock ,Stream = _stream as NetworkStream}; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool unmanaged) + { + if (unmanaged) + { + if (Stream != null) + { + try + { + if (Stream.CanWrite) + Stream.Flush(); + + Cleanup(); + + } + catch (IOException) + { + + } + } + + } + + } + + ~HttpClientContext() + { + Dispose(); + } + } +} \ No newline at end of file diff --git a/old/HttpServer_OpenSim/original/source/HttpContextFactory.cs b/old/HttpServer_OpenSim/original/source/HttpContextFactory.cs new file mode 100644 index 0000000..a50b9a3 --- /dev/null +++ b/old/HttpServer_OpenSim/original/source/HttpContextFactory.cs @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +namespace HttpServer +{ + /// + /// Used to create and reuse contexts. + /// + public class HttpContextFactory : IHttpContextFactory + { + private readonly int _bufferSize; + private readonly Queue _contextQueue = new Queue(); + private readonly IRequestParserFactory _factory; + private readonly ILogWriter _logWriter; + private readonly ContextTimeoutManager _contextTimeoutManager; + + /// + /// Initializes a new instance of the class. + /// + /// The writer. + /// Amount of bytes to read from the incoming socket stream. + /// Used to create a request parser. + public HttpContextFactory(ILogWriter writer, int bufferSize, IRequestParserFactory factory) + { + _logWriter = writer; + _bufferSize = bufferSize; + _factory = factory; + _contextTimeoutManager = new ContextTimeoutManager(ContextTimeoutManager.MonitorType.Thread); + } + + /// + /// True if detailed trace logs should be written. + /// + public bool UseTraceLogs { get; set; } + + /// + /// Create a new context. + /// + /// true if socket is running HTTPS. + /// Client that connected + /// Network/SSL stream. + /// A context. + protected HttpClientContext CreateContext(bool isSecured, IPEndPoint endPoint, Stream stream, Socket sock) + { + HttpClientContext context; + lock (_contextQueue) + { + if (_contextQueue.Count > 0) + { + context = _contextQueue.Dequeue(); + if (!context.Available) + { + context = CreateNewContext(isSecured, endPoint, stream, sock); + context.Disconnected += OnFreeContext; + context.RequestReceived += OnRequestReceived; + context.EndWhenDone = true; + + } + } + else + { + context = CreateNewContext(isSecured, endPoint, stream, sock); + context.Disconnected += OnFreeContext; + context.RequestReceived += OnRequestReceived; + } + } + + context.Stream = stream; + context.IsSecured = isSecured; + context.RemotePort = endPoint.Port.ToString(); + context.RemoteAddress = endPoint.Address.ToString(); + _contextTimeoutManager.StartMonitoringContext(context); + context.Start(); + + return context; + } + + /// + /// Create a new context. + /// + /// true if HTTPS is used. + /// Remote client + /// Network stream, uses . + /// A new context (always). + protected virtual HttpClientContext CreateNewContext(bool isSecured, IPEndPoint endPoint, Stream stream, Socket sock) + { + return new HttpClientContext(isSecured, endPoint, stream, _factory, _bufferSize, sock); + } + + private void OnRequestReceived(object sender, RequestEventArgs e) + { + RequestReceived(sender, e); + } + + private void OnFreeContext(object sender, DisconnectedEventArgs e) + { + var imp = (HttpClientContext) sender; + imp.Cleanup(); + + if (!imp.EndWhenDone) + { + lock (_contextQueue) + _contextQueue.Enqueue(imp); + } + else + { + + imp.Close(); + } + } + + + #region IHttpContextFactory Members + + /// + /// Create a secure . + /// + /// Client socket (accepted by the ). + /// HTTPS certificate to use. + /// Kind of HTTPS protocol. Usually TLS or SSL. + /// + /// A created . + /// + public IHttpClientContext CreateSecureContext(Socket socket, X509Certificate certificate, SslProtocols protocol) + { + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + + var sslStream = new SslStream(networkStream, false); + try + { + //TODO: this may fail + sslStream.AuthenticateAsServer(certificate, false, protocol, false); + return CreateContext(true, remoteEndPoint, sslStream, socket); + } + catch (IOException err) + { + if (UseTraceLogs) + _logWriter.Write(this, LogPrio.Trace, err.Message); + } + catch (ObjectDisposedException err) + { + if (UseTraceLogs) + _logWriter.Write(this, LogPrio.Trace, err.Message); + } + + return null; + } + + + /// + /// A request have been received from one of the contexts. + /// + public event EventHandler RequestReceived = delegate{}; + + /// + /// Creates a that handles a connected client. + /// + /// Client socket (accepted by the ). + /// + /// A creates . + /// + public IHttpClientContext CreateContext(Socket socket) + { + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + return CreateContext(false, remoteEndPoint, networkStream, socket); + } + + #endregion + + /// + /// Server is shutting down so shut down the factory + /// + public void Shutdown() + { + _contextTimeoutManager.StopMonitoring(); + } + } + + /// + /// Custom network stream to mark sockets as reusable when disposing the stream. + /// + internal class ReusableSocketNetworkStream : NetworkStream + { + private bool disposed = false; + /// + /// Creates a new instance of the class for the specified . + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// The property of the parameter is not . + /// -or- + /// The parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket) + : base(socket) + { + } + + /// + /// Initializes a new instance of the class for the specified with the specified ownership. + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// Set to true to indicate that the will take ownership of the ; otherwise, false. + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// the value of the property of the parameter is not . + /// -or- + /// the parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket, bool ownsSocket) + : base(socket, ownsSocket) + { + } + + /// + /// Creates a new instance of the class for the specified with the specified access rights. + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// A bitwise combination of the values that specify the type of access given to the over the provided . + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// the property of the parameter is not . + /// -or- + /// the parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket, FileAccess access) + : base(socket, access) + { + } + + /// + /// Creates a new instance of the class for the specified with the specified access rights and the specified ownership. + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// A bitwise combination of the values that specifies the type of access given to the over the provided . + /// + /// + /// Set to true to indicate that the will take ownership of the ; otherwise, false. + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// The property of the parameter is not . + /// -or- + /// The parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket, FileAccess access, bool ownsSocket) + : base(socket, access, ownsSocket) + { + } + + /// + /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + /// + public override void Close() + { + + if (Socket != null && Socket.Connected) + Socket.Close(); //TODO: Maybe use Disconnect with reuseSocket=true? I tried but it took forever. + base.Close(); + + } + + /// + /// Releases the unmanaged resources used by the and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + + try + { + if (!disposed) + { + disposed = true; + if (Socket != null && Socket.Connected) + Socket.Disconnect(true); + + } + base.Dispose(disposing); + } + catch { } // Best effort, ignore fails + } + } + + /// + /// Used to create es. + /// + public interface IHttpContextFactory + { + /// + /// Creates a that handles a connected client. + /// + /// Client socket (accepted by the ). + /// A creates . + IHttpClientContext CreateContext(Socket socket); + + /// + /// Create a secure . + /// + /// Client socket (accepted by the ). + /// HTTPS certificate to use. + /// Kind of HTTPS protocol. Usually TLS or SSL. + /// A created . + IHttpClientContext CreateSecureContext(Socket socket, X509Certificate certificate, SslProtocols protocol); + + /// + /// A request have been received from one of the contexts. + /// + event EventHandler RequestReceived; + + /// + /// Server is shutting down so shut down the factory + /// + void Shutdown(); + } +} \ No newline at end of file diff --git a/old/HttpServer_OpenSim/original/source/IHttpClientContext.cs b/old/HttpServer_OpenSim/original/source/IHttpClientContext.cs new file mode 100644 index 0000000..174e7e2 --- /dev/null +++ b/old/HttpServer_OpenSim/original/source/IHttpClientContext.cs @@ -0,0 +1,143 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace HttpServer +{ + /// + /// Contains a connection to a browser/client. + /// + public interface IHttpClientContext + { + /// + /// Using SSL or other encryption method. + /// + [Obsolete("Use IsSecured instead.")] + bool Secured { get; } + + /// + /// Using SSL or other encryption method. + /// + bool IsSecured { get; } + + /// + /// Disconnect from client + /// + /// error to report in the event. + void Disconnect(SocketError error); + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + /// HTML body contents, can be null or empty. + /// A content type to return the body as, i.e. 'text/html' or 'text/plain', defaults to 'text/html' if null or empty + /// If is invalid. + void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType); + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + void Respond(string httpVersion, HttpStatusCode statusCode, string reason); + + /// + /// Send a response. + /// + /// + void Respond(string body); + + /// + /// send a whole buffer + /// + /// buffer to send + /// + void Send(byte[] buffer); + + /// + /// Send data using the stream + /// + /// Contains data to send + /// Start position in buffer + /// number of bytes to send + /// + /// + void Send(byte[] buffer, int offset, int size); + + /// + /// Closes the streams and disposes of the unmanaged resources + /// + void Close(); + + bool EndWhenDone { get; set; } + + /// + /// The context have been disconnected. + /// + /// + /// Event can be used to clean up a context, or to reuse it. + /// + event EventHandler Disconnected; + + /// + /// A request have been received in the context. + /// + event EventHandler RequestReceived; + + HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing(); + } + public class HTTPNetworkContext + { + public NetworkStream Stream; + public Socket Socket; + } + + /// + /// A have been disconnected. + /// + public class DisconnectedEventArgs : EventArgs + { + /// + /// Gets reason to why client disconnected. + /// + public SocketError Error { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// Reason to disconnection. + public DisconnectedEventArgs(SocketError error) + { + Check.Require(error, "error"); + + Error = error; + } + } + + /// + /// + /// + public class RequestEventArgs : EventArgs + { + /// + /// Gets received request. + /// + public IHttpRequest Request { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The request. + public RequestEventArgs(IHttpRequest request) + { + Check.Require(request, "request"); + + Request = request; + } + } + +} diff --git a/old/HttpServer_OpenSim/patch/HttpServer.patch b/old/HttpServer_OpenSim/patch/HttpServer.patch new file mode 100644 index 0000000..1ae4237 --- /dev/null +++ b/old/HttpServer_OpenSim/patch/HttpServer.patch @@ -0,0 +1,116 @@ +diff -Nur HttpServer.orig/HttpClientContext.cs HttpServer/HttpClientContext.cs +--- HttpServer.orig/HttpClientContext.cs 2016-07-23 11:49:36.242240234 +0900 ++++ HttpServer/HttpClientContext.cs 2016-07-23 11:52:31.801952465 +0900 +@@ -6,6 +6,10 @@ + using HttpServer.Exceptions; + using HttpServer.Parser; + ++// by Fumi.Iseki ++using System.Net.Security; ++using System.Security.Cryptography.X509Certificates; ++ + namespace HttpServer + { + /// +@@ -92,6 +96,18 @@ + _sock = sock; + _buffer = new byte[bufferSize]; + ++ // by Fumi.Iseki ++ SSLCommonName = ""; ++ if (secured) ++ { ++ SslStream _ssl = (SslStream)_stream; ++ X509Certificate _cert1 = _ssl.RemoteCertificate; ++ if (_cert1 != null) ++ { ++ X509Certificate2 _cert2 = new X509Certificate2(_cert1); ++ if (_cert2 != null) SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ } ++ } + } + + public bool EndWhenDone +@@ -215,6 +231,11 @@ + /// + public bool IsSecured { get; internal set; } + ++ // ++ // ++ // by Fumi.Iseki ++ public string SSLCommonName { get; internal set; } ++ + /// + /// Specify which logger to use. + /// +diff -Nur HttpServer.orig/HttpContextFactory.cs HttpServer/HttpContextFactory.cs +--- HttpServer.orig/HttpContextFactory.cs 2016-07-23 11:49:36.242240234 +0900 ++++ HttpServer/HttpContextFactory.cs 2016-07-23 11:52:32.648951102 +0900 +@@ -20,6 +20,10 @@ + private readonly ILogWriter _logWriter; + private readonly ContextTimeoutManager _contextTimeoutManager; + ++ // by Fumi.Iseki ++ public static RemoteCertificateValidationCallback ClientCertificateValidationCallback = null; ++ private RemoteCertificateValidationCallback _clientCallback = null; ++ + /// + /// Initializes a new instance of the class. + /// +@@ -32,6 +36,13 @@ + _bufferSize = bufferSize; + _factory = factory; + _contextTimeoutManager = new ContextTimeoutManager(ContextTimeoutManager.MonitorType.Thread); ++ ++ // by Fumi.Iseki ++ if (ClientCertificateValidationCallback != null) ++ { ++ _clientCallback = ClientCertificateValidationCallback; ++ ClientCertificateValidationCallback = null; ++ } + } + + /// +@@ -132,11 +143,25 @@ + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + +- var sslStream = new SslStream(networkStream, false); ++ // by Fumi.Iseki ++ //var sslStream = new SslStream(networkStream, false); ++ SslStream sslStream = null; + try + { + //TODO: this may fail +- sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ // by Fumi.Iseki ++ //sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ if (_clientCallback == null) ++ { ++ sslStream = new SslStream(networkStream, false); ++ sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ } ++ else ++ { ++ sslStream = new SslStream(networkStream, false, new RemoteCertificateValidationCallback(_clientCallback)); ++ sslStream.AuthenticateAsServer(certificate, true, protocol, false); ++ } ++ + return CreateContext(true, remoteEndPoint, sslStream, socket); + } + catch (IOException err) +diff -Nur HttpServer.orig/IHttpClientContext.cs HttpServer/IHttpClientContext.cs +--- HttpServer.orig/IHttpClientContext.cs 2016-07-23 11:49:36.245240228 +0900 ++++ HttpServer/IHttpClientContext.cs 2016-07-23 11:52:33.369949910 +0900 +@@ -9,6 +9,11 @@ + /// + public interface IHttpClientContext + { ++ // ++ // ++ // by Fumi.Iseki ++ string SSLCommonName { get; } ++ + /// + /// Using SSL or other encryption method. + /// diff --git a/old/HttpServer_OpenSim/source/HttpClientContext.cs b/old/HttpServer_OpenSim/source/HttpClientContext.cs new file mode 100644 index 0000000..b0cf212 --- /dev/null +++ b/old/HttpServer_OpenSim/source/HttpClientContext.cs @@ -0,0 +1,599 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using HttpServer.Exceptions; +using HttpServer.Parser; + +// by Fumi.Iseki +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; + +namespace HttpServer +{ + /// + /// Contains a connection to a browser/client. + /// + /// + /// Remember to after you have hooked the event. + /// + /// TODO: Maybe this class should be broken up into HttpClientChannel and HttpClientContext? + public class HttpClientContext : IHttpClientContext ,IDisposable + { + private readonly byte[] _buffer; + private int _bytesLeft; + private ILogWriter _log; + private readonly IHttpRequestParser _parser; + private readonly int _bufferSize; + private IHttpRequest _currentRequest; + private Socket _sock; + + public bool Available = true; + private bool _endWhenDone = false; + public bool StreamPassedOff = false; + public int MonitorStartMS = 0; + public int MonitorKeepaliveMS = 0; + public bool TriggerKeepalive = false; + public int TimeoutFirstLine = 70000; // 70 seconds + public int TimeoutRequestReceived = 180000; // 180 seconds + + // The difference between this and request received is on POST more time is needed before we get the full request. + public int TimeoutFullRequestProcessed = 1200000; // 20 minutes + public int TimeoutKeepAlive = 400000; // 400 seconds before keepalive timeout + + public bool FirstRequestLineReceived; + public bool FullRequestReceived; + public bool FullRequestProcessed; + + public bool StopMonitoring; + /// + /// This context have been cleaned, which means that it can be reused. + /// + public event EventHandler Cleaned = delegate { }; + + /// + /// Context have been started (a new client have connected) + /// + public event EventHandler Started = delegate { }; + + /// + /// Initializes a new instance of the class. + /// + /// true if the connection is secured (SSL/TLS) + /// client that connected. + /// Stream used for communication + /// Used to create a . + /// Size of buffer to use when reading data. Must be at least 4096 bytes. + /// If fails + /// Stream must be writable and readable. + public HttpClientContext(bool secured, IPEndPoint remoteEndPoint, + Stream stream, IRequestParserFactory parserFactory, int bufferSize, Socket sock) + { + Check.Require(remoteEndPoint, "remoteEndPoint"); + Check.NotEmpty(remoteEndPoint.Address.ToString(), "remoteEndPoint.Address"); + Check.Require(stream, "stream"); + Check.Require(parserFactory, "parser"); + Check.Min(4096, bufferSize, "bufferSize"); + Check.Require(sock, "socket"); + + if (!stream.CanWrite || !stream.CanRead) + throw new ArgumentException("Stream must be writable and readable."); + + _bufferSize = bufferSize; + RemoteAddress = remoteEndPoint.Address.ToString(); + RemotePort = remoteEndPoint.Port.ToString(); + _log = NullLogWriter.Instance; + _parser = parserFactory.CreateParser(_log); + _parser.RequestCompleted += OnRequestCompleted; + _parser.RequestLineReceived += OnRequestLine; + _parser.HeaderReceived += OnHeaderReceived; + _parser.BodyBytesReceived += OnBodyBytesReceived; + _currentRequest = new HttpRequest(); + Available = false; + IsSecured = secured; + _stream = stream; + _sock = sock; + _buffer = new byte[bufferSize]; + + // by Fumi.Iseki + SSLCommonName = ""; + if (secured) + { + SslStream _ssl = (SslStream)_stream; + X509Certificate _cert1 = _ssl.RemoteCertificate; + if (_cert1 != null) + { + X509Certificate2 _cert2 = new X509Certificate2(_cert1); + if (_cert2 != null) SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); + } + } + } + + public bool EndWhenDone + { + get { return _endWhenDone; } + set { _endWhenDone = value;} + } + + /// + /// Process incoming body bytes. + /// + /// + /// Bytes + protected virtual void OnBodyBytesReceived(object sender, BodyEventArgs e) + { + _currentRequest.AddToBody(e.Buffer, e.Offset, e.Count); + } + + /// + /// + /// + /// + /// + protected virtual void OnHeaderReceived(object sender, HeaderEventArgs e) + { + if (string.Compare(e.Name, "expect", true) == 0 && e.Value.Contains("100-continue")) + { + Respond("HTTP/1.0", HttpStatusCode.Continue, "Please continue mate."); + } + + _currentRequest.AddHeader(e.Name, e.Value); + } + + private void OnRequestLine(object sender, RequestLineEventArgs e) + { + _currentRequest.Method = e.HttpMethod; + _currentRequest.HttpVersion = e.HttpVersion; + _currentRequest.UriPath = e.UriPath; + FirstRequestLineReceived = true; + } + + /// + /// Overload to specify own type. + /// + /// + /// Must be specified before the context is being used. + /// + protected IHttpRequest CurrentRequest + { get { return _currentRequest; } set { _currentRequest = value; } } + + /// + /// Start reading content. + /// + /// + /// Make sure to call base.Start() if you override this method. + /// + public virtual void Start() + { + try + { + _stream.BeginRead(_buffer, 0, _bufferSize, OnReceive, null); + } + catch (IOException err) + { + LogWriter.Write(this, LogPrio.Debug, err.ToString()); + } + + Started(this, EventArgs.Empty); + } + + /// + /// Clean up context. + /// + /// + /// Make sure to call base.Cleanup() if you override the method. + /// + public virtual void Cleanup() + { + if (Stream == null) + return; + if (StreamPassedOff) + return; + _sock = null; + + Stream.Dispose(); + Stream = null; + _currentRequest.Clear(); + _bytesLeft = 0; + + FirstRequestLineReceived = false; + FullRequestReceived = false; + FullRequestProcessed = false; + MonitorStartMS = 0; + StopMonitoring = false; + MonitorKeepaliveMS = 0; + TriggerKeepalive = false; + + Cleaned(this, EventArgs.Empty); + _parser.Clear(); + } + + public void Close() + { + if (StreamPassedOff) + return; + Cleanup(); + Available = true; + } + + /// + /// Using SSL or other encryption method. + /// + [Obsolete("Use IsSecured instead.")] + public bool Secured + { + get { return IsSecured; } + } + + /// + /// Using SSL or other encryption method. + /// + public bool IsSecured { get; internal set; } + + // + // + // by Fumi.Iseki + public string SSLCommonName { get; internal set; } + + /// + /// Specify which logger to use. + /// + public ILogWriter LogWriter + { + get { return _log; } + set + { + _log = value ?? NullLogWriter.Instance; + _parser.LogWriter = _log; + } + } + + private Stream _stream; + + /// + /// Gets or sets the network stream. + /// + internal Stream Stream + { + get { return _stream; } + set { _stream = value; } + } + + /// + /// Gets or sets IP address that the client connected from. + /// + internal string RemoteAddress { get; set; } + + /// + /// Gets or sets port that the client connected from. + /// + internal string RemotePort { get; set; } + + /// + /// Disconnect from client + /// + /// error to report in the event. + public void Disconnect(SocketError error) + { + // disconnect may not throw any exceptions + try + { + //_sock.Disconnect(true); + if (error == SocketError.Success) + { + if (Stream is ReusableSocketNetworkStream) + ((NetworkStream)Stream).Flush(); + if (_currentRequest.Connection == ConnectionType.Close) + _sock = null; + + } + if (error == SocketError.TimedOut) + { + try + { + if (Stream != null) + Stream.Close(); + _sock = null; + } + catch {} // Best Try + } + //Stream.Close(); + Disconnected(this, new DisconnectedEventArgs(error)); + } + catch (Exception err) + { + LogWriter.Write(this, LogPrio.Error, "Disconnect threw an exception: " + err); + } + } + + private void OnReceive(IAsyncResult ar) + { + try + { + int bytesRead = 0; + + try + { + bytesRead = Stream.EndRead(ar); + } + catch (NullReferenceException) + { + Disconnect(SocketError.ConnectionReset); + return; + } + + if (bytesRead == 0) + { + Disconnect(SocketError.ConnectionReset); + return; + } + _bytesLeft += bytesRead; + if (_bytesLeft > _buffer.Length) + { +#if DEBUG + throw new BadRequestException("Too large HTTP header: " + Encoding.UTF8.GetString(_buffer, 0, bytesRead)); +#else + throw new BadRequestException("Too large HTTP header: " + _bytesLeft); +#endif + } + +#if DEBUG +#pragma warning disable 219 + string temp = Encoding.ASCII.GetString(_buffer, 0, _bytesLeft); + LogWriter.Write(this, LogPrio.Trace, "Received: " + temp); +#pragma warning restore 219 +#endif + int offset = _parser.Parse(_buffer, 0, _bytesLeft); + if (Stream == null) + return; // "Connection: Close" in effect. + + // try again to see if we can parse another message (check parser to see if it is looking for a new message) + int oldOffset = offset; + while (_parser.CurrentState == RequestParserState.FirstLine && offset != 0 && _bytesLeft - offset > 0) + { +#if DEBUG + temp = Encoding.ASCII.GetString(_buffer, offset, _bytesLeft - offset); + LogWriter.Write(this, LogPrio.Trace, "Processing: " + temp); +#endif + offset = _parser.Parse(_buffer, offset, _bytesLeft - offset); + if (Stream == null) + return; // "Connection: Close" in effect. + } + + // need to be able to move prev bytes, so restore offset. + if (offset == 0) + offset = oldOffset; + + // copy unused bytes to the beginning of the array + if (offset > 0 && _bytesLeft > offset) + Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bytesLeft - offset); + + _bytesLeft -= offset; + if (Stream != null && Stream.CanRead && !StreamPassedOff) + Stream.BeginRead(_buffer, _bytesLeft, _buffer.Length - _bytesLeft, OnReceive, null); + else + { + _log.Write(this, LogPrio.Warning, "Could not read any more from the socket."); + Disconnect(SocketError.Success); + } + } + catch (BadRequestException err) + { + LogWriter.Write(this, LogPrio.Warning, "Bad request, responding with it. Error: " + err); + try + { + Respond("HTTP/1.0", HttpStatusCode.BadRequest, err.Message); + } + catch(Exception err2) + { + LogWriter.Write(this, LogPrio.Fatal, "Failed to reply to a bad request. " + err2); + } + Disconnect(SocketError.NoRecovery); + } + catch (IOException err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive: " + err.Message); + if (err.InnerException is SocketException) + Disconnect((SocketError) ((SocketException) err.InnerException).ErrorCode); + else + Disconnect(SocketError.ConnectionReset); + } + catch (ObjectDisposedException err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive : " + err.Message); + Disconnect(SocketError.NotSocket); + } + catch (NullReferenceException err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive : NullRef: " + err.Message); + Disconnect(SocketError.NoRecovery); + } + catch (Exception err) + { + LogWriter.Write(this, LogPrio.Debug, "Failed to end receive: " + err.Message); + Disconnect(SocketError.NoRecovery); + } + } + + private void OnRequestCompleted(object source, EventArgs args) + { + _currentRequest.AddHeader("remote_addr", RemoteAddress); + _currentRequest.AddHeader("remote_port", RemotePort); + + // load cookies if they exist + RequestCookies cookies = _currentRequest.Headers["cookie"] != null + ? new RequestCookies(_currentRequest.Headers["cookie"]) + : new RequestCookies(String.Empty); + _currentRequest.SetCookies(cookies); + + _currentRequest.Body.Seek(0, SeekOrigin.Begin); + RequestReceived(this, new RequestEventArgs(_currentRequest)); + + FullRequestReceived = true; + + if (_currentRequest.Connection == ConnectionType.Close) + _sock = null; + else + TriggerKeepalive = true; + + if (!StreamPassedOff) + _currentRequest.Clear(); + } + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + /// HTML body contents, can be null or empty. + /// A content type to return the body as, i.e. 'text/html' or 'text/plain', defaults to 'text/html' if null or empty + /// If is invalid. + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) + { + if (string.IsNullOrEmpty(contentType)) + contentType = "text/html"; + + if (string.IsNullOrEmpty(httpVersion) || !httpVersion.StartsWith("HTTP/1")) + throw new ArgumentException("Invalid HTTP version"); + + if (string.IsNullOrEmpty(reason)) + reason = statusCode.ToString(); + + string response = string.IsNullOrEmpty(body) + ? httpVersion + " " + (int) statusCode + " " + reason + "\r\n\r\n" + : string.Format("{0} {1} {2}\r\nContent-Type: {5}\r\nContent-Length: {3}\r\n\r\n{4}", + httpVersion, (int) statusCode, reason ?? statusCode.ToString(), + body.Length, body, contentType); + byte[] buffer = Encoding.ASCII.GetBytes(response); + + Send(buffer); + if (_currentRequest.Connection == ConnectionType.Close) + FullRequestProcessed = true; + + } + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) + { + Respond(httpVersion, statusCode, reason, null, null); + } + + /// + /// Send a response. + /// + /// + public void Respond(string body) + { + if (body == null) + throw new ArgumentNullException("body"); + Respond("HTTP/1.1", HttpStatusCode.OK, HttpStatusCode.OK.ToString(), body, null); + } + + /// + /// send a whole buffer + /// + /// buffer to send + /// + public void Send(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException("buffer"); + Send(buffer, 0, buffer.Length); + } + + /// + /// Send data using the stream + /// + /// Contains data to send + /// Start position in buffer + /// number of bytes to send + /// + /// + public void Send(byte[] buffer, int offset, int size) + { + + if (offset + size > buffer.Length) + throw new ArgumentOutOfRangeException("offset", offset, "offset + size is beyond end of buffer."); + + if (Stream != null && Stream.CanWrite) + { + try + { + Stream.Write(buffer, offset, size); + } + catch (IOException) + { + + } + } + + } + + /// + /// The context have been disconnected. + /// + /// + /// Event can be used to clean up a context, or to reuse it. + /// + public event EventHandler Disconnected = delegate{}; + /// + /// A request have been received in the context. + /// + public event EventHandler RequestReceived = delegate{}; + + public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing() + { + _endWhenDone = true; + StreamPassedOff = true; + _parser.RequestCompleted -= OnRequestCompleted; + _parser.RequestLineReceived -= OnRequestLine; + _parser.HeaderReceived -= OnHeaderReceived; + _parser.BodyBytesReceived -= OnBodyBytesReceived; + _parser.Clear(); + + return new HTTPNetworkContext() { Socket = _sock ,Stream = _stream as NetworkStream}; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool unmanaged) + { + if (unmanaged) + { + if (Stream != null) + { + try + { + if (Stream.CanWrite) + Stream.Flush(); + + Cleanup(); + + } + catch (IOException) + { + + } + } + + } + + } + + ~HttpClientContext() + { + Dispose(); + } + } +} \ No newline at end of file diff --git a/old/HttpServer_OpenSim/source/HttpContextFactory.cs b/old/HttpServer_OpenSim/source/HttpContextFactory.cs new file mode 100644 index 0000000..e2b0765 --- /dev/null +++ b/old/HttpServer_OpenSim/source/HttpContextFactory.cs @@ -0,0 +1,379 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +namespace HttpServer +{ + /// + /// Used to create and reuse contexts. + /// + public class HttpContextFactory : IHttpContextFactory + { + private readonly int _bufferSize; + private readonly Queue _contextQueue = new Queue(); + private readonly IRequestParserFactory _factory; + private readonly ILogWriter _logWriter; + private readonly ContextTimeoutManager _contextTimeoutManager; + + // by Fumi.Iseki + public static RemoteCertificateValidationCallback ClientCertificateValidationCallback = null; + private RemoteCertificateValidationCallback _clientCallback = null; + + /// + /// Initializes a new instance of the class. + /// + /// The writer. + /// Amount of bytes to read from the incoming socket stream. + /// Used to create a request parser. + public HttpContextFactory(ILogWriter writer, int bufferSize, IRequestParserFactory factory) + { + _logWriter = writer; + _bufferSize = bufferSize; + _factory = factory; + _contextTimeoutManager = new ContextTimeoutManager(ContextTimeoutManager.MonitorType.Thread); + + // by Fumi.Iseki + if (ClientCertificateValidationCallback != null) + { + _clientCallback = ClientCertificateValidationCallback; + ClientCertificateValidationCallback = null; + } + } + + /// + /// True if detailed trace logs should be written. + /// + public bool UseTraceLogs { get; set; } + + /// + /// Create a new context. + /// + /// true if socket is running HTTPS. + /// Client that connected + /// Network/SSL stream. + /// A context. + protected HttpClientContext CreateContext(bool isSecured, IPEndPoint endPoint, Stream stream, Socket sock) + { + HttpClientContext context; + lock (_contextQueue) + { + if (_contextQueue.Count > 0) + { + context = _contextQueue.Dequeue(); + if (!context.Available) + { + context = CreateNewContext(isSecured, endPoint, stream, sock); + context.Disconnected += OnFreeContext; + context.RequestReceived += OnRequestReceived; + context.EndWhenDone = true; + + } + } + else + { + context = CreateNewContext(isSecured, endPoint, stream, sock); + context.Disconnected += OnFreeContext; + context.RequestReceived += OnRequestReceived; + } + } + + context.Stream = stream; + context.IsSecured = isSecured; + context.RemotePort = endPoint.Port.ToString(); + context.RemoteAddress = endPoint.Address.ToString(); + _contextTimeoutManager.StartMonitoringContext(context); + context.Start(); + + return context; + } + + /// + /// Create a new context. + /// + /// true if HTTPS is used. + /// Remote client + /// Network stream, uses . + /// A new context (always). + protected virtual HttpClientContext CreateNewContext(bool isSecured, IPEndPoint endPoint, Stream stream, Socket sock) + { + return new HttpClientContext(isSecured, endPoint, stream, _factory, _bufferSize, sock); + } + + private void OnRequestReceived(object sender, RequestEventArgs e) + { + RequestReceived(sender, e); + } + + private void OnFreeContext(object sender, DisconnectedEventArgs e) + { + var imp = (HttpClientContext) sender; + imp.Cleanup(); + + if (!imp.EndWhenDone) + { + lock (_contextQueue) + _contextQueue.Enqueue(imp); + } + else + { + + imp.Close(); + } + } + + + #region IHttpContextFactory Members + + /// + /// Create a secure . + /// + /// Client socket (accepted by the ). + /// HTTPS certificate to use. + /// Kind of HTTPS protocol. Usually TLS or SSL. + /// + /// A created . + /// + public IHttpClientContext CreateSecureContext(Socket socket, X509Certificate certificate, SslProtocols protocol) + { + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + + // by Fumi.Iseki + //var sslStream = new SslStream(networkStream, false); + SslStream sslStream = null; + try + { + //TODO: this may fail + // by Fumi.Iseki + //sslStream.AuthenticateAsServer(certificate, false, protocol, false); + if (_clientCallback == null) + { + sslStream = new SslStream(networkStream, false); + sslStream.AuthenticateAsServer(certificate, false, protocol, false); + } + else + { + sslStream = new SslStream(networkStream, false, new RemoteCertificateValidationCallback(_clientCallback)); + sslStream.AuthenticateAsServer(certificate, true, protocol, false); + } + + return CreateContext(true, remoteEndPoint, sslStream, socket); + } + catch (IOException err) + { + if (UseTraceLogs) + _logWriter.Write(this, LogPrio.Trace, err.Message); + } + catch (ObjectDisposedException err) + { + if (UseTraceLogs) + _logWriter.Write(this, LogPrio.Trace, err.Message); + } + + return null; + } + + + /// + /// A request have been received from one of the contexts. + /// + public event EventHandler RequestReceived = delegate{}; + + /// + /// Creates a that handles a connected client. + /// + /// Client socket (accepted by the ). + /// + /// A creates . + /// + public IHttpClientContext CreateContext(Socket socket) + { + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + return CreateContext(false, remoteEndPoint, networkStream, socket); + } + + #endregion + + /// + /// Server is shutting down so shut down the factory + /// + public void Shutdown() + { + _contextTimeoutManager.StopMonitoring(); + } + } + + /// + /// Custom network stream to mark sockets as reusable when disposing the stream. + /// + internal class ReusableSocketNetworkStream : NetworkStream + { + private bool disposed = false; + /// + /// Creates a new instance of the class for the specified . + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// The property of the parameter is not . + /// -or- + /// The parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket) + : base(socket) + { + } + + /// + /// Initializes a new instance of the class for the specified with the specified ownership. + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// Set to true to indicate that the will take ownership of the ; otherwise, false. + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// the value of the property of the parameter is not . + /// -or- + /// the parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket, bool ownsSocket) + : base(socket, ownsSocket) + { + } + + /// + /// Creates a new instance of the class for the specified with the specified access rights. + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// A bitwise combination of the values that specify the type of access given to the over the provided . + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// the property of the parameter is not . + /// -or- + /// the parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket, FileAccess access) + : base(socket, access) + { + } + + /// + /// Creates a new instance of the class for the specified with the specified access rights and the specified ownership. + /// + /// + /// The that the will use to send and receive data. + /// + /// + /// A bitwise combination of the values that specifies the type of access given to the over the provided . + /// + /// + /// Set to true to indicate that the will take ownership of the ; otherwise, false. + /// + /// + /// The parameter is null. + /// + /// + /// The parameter is not connected. + /// -or- + /// The property of the parameter is not . + /// -or- + /// The parameter is in a nonblocking state. + /// + public ReusableSocketNetworkStream(Socket socket, FileAccess access, bool ownsSocket) + : base(socket, access, ownsSocket) + { + } + + /// + /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + /// + public override void Close() + { + + if (Socket != null && Socket.Connected) + Socket.Close(); //TODO: Maybe use Disconnect with reuseSocket=true? I tried but it took forever. + base.Close(); + + } + + /// + /// Releases the unmanaged resources used by the and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + + try + { + if (!disposed) + { + disposed = true; + if (Socket != null && Socket.Connected) + Socket.Disconnect(true); + + } + base.Dispose(disposing); + } + catch { } // Best effort, ignore fails + } + } + + /// + /// Used to create es. + /// + public interface IHttpContextFactory + { + /// + /// Creates a that handles a connected client. + /// + /// Client socket (accepted by the ). + /// A creates . + IHttpClientContext CreateContext(Socket socket); + + /// + /// Create a secure . + /// + /// Client socket (accepted by the ). + /// HTTPS certificate to use. + /// Kind of HTTPS protocol. Usually TLS or SSL. + /// A created . + IHttpClientContext CreateSecureContext(Socket socket, X509Certificate certificate, SslProtocols protocol); + + /// + /// A request have been received from one of the contexts. + /// + event EventHandler RequestReceived; + + /// + /// Server is shutting down so shut down the factory + /// + void Shutdown(); + } +} diff --git a/old/HttpServer_OpenSim/source/IHttpClientContext.cs b/old/HttpServer_OpenSim/source/IHttpClientContext.cs new file mode 100644 index 0000000..ff1d0f1 --- /dev/null +++ b/old/HttpServer_OpenSim/source/IHttpClientContext.cs @@ -0,0 +1,148 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace HttpServer +{ + /// + /// Contains a connection to a browser/client. + /// + public interface IHttpClientContext + { + // + // + // by Fumi.Iseki + string SSLCommonName { get; } + + /// + /// Using SSL or other encryption method. + /// + [Obsolete("Use IsSecured instead.")] + bool Secured { get; } + + /// + /// Using SSL or other encryption method. + /// + bool IsSecured { get; } + + /// + /// Disconnect from client + /// + /// error to report in the event. + void Disconnect(SocketError error); + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + /// HTML body contents, can be null or empty. + /// A content type to return the body as, i.e. 'text/html' or 'text/plain', defaults to 'text/html' if null or empty + /// If is invalid. + void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType); + + /// + /// Send a response. + /// + /// Either or + /// HTTP status code + /// reason for the status code. + void Respond(string httpVersion, HttpStatusCode statusCode, string reason); + + /// + /// Send a response. + /// + /// + void Respond(string body); + + /// + /// send a whole buffer + /// + /// buffer to send + /// + void Send(byte[] buffer); + + /// + /// Send data using the stream + /// + /// Contains data to send + /// Start position in buffer + /// number of bytes to send + /// + /// + void Send(byte[] buffer, int offset, int size); + + /// + /// Closes the streams and disposes of the unmanaged resources + /// + void Close(); + + bool EndWhenDone { get; set; } + + /// + /// The context have been disconnected. + /// + /// + /// Event can be used to clean up a context, or to reuse it. + /// + event EventHandler Disconnected; + + /// + /// A request have been received in the context. + /// + event EventHandler RequestReceived; + + HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing(); + } + public class HTTPNetworkContext + { + public NetworkStream Stream; + public Socket Socket; + } + + /// + /// A have been disconnected. + /// + public class DisconnectedEventArgs : EventArgs + { + /// + /// Gets reason to why client disconnected. + /// + public SocketError Error { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// Reason to disconnection. + public DisconnectedEventArgs(SocketError error) + { + Check.Require(error, "error"); + + Error = error; + } + } + + /// + /// + /// + public class RequestEventArgs : EventArgs + { + /// + /// Gets received request. + /// + public IHttpRequest Request { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The request. + public RequestEventArgs(IHttpRequest request) + { + Check.Require(request, "request"); + + Request = request; + } + } + +} diff --git a/patch/HttpServer-20130201.patch b/patch/HttpServer-20130201.patch new file mode 100644 index 0000000..71e930b --- /dev/null +++ b/patch/HttpServer-20130201.patch @@ -0,0 +1,109 @@ +diff -Nur HttpServer-/HttpClientContext.cs HttpServer/HttpClientContext.cs +--- HttpServer-/HttpClientContext.cs 2013-02-01 18:39:44.868009882 +0900 ++++ HttpServer/HttpClientContext.cs 2013-02-01 18:45:07.740259535 +0900 +@@ -6,6 +6,9 @@ + using HttpServer.Exceptions; + using HttpServer.Parser; + ++using System.Net.Security; ++using System.Security.Cryptography.X509Certificates; ++ + namespace HttpServer + { + /// +@@ -77,6 +80,18 @@ + + _buffer = new byte[bufferSize]; + ++ // by Fumi.Iseki ++ SSLCommonName = ""; ++ if (secured) ++ { ++ SslStream _ssl = (SslStream)_stream; ++ X509Certificate _cert1 = _ssl.RemoteCertificate; ++ if (_cert1 != null) ++ { ++ X509Certificate2 _cert2 = new X509Certificate2(_cert1); ++ if (_cert2 != null) SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ } ++ } + } + + public bool EndWhenDone +@@ -185,6 +200,11 @@ + /// + public bool IsSecured { get; internal set; } + ++ // ++ // ++ // by Fumi.Iseki ++ public string SSLCommonName { get; internal set; } ++ + /// + /// Specify which logger to use. + /// +diff -Nur HttpServer-/HttpContextFactory.cs HttpServer/HttpContextFactory.cs +--- HttpServer-/HttpContextFactory.cs 2013-02-01 18:39:44.868009882 +0900 ++++ HttpServer/HttpContextFactory.cs 2013-02-01 18:44:42.408133328 +0900 +@@ -19,6 +19,10 @@ + private readonly IRequestParserFactory _factory; + private readonly ILogWriter _logWriter; + ++ // by Fumi.Iseki ++ public static RemoteCertificateValidationCallback ClientCertificateValidationCallback = null; ++ private RemoteCertificateValidationCallback _clientCallback = null; ++ + /// + /// Initializes a new instance of the class. + /// +@@ -30,6 +34,13 @@ + _logWriter = writer; + _bufferSize = bufferSize; + _factory = factory; ++ ++ // by Fumi.Iseki ++ if (ClientCertificateValidationCallback != null) ++ { ++ _clientCallback = ClientCertificateValidationCallback; ++ ClientCertificateValidationCallback = null; ++ } + } + + /// +@@ -127,11 +138,19 @@ + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + +- var sslStream = new SslStream(networkStream, false); ++ // by Fumi.Iseki ++ var sslStream = new SslStream(networkStream, false, new RemoteCertificateValidationCallback(_clientCallback)); + try + { + //TODO: this may fail +- sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ if (_clientCallback == null) // by Fumi.Iseki ++ { ++ sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ } ++ else ++ { ++ sslStream.AuthenticateAsServer(certificate, true, protocol, false); ++ } + return CreateContext(true, remoteEndPoint, sslStream, socket); + } + catch (IOException err) +diff -Nur HttpServer-/IHttpClientContext.cs HttpServer/IHttpClientContext.cs +--- HttpServer-/IHttpClientContext.cs 2013-02-01 18:39:44.872009815 +0900 ++++ HttpServer/IHttpClientContext.cs 2013-02-01 18:44:05.196259567 +0900 +@@ -9,6 +9,11 @@ + /// + public interface IHttpClientContext + { ++ // ++ // ++ // by Fumi.Iseki ++ string SSLCommonName { get; } ++ + /// + /// Using SSL or other encryption method. + /// diff --git a/patch/HttpServer-20131020.patch b/patch/HttpServer-20131020.patch new file mode 100644 index 0000000..ec140a9 --- /dev/null +++ b/patch/HttpServer-20131020.patch @@ -0,0 +1,112 @@ +diff -Nur HttpServer-/HttpClientContext.cs HttpServer/HttpClientContext.cs +--- HttpServer-/HttpClientContext.cs 2013-10-21 13:08:30.861101971 +0900 ++++ HttpServer/HttpClientContext.cs 2013-10-21 15:17:40.493510079 +0900 +@@ -6,6 +6,10 @@ + using HttpServer.Exceptions; + using HttpServer.Parser; + ++// by Fumi.Iseki ++using System.Net.Security; ++using System.Security.Cryptography.X509Certificates; ++ + namespace HttpServer + { + /// +@@ -92,6 +96,18 @@ + _sock = sock; + _buffer = new byte[bufferSize]; + ++ // by Fumi.Iseki ++ SSLCommonName = ""; ++ if (secured) ++ { ++ SslStream _ssl = (SslStream)_stream; ++ X509Certificate _cert1 = _ssl.RemoteCertificate; ++ if (_cert1 != null) ++ { ++ X509Certificate2 _cert2 = new X509Certificate2(_cert1); ++ if (_cert2 != null) SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ } ++ } + } + + public bool EndWhenDone +@@ -215,6 +231,11 @@ + /// + public bool IsSecured { get; internal set; } + ++ // ++ // ++ // by Fumi.Iseki ++ public string SSLCommonName { get; internal set; } ++ + /// + /// Specify which logger to use. + /// +diff -Nur HttpServer-/HttpContextFactory.cs HttpServer/HttpContextFactory.cs +--- HttpServer-/HttpContextFactory.cs 2013-10-21 13:08:30.861101971 +0900 ++++ HttpServer/HttpContextFactory.cs 2013-10-21 15:19:36.431821703 +0900 +@@ -20,6 +20,10 @@ + private readonly ILogWriter _logWriter; + private readonly ContextTimeoutManager _contextTimeoutManager; + ++ // by Fumi.Iseki ++ public static RemoteCertificateValidationCallback ClientCertificateValidationCallback = null; ++ private RemoteCertificateValidationCallback _clientCallback = null; ++ + /// + /// Initializes a new instance of the class. + /// +@@ -32,6 +36,13 @@ + _bufferSize = bufferSize; + _factory = factory; + _contextTimeoutManager = new ContextTimeoutManager(ContextTimeoutManager.MonitorType.Thread); ++ ++ // by Fumi.Iseki ++ if (ClientCertificateValidationCallback != null) ++ { ++ _clientCallback = ClientCertificateValidationCallback; ++ ClientCertificateValidationCallback = null; ++ } + } + + /// +@@ -132,11 +143,21 @@ + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + +- var sslStream = new SslStream(networkStream, false); ++ // by Fumi.Iseki ++ SslStream sslStream = null; + try + { + //TODO: this may fail +- sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ if (_clientCallback == null) // by Fumi.Iseki ++ { ++ sslStream = new SslStream(networkStream, false); ++ sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ } ++ else ++ { ++ sslStream = new SslStream(networkStream, false, new RemoteCertificateValidationCallback(_clientCallback)); ++ sslStream.AuthenticateAsServer(certificate, true, protocol, false); ++ } + return CreateContext(true, remoteEndPoint, sslStream, socket); + } + catch (IOException err) +diff -Nur HttpServer-/IHttpClientContext.cs HttpServer/IHttpClientContext.cs +--- HttpServer-/IHttpClientContext.cs 2013-10-21 13:08:30.865101913 +0900 ++++ HttpServer/IHttpClientContext.cs 2013-10-21 15:17:40.518509254 +0900 +@@ -9,6 +9,11 @@ + /// + public interface IHttpClientContext + { ++ // ++ // ++ // by Fumi.Iseki ++ string SSLCommonName { get; } ++ + /// + /// Using SSL or other encryption method. + /// diff --git a/patch/HttpServer-20140307.patch b/patch/HttpServer-20140307.patch new file mode 100644 index 0000000..1e34fba --- /dev/null +++ b/patch/HttpServer-20140307.patch @@ -0,0 +1,116 @@ +diff -Nur HttpServer-/HttpClientContext.cs HttpServer/HttpClientContext.cs +--- HttpServer-/HttpClientContext.cs 2014-03-06 16:53:10.802499259 +0900 ++++ HttpServer/HttpClientContext.cs 2014-03-07 13:33:26.265146166 +0900 +@@ -6,6 +6,10 @@ + using HttpServer.Exceptions; + using HttpServer.Parser; + ++// by Fumi.Iseki ++using System.Net.Security; ++using System.Security.Cryptography.X509Certificates; ++ + namespace HttpServer + { + /// +@@ -92,6 +96,18 @@ + _sock = sock; + _buffer = new byte[bufferSize]; + ++ // by Fumi.Iseki ++ SSLCommonName = ""; ++ if (secured) ++ { ++ SslStream _ssl = (SslStream)_stream; ++ X509Certificate _cert1 = _ssl.RemoteCertificate; ++ if (_cert1 != null) ++ { ++ X509Certificate2 _cert2 = new X509Certificate2(_cert1); ++ if (_cert2 != null) SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ } ++ } + } + + public bool EndWhenDone +@@ -215,6 +231,11 @@ + /// + public bool IsSecured { get; internal set; } + ++ // ++ // ++ // by Fumi.Iseki ++ public string SSLCommonName { get; internal set; } ++ + /// + /// Specify which logger to use. + /// +diff -Nur HttpServer-/HttpContextFactory.cs HttpServer/HttpContextFactory.cs +--- HttpServer-/HttpContextFactory.cs 2014-03-06 16:53:10.802499259 +0900 ++++ HttpServer/HttpContextFactory.cs 2014-03-07 13:39:25.522879915 +0900 +@@ -20,6 +20,10 @@ + private readonly ILogWriter _logWriter; + private readonly ContextTimeoutManager _contextTimeoutManager; + ++ // by Fumi.Iseki ++ public static RemoteCertificateValidationCallback ClientCertificateValidationCallback = null; ++ private RemoteCertificateValidationCallback _clientCallback = null; ++ + /// + /// Initializes a new instance of the class. + /// +@@ -32,6 +36,13 @@ + _bufferSize = bufferSize; + _factory = factory; + _contextTimeoutManager = new ContextTimeoutManager(ContextTimeoutManager.MonitorType.Thread); ++ ++ // by Fumi.Iseki ++ if (ClientCertificateValidationCallback != null) ++ { ++ _clientCallback = ClientCertificateValidationCallback; ++ ClientCertificateValidationCallback = null; ++ } + } + + /// +@@ -132,11 +143,25 @@ + var networkStream = new ReusableSocketNetworkStream(socket, true); + var remoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; + +- var sslStream = new SslStream(networkStream, false); ++ // by Fumi.Iseki ++ //var sslStream = new SslStream(networkStream, false); ++ SslStream sslStream = null; + try + { + //TODO: this may fail +- sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ // by Fumi.Iseki ++ //sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ if (_clientCallback == null) ++ { ++ sslStream = new SslStream(networkStream, false); ++ sslStream.AuthenticateAsServer(certificate, false, protocol, false); ++ } ++ else ++ { ++ sslStream = new SslStream(networkStream, false, new RemoteCertificateValidationCallback(_clientCallback)); ++ sslStream.AuthenticateAsServer(certificate, true, protocol, false); ++ } ++ + return CreateContext(true, remoteEndPoint, sslStream, socket); + } + catch (IOException err) +diff -Nur HttpServer-/IHttpClientContext.cs HttpServer/IHttpClientContext.cs +--- HttpServer-/IHttpClientContext.cs 2014-03-06 16:53:10.805499220 +0900 ++++ HttpServer/IHttpClientContext.cs 2014-03-07 13:33:38.190006080 +0900 +@@ -9,6 +9,11 @@ + /// + public interface IHttpClientContext + { ++ // ++ // ++ // by Fumi.Iseki ++ string SSLCommonName { get; } ++ + /// + /// Using SSL or other encryption method. + /// diff --git a/patch/opensim-0.7.5.patch b/patch/opensim-0.7.5.patch new file mode 100644 index 0000000..fefa807 --- /dev/null +++ b/patch/opensim-0.7.5.patch @@ -0,0 +1,26 @@ +diff -Nur opensim-0.7.5-rc2-source-/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs opensim-0.7.5-rc2-source/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +--- opensim-0.7.5-rc2-source-/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2013-01-26 09:33:28.000000000 +0900 ++++ opensim-0.7.5-rc2-source/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2013-02-01 19:36:52.090259990 +0900 +@@ -923,6 +923,7 @@ + } + } + xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] ++ xmlRprcRequest.Params.Add(request.IHttpClientContext.SSLCommonName); // Param[4] + + try + { +diff -Nur opensim-0.7.5-rc2-source-/OpenSim/Framework/Servers/Tests/OSHttpTests.cs opensim-0.7.5-rc2-source/OpenSim/Framework/Servers/Tests/OSHttpTests.cs +--- opensim-0.7.5-rc2-source-/OpenSim/Framework/Servers/Tests/OSHttpTests.cs 2013-01-26 09:33:28.000000000 +0900 ++++ opensim-0.7.5-rc2-source/OpenSim/Framework/Servers/Tests/OSHttpTests.cs 2013-02-01 19:37:57.065259588 +0900 +@@ -60,6 +60,11 @@ + _secured = secured; + } + ++ public string SSLCommonName ++ { ++ get { return "";} ++ } ++ + public void Disconnect(SocketError error) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {} diff --git a/patch/opensim-0.7.6.patch b/patch/opensim-0.7.6.patch new file mode 100644 index 0000000..49e6aeb --- /dev/null +++ b/patch/opensim-0.7.6.patch @@ -0,0 +1,26 @@ +diff -Nur opensim-0.7.6-source-/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs opensim-0.7.6-source/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +--- opensim-0.7.6-source-/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2013-10-05 04:45:02.000000000 +0900 ++++ opensim-0.7.6-source/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2013-10-19 22:14:51.000000000 +0900 +@@ -1021,6 +1021,7 @@ + } + } + xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] ++ xmlRprcRequest.Params.Add(request.IHttpClientContext.SSLCommonName); // Param[4] + + try + { +diff -Nur opensim-0.7.6-source-/OpenSim/Framework/Servers/Tests/OSHttpTests.cs opensim-0.7.6-source/OpenSim/Framework/Servers/Tests/OSHttpTests.cs +--- opensim-0.7.6-source-/OpenSim/Framework/Servers/Tests/OSHttpTests.cs 2013-10-05 04:45:02.000000000 +0900 ++++ opensim-0.7.6-source/OpenSim/Framework/Servers/Tests/OSHttpTests.cs 2013-10-19 22:14:51.000000000 +0900 +@@ -60,6 +60,11 @@ + _secured = secured; + } + ++ public string SSLCommonName ++ { ++ get { return "";} ++ } ++ + public void Disconnect(SocketError error) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {} diff --git a/patch/opensim-0.8.0.patch b/patch/opensim-0.8.0.patch new file mode 100644 index 0000000..3638bd4 --- /dev/null +++ b/patch/opensim-0.8.0.patch @@ -0,0 +1,26 @@ +diff -Nur opensim/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs opensim+/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +--- opensim/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2014-05-17 16:15:44.791286687 +0900 ++++ opensim+/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2014-05-17 16:24:12.446449197 +0900 +@@ -1053,6 +1053,7 @@ + } + } + xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] ++ xmlRprcRequest.Params.Add(request.IHttpClientContext.SSLCommonName); // Param[4] + + try + { +diff -Nur opensim/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs opensim+/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs +--- opensim/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs 2014-05-17 15:48:53.785383361 +0900 ++++ opensim+/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs 2014-05-17 16:23:40.934998601 +0900 +@@ -71,6 +71,11 @@ + // Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error); + } + ++ public string SSLCommonName ++ { ++ get { return "";} ++ } ++ + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");} + public void Respond(string body) { Console.WriteLine("xxx");} diff --git a/patch/opensim-0.8.1.patch b/patch/opensim-0.8.1.patch new file mode 100644 index 0000000..5616c6a --- /dev/null +++ b/patch/opensim-0.8.1.patch @@ -0,0 +1,26 @@ +diff -Nur opensim/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs opensim_server/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +--- opensim/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2015-01-24 17:01:54.940426676 +0900 ++++ opensim_server/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2015-01-24 17:02:49.084542865 +0900 +@@ -1079,6 +1079,7 @@ + } + } + xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] ++ xmlRprcRequest.Params.Add(request.IHttpClientContext.SSLCommonName); // Param[4] + + try + { +diff -Nur opensim/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs opensim_server/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs +--- opensim/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs 2015-01-24 17:01:54.940426676 +0900 ++++ opensim_server/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs 2015-01-24 17:02:49.085542868 +0900 +@@ -71,6 +71,11 @@ + // Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error); + } + ++ public string SSLCommonName ++ { ++ get { return "";} ++ } ++ + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");} + public void Respond(string body) { Console.WriteLine("xxx");} diff --git a/patch/opensim-0.8.2.patch b/patch/opensim-0.8.2.patch new file mode 100644 index 0000000..561fd3b --- /dev/null +++ b/patch/opensim-0.8.2.patch @@ -0,0 +1,26 @@ +diff -Nur OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +--- OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs 2015-11-16 12:37:24.000000000 +0900 ++++ OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2015-11-20 16:16:46.111890755 +0900 +@@ -1080,6 +1080,7 @@ + } + } + xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] ++ xmlRprcRequest.Params.Add(request.IHttpClientContext.SSLCommonName); // Param[4] + + try + { +diff -Nur OpenSim-/Tests/Common/Mock/TestHttpClientContext.cs OpenSim/Tests/Common/Mock/TestHttpClientContext.cs +--- OpenSim-/Tests/Common/Mock/TestHttpClientContext.cs 2015-11-16 12:37:24.000000000 +0900 ++++ OpenSim/Tests/Common/Mock/TestHttpClientContext.cs 2015-11-20 16:16:46.111890755 +0900 +@@ -71,6 +71,11 @@ + // Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error); + } + ++ public string SSLCommonName ++ { ++ get { return "";} ++ } ++ + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");} + public void Respond(string body) { Console.WriteLine("xxx");} diff --git a/patch/opensim-0.9.0.patch b/patch/opensim-0.9.0.patch new file mode 100644 index 0000000..8e9ebeb --- /dev/null +++ b/patch/opensim-0.9.0.patch @@ -0,0 +1,46 @@ +diff -Nur OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +--- OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs 2018-04-22 14:34:37.642698003 +0900 ++++ OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2018-04-22 14:35:35.331826307 +0900 +@@ -1094,6 +1094,10 @@ + + if (gridproxy) + xmlRprcRequest.Params.Add("gridproxy"); // Param[4] ++ ++ // by Fumi.Iseki for DTLNSLMoneyServer ++ xmlRprcRequest.Params.Add(request.IHttpClientContext.SSLCommonName); // Param[4] or Param[5] ++ + try + { + xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint); +diff -Nur OpenSim-/Framework/Servers/Tests/OSHttpTests.cs OpenSim/Framework/Servers/Tests/OSHttpTests.cs +--- OpenSim-/Framework/Servers/Tests/OSHttpTests.cs 2018-04-22 14:34:37.643698006 +0900 ++++ OpenSim/Framework/Servers/Tests/OSHttpTests.cs 2018-04-22 14:35:35.331826307 +0900 +@@ -62,6 +62,12 @@ + _secured = secured; + } + ++ // by Fumi.Iseki for DTLNSLMoenyServer ++ public string SSLCommonName ++ { ++ get { return "";} ++ } ++ + public void Disconnect(SocketError error) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {} +diff -Nur OpenSim-/Tests/Common/Mock/TestHttpClientContext.cs OpenSim/Tests/Common/Mock/TestHttpClientContext.cs +--- OpenSim-/Tests/Common/Mock/TestHttpClientContext.cs 2018-04-22 14:34:37.643698006 +0900 ++++ OpenSim/Tests/Common/Mock/TestHttpClientContext.cs 2018-04-22 14:35:35.332826313 +0900 +@@ -72,6 +72,12 @@ + // Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error); + } + ++ // by Fumi.Iseki for DTLNSLMoenyServer ++ public string SSLCommonName ++ { ++ get { return "";} ++ } ++ + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");} + public void Respond(string body) { Console.WriteLine("xxx");} diff --git a/patch/opensim-0.9.1.patch b/patch/opensim-0.9.1.patch new file mode 100644 index 0000000..e803d15 --- /dev/null +++ b/patch/opensim-0.9.1.patch @@ -0,0 +1,15 @@ +diff -Nur OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +--- OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs 2019-02-13 17:07:00.037657561 +0900 ++++ OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2019-02-13 17:29:49.371393303 +0900 +@@ -158,6 +158,11 @@ + m_port = port; + } + ++ public RemoteCertificateValidationCallback CertificateValidationCallback ++ { ++ set { m_certificateValidationCallback = value; } ++ } ++ + private void load_cert(string CPath, string CPass) + { + try diff --git a/patch/opensim-0.9.2.2.patch b/patch/opensim-0.9.2.2.patch new file mode 100644 index 0000000..5b9a527 --- /dev/null +++ b/patch/opensim-0.9.2.2.patch @@ -0,0 +1,30 @@ +diff -Nur OpenSim-/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs +--- OpenSim-/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs 2023-06-02 17:03:08.247494109 +0900 ++++ OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs 2023-06-02 17:07:01.767935412 +0900 +@@ -10,6 +10,8 @@ + using System.Security.Cryptography.X509Certificates; + using OpenMetaverse; + ++using System.Text.RegularExpressions; ++ + namespace OSHttpServer + { + /// +@@ -133,8 +135,15 @@ + if (_cert1 != null) + { + X509Certificate2 _cert2 = new X509Certificate2(_cert1); +- if (_cert2 != null) +- SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ if (_cert2 != null) { ++ string _sbj = _cert2.Subject.ToString(); ++ Match _cn = Regex.Match(_sbj, @"CN=(.*?),"); ++ if (_cn.Success) { ++ SSLCommonName = _cn.Groups[1].Value; ++ } ++ // ++ //SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ } + } + } + diff --git a/patch/opensim-0.9.2.patch b/patch/opensim-0.9.2.patch new file mode 100644 index 0000000..e5b1a46 --- /dev/null +++ b/patch/opensim-0.9.2.patch @@ -0,0 +1,19 @@ +diff -Nur OpenSim.orig/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs +--- OpenSim.orig/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs 2021-08-05 13:44:09.896571627 +0900 ++++ OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpClientContext.cs 2021-08-05 13:43:51.435572375 +0900 +@@ -134,7 +134,14 @@ + { + X509Certificate2 _cert2 = new X509Certificate2(_cert1); + if (_cert2 != null) +- SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ { ++ try { ++ SSLCommonName = _cert2.GetNameInfo(X509NameType.SimpleName, false); ++ } ++ catch { ++ SSLCommonName = "unknownName"; ++ } ++ } + } + } + diff --git a/patch/opensim_server.patch b/patch/opensim_server.patch new file mode 120000 index 0000000..59381f5 --- /dev/null +++ b/patch/opensim_server.patch @@ -0,0 +1 @@ +opensim-0.9.2.2.patch \ No newline at end of file diff --git a/prebuild.net.xml b/prebuild.net.xml new file mode 100644 index 0000000..ab296c7 --- /dev/null +++ b/prebuild.net.xml @@ -0,0 +1,142 @@ + + + + + + TRACE;DEBUG + false + false + false + 4 + false + + bin + true + true + false + + + + + TRACE + true + false + false + 4 + false + + bin + false + true + false + + + + + + + ../bin/ + + + + + ../bin/ + + + + ../../bin/ + + + + + + + + + + + + + + + + + + + + + + + + + ../bin/ + + + + + ../bin/ + + + + ../../bin/ + + + + + + + + + + + + + + + + + + + + + + + + + + ../bin/ + + + + + ../bin/ + + + ../../bin/ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prebuild.xml b/prebuild.xml new file mode 100644 index 0000000..2f5e309 --- /dev/null +++ b/prebuild.xml @@ -0,0 +1,159 @@ + + + + + + TRACE;DEBUG + false + false + false + 4 + false + + bin + true + true + false + + + + + TRACE + true + false + false + 4 + false + + bin + false + true + false + + + + + + + ../bin/ + + + + + ../bin/ + + + + ../../bin/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../bin/ + + + + + ../bin/ + + + + ../../bin/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../bin/ + + + + + ../bin/ + + + ../../bin/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/release/0.8.2/bin/MoneyServer.exe b/release/0.8.2/bin/MoneyServer.exe new file mode 100755 index 0000000..f6e823c Binary files /dev/null and b/release/0.8.2/bin/MoneyServer.exe differ diff --git a/release/0.8.2/bin/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll b/release/0.8.2/bin/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll new file mode 100755 index 0000000..ecf5bf3 Binary files /dev/null and b/release/0.8.2/bin/OpenSim.Data.MySQL.MySQLMoneyDataWrapper.dll differ diff --git a/release/0.8.2/bin/OpenSim.Modules.Currency.dll b/release/0.8.2/bin/OpenSim.Modules.Currency.dll new file mode 100755 index 0000000..133d13f Binary files /dev/null and b/release/0.8.2/bin/OpenSim.Modules.Currency.dll differ diff --git a/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/IMoneyManager.cs b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/IMoneyManager.cs new file mode 100644 index 0000000..17d3d7b --- /dev/null +++ b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/IMoneyManager.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public interface IMoneyManager + { + int getBalance(string userID); + + //int getBalanceStatus(string userID); + + //bool updateBalanceStatus(string userID,int status); + + bool withdrawMoney(UUID transactionID,string senderID, int amount); + + bool giveMoney(UUID transactionID,string receiverID, int amount); + + bool addTransaction(TransactionData transaction); + + bool updateTransactionStatus(UUID transactionID, int status,string description); + + TransactionData FetchTransaction(UUID transactionID); + + TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index,uint retNum); + + int getTransactionNum(string userID, int startTime, int endTime); + + bool addUser(string userID, int balance, int status); + + bool SetTransExpired(int deadTime); + + bool ValidateTransfer(string secureCode, UUID transactionID); + + bool addUserInfo(UserInfo user); + + UserInfo fetchUserInfo(string userID); + + bool updateUserInfo(UserInfo user); + + } +} diff --git a/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLMoneyManager.cs b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLMoneyManager.cs new file mode 100644 index 0000000..0be9f48 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLMoneyManager.cs @@ -0,0 +1,1133 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Data; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using log4net; +using MySql.Data.MySqlClient; +using OpenMetaverse; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public class MySQLMoneyManager:IMoneyManager + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // by Fumi.Iseki + private string Table_of_Balance = "balances"; + private string Table_of_UserInfo = "userinfo"; + private string Table_of_Transaction = "transactions"; + //private string Table_of_UserInfo = "currency_users"; // for Aurora-Sim + + private string connectString; + + private int m_defaultMoney = 0; + + private MySqlConnection dbcon; + + + + public MySQLMoneyManager(string hostname,string database,string username ,string password,string cpooling, string port) + { + string s = "Server=" + hostname + ";Port=" + port + ";Database=" + database + ";User ID=" + + username + ";Password=" + password + ";Pooling=" + cpooling + ";"; + Initialise(s); + } + + + + public MySQLMoneyManager(string connect) + { + Initialise(connect); + } + + + + private void Initialise(string connect) + { + try + { + connectString = connect; + dbcon = new MySqlConnection(connectString); + try + { + dbcon.Open(); + } + catch (Exception e) + { + throw new Exception("[MONEY DB]: Connection error while using connection string ["+connectString+"]", e); + } + //m_log.Info("[MONEY DB]: Connection established"); + } + + catch(Exception e) + { + throw new Exception("[MONEY DB]: Error initialising MySql Database: " + e.ToString()); + } + + try + { + Dictionary tableList = new Dictionary(); + tableList = CheckTables(); + + // Balances Table + if (!tableList.ContainsKey(Table_of_Balance)) + { + try + { + CreateBalanceTable(); + } + catch (Exception e) + { + throw new Exception("[MONEY DB]: Error creating balance table: " + e.ToString()); + } + } + else + { + string version = tableList[Table_of_Balance].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) + { + case 1: //Rev.1 + UpdateBalanceTable1(); + break; + } + } + + // + // UserInfo Table + if (!tableList.ContainsKey(Table_of_UserInfo)) + { + try + { + CreateUserTable(); + } + catch (Exception e) + { + throw new Exception("[MONEY DB]: Unable to create currency userinfo table: " + e.ToString()); + } + } + else + { + string version = tableList[Table_of_UserInfo].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) + { + case 1: //Rev.1 + UpdateUserInfoTable1(); + break; + } + } + + // + // Transaction Table + if (!tableList.ContainsKey(Table_of_Transaction)) + { + try + { + CreateTransactionTable(); + } + catch (Exception e) + { + throw new Exception("[MONEY DB]: Error creating transaction table: " + e.ToString()); + } + } + else // check transaction table version + { + string version = tableList[Table_of_Transaction].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) + { + case 2: //Rev.2 + UpdateTransactionTable2(); + UpdateTransactionTable3(); + UpdateTransactionTable4(); + UpdateTransactionTable5(); + UpdateTransactionTable6(); + break; + case 3: //Rev.3 + UpdateTransactionTable3(); + UpdateTransactionTable4(); + UpdateTransactionTable5(); + UpdateTransactionTable6(); + break; + case 4: //Rev.4 + UpdateTransactionTable4(); + UpdateTransactionTable5(); + UpdateTransactionTable6(); + break; + case 5: //Rev.5 + UpdateTransactionTable5(); + UpdateTransactionTable6(); + break; + case 6: //Rev.6 + UpdateTransactionTable6(); + break; + } + } + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Error checking or creating tables: " + e.ToString()); + throw new Exception("[MONEY DB]: Error checking or creating tables: " + e.ToString()); + } + } + + + + private int getTableVersionNum(string version) + { + int nVer = 0; + + Regex _commentPattenRegex = new Regex(@"\w+\.(?\d+)"); + Match m = _commentPattenRegex.Match(version); + if (m.Success) + { + string ver = m.Groups["ver"].Value; + nVer = Convert.ToInt32(ver); + } + return nVer; + } + + + + private void CreateBalanceTable() + { + string sql = string.Empty; + + sql += "CREATE TABLE `" + Table_of_Balance + "`("; + sql += "`user` varchar(128) NOT NULL,"; + sql += "`balance` int(10) NOT NULL,"; + sql += "`status` tinyint(2) default NULL,"; + sql += "PRIMARY KEY (`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev.2';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + } + + + + private void CreateTransactionTable() + { + string sql = string.Empty; + + sql += "CREATE TABLE `" + Table_of_Transaction + "`("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`sender` varchar(128) NOT NULL,"; + sql += "`receiver` varchar(128) NOT NULL,"; + sql += "`amount` int(10) NOT NULL,"; + sql += "`objectUUID` varchar(36) DEFAULT NULL,"; + sql += "`regionHandle` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`time` int(11) NOT NULL,"; + sql += "`secure` varchar(36) NOT NULL,"; + sql += "`status` tinyint(1) NOT NULL,"; + sql += "`commonName` varchar(128) default NULL,"; + sql += "`description` varchar(255) default NULL,"; + sql += "PRIMARY KEY (`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev.7';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + } + + + + private void CreateUserTable() + { + string sql = string.Empty; + + sql += "CREATE TABLE `" + Table_of_UserInfo + "`("; + sql += "`user` varchar(128) NOT NULL,"; + sql += "`simip` varchar(64) NOT NULL,"; + sql += "`avatar` varchar(50) NOT NULL,"; + sql += "`pass` varchar(36) DEFAULT NULL,"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev.2';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + } + + + + + /////////////////////////////////////////////////////////////////////// + + // + private void UpdateBalanceTable1() + { + m_log.Info("[MONEY DB]: Converting Balance Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Balance; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT * FROM " + Table_of_Balance; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i=0) { + amount += balance; + updatedb = updateBalance(uuid, amount); + } + else { + updatedb = addUser(uuid, amount, int.Parse(row[i,2])); + } + if (!updatedb) break; + } + } + + // Delete + if (updatedb) { + for (int i=0; i + /// update transaction table from Rev.2 to Rev.3 + /// + private void UpdateTransactionTable2() + { + string sql = string.Empty; + + sql += "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transaction + "`"; + sql += "ADD(`objectUUID` varchar(36) DEFAULT NULL),"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + } + + + /// + /// update transaction table from Rev.3 to Rev.4 + /// + private void UpdateTransactionTable3() + { + string sql = string.Empty; + + sql += "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transaction + "`"; + sql += "ADD(`secure` varchar(36) NOT NULL),"; + sql += "COMMENT = 'Rev.4';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + } + + + /// + /// update transaction table from Rev.4 to Rev.5 + /// + private void UpdateTransactionTable4() + { + string sql = string.Empty; + + sql += "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transaction + "`"; + sql += "ADD(`regionHandle` varchar(36) NOT NULL),"; + sql += "COMMENT = 'Rev.5';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + } + + + /// + /// update transaction table from Rev.5 to Rev.6 + /// + private void UpdateTransactionTable5() + { + string sql = string.Empty; + + sql += "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transaction + "`"; + sql += "ADD(`commonName` varchar(128) NOT NULL),"; + sql += "COMMENT = 'Rev.6';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + } + + + /// + /// update transaction table from Rev.6 to Rev.7 + /// + private void UpdateTransactionTable6() + { + m_log.Info("[MONEY DB]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Transaction; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT UUID,sender,receiver FROM " + Table_of_Transaction; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i CheckTables() + { + Dictionary tableDic = new Dictionary(); + lock (dbcon) + { + string sql = string.Empty; + + sql += "SELECT TABLE_NAME,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?dbname"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?dbname", dbcon.Database); + + using (MySqlDataReader r = cmd.ExecuteReader()) + { + while (r.Read()) + { + try + { + string tableName = (string)r["TABLE_NAME"]; + string comment = (string)r["TABLE_COMMENT"]; + tableDic.Add(tableName, comment); + } + catch (Exception e) + { + throw new Exception("[MONEY DB]: Error checking tables" + e.ToString()); + } + } + r.Close(); + } + return tableDic; + } + } + + + /// + /// Reconnect to the database + /// + public void Reconnect() + { + m_log.Info("[MONEY DB]: Reconnecting database"); + lock (dbcon) + { + try + { + dbcon.Close(); + dbcon = new MySqlConnection(connectString); + dbcon.Open(); + m_log.Info("[MONEY DB]: Reconnected database"); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Unable to reconnect to database" + e.ToString()); + } + } + } + + + + /////////////////////////////////////////////////////////////////////// + + /// + /// Get balance from database. returns -1 if failed. + /// + /// + /// + public int getBalance(string userID) + { + string sql = string.Empty; + int retValue = -1; + sql += "SELECT balance FROM " + Table_of_Balance + " WHERE user = ?userid"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userid", userID); + try + { + using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (dbReader.Read()) + { + retValue = Convert.ToInt32(dbReader["balance"]); + } + dbReader.Close(); + cmd.Dispose(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[MoneyDB]: MySql failed to fetch balance {0}" + Environment.NewLine + e.ToString() + + Environment.NewLine + "Reconnecting" + userID); + Reconnect(); + return -2; + } + return retValue; + } + + + public bool updateBalance(string uuid, int amount) + { + bool bRet = false; + string sql = string.Empty; + + sql += "UPDATE " + Table_of_Balance + " SET balance = ?amount where user = ?uuid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?uuid", uuid); + + try + { + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: update money error " + e.ToString()); + return false; + } + + return bRet; + } + + + public bool addUser(string userID,int balance,int status) + { + bool bRet = false; + string sql = string.Empty; + + sql += "INSERT INTO " + Table_of_Balance + " (`user`,`balance`,`status`) VALUES "; + sql += "(?userID,?balance,?status);"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userID", userID); + cmd.Parameters.AddWithValue("?balance", balance); + cmd.Parameters.AddWithValue("?status", status); + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + return bRet; + } + + + /// + /// Add user,for internal use + /// + /// + private void addUser(string userID) + { + string sql = string.Empty; + + sql += "INSERT INTO " + Table_of_Balance + " (`user`,`balance`,`status`) VALUES "; + sql += "(?userID,?balance,?status)"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userID", userID); + cmd.Parameters.AddWithValue("?balance", m_defaultMoney); + cmd.Parameters.AddWithValue("?status", 0); + cmd.ExecuteNonQuery(); + } + + + /// + /// Here we'll make a withdraw from the sender and update transaction status + /// + /// + /// + /// + /// + public bool withdrawMoney(UUID transactionID,string senderID, int amount) + { + bool bRet = false; + string sql = string.Empty; + + sql += "BEGIN;"; + sql += "UPDATE " + Table_of_Balance + " SET balance = balance - ?amount where user = ?userid;"; + sql += "UPDATE " + Table_of_Transaction + " SET status = ?status where UUID = ?tranid;"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", senderID); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + + try + { + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: withdraw money error " + e.ToString()); + return false; + } + + return bRet; + } + + + /// + /// Give money to the receiver and change the transaction status to success. + /// + /// + /// + /// + /// + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + string sql = string.Empty; + bool bRet = false; + + sql += "BEGIN;"; + sql += "UPDATE " + Table_of_Balance + " SET balance = balance + ?amount where user = ?userid;"; + sql += "UPDATE " + Table_of_Transaction + " SET status = ?status where UUID = ?tranid;"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", receiverID); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS);//Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + + try + { + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: give money error " + e.ToString()); + return false; + } + + return bRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // transaction + // + public bool addTransaction(TransactionData transaction) + { + bool bRet = false; + string sql = string.Empty; + + sql += "INSERT INTO " + Table_of_Transaction; + sql += " (`UUID`,`sender`,`receiver`,`amount`,`objectUUID`,`regionHandle`,`type`,`time`,`secure`,`status`,`commonName`,`description`) VALUES"; + sql += " (?transID,?sender,?receiver,?amount,?objID,?regionHandle,?type,?time,?secure,?status,?cname,?desc)"; + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transaction.TransUUID.ToString()); + cmd.Parameters.AddWithValue("?sender", transaction.Sender); + cmd.Parameters.AddWithValue("?receiver", transaction.Receiver); + cmd.Parameters.AddWithValue("?amount", transaction.Amount); + cmd.Parameters.AddWithValue("?objID", transaction.ObjectUUID); + cmd.Parameters.AddWithValue("?regionHandle", transaction.RegionHandle); + cmd.Parameters.AddWithValue("?type", transaction.Type); + cmd.Parameters.AddWithValue("?time", transaction.Time); + cmd.Parameters.AddWithValue("?secure", transaction.SecureCode); + cmd.Parameters.AddWithValue("?status", transaction.Status); + cmd.Parameters.AddWithValue("?cname", transaction.CommonName); + cmd.Parameters.AddWithValue("?desc", transaction.Description); + + try + { + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Error adding transation to DB: " + e.ToString()); + return false; + } + return bRet; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + bool bRet = false; + string sql = string.Empty; + + sql += "UPDATE " + Table_of_Transaction + " SET status = ?status,description = ?desc where UUID = ?tranid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", status); + cmd.Parameters.AddWithValue("?desc", description); + cmd.Parameters.AddWithValue("?tranid", transactionID); + + try + { + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Error updating transation in DB: " + e.ToString()); + return false; + } + return bRet; + } + + + public bool SetTransExpired(int deadTime) + { + bool bRet = false; + string sql = string.Empty; + + sql += "UPDATE " + Table_of_Transaction; + sql += " SET status = ?failedstatus,description = ?desc where time <= ?deadTime and status = ?pendingstatus;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?failedstatus", (int)Status.FAILED_STATUS); + cmd.Parameters.AddWithValue("?desc", "expired"); + cmd.Parameters.AddWithValue("?deadTime", deadTime); + cmd.Parameters.AddWithValue("?pendingstatus", (int)Status.PENDING_STATUS); + + try + { + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Error updating transation in DB: " + e.ToString()); + return false; + } + return bRet; + } + + + /// + /// Validate if the transacion is legal + /// + /// + /// + /// + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + bool bRet = false; + string secure = string.Empty; + string sql = string.Empty; + + sql += "SELECT secure from " + Table_of_Transaction + " where UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + using (MySqlDataReader r = cmd.ExecuteReader()) + { + if(r.Read()) + { + try + { + secure = (string)r["secure"]; + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: get transaction from DB failed: " + e.ToString()); + return false; + } + if (secureCode == secure) bRet = true; + else bRet = false; + } + r.Close(); + } + return bRet; + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + TransactionData transactionData = new TransactionData(); + transactionData.TransUUID = transactionID; + string sql = string.Empty; + + sql += "SELECT * from " + Table_of_Transaction + " where UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) + { + if (r.Read()) + { + try + { + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.ObjectUUID = (string)r["objectUUID"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.Description = (string)r["description"]; + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Fetching transaction failed: " + e.ToString()); + return null; + } + + } + r.Close(); + } + + return transactionData; + } + + + + public TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index, uint retNum) + { + List rows = new List(); + string sql = string.Empty; + + sql += "SELECT * from " + Table_of_Transaction + " where time>=?start AND time<=?end "; + sql += "AND (sender=?user or receiver=?user) order by time asc limit ?index,?num;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + cmd.Parameters.AddWithValue("?index", index); + cmd.Parameters.AddWithValue("?num", retNum); + + using (MySqlDataReader r = cmd.ExecuteReader()) + { + for (int i = 0; i < retNum; i++) + { + if (r.Read()) + { + try + { + TransactionData transactionData = new TransactionData(); + string uuid = (string)r["UUID"]; + UUID transUUID; + UUID.TryParse(uuid,out transUUID); + + transactionData.TransUUID = transUUID; + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + if (r["objectUUID"] is System.DBNull) + { + transactionData.ObjectUUID = "null"; + } + else + { + transactionData.ObjectUUID = (string)r["objectUUID"]; + } + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.Description = (string)r["description"]; + rows.Add(transactionData); + } + + catch (Exception e) + { + m_log.Error("[MONEY DB]: Fetching transaction failed: " + e.ToString()); + return null; + } + + } + } + r.Close(); + } + + cmd.Dispose(); + return rows.ToArray(); + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + int iRet = -1; + string sql = string.Empty; + + sql += "SELECT COUNT(*) AS number FROM " + Table_of_Transaction + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user);"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) + { + if(r.Read()) + { + try + { + iRet = Convert.ToInt32(r["number"]); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Unable to get transaction info: " + e.ToString()); + return -1; + } + } + } + cmd.Dispose(); + return iRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // userinfo + // + public bool addUserInfo(UserInfo userInfo) + { + bool bRet = false; + string sql = string.Empty; + + if (userInfo.Avatar==null) return false; + + sql += "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`) VALUES"; + sql += "(?user,?simip,?avatar,?password);"; + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?avatar", userInfo.Avatar); + cmd.Parameters.AddWithValue("?password", userInfo.PswHash); + + try + { + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Unable to add user information to database: " + e.ToString()); + bRet = false; + } + + return bRet; + } + + + public UserInfo fetchUserInfo(string userID) + { + UserInfo userInfo = new UserInfo(); + userInfo.UserID = userID; + string sql = string.Empty; + + sql += "SELECT * from " + Table_of_UserInfo + " WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userID", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) + { + if (r.Read()) + { + try + { + userInfo.SimIP = (string)r["simip"]; + userInfo.Avatar = (string)r["avatar"]; + userInfo.PswHash = (string)r["pass"]; + } + catch (Exception e) + { + m_log.Error("[MONEY DB]: Fetching UserInfo failed: " + e.ToString()); + return null; + } + } + else + { + return null; + } + r.Close(); + } + + return userInfo; + } + + + public bool updateUserInfo(UserInfo user) + { + bool bRet = false; + string sql = string.Empty; + + sql += "UPDATE " + Table_of_UserInfo + " SET simip=?simip,avatar=?avatar,pass=?pass WHERE user=?user;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?simip", user.SimIP); + cmd.Parameters.AddWithValue("?avatar", user.Avatar); + cmd.Parameters.AddWithValue("?pass", user.PswHash); + cmd.Parameters.AddWithValue("?user", user.UserID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + else bRet = false; + cmd.Dispose(); + + return bRet; + } + + + } +} diff --git a/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs new file mode 100644 index 0000000..cd2bae4 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Threading; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + // This bit of code is from OpenSim.Data.MySQLSuperManager + public class MySQLSuperManager + { + public bool Locked; + private readonly Mutex m_lock = new Mutex(false); + public MySQLMoneyManager Manager; + public string Running; + + public void GetLock() + { + Locked = true; + m_lock.WaitOne(); + } + + public void Release() + { + m_lock.ReleaseMutex(); + Locked = false; + } + } +} diff --git a/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f4a2a82 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("03f4a266-2e30-47e4-b785-ff02cdb4bbb9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs new file mode 100644 index 0000000..7ae23ed --- /dev/null +++ b/release/0.8.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs @@ -0,0 +1,160 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenMetaverse; + + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public class TransactionData + { + UUID m_uuid; + string m_sender = string.Empty; + string m_receiver = string.Empty; + int m_amount; + int m_type; + int m_time; + int m_status; + string m_description = string.Empty; + string m_objectID = string.Empty; + string m_regionHandle = string.Empty; + string m_secureCode = string.Empty; + string m_commonName = string.Empty; + + //public TransactionData(string uuid, string sender, string receiver, + // int amount, int time, int status, string description) + //{ + // this.m_uuid = uuid; + // this.m_sender = sender; + // this.m_receiver = receiver; + // this.m_amount = amount; + //} + public UUID TransUUID + { + get { return m_uuid; } + set { m_uuid = value; } + } + public string Sender + { + get { return m_sender; } + set { m_sender = value; } + } + public string Receiver + { + get { return m_receiver; } + set { m_receiver = value; } + } + public int Amount + { + get { return m_amount; } + set { m_amount = value; } + } + public int Type + { + get { return m_type; } + set { m_type = value; } + } + public int Time + { + get { return m_time; } + set { m_time = value; } + } + public int Status + { + get { return m_status; } + set { m_status = value; } + } + public string Description + { + get { return m_description; } + set { m_description = value; } + } + public string ObjectUUID + { + get { return m_objectID; } + set { m_objectID = value; } + } + public string RegionHandle + { + get { return m_regionHandle; } + set { m_regionHandle = value; } + } + public string SecureCode + { + get { return m_secureCode; } + set { m_secureCode = value; } + } + public string CommonName + { + get { return m_commonName; } + set { m_commonName = value; } + } + } + + + public enum Status + { + SUCCESS_STATUS = 0, + PENDING_STATUS = 1, + FAILED_STATUS = 2 + } + + + public class UserInfo + { + string m_userID = string.Empty; + string m_simIP = string.Empty; + string m_avatarName = string.Empty; + string m_passwordHash = string.Empty; + + public string UserID + { + get { return m_userID; } + set { m_userID = value; } + } + + public string SimIP + { + get { return m_simIP; } + set { m_simIP = value; } + } + public string Avatar + { + get { return m_avatarName; } + set { m_avatarName = value; } + } + public string PswHash + { + get { return m_passwordHash; } + set { m_passwordHash = value; } + } + } +} diff --git a/release/0.8.2/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs b/release/0.8.2/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs new file mode 100644 index 0000000..b3b6f00 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs @@ -0,0 +1,72 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenMetaverse; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; + + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyDBService + { + int getBalance(string userID); + + bool withdrawMoney(UUID transactionID, string senderID, int amount); + + bool giveMoney(UUID transactionID, string receiverID, int amount); + + bool addTransaction(TransactionData transaction); + + bool addUser(string userID, int balance, int status); + + bool updateTransactionStatus(UUID transactionID, int status, string description); + + bool SetTransExpired(int deadTime); + + bool ValidateTransfer(string secureCode, UUID transactionID); + + TransactionData FetchTransaction(UUID transactionID); + + TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex); + + int getTransactionNum(string userID, int startTime, int endTime); + + bool DoTransfer(UUID transactionUUID); + + bool DoAddMoney(UUID transactionUUID); // Added by Fumi.Iseki + + bool TryAddUserInfo(UserInfo user); + + UserInfo FetchUserInfo(string userID); + + + } +} diff --git a/release/0.8.2/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs b/release/0.8.2/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs new file mode 100644 index 0000000..9f31284 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs @@ -0,0 +1,44 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyServiceCore + { + BaseHttpServer GetHttpServer(); + Dictionary GetSessionDic(); + Dictionary GetSecureSessionDic(); + Dictionary GetWebSessionDic(); + } +} diff --git a/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs b/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs new file mode 100644 index 0000000..a0f7cb2 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs @@ -0,0 +1,496 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using log4net; +using System.Reflection; +using OpenMetaverse; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyDBService: IMoneyDBService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string m_connect; + private MySQLMoneyManager m_moneyManager; + + // DB manager pool + protected Dictionary m_dbconnections = new Dictionary(); + private int m_maxConnections; + public int m_lastConnect = 0; + + + public MoneyDBService(string connect) + { + m_connect = connect; + Initialise(m_connect,10); + } + + + public MoneyDBService() + { + } + + + public void Initialise(string connectionString,int maxDBConnections) + { + m_maxConnections = maxDBConnections; + if (connectionString != string.Empty) + { + m_moneyManager = new MySQLMoneyManager(connectionString); + //m_log.Info("Creating " + m_maxConnections + " DB connections..."); + for (int i = 0; i < m_maxConnections; i++) + { + //m_log.Info("Connecting to DB... [" + i + "]"); + MySQLSuperManager msm = new MySQLSuperManager(); + msm.Manager = new MySQLMoneyManager(connectionString); + m_dbconnections.Add(i, msm); + } + } + else + { + m_log.Error("[MONEY DB]: Connection string is null,initialise database failed"); + throw new Exception("Failed to initialise MySql database"); + } + } + + + private MySQLSuperManager GetLockedConnection() + { + int lockedCons = 0; + while (true) + { + m_lastConnect++; + + // Overflow protection + if (m_lastConnect == int.MaxValue) + m_lastConnect = 0; + + MySQLSuperManager x = m_dbconnections[m_lastConnect % m_maxConnections]; + if (!x.Locked) + { + x.GetLock(); + return x; + } + + lockedCons++; + if (lockedCons > m_maxConnections) + { + lockedCons = 0; + System.Threading.Thread.Sleep(1000); // Wait some time before searching them again. + m_log.Debug( + "WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound."); + } + } + } + + + public int getBalance(string userID) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.getBalance(userID); + } + catch(Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return 0; + } + finally + { + dbm.Release(); + } + } + + + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public bool addTransaction(TransactionData transaction) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.addTransaction(transaction); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public bool addUser(string userID, int balance, int status) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.addUser(userID, balance, status); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public bool SetTransExpired(int deadTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.SetTransExpired(deadTime); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.FetchTransaction(transactionID); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return null; + } + finally + { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex) + { + MySQLSuperManager dbm = GetLockedConnection(); + TransactionData[] arrTransaction; + try + { + if (lastIndex < 0) + { + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, 0, 1); + if (arrTransaction.Length > 0) + { + return arrTransaction[0]; + } + else + return null; + } + else + { + uint index = Convert.ToUInt32(lastIndex); + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index + 1, 1); + if (arrTransaction.Length > 0) + { + return arrTransaction[0]; + } + else + return null; + } + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return null; + } + finally + { + dbm.Release(); + } + } + + + public bool DoTransfer(UUID transactionUUID) + { + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + if (transaction != null && transaction.Status == (int)Status.PENDING_STATUS) + { + int balance = getBalance(transaction.Sender); + //check the amount + if (transaction.Amount >= 0 && balance >= transaction.Amount) + { + if (withdrawMoney(transactionUUID, transaction.Sender, transaction.Amount)) + { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver) == -1) + { + addUser(transaction.Receiver, 0, (int)Status.SUCCESS_STATUS); + } + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) + return true; + else // give money to receiver failed. + { + m_log.ErrorFormat("[MONEY DB]: Give money to receiver {0} failed", transaction.Receiver); + //Return money to sender + if (giveMoney(transactionUUID, transaction.Sender, transaction.Amount)) + { + m_log.ErrorFormat("[MONEY DB]: give money to receiver {0} failed but return it to sender {1} successfully", + transaction.Receiver, + transaction.Sender); + updateTransactionStatus(transactionUUID, + (int)Status.FAILED_STATUS, + "give money to receiver failed but return it to sender successfully"); + } + else + { + m_log.ErrorFormat("[MONEY DB]: FATAL ERROR: Money withdrawn from sender: {0}, but failed to be given to receiver {1}", + transaction.Sender, transaction.Receiver); + } + } + } + else // withdraw money failed + { + m_log.ErrorFormat("[MONEY DB]: Withdraw money from sender {0} failed", transaction.Sender); + } + } + else // not enough balance to finish the transaction + { + m_log.ErrorFormat("[MONEY DB]: Not enough balance for user: {0} to apply the transaction.", transaction.Sender); + } + } + else // Can not fetch the transaction or it has expired + { + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + return false; + } + + + // by Fumi.Iseki + public bool DoAddMoney(UUID transactionUUID) + { + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction != null && transaction.Status == (int)Status.PENDING_STATUS) + { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver)==-1) + { + addUser(transaction.Receiver, 0, (int)Status.SUCCESS_STATUS); + } + + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) return true; + else // give money to receiver failed. + { + m_log.ErrorFormat("[MONEY DB]: Add money to receiver {0} failed", transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "add money to receiver failed"); + } + } + else // Can not fetch the transaction or it has expired + { + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + return false; + } + + + public bool TryAddUserInfo(UserInfo user) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + if (dbm.Manager.fetchUserInfo(user.UserID) != null) + { + m_log.InfoFormat("[MONEY DB]: Found user \"{0}\", now update information", user.Avatar); + if (m_moneyManager.updateUserInfo(user)) + return true; + } + else if (dbm.Manager.addUserInfo(user)) + { + m_log.InfoFormat("[MONEY DB]: Unable to find user \"{0}\", add it to DB successfully", user.Avatar); + return true; + } + return false; + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + // Fumi.Iseki + m_moneyManager.Reconnect(); + m_log.Error(e.ToString()); + return false; + } + finally + { + dbm.Release(); + } + } + + + public UserInfo FetchUserInfo(string userID) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.fetchUserInfo(userID); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return null; + } + finally + { + dbm.Release(); + } + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + try + { + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return -1; + } + finally + { + dbm.Release(); + } + } + } +} diff --git a/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs b/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs new file mode 100644 index 0000000..d4f92d1 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs @@ -0,0 +1,323 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Security; +using System.Reflection; +using System.Timers; +//using System.Security.Authentication; +//using System.Security.Cryptography; +//using System.Security.Cryptography.X509Certificates; + +using HttpServer; +using Nini.Config; +using log4net; + +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data; + +using NSL.Certificate.Tools; + + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string connectionString = string.Empty; + private uint m_moneyServerPort = 8008; + private string m_hostName = "localhost"; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private string m_cacertFilename = ""; + private string m_clcrlFilename = ""; + private bool m_checkClientCert = false; + + private int DEAD_TIME; + private int MAX_DB_CONNECTION; + + private MoneyXmlRpcModule m_moneyXmlRpcModule; + private MoneyDBService m_moneyDBService; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // クライアント認証用 + + private Dictionary m_sessionDic = new Dictionary(); + private Dictionary m_secureSessionDic = new Dictionary(); + private Dictionary m_webSessionDic = new Dictionary(); + + IConfig m_config; + + + public MoneyServerBase() + { + m_console = new LocalConsole("Money "); +// m_console = new CommandConsole("Money "); + MainConsole.Instance = m_console; + } + + + public void Work() + { + //m_console.Notice("Enter help for a list of commands\n"); + + //The timer checks the transactions table every 60 seconds + Timer checkTimer = new Timer(); + checkTimer.Interval = 60*1000; + checkTimer.Enabled = true; + checkTimer.Elapsed += new ElapsedEventHandler(CheckTransaction); + checkTimer.Start(); + + while (true) + { + m_console.Prompt(); + } + } + + + /// + /// Check the transactions table, set expired transaction state to failed + /// + private void CheckTransaction(object sender, ElapsedEventArgs e) + { + long ticksToEpoch = new DateTime(1970, 1, 1).Ticks; + int unixEpochTime =(int) ((DateTime.Now.Ticks - ticksToEpoch )/10000000); + int deadTime = unixEpochTime - DEAD_TIME; + m_moneyDBService.SetTransExpired(deadTime); + } + + + protected override void StartupSpecific() + { + m_log.Info("[MONEY SERVER]: Setup HTTP Server process"); + + ReadIniConfig(); + + try { + //HttpContextFactory.ClientCertificateValidationCallback = null; + Type typeHttpContextFactory = typeof(HttpContextFactory); + FieldInfo finfo = typeHttpContextFactory.GetField("ClientCertificateValidationCallback"); + if (finfo!=null) finfo.SetValue(new HttpContextFactory(null, 0, null), null); + + if (m_certFilename!="") + { + m_httpServer = new BaseHttpServer(m_moneyServerPort, true, m_certFilename, m_certPassword); + if (m_checkClientCert) { + if (finfo!=null) { + //HttpContextFactory.ClientCertificateValidationCallback = m_certVerify.ValidateClientCertificate; + finfo.SetValue(new HttpContextFactory(null, 0, null), (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate); + m_log.Info("[MONEY SERVER]: Set RemoteCertificateValidationCallback"); + } + else { + m_log.Error("[MONEY SERVER]: StartupSpecific: CheckClientCert is true. But this MoneyServer does not support CheckClientCert!!"); + + } + } + } + else + { + m_httpServer = new BaseHttpServer(m_moneyServerPort, false); + } + + SetupMoneyServices(); + m_httpServer.Start(); + base.StartupSpecific(); // OpenSim/Framework/Servers/BaseOpenSimServer.cs + } + + catch (Exception e) + { + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Fail to start HTTPS process"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Please Check Certificate File or Password. Exit"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: {0}", e); + Environment.Exit(1); + } + + //TODO : Add some console commands here + } + + + + protected void ReadIniConfig() + { + MoneyServerConfigSource moneyConfig = new MoneyServerConfigSource(); + Config = moneyConfig.m_config; // for base.StartupSpecific() + + try { + // [Startup] + IConfig st_config = moneyConfig.m_config.Configs["Startup"]; + string PIDFile = st_config.GetString("PIDFile", ""); + if (PIDFile!="") Create_PIDFile(PIDFile); + + // [MySql] + IConfig db_config = moneyConfig.m_config.Configs["MySql"]; + string sqlserver = db_config.GetString("hostname", "localhost"); + string database = db_config.GetString("database", "OpenSim"); + string username = db_config.GetString("username", "root"); + string password = db_config.GetString("password", "password"); + string pooling = db_config.GetString("pooling", "false"); + string port = db_config.GetString("port", "3306"); + MAX_DB_CONNECTION = db_config.GetInt ("MaxConnection", 10); + + connectionString = "Server=" + sqlserver + ";Port=" + port + ";Database=" + database + ";User ID=" + + username + ";Password=" + password + ";Pooling=" + pooling + ";"; + + // [MoneyServer] + m_config = moneyConfig.m_config.Configs["MoneyServer"]; + DEAD_TIME = m_config.GetInt ("ExpiredTime", 120); + m_hostName = m_config.GetString("HostName", "localhost"); // be not used + + // サーバ証明書 + m_certFilename = m_config.GetString("ServerCertFilename", ""); + m_certPassword = m_config.GetString("ServerCertPassword", ""); + if (m_certFilename!="") { + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute HTTPS comunication. Cert file is " + m_certFilename); + } + + // クライアント認証 + string checkcert = m_config.GetString("CheckClientCert", "false"); + if (checkcert.ToLower()=="true") m_checkClientCert = true; + + m_cacertFilename = m_config.GetString("CACertFilename", ""); + m_clcrlFilename = m_config.GetString("ClientCrlFilename", ""); + // + if (m_checkClientCert && m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CA file is " + m_cacertFilename); + } + else { + m_checkClientCert = false; + } + + if (m_checkClientCert) { + if (m_clcrlFilename!="") { + m_certVerify.SetPrivateCRL(m_clcrlFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CRL file is " + m_clcrlFilename); + } + } + } + + catch (Exception) + { + m_log.Error("[MONEY SERVER]: ReadIniConfig: Fail to setup configure. Please check MoneyServer.ini. Exit"); + Environment.Exit(1); + } + } + + + // added by skidz + protected void Create_PIDFile(string path) + { + try + { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + m_pidFile = path; + } + catch (Exception) + { + } + } + + + protected virtual void SetupMoneyServices() + { + m_log.Info("[MONEY SERVER]: Connecting to Money Storage Server"); + + m_moneyDBService = new MoneyDBService(); + m_moneyDBService.Initialise(connectionString, MAX_DB_CONNECTION); + + m_moneyXmlRpcModule = new MoneyXmlRpcModule(); + m_moneyXmlRpcModule.Initialise(m_version, m_config, m_moneyDBService, this); + m_moneyXmlRpcModule.PostInitialise(); + } + + + public BaseHttpServer GetHttpServer() + { + return m_httpServer; + } + + + public Dictionary GetSessionDic() + { + return m_sessionDic; + } + + + public Dictionary GetSecureSessionDic() + { + return m_secureSessionDic; + } + + + public Dictionary GetWebSessionDic() + { + return m_webSessionDic; + } + + } + + + + class MoneyServerConfigSource + { + public IniConfigSource m_config; + + public MoneyServerConfigSource() + { + string configPath = Path.Combine(Directory.GetCurrentDirectory(), "MoneyServer.ini"); + if (File.Exists(configPath)) + { + m_config = new IniConfigSource(configPath); + } + else + { + //TODO: create default configuration. + //m_config = DefaultConfig(); + } + } + + public void Save(string path) + { + m_config.Save(path); + } + + } +} diff --git a/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs b/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs new file mode 100644 index 0000000..fa05e6c --- /dev/null +++ b/release/0.8.2/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs @@ -0,0 +1,1761 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Collections; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; + +using NSL.Network.XmlRpc; +using NSL.Certificate.Tools; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyXmlRpcModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private int m_defaultBalance = 0; + // + private bool m_forceTransfer = false; + private string m_bankerAvatar = ""; + + private bool m_scriptSendMoney = false; + private string m_scriptAccessKey = ""; + private string m_scriptIPaddress = "127.0.0.1"; + + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private X509Certificate2 m_cert = null; + + private string m_sslCommonName = ""; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用 + + + // Update Balance Messages + private string m_BalanceMessageLandSale = "Paid the Money L${0} for Land."; + private string m_BalanceMessageRcvLandSale = ""; + private string m_BalanceMessageSendGift = "Sent Gift L${0} to {1}."; + private string m_BalanceMessageReceiveGift = "Received Gift L${0} from {1}."; + private string m_BalanceMessagePayCharge = ""; + private string m_BalanceMessageBuyObject = "Bought the Object L${0} from {1}."; + private string m_BalanceMessageGetMoney = "Got the Money L${0} from {1}."; + private string m_BalanceMessageBuyMoney = "Bought the Money L${0}."; + private string m_BalanceMessageReceiveMoney = "Received L${0} from System."; + private string m_BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}."; + + + const int MONEYMODULE_REQUEST_TIMEOUT = 30 * 1000; //30 seconds + private long TicksToEpoch = new DateTime(1970, 1, 1).Ticks; + + private IMoneyDBService m_moneyDBService; + private IMoneyServiceCore m_moneyCore; + + protected IConfig m_config; + + /// + /// Used to notify old regions as to which OpenSim version to upgrade to + /// + private string m_opensimVersion; + + private Dictionary m_sessionDic; + private Dictionary m_secureSessionDic; + private Dictionary m_webSessionDic; + + protected BaseHttpServer m_httpServer; + + + public MoneyXmlRpcModule() + { + } + + + public void Initialise(string opensimVersion, IConfig config, IMoneyDBService moneyDBService, IMoneyServiceCore moneyCore) + { + m_opensimVersion = opensimVersion; + m_moneyDBService = moneyDBService; + m_moneyCore = moneyCore; + m_config = config; // [MoneyServer] Section + + m_defaultBalance = m_config.GetInt("DefaultBalance", 1000); + + string ftrans = m_config.GetString ("enableForceTransfer", "false"); + if (ftrans.ToLower()=="true") m_forceTransfer = true; + m_forceTransfer = m_config.GetBoolean("EnableForceTransfer", m_forceTransfer); + + string banker = m_config.GetString("BankerAvatar", ""); + m_bankerAvatar = banker.ToLower(); + + string sendmoney = m_config.GetString ("enableScriptSendMoney", "false"); + if (sendmoney.ToLower()=="true") m_scriptSendMoney = true; + m_scriptSendMoney = m_config.GetBoolean("EnableScriptSendMoney", m_scriptSendMoney); + + m_scriptAccessKey = m_config.GetString("MoneyScriptAccessKey", ""); + m_scriptIPaddress = m_config.GetString("MoneyScriptIPaddress", "127.0.0.1"); + + // クライアント証明書 + m_certFilename = m_config.GetString("ClientCertFilename", ""); + m_certPassword = m_config.GetString("ClientCertPassword", ""); + if (m_certFilename!="") { + m_cert = new X509Certificate2(m_certFilename, m_certPassword); + m_log.Info("[MONEY RPC]: Initialise: Issue Authentication of Client. Cert file is " + m_cacertFilename); + } + + // サーバ認証 + string checkcert = m_config.GetString("CheckServerCert", "false"); + if (checkcert.ToLower()=="true") m_checkServerCert = true; + + m_cacertFilename = m_config.GetString("CACertFilename", ""); + if (m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + m_log.Info("[MONEY RPC]: Initialise: Execute Authentication of Server. CA file is " + m_cacertFilename); + } + else { + m_checkServerCert = false; + ServicePointManager.ServerCertificateValidationCallback = null; + } + + // Update Balance Messages + m_BalanceMessageLandSale = m_config.GetString("BalanceMessageLandSale", m_BalanceMessageLandSale); + m_BalanceMessageRcvLandSale = m_config.GetString("BalanceMessageRcvLandSale", m_BalanceMessageRcvLandSale); + m_BalanceMessageSendGift = m_config.GetString("BalanceMessageSendGift", m_BalanceMessageSendGift); + m_BalanceMessageReceiveGift = m_config.GetString("BalanceMessageReceiveGift", m_BalanceMessageReceiveGift); + m_BalanceMessagePayCharge = m_config.GetString("BalanceMessagePayCharge", m_BalanceMessagePayCharge); + m_BalanceMessageBuyObject = m_config.GetString("BalanceMessageBuyObject", m_BalanceMessageBuyObject); + m_BalanceMessageGetMoney = m_config.GetString("BalanceMessageGetMoney", m_BalanceMessageGetMoney); + m_BalanceMessageBuyMoney = m_config.GetString("BalanceMessageBuyMoney", m_BalanceMessageBuyMoney); + m_BalanceMessageReceiveMoney = m_config.GetString("BalanceMessageReceiveMoney", m_BalanceMessageReceiveMoney); + m_BalanceMessageRollBack = m_config.GetString("BalanceMessageRollBack", m_BalanceMessageRollBack); + + m_sessionDic = m_moneyCore.GetSessionDic(); + m_secureSessionDic = m_moneyCore.GetSecureSessionDic(); + m_webSessionDic = m_moneyCore.GetWebSessionDic(); + RegisterHandlers(); + } + + + public void PostInitialise() + { + } + + + public void RegisterHandlers() + { + m_httpServer = m_moneyCore.GetHttpServer(); + m_httpServer.AddXmlRPCHandler("ClientLogin", handleClientLogin); + m_httpServer.AddXmlRPCHandler("ClientLogout", handleClientLogout); + m_httpServer.AddXmlRPCHandler("GetBalance", handleGetBalance); + m_httpServer.AddXmlRPCHandler("GetTransaction", handleGetTransaction); + + m_httpServer.AddXmlRPCHandler("CancelTransfer", handleCancelTransfer); + m_httpServer.AddXmlRPCHandler("TransferMoney", handleTransaction); + m_httpServer.AddXmlRPCHandler("ForceTransferMoney", handleForceTransaction); // added + m_httpServer.AddXmlRPCHandler("PayMoneyCharge", handlePayMoneyCharge); // added + m_httpServer.AddXmlRPCHandler("AddBankerMoney", handleAddBankerMoney); // added + m_httpServer.AddXmlRPCHandler("SendMoneyBalance", handleSendMoneyBalance); // added + + // this is from original DTL. not check yet. + m_httpServer.AddXmlRPCHandler("WebLogin", handleWebLogin); + m_httpServer.AddXmlRPCHandler("WebLogout", handleWebLogout); + m_httpServer.AddXmlRPCHandler("WebGetBalance", handleWebGetBalance); + m_httpServer.AddXmlRPCHandler("WebGetTransaction", handleWebGetTransaction); + m_httpServer.AddXmlRPCHandler("WebGetTransactionNum", handleWebGetTransactionNum); + } + + + // + // + // + public string GetSSLCommonName(XmlRpcRequest request) + { + if (request.Params.Count>4) { + m_sslCommonName = (string)request.Params[4]; + } + else { + m_sslCommonName = ""; + } + return m_sslCommonName; + } + + + // + public string GetSSLCommonName() + { + return m_sslCommonName; + } + + + + + /// + /// Get the user balance when user entering a parcel. + /// + /// + /// + public XmlRpcResponse handleClientLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleClientLogin:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string simIP = string.Empty; + string avatarName = string.Empty; + int balance = 0; + + response.Value = responseData; + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + if (requestData.ContainsKey("openSimServIP")) simIP = (string)requestData["openSimServIP"]; + if (requestData.ContainsKey("userName")) avatarName = (string)requestData["userName"]; + + //m_log.InfoFormat("[MONEY RPC]: handleClientLogin: client UUID is {0}", clientUUID); + + if (avatarName=="") { + responseData["success"] = false; + responseData["clientBalance"] = 0; + return response; + } + + //Update the session and secure session dictionary + lock (m_sessionDic) + { + if (!m_sessionDic.ContainsKey(clientUUID)) + { + m_sessionDic.Add(clientUUID, sessionID); + } + else m_sessionDic[clientUUID] = sessionID; + } + + lock (m_secureSessionDic) + { + if (!m_secureSessionDic.ContainsKey(clientUUID)) + { + m_secureSessionDic.Add(clientUUID, secureID); + } + else m_secureSessionDic[clientUUID] = secureID; + } + + try + { + //m_log.InfoFormat("[MONEY RPC]: handleClientLogin: User {0} has logged in, getting balance...", clientUUID); + balance = m_moneyDBService.getBalance(clientUUID); + //add user if not exist + if (balance==-1) + { + if (m_moneyDBService.addUser(clientUUID, m_defaultBalance, 0)) + { + responseData["success"] = true; + responseData["description"] = "add user successfully"; + responseData["clientBalance"] = m_defaultBalance; + } + else + { + responseData["success"] = false; + responseData["description"] = "add user failed"; + responseData["clientBalance"] = 0; + } + } + else if (balance >= 0) //Success + { + responseData["success"] = true; + responseData["description"] = "get user balance successfully"; + responseData["clientBalance"] = balance; + } + UserInfo user = new UserInfo(); + user.UserID = clientUUID; + user.SimIP = simIP; + user.Avatar = avatarName; + //TODO: Add password protection here + user.PswHash = UUID.Zero.ToString(); + + if (!m_moneyDBService.TryAddUserInfo(user)) + { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Unable to refresh information for user \"{0}\" in DB", avatarName); + responseData["success"] = false; + responseData["description"] = "Update or add user information to db failed"; + responseData["clientBalance"] = balance; + } + return response; + + } + catch (Exception e) + { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Can't get balance of user {0}", clientUUID); + responseData["success"] = false; + responseData["description"] = "Exception occured" + e.ToString(); + responseData["clientBalance"] = 0; + } + return response; + + } + + + + // + // deleted using ASP.NET by Fumi.Iseki + // + /// + /// handle incoming transaction + /// + /// + /// + public XmlRpcResponse handleTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = string.Empty; + string regionHandle = string.Empty; + string description = "Newly added on"; + + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = (Int32)requestData["amount"]; + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("transactionType")) transactionType = (Int32)requestData["transactionType"]; + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) + { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) + { + m_log.InfoFormat("[MONEY RPC]: handleTransaction: Transfering money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.Now.Ticks - TicksToEpoch) / 10000000); + try + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.RegionHandle = regionHandle; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.Now.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) + { + m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Receive User is not yet in DB {0}", receiverID); + responseData["success"] = false; + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) + { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) + { + if (amount!=0) + { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + rcv_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message); + } + else + { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else // add transaction failed + { + m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Add transaction for user {0} failed", senderID); + } + + responseData["success"] = false; + return response; + } + catch (Exception e) + { + m_log.Error("[MONEY RPC]: handleTransaction: Exception occurred while adding transaction " + e.ToString()); + responseData["success"] = false; + return response; + } + + } + + } + + m_log.Error("[MONEY RPC]: handleTransaction: Session authentication failure for sender " + senderID); + responseData["success"] = false; + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + + // + // added by Fumi.Iseki + // + /// + /// handle incoming force transaction. no check senderSessionID and senderSecureSessionID + /// + /// + /// + public XmlRpcResponse handleForceTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleForceTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string objectID = string.Empty; + string regionHandle = string.Empty; + string description = "Newly added on"; + + UUID transactionUUID = UUID.Random(); + + // + if (!m_forceTransfer) + { + m_log.Error("[MONEY RPC]: handleForceTransaction: Not allowed force transfer of Money. Set enableForceTransfer at [MoneyServer] to true in MoneyServer.ini"); + responseData["success"] = false; + responseData["message"] = "not allowed force transfer of Money!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = (Int32)requestData["amount"]; + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("transactionType")) transactionType = (Int32)requestData["transactionType"]; + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY RPC]: handleForceTransaction: Force transfering money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.Now.Ticks - TicksToEpoch) / 10000000); + + try + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.RegionHandle = regionHandle; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.Now.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) + { + m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Force receive User is not yet in DB {0}", receiverID); + responseData["success"] = false; + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) + { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) + { + if (amount!=0) + { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + snd_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message); + } + else + { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else // add transaction failed + { + m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Add force transaction for user {0} failed", senderID); + } + + responseData["success"] = false; + return response; + } + catch (Exception e) + { + m_log.Error("[MONEY RPC]: handleForceTransaction: Exception occurred while adding force transaction " + e.ToString()); + responseData["success"] = false; + return response; + } + } + + + + // + // added by Fumi.Iseki + // + /// + /// handle adding money transaction. + /// + /// + /// + public XmlRpcResponse handleAddBankerMoney(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string bankerID = string.Empty; + string regionHandle = "0"; + string description = "Add Money to Avatar on"; + + UUID transactionUUID = UUID.Random(); + + responseData["success"] = false; + + if (requestData.ContainsKey("bankerID")) bankerID = (string)requestData["bankerID"]; + if (requestData.ContainsKey("amount")) amount = (Int32)requestData["amount"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("transactionType")) transactionType = (Int32)requestData["transactionType"]; + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + // Check Banker Avatar + if (m_bankerAvatar!=UUID.Zero.ToString() && m_bankerAvatar!=bankerID) + { + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Not allowed add money to avatar!!"); + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Set BankerAvatar at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed add money to avatar!"; + responseData["banker"] = false; + return response; + } + responseData["banker"] = true; + + m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Add money to avatar {0}", bankerID); + int time = (int)((DateTime.Now.Ticks - TicksToEpoch) / 10000000); + + try + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = bankerID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle = regionHandle; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.Now.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(bankerID); + if (rcvr==null) + { + m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Avatar is not yet in DB {0}", bankerID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) + { + if (amount!=0) + { + if (m_moneyDBService.DoAddMoney(transactionUUID)) + { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) + { + m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Adding money finished successfully, now update balance: {0}", + transactionUUID.ToString()); + string message = string.Format(m_BalanceMessageBuyMoney, amount, "SYSTEM"); + UpdateBalance(transaction.Receiver, message); + responseData["success"] = true; + } + } + } + else + { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else // add transaction failed + { + m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Add force transaction for user {0} failed", senderID); + } + + return response; + } + catch (Exception e) + { + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Exception occurred while adding money transaction " + e.ToString()); + return response; + } + } + + + + // + // added by Fumi.Iseki + // + /// + /// handle sending money transaction. + /// + /// + /// + public XmlRpcResponse handleSendMoneyBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleSendMoneyBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string avatarID = string.Empty; + string description = "Send Money to Avatar on"; + string clientIP = remoteClient.Address.ToString(); + string secretCode = string.Empty; + + UUID transactionUUID = UUID.Random(); + + responseData["success"] = false; + + if (!m_scriptSendMoney || m_scriptAccessKey=="") + { + m_log.Error("[MONEY RPC]: handleSendMoneyBalance: Not allowed send money to avatar!!"); + m_log.Error("[MONEY RPC]: handleSendMoneyBalance: Set enableScriptSendMoney and MoneyScriptAccessKey at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed set money to avatar!"; + return response; + } + + if (requestData.ContainsKey("avatarID")) avatarID = (string)requestData["avatarID"]; + if (requestData.ContainsKey("amount")) amount = (Int32)requestData["amount"]; + if (requestData.ContainsKey("transactionType")) transactionType = (Int32)requestData["transactionType"]; + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + if (requestData.ContainsKey("secretAccessCode")) secretCode = (string)requestData["secretAccessCode"]; + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(m_scriptAccessKey + "_" + clientIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(hash + "_" + m_scriptIPaddress)); + hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + + if (secretCode.ToLower()!=hash) + { + m_log.Error("[MONEY RPC]: handleSendMoneyBalance: Not allowed send money to avatar!!"); + m_log.Error("[MONEY RPC]: handleSendMoneyBalance: Not match Script Key"); + responseData["message"] = "not allowed send money to avatar! not match Script Key"; + return response; + } + + m_log.InfoFormat("[MONEY RPC]: handleSendMoneyBalance: Send money to avatar {0}", avatarID); + int time = (int)((DateTime.Now.Ticks - TicksToEpoch) / 10000000); + + try + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = avatarID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle = "0"; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.Now.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(avatarID); + if (rcvr==null) + { + m_log.ErrorFormat("[MONEY RPC]: handleSendMoneyBalance: Avatar is not yet in DB: {0}", avatarID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) + { + if (amount!=0) + { + if (m_moneyDBService.DoAddMoney(transactionUUID)) + { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) + { + m_log.InfoFormat("[MONEY RPC]: handleSendMoneyBalance: Sending money finished successfully, now update balance {0}", + transactionUUID.ToString()); + string message = string.Format(m_BalanceMessageReceiveMoney, amount, "SYSTEM"); + UpdateBalance(transaction.Receiver, message); + responseData["success"] = true; + } + } + } + else + { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else // add transaction failed + { + m_log.ErrorFormat("[MONEY RPC]: handleSendMoneyBalance: Add force transaction for user {0} failed", senderID); + } + + return response; + } + catch (Exception e) + { + m_log.Error("[MONEY RPC]: handleSendMoneyBalance: Exception occurred while adding money transaction " + e.ToString()); + return response; + } + } + + + + // + // added by Fumi.Iseki + // + /// + /// handle pay charge transaction. no check receiver information. + /// + /// + /// + public XmlRpcResponse handlePayMoneyCharge(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = UUID.Zero.ToString(); + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = UUID.Zero.ToString(); + string regionHandle = string.Empty; + string description = "Pay Charge on"; + + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = (Int32)requestData["amount"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("transactionType")) transactionType = (Int32)requestData["transactionType"]; + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) + { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) + { + m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge: Pay from {0}", senderID); + int time = (int)((DateTime.Now.Ticks - TicksToEpoch) / 10000000); + try + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.RegionHandle = regionHandle; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.Now.ToString(); + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) + { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) + { + if (amount!=0) + { + string message = string.Format(m_BalanceMessagePayCharge, amount, "SYSTEM"); + responseData["success"] = NotifyTransfer(transactionUUID, message, ""); + } + else + { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else // add transaction failed + { + m_log.ErrorFormat("[MONEY RPC]: handlePayMoneyCharge: Pay money transaction for user {0} failed", senderID); + } + + responseData["success"] = false; + return response; + } + catch (Exception e) + { + m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Exception occurred while pay money transaction " + e.ToString()); + responseData["success"] = false; + return response; + } + + } + + } + + m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Session authentication failure for sender " + senderID); + responseData["success"] = false; + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + + // + // added by Fumi.Iseki + // + /// + /// Continue transaction with no confirm. + /// + /// + /// + public bool NotifyTransfer(UUID transactionUUID, string msg2sender, string msg2receiver) + { + //m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: User has accepted the transaction, now continue with the transaction"); + + try + { + if (m_moneyDBService.DoTransfer(transactionUUID)) + { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) + { + //m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction Type = {0}", transaction.Type); + //m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Payment finished successfully, now update balance {0}", transactionUUID.ToString()); + + bool updateSender = true; + bool updateReceiv = true; + if (transaction.Sender==transaction.Receiver) updateSender = false; + //if (transaction.Type==(int)TransactionType.UploadCharge) return true; + if (transaction.Type==(int)TransactionType.UploadCharge) updateReceiv = false; + + if (updateSender) { + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string receiverName = "unknown user"; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + string snd_message = string.Format(msg2sender, transaction.Amount, receiverName); + UpdateBalance(transaction.Sender, snd_message); + } + if (updateReceiv) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + string senderName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + string rcv_message = string.Format(msg2receiver, transaction.Amount, senderName); + UpdateBalance(transaction.Receiver, rcv_message); + } + + // Notify to sender? + if (transaction.Type==(int)TransactionType.PayObject) + { + //m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Now notify opensim to give object to customer {0} ", transaction.Sender); + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = transaction.Sender; + requestTable["receiverUUID"] = transaction.Receiver; + + if(m_sessionDic.ContainsKey(transaction.Sender)&&m_secureSessionDic.ContainsKey(transaction.Sender)) + { + requestTable["clientSessionID"] = m_sessionDic[transaction.Sender]; + requestTable["clientSecureSessionID"] = m_secureSessionDic[transaction.Sender]; + } + else + { + requestTable["clientSessionID"] = UUID.Zero.ToString(); + requestTable["clientSecureSessionID"] = UUID.Zero.ToString(); + } + requestTable["transactionType"] = transaction.Type; + requestTable["amount"] = transaction.Amount; + requestTable["objectID"] = transaction.ObjectUUID; + requestTable["regionHandle"] = transaction.RegionHandle; + + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (user!=null) + { + Hashtable responseTable = genericCurrencyXMLRPCRequest(requestTable, "OnMoneyTransfered", user.SimIP); + + if (responseTable!=null && responseTable.ContainsKey("success")) + { + //User not online or failed to get object ? + if (!(bool)responseTable["success"]) + { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: User {0} can't get the object, rolling back", transaction.Sender); + if (RollBackTransaction(transaction)) + { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed but roll back succeeded", transactionUUID.ToString()); + } + else + { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed and roll back failed as well", + transactionUUID.ToString()); + } + } + else + { + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} finished successfully", transactionUUID.ToString()); + return true; + } + } + } + return false; + } + return true; + } + + } + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed", transactionUUID.ToString()); + } + catch (Exception e) + { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: exception occurred when transaction {0}: {1}", transactionUUID.ToString(), e.ToString()); + } + return false; + } + + + + /// + /// Get the user balance. + /// + /// + /// + public XmlRpcResponse handleGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + int balance; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + m_log.InfoFormat("[MONEY RPC]: handleGetBalance: Getting balance for user {0}", clientUUID); + if (m_sessionDic.ContainsKey(clientUUID) && m_secureSessionDic.ContainsKey(clientUUID)) + { + if (m_sessionDic[clientUUID]==sessionID && m_secureSessionDic[clientUUID]==secureID) + { + try + { + balance = m_moneyDBService.getBalance(clientUUID); + + if (balance==-1) // User not found + { + if (m_moneyDBService.addUser(clientUUID, m_defaultBalance, 0)) + { + responseData["success"] = true; + responseData["description"] = "add user successfully"; + responseData["clientBalance"] = m_defaultBalance; + } + else + { + responseData["success"] = false; + responseData["description"] = "add user failed"; + responseData["clientBalance"] = 0; + } + } + + else if (balance >= 0) + { + responseData["success"] = true; + responseData["clientBalance"] = balance; + } + return response; + } + catch (Exception e) + { + m_log.ErrorFormat("[MONEY RPC]: handleGetBalance: Can't get balance for user {0}, Exception {1}", clientUUID, e.ToString()); + } + + } + } + + m_log.Error("[MONEY RPC]: handleGetBalance: Session authentication failed when getting balance for user " + clientUUID); + + responseData["success"] = false; + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + + public XmlRpcResponse handleClientLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleClientLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + string clientUUID = string.Empty; + + response.Value = responseData; + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + + //m_log.InfoFormat("[MONEY RPC]: handleClientLogout: User {0} is logging off", clientUUID); + try + { + lock (m_sessionDic) + { + if (m_sessionDic.ContainsKey(clientUUID)) + { + m_sessionDic.Remove(clientUUID); + } + } + + lock (m_secureSessionDic) + { + if (m_secureSessionDic.ContainsKey(clientUUID)) + { + m_secureSessionDic.Remove(clientUUID); + } + } + } + catch (Exception e) + { + m_log.Error("[MONEY RPC]: handleClientLogout: Failed to delete user session " + e.ToString() ); + responseData["success"] = false; + } + responseData["success"] = true; + + return response; + } + + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method, string uri) + { + m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: to {0}", uri); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) + { + if (!uri.StartsWith("https://")) + { + m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file"); + //return null; + } + } + else + { + if (!uri.StartsWith("https://") && !uri.StartsWith("http://")) + { + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Invalid Region Server URL: {0}", uri); + return null; + } + } + + + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try + { + //XmlRpcRequest moneyModuleReq = new XmlRpcRequest(method, arrayParams); + //moneyServResp = moneyModuleReq.Send(uri, MONEYMODULE_REQUEST_TIMEOUT); + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + moneyServResp = moneyModuleReq.certSend(uri, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) + { + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Unable to connect to Region Server {0}", uri); + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: {0}", ex.ToString()); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp.IsFault) + { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + + return moneyRespData; + } + + + + /// + /// Update the client balance.We don't care about the result. + /// + /// + private void UpdateBalance(string userID, string message) + { + //m_log.InfoFormat("[MONEY RPC]: UpdateBalance: ID = {0}, Message = {1}", userID, message); + + string sessionID = string.Empty; + string secureID = string.Empty; + + if (m_sessionDic.ContainsKey(userID) && m_secureSessionDic.ContainsKey(userID)) + { + sessionID = m_sessionDic[userID]; + secureID = m_secureSessionDic[userID]; + + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = userID; + requestTable["clientSessionID"] = sessionID; + requestTable["clientSecureSessionID"] = secureID; + requestTable["Balance"] = m_moneyDBService.getBalance(userID); + if (message!="") requestTable["Message"] = message; + + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + genericCurrencyXMLRPCRequest(requestTable, "UpdateBalance", user.SimIP); + //m_log.InfoFormat("[MONEY RPC]: UpdateBalance: Sended UpdateBalance Request to {0}", user.SimIP.ToString()); + } + } + } + + + + /// + /// RollBack the transaction if user failed to get the object paid + /// + /// + /// + protected bool RollBackTransaction(TransactionData transaction) + { + //m_log.InfoFormat("[MONEY RPC]: RollBackTransaction:"); + + if(m_moneyDBService.withdrawMoney(transaction.TransUUID, transaction.Receiver, transaction.Amount)) + { + if(m_moneyDBService.giveMoney(transaction.TransUUID, transaction.Sender, transaction.Amount)) + { + m_log.InfoFormat("[MONEY RPC]: RollBackTransaction: Transaction {0} successfully", transaction.TransUUID.ToString()); + m_moneyDBService.updateTransactionStatus(transaction.TransUUID, (int)Status.FAILED_STATUS, + "The buyer failed to get the object, roll back the transaction"); + + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string senderName = "unknown user"; + string receiverName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + + string snd_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, receiverName); + string rcv_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, senderName); + + if (transaction.Sender!=transaction.Receiver) UpdateBalance(transaction.Sender, snd_message); + UpdateBalance(transaction.Receiver, rcv_message); + return true; + } + } + return false; + } + + + + // + public XmlRpcResponse handleCancelTransfer(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + + string secureCode = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + response.Value = responseData; + + if (requestData.ContainsKey("secureCode")) secureCode = (string)requestData["secureCode"]; + if (requestData.ContainsKey("transactionID")) + { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (string.IsNullOrEmpty(secureCode) || string.IsNullOrEmpty(transactionID)) + { + responseData["success"] = false; + m_log.Error("[MONEY RPC]: handleCancelTransfer: secureCode or transactionID can't be empty"); + return response; + } + + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + + try + { + m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} wanted to cancel the transaction", user.Avatar); + if (m_moneyDBService.ValidateTransfer(secureCode, transactionUUID)) + { + m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} has canceled the transaction {1}", user.Avatar, transactionID); + m_moneyDBService.updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, + "User canceled the transaction on " + DateTime.Now.ToString()); + responseData["success"] = true; + } + } + catch (Exception e) + { + m_log.ErrorFormat("[MONEY RPC]: handleCancelTransfer: Exception occurred when transaction {0}: {1}", transactionID, e.ToString()); + responseData["success"] = false; + } + return response; + } + + + + // + public XmlRpcResponse handleGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + if (requestData.ContainsKey("clientUUID")) clientID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + if (requestData.ContainsKey("transactionID")) + { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (m_sessionDic.ContainsKey(clientID) && m_secureSessionDic.ContainsKey(clientID)) + { + if (m_sessionDic[clientID]==sessionID && m_secureSessionDic[clientID]==secureID) + { + if (string.IsNullOrEmpty(transactionID)) + { + responseData["success"] = false; + responseData["description"] = "TransactionID is empty"; + m_log.Error("[MONEY RPC]: handleGetTransaction: TransactionID is empty"); + return response; + } + + try { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null) + { + responseData["success"] = true; + responseData["amount"] = transaction.Amount; + responseData["time"] = transaction.Time; + responseData["type"] = transaction.Type; + responseData["sender"] = transaction.Sender.ToString(); + responseData["receiver"] = transaction.Receiver.ToString(); + responseData["description"] = transaction.Description; + } + else + { + responseData["success"] = false; + responseData["description"] = "Invalid Transaction UUID"; + } + + return response; + } + + catch (Exception e) + { + m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: {0}", e.ToString()); + m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: Can't get transaction information for {0}", transactionUUID.ToString()); + } + + } + } + + responseData["success"] = false; + responseData["description"] = "Session check failure, please re-login"; + + return response; + } + + + + // + public XmlRpcResponse handleWebLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebLogin:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + string userID = string.Empty; + string webSessionID = string.Empty; + + + response.Value = responseData; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) + { + responseData["success"] = false; + responseData["errorMessage"] = "userID or sessionID can`t be empty, login failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) + { + if (!m_webSessionDic.ContainsKey(userID)) + { + m_webSessionDic.Add(userID, webSessionID); + } + else m_webSessionDic[userID] = webSessionID; + } + + m_log.InfoFormat("[MONEY RPC]: handleWebLogin: User {0} has logged in from web", userID); + responseData["success"] = true; + return response; + } + + + + // + public XmlRpcResponse handleWebLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + string userID = string.Empty; + string webSessionID = string.Empty; + + response.Value = responseData; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) + { + responseData["success"] = false; + responseData["errorMessage"] = "userID or sessionID can`t be empty, log out failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) + { + if (m_webSessionDic.ContainsKey(userID)) + { + m_webSessionDic.Remove(userID); + } + } + + m_log.InfoFormat("[MONEY RPC]: handleWebLogout: User {0} has logged out from web", userID); + responseData["success"] = true; + return response; + + } + + + + /// + /// Get balance method for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + string userID = string.Empty; + string webSessionID = string.Empty; + int balance = 0; + + response.Value = responseData; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance: Getting balance for user {0}", userID); + + if (m_webSessionDic.ContainsKey(userID)) //perform session check + { + if (m_webSessionDic[userID]==webSessionID) + { + try + { + balance = m_moneyDBService.getBalance(userID); + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) + { + responseData["userName"] = user.Avatar; + } + else + { + responseData["userName"] = "unknown user"; + } + if (balance==-1) // User not found + { + responseData["success"] = false; + responseData["errorMessage"] = "User not found"; + responseData["balance"] = 0; + } + + else if (balance >= 0) + { + responseData["success"] = true; + responseData["balance"] = balance; + } + return response; + } + catch (Exception e) + { + m_log.ErrorFormat("[MONEY RPC]: handleWebGetBalance: Can't get balance for user {0}, Exception {1}", userID, e.ToString()); + responseData["success"] = false; + responseData["errorMessage"] = "Exception occurred when getting balance"; + return response; + } + + } + } + + m_log.Error("[MONEY RPC]: handleWebLogout: Session authentication failed when getting balance for user " + userID); + + responseData["success"] = false; + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + + /// + /// Get transaction for web pages + /// + /// + /// + public XmlRpcResponse handleWebGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + string userID = string.Empty; + string webSessionID = string.Empty; + int lastIndex = -1; + int startTime = 0; + int endTime = 0; + + response.Value = responseData; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + if (requestData.ContainsKey("lastIndex")) lastIndex = (int)requestData["lastIndex"]; + + if (m_webSessionDic.ContainsKey(userID)) + { + if (m_webSessionDic[userID]==webSessionID) + { + try + { + int total = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + TransactionData tran = null; + m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction: Getting transation[{0}] for user {1}", lastIndex + 1, userID); + if (total > lastIndex + 2) + { + responseData["isEnd"] = false; + } + else + { + responseData["isEnd"] = true; + } + + tran = m_moneyDBService.FetchTransaction(userID, startTime, endTime, lastIndex); + if (tran!=null) + { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(tran.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(tran.Receiver); + if (senderInfo!=null && receiverInfo!=null) + { + responseData["senderName"] = senderInfo.Avatar; + responseData["receiverName"] = receiverInfo.Avatar; + } + else + { + responseData["senderName"] = "unknown user"; + responseData["receiverName"] = "unknown user"; + } + responseData["success"] = true; + responseData["transactionIndex"] = lastIndex + 1; + responseData["transactionUUID"] = tran.TransUUID.ToString(); + responseData["senderID"] = tran.Sender; + responseData["receiverID"] = tran.Receiver; + responseData["amount"] = tran.Amount; + responseData["type"] = tran.Type; + responseData["time"] = tran.Time; + responseData["status"] = tran.Status; + responseData["description"] = tran.Description; + } + else + { + responseData["success"] = false; + responseData["errorMessage"] = string.Format("Unable to fetch transaction data with the index {0}", lastIndex + 1); + } + return response; + } + catch (Exception e) + { + m_log.ErrorFormat("[MONEY RPC]: handleWebGetTransaction: Can't get transaction for user {0}, Exception {1}", userID, e.ToString()); + responseData["success"] = false; + responseData["errorMessage"] = "Exception occurred when getting transaction"; + return response; + } + } + } + + m_log.Error("[MONEY RPC]: handleWebGetTransaction: Session authentication failed when getting transaction for user " + userID); + + responseData["success"] = false; + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + + } + + + + /// + /// Get total number of transactions for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetTransactionNum(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + string userID = string.Empty; + string webSessionID = string.Empty; + int startTime = 0; + int endTime = 0; + + response.Value = responseData; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + + if (m_webSessionDic.ContainsKey(userID)) + { + if (m_webSessionDic[userID]==webSessionID) + { + int it = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + if (it>=0) + { + m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum: Get {0} transactions for user {1}", it, userID); + responseData["success"] = true; + responseData["number"] = it; + } + else + { + responseData["success"] = false; + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handleWebGetTransactionNum: Session authentication failed when getting transaction number for user " + userID); + responseData["success"] = false; + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + } +} + diff --git a/release/0.8.2/src/OpenSim.Grid.MoneyServer/Program.cs b/release/0.8.2/src/OpenSim.Grid.MoneyServer/Program.cs new file mode 100644 index 0000000..3fbd12d --- /dev/null +++ b/release/0.8.2/src/OpenSim.Grid.MoneyServer/Program.cs @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net.Config; + +namespace OpenSim.Grid.MoneyServer +{ + class Program + { + public static void Main(string[] args) + { + XmlConfigurator.Configure(); + MoneyServerBase app = new MoneyServerBase(); + app.Startup(); + app.Work(); + } + } +} diff --git a/release/0.8.2/src/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs b/release/0.8.2/src/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..407ecee --- /dev/null +++ b/release/0.8.2/src/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Grid.MoneyServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("OpenSim.Grid.MoneyServer")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f554c84a-d8c7-41ea-833d-2483cde29e0f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/release/0.8.2/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs b/release/0.8.2/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs new file mode 100644 index 0000000..3175b30 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs @@ -0,0 +1,1940 @@ +// * Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp +// * +// * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ +// * See CONTRIBUTORS.TXT for a full list of copyright holders. +// * +// * Redistribution and use in source and binary forms, with or without +// * modification, are permitted provided that the following conditions are met: +// * * Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * * Redistributions in binary form must reproduce the above copyright +// * notice, this list of conditions and the following disclaimer in the +// * documentation and/or other materials provided with the distribution. +// * * Neither the name of the OpenSim Project nor the +// * names of its contributors may be used to endorse or promote products +// * derived from this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +// * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using Mono.Addins; + +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using NSL.Certificate.Tools; +using NSL.Network.XmlRpc; + + + +[assembly: Addin("DTLNSLMoneyModule", "1.0")] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] + + + +namespace OpenSim.Modules.Currency +{ + // + public enum TransactionType : int + { + // One-Time Charges + GroupCreate = 1002, + GroupJoin = 1004, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge= 1103, + // Recurrent Charges + ParcelDirFee = 2003, + ClassifiedRenew = 2005, + ScheduledFee = 2900, + // Inventory Transactions + GiveInventory = 3000, + // Transfers Between Users + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InvntorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + BuyMoney = 5010, + MoveMoney = 5011, + // Group Transactions + GroupLiability = 6003, + GroupDividend = 6004, + // Stipend Credits + StipendPayment = 10000 + } + + +/* + public enum OpenMetaverse.MoneyTransactionType : int + { + None = 0, + FailSimulatorTimeout = 1, + FailDataserverTimeout = 2, + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + ObjectPublicClaim = 1003, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + GiveInventory = 3000, + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InventorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + ObjectRelease = 8000, + LandRelease = 8001, + ObjectDelete = 8002, + ObjectPublicDecay = 8003, + ObjectPublicDelete = 8004, + LindenAdjustment = 9000, + LindenGrant = 9001, + LindenPenalty = 9002, + EventFee = 9003, + EventPrize = 9004, + StipendBasic = 10000, + StipendDeveloper = 10001, + StipendAlways = 10002, + StipendDaily = 10003, + StipendRating = 10004, + StipendDelta = 10005 + } +*/ + + + + // + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")] + public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule + { + #region Constant numbers and members. + + // Constant memebers + private const int MONEYMODULE_REQUEST_TIMEOUT = 10000; + + // Private data members. + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_enabled = true; + private bool m_sellEnabled = false; + private bool m_enable_server = true; // enable Money Server + + private IConfigSource m_config; + + private string m_moneyServURL = string.Empty; + public BaseHttpServer HttpServer; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + private X509Certificate2 m_cert = null; + + // + private bool m_use_web_settle = false; + private string m_settle_url = ""; + private string m_settle_message = ""; + private bool m_settle_user = false; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用 + + + /// + /// Scene dictionary indexed by Region Handle + /// + private Dictionary m_sceneList = new Dictionary(); + + /// + /// To cache the balance data while the money server is not available. + /// + private Dictionary m_moneyServer = new Dictionary(); + + // Events + public event ObjectPaid OnObjectPaid; + + + // Price + private int ObjectCount = 0; + private int PriceEnergyUnit = 0; + private int PriceGroupCreate = 0; + private int PriceObjectClaim = 0; + private float PriceObjectRent = 0f; + private float PriceObjectScaleFactor = 0f; + private int PriceParcelClaim = 0; + private int PriceParcelRent = 0; + private float PriceParcelClaimFactor = 0f; + private int PricePublicObjectDecay = 0; + private int PricePublicObjectDelete = 0; + private int PriceRentLight = 0; + private int PriceUpload = 0; + private int TeleportMinPrice = 0; + private float TeleportPriceExponent = 0f; + private float EnergyEfficiency = 0f; + + #endregion + + + // + public void Initialise(Scene scene, IConfigSource source) + { + Initialise(source); + if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false; + // + AddRegion(scene); + } + + + + #region ISharedRegionModule interface + + public void Initialise(IConfigSource source) + { + //m_log.InfoFormat("[MONEY]: Initialise:"); + + // Handle the parameters errors. + if (source==null) return; + + try + { + m_config = source; + + // [Economy] section + IConfig economyConfig = m_config.Configs["Economy"]; + + if (economyConfig.GetString("EconomyModule")!=Name) + { + m_enabled = false; + m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is disabled"); + return; + } + else + { + m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is enabled"); + } + + m_sellEnabled = economyConfig.GetBoolean("SellEnabled", false); + m_moneyServURL = economyConfig.GetString("CurrencyServer"); + + // クライアント証明書 + m_certFilename = economyConfig.GetString("ClientCertFilename", ""); + m_certPassword = economyConfig.GetString("ClientCertPassword", ""); + if (m_certFilename!="") { + m_cert = new X509Certificate2(m_certFilename, m_certPassword); + m_log.InfoFormat("[MONEY]: Issue Authentication of Client. Cert File is " + m_certFilename); + } + + // サーバ認証 + string checkcert = economyConfig.GetString("CheckServerCert", "false"); + if (checkcert.ToLower()=="true") m_checkServerCert = true; + + m_cacertFilename = economyConfig.GetString("CACertFilename", ""); + if (m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.InfoFormat("[MONEY]: Execute Authentication of Server. CA Cert File is " + m_cacertFilename); + } + else { + m_checkServerCert = false; + } + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + + + // Settlement + m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", false); + m_settle_url = economyConfig.GetString ("SettlementURL", ""); + m_settle_message = economyConfig.GetString ("SettlementMessage", ""); + + // Price + PriceEnergyUnit = economyConfig.GetInt ("PriceEnergyUnit", 100); + PriceObjectClaim = economyConfig.GetInt ("PriceObjectClaim", 10); + PricePublicObjectDecay = economyConfig.GetInt ("PricePublicObjectDecay", 4); + PricePublicObjectDelete = economyConfig.GetInt ("PricePublicObjectDelete", 4); + PriceParcelClaim = economyConfig.GetInt ("PriceParcelClaim", 1); + PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", 1f); + PriceUpload = economyConfig.GetInt ("PriceUpload", 0); + PriceRentLight = economyConfig.GetInt ("PriceRentLight", 5); + PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", 1); + PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", 10); + PriceParcelRent = economyConfig.GetInt ("PriceParcelRent", 1); + PriceGroupCreate = economyConfig.GetInt ("PriceGroupCreate", 0); + TeleportMinPrice = economyConfig.GetInt ("TeleportMinPrice", 2); + TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", 2f); + EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", 1); + + } + catch + { + m_log.ErrorFormat("[MONEY]: Initialise: Faile to read configuration file"); + } + } + + + + public void AddRegion(Scene scene) + { + //m_log.InfoFormat("[MONEY]: AddRegion:"); + + if (scene==null) return; + + scene.RegisterModuleInterface(this); // 競合するモジュールの排除 + + lock (m_sceneList) + { + if (m_sceneList.Count==0) + { + if (m_enable_server) + { + HttpServer = new BaseHttpServer(9000); + HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo)); + + HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler); + HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + HttpServer.AddXmlRPCHandler("SendMoneyBalance", SendMoneyBalanceHandler); // added + //HttpServer.AddXmlRPCHandler("UploadCovered", UploadCoveredHandler); // added for Aurora-Sim + //HttpServer.AddXmlRPCHandler("UploadCharge", UploadChargeHandler); // added for Aurora-Sim + + MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler); + MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("SendMoneyBalance", SendMoneyBalanceHandler); // added + //MainServer.Instance.AddXmlRPCHandler("UploadCovered", UploadCoveredHandler); // added for Aurora-Sim + //MainServer.Instance.AddXmlRPCHandler("UploadCharge", UploadChargeHandler); // added for Aurora-Sim + } + } + + if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle)) + { + m_sceneList[scene.RegionInfo.RegionHandle] = scene; + } + else + { + m_sceneList.Add(scene.RegionInfo.RegionHandle, scene); + } + + } + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer += MoneyTransferAction; + scene.EventManager.OnValidateLandBuy += ValidateLandBuy; + scene.EventManager.OnLandBuy += processLandBuy; + } + + + + public void RemoveRegion(Scene scene) + { + } + + + public void RegionLoaded(Scene scene) + { + } + + + public Type ReplaceableInterface + { + //get { return typeof(IMoneyModule); } + get { return null; } + } + + + public bool IsSharedModule + { + get { return true; } + } + + + public string Name + { + get { return "DTLNSLMoneyModule"; } + } + + + public void PostInitialise() + { + } + + + public void Close() + { + } + + + #endregion + + + + + #region IMoneyModule interface. + + // for LSL llGiveMoney() function + public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount) + { + //m_log.InfoFormat("[MONEY]: ObjectGiveMoney: LSL ObjectGiveMoney. UUID = {0}", objectID.ToString()); + + if (!m_sellEnabled) return false; + + string objName = string.Empty; + string avatarName = string.Empty; + + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj!=null) + { + objName = sceneObj.Name; + } + + Scene scene = GetLocateScene(toID); + if (scene!=null) + { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID); + if (account!=null) + { + avatarName = account.FirstName + " " + account.LastName; + } + } + + bool ret = false; + string description = String.Format("Object {0} pays {1}", objName, avatarName); + + if (sceneObj.OwnerID==fromID) + { + ulong regionHandle = sceneObj.RegionHandle; + if (GetLocateClient(fromID)!=null) + { + ret = TransferMoney(fromID, toID, amount, (int)MoneyTransactionType.ObjectPays, objectID, regionHandle, description); + } + else + { + ret = ForceTransferMoney(fromID, toID, amount, (int)MoneyTransactionType.ObjectPays, objectID, regionHandle, description); + } + } + + return ret; + } + + + // + public int UploadCharge + { + get { return PriceUpload; } + } + + + // + public int GroupCreationCharge + { + get { return PriceGroupCreate; } + } + + + public int GetBalance(UUID agentID) + { + IClientAPI client = GetLocateClient(agentID); + return QueryBalanceFromMoneyServer(client); + } + + + public bool UploadCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + int balance = QueryBalanceFromMoneyServer(client); + if (balance= landBuyEvent.parcelPrice) + { + lock(landBuyEvent) + { + landBuyEvent.economyValidated = true; + } + } + } + } + + + + /**/ + // for LandBuy even + // For Aurora-Sim, OnParcelBuy event function is already defined + // in OpenSim/Region/CoreModules/World/Land/ParcelManagementModule.cs + private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY]: processLandBuy:"); + + if (!m_sellEnabled) return; + + lock(landBuyEvent) + { + if (landBuyEvent.economyValidated==true && landBuyEvent.transactionID==0) + { + landBuyEvent.transactionID = Util.UnixTimeSinceEpoch(); + + ulong parcelID = (ulong)landBuyEvent.parcelLocalID; + UUID regionID = UUID.Zero; + if (sender is Scene) regionID = ((Scene)sender).RegionInfo.RegionID; + + if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID, + landBuyEvent.parcelPrice, (int)MoneyTransactionType.LandSale, regionID, parcelID, "Land Purchase")) + { + landBuyEvent.amountDebited = landBuyEvent.parcelPrice; + } + } + } + } + + + + /**/ + // for OnObjectBuy event + // For Aurora-Sim, OnObjectBuy event function is already defined + // in OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs + public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID, + UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice) + { + //m_log.InfoFormat("[MONEY]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId); + + // Handle the parameters error. + if (!m_sellEnabled) return; + if (remoteClient==null || salePrice<0) return; // for L$0 Sell + + // Get the balance from money server. + int balance = QueryBalanceFromMoneyServer(remoteClient); + if (balance(); + if (mod!=null) + { + UUID receiverId = sceneObj.OwnerID; + ulong regionHandle = sceneObj.RegionHandle; + bool ret = true; + if (salePrice>0) { + ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice, + (int)MoneyTransactionType.PayObject, sceneObj.UUID, regionHandle, "Object Buy"); + } + if (ret) + { + mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); + } + } + } + else + { + remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false); + return; + } + } + } + + + + /// + /// Sends the the stored money balance to the client + /// + /// + /// + /// + /// + private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID) + { + //m_log.InfoFormat("[MONEY]: OnMoneyBalanceRequest:"); + + if (client.AgentId==agentID && client.SessionId==SessionID) + { + int balance = 0; + // + if (m_enable_server) + { + balance = QueryBalanceFromMoneyServer(client); + } + + client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + } + else + { + client.SendAlertMessage("Unable to send your money balance"); + } + } + + + + private void OnRequestPayPrice(IClientAPI client, UUID objectID) + { + //m_log.InfoFormat("[MONEY]: OnRequestPayPrice:"); + + Scene scene = GetLocateScene(client.AgentId); + if (scene==null) return; + SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID); + if (sceneObj==null) return; + SceneObjectGroup group = sceneObj.ParentGroup; + SceneObjectPart root = group.RootPart; + + client.SendPayPrice(objectID, root.PayPrice); + } + + + + // + //private void OnEconomyDataRequest(UUID agentId) + private void OnEconomyDataRequest(IClientAPI user) + { + //m_log.InfoFormat("[MONEY]: OnEconomyDataRequest:"); + + //IClientAPI user = GetLocateClient(agentId); + + if (user!=null) + { + //Scene s = GetLocateScene(user.AgentId); + Scene s = (Scene)user.Scene; + + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, + PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, + PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, + TeleportMinPrice, TeleportPriceExponent); + } + } + + + #endregion + + + + #region MoneyModule XML-RPC Handler + + // "OnMoneyTransfered" RPC from MoneyServer + public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + //requestParam.Contains("receiverUUID") && + requestParam.Contains("clientSessionID") && + requestParam.Contains("clientSecureSessionID")) + { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + //UUID receiverUUID = UUID.Zero; + //UUID.TryParse((string)requestParam["receiverUUID"], out receiverUUID); + if (clientUUID!=UUID.Zero) + { + IClientAPI client = GetLocateClient(clientUUID); + if (client!=null && + client.SessionId.ToString()==(string)requestParam["clientSessionID"] && + client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"]) + { + if (requestParam.Contains("transactionType") && + requestParam.Contains("objectID") && + requestParam.Contains("amount")) + { + //m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]); + if ((int)requestParam["transactionType"]==(int)MoneyTransactionType.PayObject) // Pay for the object. + { + // Send notify to the client(viewer) for Money Event Trigger. + ObjectPaid handlerOnObjectPaid = OnObjectPaid; + if (handlerOnObjectPaid!=null) + { + UUID objectID = UUID.Zero; + UUID.TryParse((string)requestParam["objectID"], out objectID); + handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money() + } + ret = true; + } + } + } + } + } + } + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) + { + m_log.ErrorFormat("[MONEY]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback"); + } + resp.Value = paramTable; + + return resp; + } + + + + // "UpdateBalance" RPC from MoneyServer or Script + public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: BalanceUpdateHandler:"); + + bool ret = false; + + #region Update the balance from money server. + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + requestParam.Contains("clientSessionID") && // unable for Aurora-Sim + requestParam.Contains("clientSecureSessionID")) + { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + if (clientUUID!=UUID.Zero) + { + IClientAPI client = GetLocateClient(clientUUID); + if (client!=null && + client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim + client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"]) + { + if (requestParam.Contains("Balance")) + { + // Send notify to the client. + string msg = ""; + if (requestParam.Contains("Message")) msg = (string)requestParam["Message"]; + //client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"]); + client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"], + 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + ret = true; + } + } + } + } + } + + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) + { + m_log.ErrorFormat("[MONEY]: BalanceUpdateHandler: Cannot update client balance from MoneyServer"); + } + resp.Value = paramTable; + + return resp; + } + + + + // "UserAlert" RPC from Script + public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: UserAlertHandler:"); + + bool ret = false; + + #region confirm the request and show the notice from money server. + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + requestParam.Contains("clientSessionID") && // unable for Aurora-Sim + requestParam.Contains("clientSecureSessionID")) + { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + if (clientUUID!=UUID.Zero) + { + IClientAPI client = GetLocateClient(clientUUID); + if (client!=null && + client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim + client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"]) + { + if (requestParam.Contains("Description")) + { + string description = (string)requestParam["Description"]; + // Show the notice dialog with money server message. + GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()), + (byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3()); + client.SendInstantMessage(gridMsg); + ret = true; + } + } + } + } + } + // + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + return resp; + } + + + + // "GetBalance" RPC from Script + public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: GetBalanceHandler:"); + + bool ret = false; + int balance = -1; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + requestParam.Contains("clientSessionID") && // unable for Aurora-Sim + requestParam.Contains("clientSecureSessionID")) + { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + if (clientUUID!=UUID.Zero) + { + IClientAPI client = GetLocateClient(clientUUID); + if (client!=null && + client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim + client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"]) + { + balance = QueryBalanceFromMoneyServer(client); + } + } + } + } + + // Send the response to caller. + if (balance<0) + { + m_log.ErrorFormat("[MONEY]: GetBalanceHandler: GetBalance transaction is failed"); + ret = false; + } + + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + paramTable["balance"] = balance; + resp.Value = paramTable; + + return resp; + } + + + + // "AddBankerMoney" RPC from Script + public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: AddBankerMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + requestParam.Contains("clientSessionID") && // unable for Aurora-Sim + requestParam.Contains("clientSecureSessionID")) + { + UUID bankerUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID); + if (bankerUUID!=UUID.Zero) + { + IClientAPI client = GetLocateClient(bankerUUID); + if (client!=null && + client.SessionId.ToString()==(string)requestParam["clientSessionID"] && // unable for Aurora-Sim + client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"]) + { + if (requestParam.Contains("amount")) + { + Scene scene = (Scene)client.Scene; + int amount = (int)requestParam["amount"]; + ret = AddBankerMoney(bankerUUID, amount, scene.RegionInfo.RegionHandle); + + if (m_use_web_settle && m_settle_user) + { + ret = true; + IDialogModule dlg = scene.RequestModuleInterface(); + if (dlg!=null) { + dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url); + } + } + } + } + } + } + } + + if (!ret) m_log.ErrorFormat("[MONEY]: AddBankerMoneyHandler: Add Banker Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["settle"] = false; + paramTable["success"] = ret; + + if (m_use_web_settle && m_settle_user) paramTable["settle"] = true; + resp.Value = paramTable; + + return resp; + } + + + + // "SendMoneyBalance" RPC from Script + public XmlRpcResponse SendMoneyBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: SendMoneyBalanceHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + requestParam.Contains("secretAccessCode")) + { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + if (clientUUID!=UUID.Zero) + { + if (requestParam.Contains("amount")) + { + int amount = (int)requestParam["amount"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY]: SendMoneyBalanceHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = SendMoneyBalance(clientUUID, amount, hash); + } + } + else { + m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("clientUUID")) { + m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: clientUUID is missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: Count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY]: SendMoneyBalanceHandler: Send Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + + + /* + // "UploadCovered" RPC for Aurora-Sim + public XmlRpcResponse UploadCoveredHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: UploadCoveredHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + requestParam.Contains("clientSessionID") && + requestParam.Contains("clientSecureSessionID")) + { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + if (clientUUID!=UUID.Zero) + { + IClientAPI client = GetLocateClient(clientUUID); + if (client!=null && + client.SessionId.ToString()==(string)requestParam["clientSessionID"] && + client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"]) + { + ret = UploadCovered(client, UploadCharge); + } + } + } + } + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + resp.Value = paramTable; + + return resp; + } + */ + + + + /* + // "UploadCovered" RPC for Aurora-Sim + public XmlRpcResponse UploadChargeHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: UploadChargeHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && + requestParam.Contains("clientSessionID") && + requestParam.Contains("clientSecureSessionID")) + { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + if (clientUUID!=UUID.Zero) + { + IClientAPI client = GetLocateClient(clientUUID); + if (client!=null && + client.SessionId.ToString()==(string)requestParam["clientSessionID"] && + client.SecureSessionId.ToString()==(string)requestParam["clientSecureSessionID"]) + { + ApplyUploadCharge(clientUUID, UploadCharge, "Upload Asset"); + ret = true; + } + } + } + } + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + resp.Value = paramTable; + + return resp; + } + */ + + + #endregion + + + + + #region MoneyModule private help functions + + /// + /// Transfer the money from one user to another. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, string description) + { + //m_log.InfoFormat("[MONEY]: TransferMoney:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + if (senderClient==null) // receiverClient could be null. + { + m_log.InfoFormat("[MONEY]: TransferMoney: Client {0} not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Force transfer the money from one user to another. + /// This function does not check sender login. + /// Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, string description) + { + //m_log.InfoFormat("[MONEY]: ForceTransferMoney:"); + + bool ret = false; + + #region Force send transaction request to money server and parse the resultes. + + if (m_enable_server) + { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = sender.ToString(); + paramTable["receiverID"] = receiver.ToString(); + paramTable["transactionType"] = type; + paramTable["objectID"] = objectID.ToString(); + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["amount"] = amount; + paramTable["description"] = description; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) + { + if ((bool)resultTable["success"]==true) + { + ret = true; + } + } + else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString()); + } + //else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Money Server is not available!!"); + + #endregion + + return ret; + } + + + + /// + /// Add the money to banker avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle) + { + //m_log.InfoFormat("[MONEY]: AddBankerMoney:"); + + bool ret = false; + m_settle_user = false; + + if (m_enable_server) + { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["bankerID"] = bankerID.ToString(); + paramTable["transactionType"] = (int)TransactionType.BuyMoney; + paramTable["amount"] = amount; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["description"] = "Add Money to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null) + { + if (resultTable.Contains("success") && (bool)resultTable["success"]==true) + { + ret = true; + } + else + { + if (resultTable.Contains("banker")) + { + m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used. + if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used."); + } + else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Fail Message {0}", resultTable["message"]); + } + } + else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not available!!"); + + return ret; + } + + + + /// + /// Send the money to avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool SendMoneyBalance(UUID avatarID, int amount, string secretCode) + { + //m_log.InfoFormat("[MONEY]: SendMoneyBalance:"); + + bool ret = false; + + if (m_enable_server) + { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["avatarID"] = avatarID.ToString(); + paramTable["transactionType"] = (int)MoneyTransactionType.ReferBonus; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Bonus to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoneyBalance"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) + { + if ((bool)resultTable["success"]==true) + { + ret = true; + } + else m_log.ErrorFormat("[MONEY]: SendMoneyBalance: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY]: SendMoneyBalance: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: SendMoneyBalance: Money Server is not available!!"); + + return ret; + } + + + + /// + /// Pay the money of charge. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, string description) + { + //m_log.InfoFormat("[MONEY]: PayMoneyCharge:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + if (senderClient==null) // receiverClient could be null. + { + m_log.InfoFormat("[MONEY]: PayMoneyCharge: Client {0} is not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Login the money server when the new client login. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LoginMoneyServer(IClientAPI client, out int balance) + { + //m_log.InfoFormat("[MONEY]: LoginMoneyServer:"); + + bool ret = false; + balance = 0; + + #region Send money server the client info for login. + + Scene scene = (Scene)client.Scene; + string userName = string.Empty; + + if (!string.IsNullOrEmpty(m_moneyServURL)) + { + // Get the username for the login user. + if (client.Scene is Scene) + { + if (scene!=null) + { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId); + if (account!=null) + { + userName = account.FirstName + " " + account.LastName; + } + } + } + + // Login the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(), + scene.RegionInfo.HttpPort.ToString()); + paramTable["userName"] = userName; + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) + { + if ((bool)resultTable["success"]==true) + { + balance = (int)resultTable["clientBalance"]; + m_log.InfoFormat("[MONEY]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL); + ret = true; + } + } + else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString()); + } + else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Money Server is not available!!"); + + #endregion + + // Viewerへ設定を通知する. + OnEconomyDataRequest(client); + + return ret; + } + + + + /// + /// Log off from the money server. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LogoffMoneyServer(IClientAPI client) + { + //m_log.InfoFormat("[MONEY]: LogoffMoneyServer:"); + + bool ret = false; + + if (!string.IsNullOrEmpty(m_moneyServURL)) + { + // Log off from the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout"); + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) + { + if ((bool)resultTable["success"]==true) + { + ret = true; + } + } + } + + return ret; + } + + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method) + { + //m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest:"); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) + { + if (!m_moneyServURL.StartsWith("https://")) + { + m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file"); + //return null; + } + } + else + { + if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://")) + { + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL); + return null; + } + } + + + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try + { + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) + { + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL); + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: {0}", ex); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp.IsFault) + { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + + private int QueryBalanceFromMoneyServer(IClientAPI client) + { + //m_log.InfoFormat("[MONEY]: QueryBalanceFromMoneyServer:"); + + int balance = 0; + + #region Send the request to get the balance from money server for cilent. + + if (client!=null) + { + if (m_enable_server) + { + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetBalance"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) + { + if ((bool)resultTable["success"]==true) + { + balance = (int)resultTable["clientBalance"]; + } + } + } + else + { + if (m_moneyServer.ContainsKey(client.AgentId)) + { + balance = m_moneyServer[client.AgentId]; + } + } + } + + #endregion + + return balance; + } + + + + // + private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID) + { + //m_log.InfoFormat("[MONEY]: GetTransactionInfo:"); + + EventManager.MoneyTransferArgs args = null; + + if (m_enable_server) + { + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + paramTable["transactionID"] = transactionID; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) + { + if ((bool)resultTable["success"]==true) + { + int amount = (int)resultTable["amount"]; + int type = (int)resultTable["type"]; + string desc = (string)resultTable["description"]; + UUID sender = UUID.Zero; + UUID recver = UUID.Zero; + UUID.TryParse((string)resultTable["sender"], out sender); + UUID.TryParse((string)resultTable["receiver"], out recver); + args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc); + } + else + { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]); + } + } + else + { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Response"); + } + } + else + { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Money Server URL"); + } + + return args; + } + + + + /// Locates a IClientAPI for the client specified + /// + /// + /// + private IClientAPI GetLocateClient(UUID AgentID) + { + IClientAPI client = null; + + lock (m_sceneList) + { + if (m_sceneList.Count>0) + { + foreach (Scene _scene in m_sceneList.Values) + { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID); + if (tPresence!=null && !tPresence.IsChildAgent) + { + IClientAPI rclient = tPresence.ControllingClient; + if (rclient!=null) + { + client = rclient; + break; + } + } + } + } + } + + return client; + } + + + + private Scene GetLocateScene(UUID AgentId) + { + Scene scene = null; + + lock (m_sceneList) + { + if (m_sceneList.Count>0) + { + foreach (Scene _scene in m_sceneList.Values) + { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId); + if (tPresence!=null && !tPresence.IsChildAgent) + { + scene = _scene; + break; + } + } + } + } + + return scene; + } + + + + private SceneObjectPart GetLocatePrim(UUID objectID) + { + SceneObjectPart sceneObj = null; + + lock (m_sceneList) + { + if (m_sceneList.Count>0) + { + foreach (Scene _scene in m_sceneList.Values) + { + SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID); + if (part!=null) + { + sceneObj = part; + break; + } + } + } + } + + return sceneObj; + } + + + #endregion + } + +} diff --git a/release/0.8.2/src/OpenSim.Modules.Currency/NSLCertificateTools.cs b/release/0.8.2/src/OpenSim.Modules.Currency/NSLCertificateTools.cs new file mode 100644 index 0000000..1b641e8 --- /dev/null +++ b/release/0.8.2/src/OpenSim.Modules.Currency/NSLCertificateTools.cs @@ -0,0 +1,215 @@ +/* + * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp + * + */ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Net; +using System.Net.Security; +using System.Text; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; + +using log4net; + + +namespace NSL.Certificate.Tools +{ + // + public class NSLCertificateVerify + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private X509Chain m_chain = null; + private X509Certificate2 m_cacert = null; + + private Mono.Security.X509.X509Crl m_clientcrl = null; + + + public NSLCertificateVerify() + { + m_chain = null; + m_cacert = null; + m_clientcrl = null; + } + + + public NSLCertificateVerify(string certfile) + { + SetPrivateCA(certfile); + } + + + public NSLCertificateVerify(string certfile, string crlfile) + { + SetPrivateCA (certfile); + SetPrivateCRL(crlfile); + } + + + public void SetPrivateCA(string certfile) + { + try { + m_cacert = new X509Certificate2(certfile); + } + catch (Exception ex) + { + m_cacert = null; + m_log.ErrorFormat("[SET PRIVATE CA]: CA File reading error [{0}]. {1}", certfile, ex); + } + + if (m_cacert!=null) { + m_chain = new X509Chain(); + m_chain.ChainPolicy.ExtraStore.Add(m_cacert); + m_chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + m_chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; + } + } + + + public void SetPrivateCRL(string crlfile) + { + try { + m_clientcrl = Mono.Security.X509.X509Crl.CreateFromFile(crlfile); + } + catch (Exception ex) + { + m_clientcrl = null; + m_log.ErrorFormat("[SET PRIVATE CRL]: CRL File reading error [{0}]. {1}", crlfile, ex); + } + } + + + + // + // + // + public bool CheckPrivateChain(X509Certificate2 cert) + { + if (m_chain==null || m_cacert==null) { + return false; + } + + bool ret = m_chain.Build((X509Certificate2)cert); + if (ret) { + return true; + } + + for (int i=0; i tableList = new Dictionary(); + tableList = CheckTables(); + + // + // Balances Table + if (!tableList.ContainsKey(Table_of_Balances)) { + try { + CreateBalancesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating balances table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_Balances].Trim(); + int nVer = getTableVersionNum(version); + balances_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateBalancesTable1(); + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 2: //Rev.2 + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 3: //Rev.3 + UpdateBalancesTable3(); + break; + } + } + + // + // UserInfo Table + if (!tableList.ContainsKey(Table_of_UserInfo)) { + try { + CreateUserInfoTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating userinfo table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_UserInfo].Trim(); + int nVer = getTableVersionNum(version); + userinfo_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateUserInfoTable1(); + UpdateUserInfoTable2(); + break; + case 2: //Rev.2 + UpdateUserInfoTable2(); + break; + } + } + + // + // Transactions Table + if (!tableList.ContainsKey(Table_of_Transactions)) { + try { + CreateTransactionsTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating transactions table: " + e.ToString()); + } + } + // check transactions table version + else { + string version = tableList[Table_of_Transactions].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 2: //Rev.2 + UpdateTransactionsTable2(); + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 3: //Rev.3 + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 4: //Rev.4 + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 5: //Rev.5 + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 6: //Rev.6 + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 7: //Rev.7 + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 8: //Rev.8 + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 9: //Rev.9 + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 10: //Rev.10 + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 11: //Rev.11 + UpdateTransactionsTable11(); + break; + } + } + + // + // TotalSales Table + if (!tableList.ContainsKey(Table_of_TotalSales)) { + try { + CreateTotalSalesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating totalsales table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_TotalSales].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 1: //Rev.1 + UpdateTotalSalesTable1(); + UpdateTotalSalesTable2(); + break; + case 2: //Rev.2 + UpdateTotalSalesTable2(); + break; + } + } + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + throw new Exception("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + } + } + + + private int getTableVersionNum(string version) + { + int nVer = 0; + + Regex _commentPattenRegex = new Regex(@"\w+\.(?\d+)"); + Match m = _commentPattenRegex.Match(version); + if (m.Success) { + string ver = m.Groups["ver"].Value; + nVer = Convert.ToInt32(ver); + } + return nVer; + } + + + + /////////////////////////////////////////////////////////////////////// + // create Tables + + private void CreateBalancesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Balances + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`balance` int(10) NOT NULL,"; + sql += "`status` tinyint(2) DEFAULT NULL,"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.4';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateUserInfoTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_UserInfo + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`simip` varchar(64) NOT NULL,"; + sql += "`avatar` varchar(50) NOT NULL,"; + sql += "`pass` varchar(36) NOT NULL DEFAULT '',"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`class` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`serverurl` varchar(255) NOT NULL DEFAULT '',"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTransactionsTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Transactions + "`("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`sender` varchar(36) NOT NULL,"; + sql += "`receiver` varchar(36) NOT NULL,"; + sql += "`amount` int(10) NOT NULL,"; + sql += "`senderBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`receiverBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`objectUUID` varchar(36) DEFAULT NULL,"; + sql += "`objectName` varchar(255) DEFAULT NULL,"; + sql += "`regionHandle` varchar(36) NOT NULL,"; + sql += "`regionUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`time` int(11) NOT NULL,"; + sql += "`secure` varchar(36) NOT NULL,"; + sql += "`status` tinyint(1) NOT NULL,"; + sql += "`commonName` varchar(128) NOT NULL,"; + sql += "`description` varchar(255) DEFAULT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.12';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTotalSalesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_TotalSales + "` ("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`objectUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`TotalCount` int(10) NOT NULL DEFAULT 0,"; + sql += "`TotalAmount` int(10) NOT NULL DEFAULT 0,"; + sql += "`time` int(11) NOT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + initTotalSalesTable(); + } + + + + /////////////////////////////////////////////////////////////////////// + // update Balances Table + + private void UpdateBalancesTable1() + { + m_log.Info("[MONEY MANAGER]: Converting Balance Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Balances; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT * FROM " + Table_of_Balances; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i=0) { + amount += balance; + updatedb = updateBalance(uuid, amount); + } + else { + updatedb = addUser(uuid, amount, int.Parse(row[i,2]), 0); + } + if (!updatedb) break; + } + } + + // Delete + if (updatedb) { + for (int i=0; i uuid, url, name, pass + bool updatedb = true; + for (int i=0; i + /// update transactions table from Rev.2 to Rev.3 + /// + private void UpdateTransactionsTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`objectUUID` varchar(36) DEFAULT NULL AFTER `amount`),"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.3 to Rev.4 + /// + private void UpdateTransactionsTable3() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`secure` varchar(36) NOT NULL AFTER `time`),"; + sql += "COMMENT = 'Rev.4';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.4 to Rev.5 + /// + private void UpdateTransactionsTable4() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`regionHandle` varchar(36) NOT NULL AFTER `objectUUID`),"; + sql += "COMMENT = 'Rev.5';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.5 to Rev.6 + /// + private void UpdateTransactionsTable5() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`commonName` varchar(128) NOT NULL AFTER `status`),"; + sql += "COMMENT = 'Rev.6';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.6 to Rev.7 + /// + private void UpdateTransactionsTable6() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Transactions; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT UUID,sender,receiver FROM " + Table_of_Transactions; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i + /// update transactions table from Rev.7 to Rev.8 + /// + private void UpdateTransactionsTable7() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `objectName` varchar(255) DEFAULT NULL AFTER `objectUUID`,"; + sql += "COMMENT = 'Rev.8';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.8 to Rev.9 + /// + private void UpdateTransactionsTable8() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `senderBalance` int(10) NOT NULL DEFAULT -1 AFTER `amount`,"; + sql += "ADD `receiverBalance` int(10) NOT NULL DEFAULT -1 AFTER `senderBalance`,"; + sql += "COMMENT = 'Rev.9';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.9 to Rev.10 + /// + private void UpdateTransactionsTable9() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "MODIFY COLUMN `sender` varchar(36) NOT NULL,"; + sql += "MODIFY COLUMN `receiver` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.10';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.10 to Rev.11 + /// change type of BirthGift from 1000 to 900 + /// + private void UpdateTransactionsTable10() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM `" + Table_of_Transactions + "` WHERE type=1000"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + if (resultCount>0) { + sql = "SELECT UUID FROM `" + Table_of_Transactions + "` WHERE type=1000"; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[] row = new string[resultCount]; + while (dbReader.Read()) { + row[l] = dbReader.GetString(0); + l++; + } + dbReader.Close(); + cmd.Dispose(); + + sql = "UPDATE `" + Table_of_Transactions + "` SET type=900 WHERE UUID=?uuid"; + for (int i=0; i + /// update transactions table from Rev.11 to Rev.12 + /// + private void UpdateTransactionsTable11() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `regionUUID` varchar(36) NOT NULL AFTER `regionHandle`,"; + sql += "COMMENT = 'Rev.12';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + // update Total Sales Table + + private void UpdateTotalSalesTable1() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "ADD `time` int(11) NOT NULL AFTER `TotalAmount`,"; + sql += "COMMENT = 'Rev.2';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + deleteTotalSalesTable(); + initTotalSalesTable(); + } + + + private void UpdateTotalSalesTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "MODIFY COLUMN `user` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + // + + private Dictionary CheckTables() + { + Dictionary tableDic = new Dictionary(); + + lock (dbcon) { + string sql = string.Empty; + + sql = "SELECT TABLE_NAME,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?dbname"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?dbname", dbcon.Database); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + while (r.Read()) { + try { + string tableName = (string)r["TABLE_NAME"]; + string comment = (string)r["TABLE_COMMENT"]; + tableDic.Add(tableName, comment); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error checking tables" + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return tableDic; + } + } + + + /// + /// Reconnect to the database + /// + public void Reconnect() + { + m_log.Info("[MONEY MANAGER]: Reconnecting database"); + lock (dbcon) { + try { + dbcon.Close(); + dbcon = new MySqlConnection(connectString); + dbcon.Open(); + m_log.Info("[MONEY MANAGER]: Reconnected database"); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to reconnect to database: " + e.ToString()); + } + } + } + + + + /////////////////////////////////////////////////////////////////////// + // + // balances + // + + /// + /// Get balance from database. returns -1 if failed. + /// + /// + /// + public int getBalance(string userID) + { + if (userID==UUID.Zero.ToString()) return 999999999; // System + + int retValue = -1; + string sql = string.Empty; + + sql = "SELECT balance FROM " + Table_of_Balances + " WHERE user = ?userid"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userid", userID); + + using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { + try { + if (dbReader.Read()) { + retValue = Convert.ToInt32(dbReader["balance"]); + } + } + catch (Exception e) { + m_log.ErrorFormat("[MoneyDB]: MySql failed to fetch balance {0}.", userID); + retValue = -2; + } + dbReader.Close(); + } + cmd.Dispose(); + + return retValue; + } + + + public bool updateBalance(string userID, int amount) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Balances + " SET balance = ?amount WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userID", userID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool addUser(string userID, int balance, int status, int type) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + if (balances_rev>=4) { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`,`type`) VALUES "; + sql += " (?userID,?balance,?status,?type);"; + } + else { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`) VALUES "; + sql += " (?userID,?balance,?status);"; + } + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userID", userID); + cmd.Parameters.AddWithValue("?balance", balance); + cmd.Parameters.AddWithValue("?status", status); + if (balances_rev>=4) { + cmd.Parameters.AddWithValue("?type", type); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + + return bRet; + } + + + /// + /// Here we'll make a withdraw from the sender and update transaction status + /// + /// + /// + /// + /// + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + bool bRet = false; + string sql = string.Empty; + MySqlCommand cmd = null; + + // System + if (senderID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET senderBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET senderBalance = balance - ?amount, "+ Table_of_Transactions + ".status = ?status, balance = balance - ?amount "; + sql += " WHERE UUID = ?tranid AND user = sender AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", senderID); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Give money to the receiver and change the transaction status to success. + /// + /// + /// + /// + /// + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + string sql = string.Empty; + bool bRet = false; + MySqlCommand cmd = null; + + // System + if (receiverID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET receiverBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET receiverBalance = balance + ?amount, " + Table_of_Transactions + ".status = ?status, balance = balance + ?amount "; + sql += " WHERE UUID = ?tranid AND user = receiver AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", receiverID); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // totalsales + // + private void initTotalSalesTable() + { + m_log.Info("[MONEY MANAGER]: Initailising TotalSales Table..."); + string sql = string.Empty; + + sql = "SELECT SQL_CALC_FOUND_ROWS receiver,objectUUID,type,COUNT(*),SUM(amount),MIN(time) FROM "+ Table_of_Transactions; + sql += " WHERE sender != receiver AND status = ?status AND sender != ?system"; + sql += " GROUP BY receiver,objectUUID,type;"; + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); + cmd.Parameters.AddWithValue("?system", UUID.Zero.ToString()); + cmd.ExecuteNonQuery(); + + MySqlCommand cmd2 = new MySqlCommand("SELECT FOUND_ROWS();", dbcon); + int lineCount = int.Parse(cmd2.ExecuteScalar().ToString()); + cmd2.Dispose(); + + if (lineCount<=0) { + cmd.Dispose(); + return; + } + + MySqlDataReader r = cmd.ExecuteReader(); + int l = 0; + string[,] row = new string[lineCount, r.FieldCount]; + while (r.Read()) { + for (int i=0; i 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTotalSale(UUID saleUUID, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_TotalSales; + sql += " SET TotalCount = TotalCount + ?count, TotalAmount = TotalAmount + ?amount, time = ?time "; + sql += " WHERE UUID = ?uuid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?uuid", saleUUID.ToString()); + cmd.Parameters.AddWithValue("?count", count); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?time", tmstamp); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + + } + + + public bool setTotalSale(string userUUID, string objectUUID, int type, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + string uuid = string.Empty; + int dbtm = 0; + + sql = "SELECT UUID,time FROM " + Table_of_TotalSales; + sql += " WHERE user = ?userid AND objectUUID = ?objID AND type = ?type;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userid", userUUID); + cmd.Parameters.AddWithValue("?objID", objectUUID); + cmd.Parameters.AddWithValue("?type", type); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + uuid = (string)r["UUID"]; + dbtm = Convert.ToInt32(r["time"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get sale data from DB failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return false; + } + } + r.Close(); + } + + if (uuid!=string.Empty) { + UUID saleUUID = UUID.Zero; + UUID.TryParse(uuid, out saleUUID); + if (dbtm 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions + " SET status = ?status,description = ?desc WHERE UUID = ?tranid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", status); + cmd.Parameters.AddWithValue("?desc", description); + cmd.Parameters.AddWithValue("?tranid", transactionID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool SetTransExpired(int deadTime) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions; + sql += " SET status = ?failedstatus,description = ?desc WHERE time <= ?deadTime AND status = ?pendingstatus;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?failedstatus", (int)Status.FAILED_STATUS); + cmd.Parameters.AddWithValue("?desc", "expired"); + cmd.Parameters.AddWithValue("?deadTime", deadTime); + cmd.Parameters.AddWithValue("?pendingstatus", (int)Status.PENDING_STATUS); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Validate if the transacion is legal + /// + /// + /// + /// + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + bool bRet = false; + string secure = string.Empty; + string sql = string.Empty; + + sql = "SELECT secure FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + secure = (string)r["secure"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get transaction from DB failed: " + e.ToString()); + } + if (secureCode == secure) bRet = true; + else bRet = false; + } + r.Close(); + } + + cmd.Dispose(); + return bRet; + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + TransactionData transactionData = new TransactionData(); + transactionData.TransUUID = transactionID; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 1: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + + } + r.Close(); + } + + cmd.Dispose(); + return transactionData; + } + + + public TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index, uint retNum) + { + List rows = new List(); + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user) ORDER BY time ASC LIMIT ?index,?num;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + cmd.Parameters.AddWithValue("?index", index); + cmd.Parameters.AddWithValue("?num", retNum); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + for (int i = 0; i < retNum; i++) { + if (r.Read()) { + try { + TransactionData transactionData = new TransactionData(); + string uuid = (string)r["UUID"]; + UUID transUUID; + UUID.TryParse(uuid,out transUUID); + + transactionData.TransUUID = transUUID; + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + // + rows.Add(transactionData); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 2: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + } + r.Close(); + } + + cmd.Dispose(); + return rows.ToArray(); + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + int iRet = -1; + string sql = string.Empty; + + sql = "SELECT COUNT(*) AS number FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user);"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + iRet = Convert.ToInt32(r["number"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to get transaction info: " + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return iRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // userinfo + // + public bool addUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Adding UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + if (userInfo.Avatar==null) return false; + + if (userinfo_rev>=3) { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`,`type`,`class`,`serverurl`) VALUES"; + sql += "(?user,?simip,?avatar,?password,?type,?class,?serverurl);"; + } + else { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`) VALUES"; + sql += "(?user,?simip,?avatar,?password);"; + } + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?avatar", userInfo.Avatar); + cmd.Parameters.AddWithValue("?password", userInfo.PswHash); + if (userinfo_rev>=3) { + cmd.Parameters.AddWithValue("?type", userInfo.Type); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + } + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public UserInfo fetchUserInfo(string userID) + { + //m_log.Error("[MONEY MANAGER]: Fetching UserInfo: " + userID); + + UserInfo userInfo = new UserInfo(); + userInfo.UserID = null; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_UserInfo + " WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userID", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + userInfo.UserID = (string)r["user"]; + userInfo.SimIP = (string)r["simip"]; + userInfo.Avatar = (string)r["avatar"]; + userInfo.PswHash = (string)r["pass"]; + userInfo.Type = Convert.ToInt32(r["type"]); + userInfo.Class = Convert.ToInt32(r["class"]); + userInfo.ServerURL = (string)r["serverurl"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching UserInfo failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + r.Close(); + } + cmd.Dispose(); + + if (userInfo.UserID!=userID) return null; + return userInfo; + } + + + public bool updateUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Updating UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_UserInfo + " SET simip=?simip,pass=?pass,class=?class,serverurl=?serverurl WHERE user=?user;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?pass", userInfo.PswHash); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + } +} diff --git a/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs b/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs new file mode 100644 index 0000000..cd2bae4 --- /dev/null +++ b/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Threading; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + // This bit of code is from OpenSim.Data.MySQLSuperManager + public class MySQLSuperManager + { + public bool Locked; + private readonly Mutex m_lock = new Mutex(false); + public MySQLMoneyManager Manager; + public string Running; + + public void GetLock() + { + Locked = true; + m_lock.WaitOne(); + } + + public void Release() + { + m_lock.ReleaseMutex(); + Locked = false; + } + } +} diff --git a/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs b/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f4a2a82 --- /dev/null +++ b/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("03f4a266-2e30-47e4-b785-ff02cdb4bbb9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs b/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs new file mode 100644 index 0000000..e73b579 --- /dev/null +++ b/release/0.9.1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs @@ -0,0 +1,237 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public class TransactionData + { + UUID m_uuid; + string m_sender = string.Empty; + string m_receiver = string.Empty; + int m_amount; + int m_senderBalance; + int m_receiverBalance; + int m_type; + int m_time; + int m_status; + string m_objectID = UUID.Zero.ToString(); +// string m_objectID = "00000000-0000-0000-0000-000000000000"; + string m_objectName = string.Empty; + string m_regionHandle = string.Empty; + string m_regionUUID = string.Empty; + string m_secureCode = string.Empty; + string m_commonName = string.Empty; + string m_description = string.Empty; + +/* + public TransactionData(string uuid, string sender, string receiver, + int amount, int time, int status, string description) + { + this.m_uuid = uuid; + this.m_sender = sender; + this.m_receiver = receiver; + this.m_amount = amount; + } +*/ + + public UUID TransUUID + { + get { return m_uuid; } + set { m_uuid = value; } + } + + public string Sender + { + get { return m_sender; } + set { m_sender = value; } + } + + public string Receiver + { + get { return m_receiver; } + set { m_receiver = value; } + } + + public int Amount + { + get { return m_amount; } + set { m_amount = value; } + } + + public int SenderBalance + { + get { return m_senderBalance; } + set { m_senderBalance = value; } + } + + public int ReceiverBalance + { + get { return m_receiverBalance; } + set { m_receiverBalance = value; } + } + + public int Type + { + get { return m_type; } + set { m_type = value; } + } + + public int Time + { + get { return m_time; } + set { m_time = value; } + } + + public int Status + { + get { return m_status; } + set { m_status = value; } + } + + public string Description + { + get { return m_description; } + set { m_description = value; } + } + + public string ObjectUUID + { + get { return m_objectID; } + set { m_objectID = value; } + } + + public string ObjectName + { + get { return m_objectName; } + set { m_objectName = value; } + } + + public string RegionHandle + { + get { return m_regionHandle; } + set { m_regionHandle = value; } + } + + public string RegionUUID + { + get { return m_regionUUID; } + set { m_regionUUID = value; } + } + + public string SecureCode + { + get { return m_secureCode; } + set { m_secureCode = value; } + } + + public string CommonName + { + get { return m_commonName; } + set { m_commonName = value; } + } + } + + + public enum Status + { + SUCCESS_STATUS = 0, + PENDING_STATUS = 1, + FAILED_STATUS = 2, + ERROR_STATUS = 9 + } + + + public enum AvatarType + { + LOCAL_AVATAR = 0, + HG_AVATAR = 1, + NPC_AVATAR = 2, + GUEST_AVATAR = 3, + FOREIGN_AVATAR = 8, + UNKNOWN_AVATAR = 9 + } + + + public class UserInfo + { + string m_userID = string.Empty; + string m_simIP = string.Empty; + string m_avatarName = string.Empty; + string m_passwordHash = string.Empty; + int m_avatarType = (int)AvatarType.LOCAL_AVATAR; + int m_avatarClass = (int)AvatarType.LOCAL_AVATAR; + string m_serverURL = string.Empty; + + public string UserID + { + get { return m_userID; } + set { m_userID = value; } + } + + public string SimIP + { + get { return m_simIP; } + set { m_simIP = value; } + } + + public string Avatar + { + get { return m_avatarName; } + set { m_avatarName = value; } + } + + public string PswHash + { + get { return m_passwordHash; } + set { m_passwordHash = value; } + } + + public int Type + { + get { return m_avatarType; } + set { m_avatarType = value; } + } + + public int Class + { + get { return m_avatarClass; } + set { m_avatarClass = value; } + } + + public string ServerURL + { + get { return m_serverURL; } + set { m_serverURL = value; } + } + } +} diff --git a/release/0.9.1/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs b/release/0.9.1/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs new file mode 100644 index 0000000..7140c0f --- /dev/null +++ b/release/0.9.1/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs @@ -0,0 +1,70 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenMetaverse; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; + + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyDBService + { + int getBalance(string userID); + + bool withdrawMoney(UUID transactionID, string senderID, int amount); + + bool giveMoney(UUID transactionID, string receiverID, int amount); + + bool addTransaction(TransactionData transaction); + + bool addUser(string userID, int balance, int status, int type); + + bool updateTransactionStatus(UUID transactionID, int status, string description); + + bool SetTransExpired(int deadTime); + + bool ValidateTransfer(string secureCode, UUID transactionID); + + TransactionData FetchTransaction(UUID transactionID); + + TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex); + + int getTransactionNum(string userID, int startTime, int endTime); + + bool DoTransfer(UUID transactionUUID); + + bool DoAddMoney(UUID transactionUUID); // Added by Fumi.Iseki + + bool TryAddUserInfo(UserInfo user); + + UserInfo FetchUserInfo(string userID); + } +} diff --git a/release/0.9.1/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs b/release/0.9.1/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs new file mode 100644 index 0000000..d6e3721 --- /dev/null +++ b/release/0.9.1/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; + +using Nini.Config; + + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyServiceCore + { + BaseHttpServer GetHttpServer(); + Dictionary GetSessionDic(); + Dictionary GetSecureSessionDic(); + Dictionary GetWebSessionDic(); + + // + IConfig GetServerConfig(); + IConfig GetCertConfig(); + bool IsCheckClientCert(); + } +} diff --git a/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs b/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs new file mode 100644 index 0000000..efa72b4 --- /dev/null +++ b/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs @@ -0,0 +1,570 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using log4net; +using System.Reflection; +using OpenMetaverse; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyDBService: IMoneyDBService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string m_connect; + //private MySQLMoneyManager m_moneyManager; + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + // DB manager pool + protected Dictionary m_dbconnections = new Dictionary(); // Lock付 + private int m_maxConnections; + + public int m_lastConnect = 0; + + + public MoneyDBService(string connect) + { + m_connect = connect; + Initialise(m_connect,10); + } + + + public MoneyDBService() + { + } + + + public void Initialise(string connectionString, int maxDBConnections) + { + m_connect = connectionString; + m_maxConnections = maxDBConnections; + if (connectionString != string.Empty) { + //m_moneyManager = new MySQLMoneyManager(connectionString); + + //m_log.Info("Creating " + m_maxConnections + " DB connections..."); + for (int i=0; im_maxConnections) { + lockedCons = 0; + System.Threading.Thread.Sleep(1000); // Wait some time before searching them again. + m_log.Debug("WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound."); + } + } + } + + + public int getBalance(string userID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getBalance(userID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.getBalance(userID); + } + catch(Exception e) { + m_log.Error(e.ToString()); + return 0; + } + finally { + dbm.Release(); + } + } + + + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool setTotalSale(TransactionData transaction) + { + if (transaction.Receiver==transaction.Sender) return false; + if (transaction.Sender==UUID.Zero.ToString()) return false; + + MySQLSuperManager dbm = GetLockedConnection(); + + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addTransaction(TransactionData transaction) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.addTransaction(transaction); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.addTransaction(transaction); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addUser(string userID, int balance, int status, int type) + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = UUID.Random(); + transaction.Sender = UUID.Zero.ToString(); + transaction.Receiver = userID; + transaction.Amount = balance; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.ObjectName = string.Empty; + transaction.RegionHandle = string.Empty; + transaction.Type = (int)TransactionType.BirthGift; + transaction.Time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);; + transaction.Status = (int)Status.PENDING_STATUS; + transaction.SecureCode = UUID.Random().ToString(); + transaction.CommonName = string.Empty; + transaction.Description = "addUser " + DateTime.UtcNow.ToString(); + + bool ret = addTransaction(transaction); + if (!ret) return false; + + // + MySQLSuperManager dbm = GetLockedConnection(); + + try { + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + + // + if (ret) ret = giveMoney(transaction.TransUUID, userID, balance); + return ret; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool SetTransExpired(int deadTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.SetTransExpired(deadTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.SetTransExpired(deadTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.FetchTransaction(transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.FetchTransaction(transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex) + { + MySQLSuperManager dbm = GetLockedConnection(); + TransactionData[] arrTransaction; + + uint index = 0; + if (lastIndex>=0) index = Convert.ToUInt32(lastIndex) + 1; + + try { + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + + // + if (arrTransaction.Length > 0) { + return arrTransaction[0]; + } + else { + return null; + } + } + + + public bool DoTransfer(UUID transactionUUID) + { + bool do_trans = false; + + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction != null && transaction.Status == (int)Status.PENDING_STATUS) { + int balance = getBalance(transaction.Sender); + + //check the amount + if (transaction.Amount >= 0 && balance >= transaction.Amount) { + if (withdrawMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver) == -1) { + m_log.ErrorFormat("[MONEY DB]: DoTransfer: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + do_trans = true; + } + else { // give money to receiver failed. 返金処理 + m_log.ErrorFormat("[MONEY DB]: Give money to receiver {0} failed", transaction.Receiver); + //Return money to sender + if (giveMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + m_log.ErrorFormat("[MONEY DB]: give money to receiver {0} failed but return it to sender {1} successfully", + transaction.Receiver, transaction.Sender); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "give money to receiver failed but return it to sender successfully"); + } + else { + m_log.ErrorFormat("[MONEY DB]: FATAL ERROR: Money withdrawn from sender: {0}, but failed to be given to receiver {1}", + transaction.Sender, transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.ERROR_STATUS, "give money to receiver failed, and return it to sender unsuccessfully!!!"); + } + } + } + else { // withdraw money failed + m_log.ErrorFormat("[MONEY DB]: Withdraw money from sender {0} failed", transaction.Sender); + } + } + else { // not enough balance to finish the transaction + m_log.ErrorFormat("[MONEY DB]: Not enough balance for user: {0} to apply the transaction.", transaction.Sender); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + // + if (do_trans) { + setTotalSale(transaction); + } + + return do_trans; + } + + + // by Fumi.Iseki + public bool DoAddMoney(UUID transactionUUID) + { + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction!=null && transaction.Status==(int)Status.PENDING_STATUS) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver)==-1) { + m_log.ErrorFormat("[MONEY DB]: DoAddMoney: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + // + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + setTotalSale(transaction); + return true; + } + else { // give money to receiver failed. + m_log.ErrorFormat("[MONEY DB]: Add money to receiver {0} failed", transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "add money to receiver failed"); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + return false; + } + + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // userinfo + // + + public bool TryAddUserInfo(UserInfo user) + { + MySQLSuperManager dbm = GetLockedConnection(); + + UserInfo userInfo = null; + + try { + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + dbm.Release(); + return false; + } + + try { + if (userInfo!=null) { + //m_log.InfoFormat("[MONEY DB]: Found user \"{0}\", now update information", user.Avatar); + if (dbm.Manager.updateUserInfo(user)) return true; + } + else if (dbm.Manager.addUserInfo(user)) { + //m_log.InfoFormat("[MONEY DB]: Unable to find user \"{0}\", add it to DB successfully", user.Avatar); + return true; + } + m_log.InfoFormat("[MONEY DB]: WARNNING: TryAddUserInfo: Unable to TryAddUserInfo."); + return false; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public UserInfo FetchUserInfo(string userID) + { + UserInfo userInfo = null; + MySQLSuperManager dbm = GetLockedConnection(); + + try { + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return -1; + } + finally { + dbm.Release(); + } + } + } +} diff --git a/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs b/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs new file mode 100644 index 0000000..654e4d1 --- /dev/null +++ b/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs @@ -0,0 +1,338 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Security; +using System.Reflection; +using System.Timers; +//using System.Security.Authentication; +//using System.Security.Cryptography; +//using System.Security.Cryptography.X509Certificates; + +using HttpServer; +using Nini.Config; +using log4net; + +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data; + +using NSL.Certificate.Tools; + + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string connectionString = string.Empty; + private uint m_moneyServerPort = 8008; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private string m_cacertFilename = ""; + private string m_clcrlFilename = ""; + private bool m_checkClientCert = false; + + private int DEAD_TIME = 120; + private int MAX_DB_CONNECTION = 10; + + private MoneyXmlRpcModule m_moneyXmlRpcModule; + private MoneyDBService m_moneyDBService; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // クライアント認証用 + + private Dictionary m_sessionDic = new Dictionary(); + private Dictionary m_secureSessionDic = new Dictionary(); + private Dictionary m_webSessionDic = new Dictionary(); + + IConfig m_server_config; + IConfig m_cert_config; + + + public MoneyServerBase() + { + m_console = new LocalConsole("Money "); +// m_console = new CommandConsole("Money "); + MainConsole.Instance = m_console; + } + + + public void Work() + { + //m_console.Notice("Enter help for a list of commands\n"); + + //The timer checks the transactions table every 60 seconds + Timer checkTimer = new Timer(); + checkTimer.Interval = 60*1000; + checkTimer.Enabled = true; + checkTimer.Elapsed += new ElapsedEventHandler(CheckTransaction); + checkTimer.Start(); + + while (true) { + m_console.Prompt(); + } + } + + + /// + /// Check the transactions table, set expired transaction state to failed + /// + private void CheckTransaction(object sender, ElapsedEventArgs e) + { + long ticksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + int unixEpochTime =(int) ((DateTime.UtcNow.Ticks - ticksToEpoch )/10000000); + int deadTime = unixEpochTime - DEAD_TIME; + m_moneyDBService.SetTransExpired(deadTime); + } + + + protected override void StartupSpecific() + { + m_log.Info("[MONEY SERVER]: Setup HTTP Server process"); + + ReadIniConfig(); + + try { + if (m_certFilename!="") { + m_httpServer = new BaseHttpServer(m_moneyServerPort, true, m_certFilename, m_certPassword); + if (m_checkClientCert) { + Type typeBaseHttpServer = typeof(BaseHttpServer); // BaseHttpServer.cs にパッチがあたっていない場合のため + PropertyInfo pinfo = typeBaseHttpServer.GetProperty("CertificateValidationCallback"); + + if (pinfo!=null) { + //m_httpServer.CertificateValidationCallback = (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate; + pinfo.SetValue(m_httpServer, (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate, null); + m_log.Info ("[MONEY SERVER]: Set RemoteCertificateValidationCallback"); + } + else { + m_log.Error("[MONEY SERVER]: StartupSpecific: CheckClientCert is true. But this MoneyServer does not support CheckClientCert!!"); + } + } + } + else { + m_httpServer = new BaseHttpServer(m_moneyServerPort); + } + + SetupMoneyServices(); + m_httpServer.Start(); + base.StartupSpecific(); // OpenSim/Framework/Servers/BaseOpenSimServer.cs + } + + catch (Exception e) { + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Fail to start HTTPS process"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Please Check Certificate File or Password. Exit"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: {0}", e); + Environment.Exit(1); + } + + //TODO : Add some console commands here + } + + + protected void ReadIniConfig() + { + MoneyServerConfigSource moneyConfig = new MoneyServerConfigSource(); + Config = moneyConfig.m_config; // for base.StartupSpecific() + + try { + // [Startup] + IConfig st_config = moneyConfig.m_config.Configs["Startup"]; + string PIDFile = st_config.GetString("PIDFile", ""); + if (PIDFile!="") Create_PIDFile(PIDFile); + + // [MySql] + IConfig db_config = moneyConfig.m_config.Configs["MySql"]; + string sqlserver = db_config.GetString("hostname", "localhost"); + string database = db_config.GetString("database", "OpenSim"); + string username = db_config.GetString("username", "root"); + string password = db_config.GetString("password", "password"); + string pooling = db_config.GetString("pooling", "false"); + string port = db_config.GetString("port", "3306"); + MAX_DB_CONNECTION = db_config.GetInt ("MaxConnection", MAX_DB_CONNECTION); + + connectionString = "Server=" + sqlserver + ";Port=" + port + ";Database=" + database + ";User ID=" + + username + ";Password=" + password + ";Pooling=" + pooling + ";"; + + // [MoneyServer] + m_server_config = moneyConfig.m_config.Configs["MoneyServer"]; + DEAD_TIME = m_server_config.GetInt("ExpiredTime", DEAD_TIME); + + // + // [Certificate] + m_cert_config = moneyConfig.m_config.Configs["Certificate"]; + if (m_cert_config==null) { + m_log.Info("[MONEY SERVER]: [Certificate] section is not found. Using [MoneyServer] section instead"); + m_cert_config = m_server_config; + } + + // HTTPS Server Cert (Server Mode) + // サーバ証明書 + m_certFilename = m_cert_config.GetString("ServerCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ServerCertPassword", m_certPassword); + if (m_certFilename!="") { + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute HTTPS comunication. Cert file is " + m_certFilename); + } + + // クライアント認証 + m_checkClientCert = m_cert_config.GetBoolean("CheckClientCert", m_checkClientCert); + m_cacertFilename = m_cert_config.GetString("CACertFilename", m_cacertFilename); + m_clcrlFilename = m_cert_config.GetString("ClientCrlFilename", m_clcrlFilename); + // + if (m_checkClientCert && m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CA file is " + m_cacertFilename); + } + else { + m_checkClientCert = false; + } + + if (m_checkClientCert) { + if (m_clcrlFilename!="") { + m_certVerify.SetPrivateCRL(m_clcrlFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CRL file is " + m_clcrlFilename); + } + } + } + + catch (Exception) { + m_log.Error("[MONEY SERVER]: ReadIniConfig: Fail to setup configure. Please check MoneyServer.ini. Exit"); + Environment.Exit(1); + } + } + + + // added by skidz + protected void Create_PIDFile(string path) + { + try { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + m_pidFile = path; + } + catch (Exception) { + } + } + + + protected virtual void SetupMoneyServices() + { + m_log.Info("[MONEY SERVER]: Connecting to Money Storage Server"); + + m_moneyDBService = new MoneyDBService(); + m_moneyDBService.Initialise(connectionString, MAX_DB_CONNECTION); + + m_moneyXmlRpcModule = new MoneyXmlRpcModule(); +// m_moneyXmlRpcModule.Initialise(m_version, m_server_config, m_cert_config, m_moneyDBService, this); + m_moneyXmlRpcModule.Initialise(m_version, m_moneyDBService, this); + m_moneyXmlRpcModule.PostInitialise(); + } + + + // + public bool IsCheckClientCert() + { + return m_checkClientCert; + } + + + public IConfig GetServerConfig() + { + return m_server_config; + } + + + public IConfig GetCertConfig() + { + return m_cert_config; + } + + + public BaseHttpServer GetHttpServer() + { + return m_httpServer; + } + + + public Dictionary GetSessionDic() + { + return m_sessionDic; + } + + + public Dictionary GetSecureSessionDic() + { + return m_secureSessionDic; + } + + + public Dictionary GetWebSessionDic() + { + return m_webSessionDic; + } + + } + + + + // + class MoneyServerConfigSource + { + public IniConfigSource m_config; + + public MoneyServerConfigSource() + { + string configPath = Path.Combine(Directory.GetCurrentDirectory(), "MoneyServer.ini"); + if (File.Exists(configPath)) { + m_config = new IniConfigSource(configPath); + } + else { + //TODO: create default configuration. + //m_config = DefaultConfig(); + } + } + + + public void Save(string path) + { + m_config.Save(path); + } + + } +} diff --git a/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs b/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs new file mode 100644 index 0000000..e28e4cc --- /dev/null +++ b/release/0.9.1/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs @@ -0,0 +1,1740 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Collections; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using OpenSim.Region.Framework.Scenes; + +using NSL.Network.XmlRpc; +using NSL.Certificate.Tools; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyXmlRpcModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private int m_defaultBalance = 1000; + // + private bool m_forceTransfer = false; + private string m_bankerAvatar = ""; + + private bool m_scriptSendMoney = false; + private string m_scriptAccessKey = ""; + private string m_scriptIPaddress = "127.0.0.1"; + + private bool m_hg_enable = false; + private bool m_gst_enable = false; + private int m_hg_defaultBalance = 0; + private int m_gst_defaultBalance = 0; + + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private X509Certificate2 m_clientCert = null; + + private string m_sslCommonName = ""; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用 + + + // Update Balance Messages + private string m_BalanceMessageLandSale = "Paid the Money L${0} for Land."; + private string m_BalanceMessageRcvLandSale = ""; + private string m_BalanceMessageSendGift = "Sent Gift L${0} to {1}."; + private string m_BalanceMessageReceiveGift = "Received Gift L${0} from {1}."; + private string m_BalanceMessagePayCharge = ""; + private string m_BalanceMessageBuyObject = "Bought the Object {2} from {1} by L${0}."; + private string m_BalanceMessageSellObject = "{1} bought the Object {2} by L${0}."; + private string m_BalanceMessageGetMoney = "Got the Money L${0} from {1}."; + private string m_BalanceMessageBuyMoney = "Bought the Money L${0}."; + private string m_BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}."; + private string m_BalanceMessageSendMoney = "Paid the Money L${0} to {1}."; + private string m_BalanceMessageReceiveMoney = "Received L${0} from {1}."; + + private bool m_enableAmountZero = false; + + const int MONEYMODULE_REQUEST_TIMEOUT = 30 * 1000; //30 seconds + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + private IMoneyDBService m_moneyDBService; + private IMoneyServiceCore m_moneyCore; + + protected IConfig m_server_config; + protected IConfig m_cert_config; + + /// + /// Used to notify old regions as to which OpenSim version to upgrade to + /// + //private string m_opensimVersion; + + private Dictionary m_sessionDic; + private Dictionary m_secureSessionDic; + private Dictionary m_webSessionDic; + + protected BaseHttpServer m_httpServer; + + + public MoneyXmlRpcModule() + { + } + + + public void Initialise(string opensimVersion, IMoneyDBService moneyDBService, IMoneyServiceCore moneyCore) + { + //m_opensimVersion = opensimVersion; + m_moneyDBService = moneyDBService; + m_moneyCore = moneyCore; + m_server_config = m_moneyCore.GetServerConfig(); // [MoneyServer] Section + m_cert_config = m_moneyCore.GetCertConfig(); // [Certificate] Section + + //////////////////////////////////////////////////////////////////////// + // [MoneyServer] Section + m_defaultBalance = m_server_config.GetInt("DefaultBalance", m_defaultBalance); + + m_forceTransfer = m_server_config.GetBoolean("EnableForceTransfer", m_forceTransfer); + + string banker = m_server_config.GetString("BankerAvatar", m_bankerAvatar); + m_bankerAvatar = banker.ToLower(); + + m_enableAmountZero = m_server_config.GetBoolean("EnableAmountZero", m_enableAmountZero); + m_scriptSendMoney = m_server_config.GetBoolean("EnableScriptSendMoney", m_scriptSendMoney); + m_scriptAccessKey = m_server_config.GetString("MoneyScriptAccessKey", m_scriptAccessKey); + m_scriptIPaddress = m_server_config.GetString("MoneyScriptIPaddress", m_scriptIPaddress); + + // Hyper Grid Avatar + m_hg_enable = m_server_config.GetBoolean("EnableHGAvatar", m_hg_enable); + m_gst_enable = m_server_config.GetBoolean("EnableGuestAvatar", m_gst_enable); + m_hg_defaultBalance = m_server_config.GetInt("HGAvatarDefaultBalance", m_hg_defaultBalance); + m_gst_defaultBalance = m_server_config.GetInt("GuestAvatarDefaultBalance", m_gst_defaultBalance); + + // Update Balance Messages + m_BalanceMessageLandSale = m_server_config.GetString("BalanceMessageLandSale", m_BalanceMessageLandSale); + m_BalanceMessageRcvLandSale = m_server_config.GetString("BalanceMessageRcvLandSale", m_BalanceMessageRcvLandSale); + m_BalanceMessageSendGift = m_server_config.GetString("BalanceMessageSendGift", m_BalanceMessageSendGift); + m_BalanceMessageReceiveGift = m_server_config.GetString("BalanceMessageReceiveGift", m_BalanceMessageReceiveGift); + m_BalanceMessagePayCharge = m_server_config.GetString("BalanceMessagePayCharge", m_BalanceMessagePayCharge); + m_BalanceMessageBuyObject = m_server_config.GetString("BalanceMessageBuyObject", m_BalanceMessageBuyObject); + m_BalanceMessageSellObject = m_server_config.GetString("BalanceMessageSellObject", m_BalanceMessageSellObject); + m_BalanceMessageGetMoney = m_server_config.GetString("BalanceMessageGetMoney", m_BalanceMessageGetMoney); + m_BalanceMessageBuyMoney = m_server_config.GetString("BalanceMessageBuyMoney", m_BalanceMessageBuyMoney); + m_BalanceMessageRollBack = m_server_config.GetString("BalanceMessageRollBack", m_BalanceMessageRollBack); + m_BalanceMessageSendMoney = m_server_config.GetString("BalanceMessageSendMoney", m_BalanceMessageSendMoney); + m_BalanceMessageReceiveMoney = m_server_config.GetString("BalanceMessageReceiveMoney", m_BalanceMessageReceiveMoney); + + + //////////////////////////////////////////////////////////////////////// + // [Certificate] Section + + // XML RPC to Region Server (Client Mode) + // クライアント証明書 + m_certFilename = m_cert_config.GetString("ClientCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename!="") { + m_clientCert = new X509Certificate2(m_certFilename, m_certPassword); + //m_clientCert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.Info("[MONEY RPC]: Initialise: Issue Authentication of Client. Cert file is " + m_cacertFilename); + } + + // サーバ認証 + m_checkServerCert = m_cert_config.GetBoolean("CheckServerCert", m_checkServerCert); + + // CA + m_cacertFilename = m_cert_config.GetString("CACertFilename", m_cacertFilename); + if (m_checkServerCert && m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + m_log.Info("[MONEY RPC]: Initialise: Execute Authentication of Server. CA file is " + m_cacertFilename); + } + else { + m_checkServerCert = false; + ServicePointManager.ServerCertificateValidationCallback = null; + } + + m_sessionDic = m_moneyCore.GetSessionDic(); + m_secureSessionDic = m_moneyCore.GetSecureSessionDic(); + m_webSessionDic = m_moneyCore.GetWebSessionDic(); + RegisterHandlers(); + } + + + public void PostInitialise() + { + } + + + public void RegisterHandlers() + { + m_httpServer = m_moneyCore.GetHttpServer(); + m_httpServer.AddXmlRPCHandler("ClientLogin", handleClientLogin); + m_httpServer.AddXmlRPCHandler("ClientLogout", handleClientLogout); + m_httpServer.AddXmlRPCHandler("GetBalance", handleGetBalance); + m_httpServer.AddXmlRPCHandler("GetTransaction", handleGetTransaction); + + m_httpServer.AddXmlRPCHandler("CancelTransfer", handleCancelTransfer); + m_httpServer.AddXmlRPCHandler("TransferMoney", handleTransaction); + m_httpServer.AddXmlRPCHandler("ForceTransferMoney", handleForceTransaction); // added + m_httpServer.AddXmlRPCHandler("PayMoneyCharge", handlePayMoneyCharge); // added + m_httpServer.AddXmlRPCHandler("AddBankerMoney", handleAddBankerMoney); // added + m_httpServer.AddXmlRPCHandler("SendMoney", handleScriptTransaction); // added + m_httpServer.AddXmlRPCHandler("MoveMoney", handleScriptTransaction); // added + + // this is from original DTL. not check yet. + m_httpServer.AddXmlRPCHandler("WebLogin", handleWebLogin); + m_httpServer.AddXmlRPCHandler("WebLogout", handleWebLogout); + m_httpServer.AddXmlRPCHandler("WebGetBalance", handleWebGetBalance); + m_httpServer.AddXmlRPCHandler("WebGetTransaction", handleWebGetTransaction); + m_httpServer.AddXmlRPCHandler("WebGetTransactionNum", handleWebGetTransactionNum); + } + + + // + public string GetSSLCommonName(XmlRpcRequest request) + { + if (request.Params.Count>5) { + m_sslCommonName = (string)request.Params[5]; + } + else if (request.Params.Count==5) { + m_sslCommonName = (string)request.Params[4]; + if (m_sslCommonName=="gridproxy") m_sslCommonName = ""; + } + else { + m_sslCommonName = ""; + } + return m_sslCommonName; + } + + + // + public string GetSSLCommonName() + { + return m_sslCommonName; + } + + + /// + /// Get the user balance when user entering a parcel. + /// + /// + /// + public XmlRpcResponse handleClientLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleClientLogin:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + responseData["success"] = false; + responseData["clientBalance"] = 0; + + // Check Client Cert + if (m_moneyCore.IsCheckClientCert()) { + string commonName = GetSSLCommonName(); + if (commonName=="") { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Warnning: Check Client Cert is set, but SSL Common Name is empty."); + responseData["success"] = false; + responseData["description"] = "SSL Common Name is empty"; + return response; + } + else { + m_log.InfoFormat("[MONEY RPC]: handleClientLogin: SSL Common Name is {0}", commonName); + } + + } + + string universalID = string.Empty; + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string simIP = string.Empty; + string userName = string.Empty; + int balance = 0; + int avatarType = (int)AvatarType.UNKNOWN_AVATAR; + int avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + if (requestData.ContainsKey("universalID")) universalID = (string)requestData["universalID"]; + if (requestData.ContainsKey("userName")) userName = (string)requestData["userName"]; + if (requestData.ContainsKey("openSimServIP")) simIP = (string)requestData["openSimServIP"]; + if (requestData.ContainsKey("avatarType")) avatarType = Convert.ToInt32(requestData["avatarType"]); + if (requestData.ContainsKey("avatarClass")) avatarClass = Convert.ToInt32(requestData["avatarClass"]); + + // + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + string securePsw = string.Empty; + // + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out securePsw); + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // Information from DB + UserInfo userInfo = m_moneyDBService.FetchUserInfo(clientUUID); + if (userInfo!=null) { + avatarType = userInfo.Type; // Avatar Type is not updated + if (avatarType ==(int)AvatarType.LOCAL_AVATAR) avatarClass = (int)AvatarType.LOCAL_AVATAR; + if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) avatarClass = userInfo.Class; + if (String.IsNullOrEmpty(userName)) userName = userInfo.Avatar; + } + if (avatarType==(int)AvatarType.UNKNOWN_AVATAR) avatarType = avatarClass; + + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: Avatar {0} ({1}) is logged on.", userName, clientUUID); + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: Avatar Type is {0} and Avatar Class is {1}", avatarType, avatarClass); + + // + // Check Avatar + if (String.IsNullOrEmpty(serverURL)) { + responseData["description"] = "Server URL is empty. Avatar is a NPC?"; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.GUEST_AVATAR && !m_gst_enable) { + responseData["description"] = "Avatar is a Guest avatar. But this Money Server does not support Guest avatars."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.HG_AVATAR && !m_hg_enable) { + responseData["description"] = "Avatar is a HG avatar. But this Money Server does not support HG avatars."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.NPC_AVATAR) { + responseData["description"] = "Avatar is a NPC."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.FOREIGN_AVATAR) { + responseData["description"] = "Avatar is a Foreign avatar."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) { + responseData["description"] = "Avatar is a Unknown avatar."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + + // + //Update the session and secure session dictionary + lock (m_sessionDic) { + if (!m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Add(clientUUID, sessionID); + } + else m_sessionDic[clientUUID] = sessionID; + } + lock (m_secureSessionDic) { + if (!m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Add(clientUUID, secureID); + } + else m_secureSessionDic[clientUUID] = secureID; + } + + // + try { + if (userInfo==null) userInfo = new UserInfo(); + userInfo.UserID = clientUUID; + userInfo.SimIP = simIP; + userInfo.Avatar = userName; + userInfo.PswHash = UUID.Zero.ToString(); + userInfo.Type = avatarType; + userInfo.Class = avatarClass; + userInfo.ServerURL = serverURL; + if (!String.IsNullOrEmpty(securePsw)) userInfo.PswHash = securePsw; + + if (!m_moneyDBService.TryAddUserInfo(userInfo)) { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Unable to refresh information for user \"{0}\" in DB.", userName); + responseData["success"] = true; // for FireStorm + responseData["description"] = "Update or add user information to db failed"; + return response; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Can't update userinfo for user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + return response; + } + + // + try { + balance = m_moneyDBService.getBalance(clientUUID); + + //add user to balances table if not exist. (if balance is -1, it means avatar is not exist at balances table) + if (balance==-1) { + int default_balance = m_defaultBalance; + if (avatarClass==(int)AvatarType.HG_AVATAR) default_balance = m_hg_defaultBalance; + if (avatarClass==(int)AvatarType.GUEST_AVATAR) default_balance = m_gst_defaultBalance; + + if (m_moneyDBService.addUser(clientUUID, default_balance, 0, avatarType)) { + responseData["success"] = true; + responseData["description"] = "add user successfully"; + responseData["clientBalance"] = default_balance; + } + else { + responseData["description"] = "add user failed"; + } + } + //Success + else if (balance >= 0) { + responseData["success"] = true; + responseData["description"] = "get user balance successfully"; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Can't get balance of user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + } + + return response; + } + + + // + public XmlRpcResponse handleClientLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleClientLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + + m_log.InfoFormat("[MONEY RPC]: handleClientLogout: User {0} is logging off.", clientUUID); + try { + lock (m_sessionDic) { + if (m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Remove(clientUUID); + } + } + + lock (m_secureSessionDic) { + if (m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Remove(clientUUID); + } + } + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleClientLogout: Failed to delete user session: " + e.ToString() ); + responseData["success"] = false; + return response; + } + + responseData["success"] = true; + return response; + } + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + /// + /// handle incoming transaction + /// + /// + /// + public XmlRpcResponse handleTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY RPC]: handleTransaction: Transfering money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + rcv_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Add transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleTransaction: Exception occurred while adding transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handleTransaction: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle incoming force transaction. no check senderSessionID and senderSecureSessionID + /// + /// + /// + public XmlRpcResponse handleForceTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleForceTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + // + if (!m_forceTransfer) { + m_log.Error("[MONEY RPC]: handleForceTransaction: Not allowed force transfer of Money."); + m_log.Error("[MONEY RPC]: handleForceTransaction: Set enableForceTransfer at [MoneyServer] to true in MoneyServer.ini"); + responseData["message"] = "not allowed force transfer of Money!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY RPC]: handleForceTransaction: Force transfering money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Force receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + snd_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleForceTransaction: Exception occurred while adding force transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle scripted sending money transaction. + /// + /// + /// + public XmlRpcResponse handleScriptTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string receiverID = UUID.Zero.ToString(); + string clientIP = remoteClient.Address.ToString(); + string secretCode = string.Empty; + string description = "Scripted Send Money from/to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (!m_scriptSendMoney || m_scriptAccessKey=="") { + m_log.Error("[MONEY RPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY RPC]: handleScriptTransaction: Set enableScriptSendMoney and MoneyScriptAccessKey at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed set money to avatar!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + if (requestData.ContainsKey("secretAccessCode")) secretCode = (string)requestData["secretAccessCode"]; + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(m_scriptAccessKey + "_" + clientIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(hash + "_" + m_scriptIPaddress)); + hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + + if (secretCode.ToLower()!=hash) { + m_log.Error("[MONEY RPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY RPC]: handleScriptTransaction: Not match Script Access Key."); + responseData["message"] = "not allowed send money to avatar! not match Script Key"; + return response; + } + + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Send money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle = "0"; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo senderInfo = null; + UserInfo receiverInfo = null; + if (transaction.Sender !=UUID.Zero.ToString()) senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (transaction.Receiver!=UUID.Zero.ToString()) receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + + if (senderInfo==null && receiverInfo==null) { + m_log.ErrorFormat("[MONEY RPC]: handleScriptTransaction: Sender and Receiver are not yet in DB, or both of them are System: {0}, {1}", + transaction.Sender, transaction.Receiver); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: ScriptTransaction money finished successfully, now update balance {0}", + transactionUUID.ToString()); + string message = string.Empty; + if (senderInfo!=null) { + if (receiverInfo==null) message = string.Format(m_BalanceMessageSendMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageSendMoney, amount, receiverInfo.Avatar, ""); + UpdateBalance(transaction.Sender, message); + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Sender, message); + } + if (receiverInfo!=null) { + if (senderInfo==null) message = string.Format(m_BalanceMessageReceiveMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageReceiveMoney, amount, senderInfo.Avatar, ""); + UpdateBalance(transaction.Receiver, message); + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Receiver, message); + } + + + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleScriptTransaction: Add force transaction for user {0} failed.", transaction.Sender); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleScriptTransaction: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle adding money transaction. + /// + /// + /// + public XmlRpcResponse handleAddBankerMoney(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string bankerID = string.Empty; + string regionHandle = "0"; + string regionUUID = UUID.Zero.ToString(); + string description = "Add Money to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("bankerID")) bankerID = (string)requestData["bankerID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + // Check Banker Avatar + if (m_bankerAvatar!=UUID.Zero.ToString() && m_bankerAvatar!=bankerID) { + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Not allowed add money to avatar!!"); + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Set BankerAvatar at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed add money to avatar!"; + responseData["banker"] = false; + return response; + } + responseData["banker"] = true; + + m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Add money to avatar {0}", bankerID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = bankerID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(bankerID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Avatar is not yet in DB {0}", bankerID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoAddMoney(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Adding money finished successfully, now update balance: {0}", + transactionUUID.ToString()); + string message = string.Format(m_BalanceMessageBuyMoney, amount, "SYSTEM", ""); + UpdateBalance(transaction.Receiver, message); + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle pay charge transaction. no check receiver information. + /// + /// + /// + public XmlRpcResponse handlePayMoneyCharge(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = UUID.Zero.ToString(); + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = UUID.Zero.ToString(); + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Pay Charge on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge: Pay from {0}", senderID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string message = string.Format(m_BalanceMessagePayCharge, amount, "SYSTEM", ""); + responseData["success"] = NotifyTransfer(transactionUUID, message, "", ""); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handlePayMoneyCharge: Pay money transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Exception occurred while pay money transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + // added by Fumi.Iseki + // + /// + /// Continue transaction with no confirm. + /// + /// + /// + public bool NotifyTransfer(UUID transactionUUID, string msg2sender, string msg2receiver, string objectName) + { + //m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: User has accepted the transaction, now continue with the transaction"); + + try { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction Type = {0}", transaction.Type); + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Payment finished successfully, now update balance {0}", transactionUUID.ToString()); + + bool updateSender = true; + bool updateReceiv = true; + if (transaction.Sender==transaction.Receiver) updateSender = false; + //if (transaction.Type==(int)TransactionType.UploadCharge) return true; + if (transaction.Type==(int)TransactionType.UploadCharge) updateReceiv = false; + + if (updateSender) { + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string receiverName = "unknown user"; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + string snd_message = string.Format(msg2sender, transaction.Amount, receiverName, objectName); + UpdateBalance(transaction.Sender, snd_message); + } + if (updateReceiv) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + string senderName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + string rcv_message = string.Format(msg2receiver, transaction.Amount, senderName, objectName); + UpdateBalance(transaction.Receiver, rcv_message); + } + + // Notify to sender + if (transaction.Type==(int)TransactionType.PayObject) { + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Now notify opensim to give object to customer {0} ", transaction.Sender); + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = transaction.Sender; + requestTable["receiverUUID"] = transaction.Receiver; + + if(m_sessionDic.ContainsKey(transaction.Sender)&&m_secureSessionDic.ContainsKey(transaction.Sender)) { + requestTable["clientSessionID"] = m_sessionDic[transaction.Sender]; + requestTable["clientSecureSessionID"] = m_secureSessionDic[transaction.Sender]; + } + else { + requestTable["clientSessionID"] = UUID.Zero.ToString(); + requestTable["clientSecureSessionID"] = UUID.Zero.ToString(); + } + requestTable["transactionType"] = transaction.Type; + requestTable["amount"] = transaction.Amount; + requestTable["objectID"] = transaction.ObjectUUID; + requestTable["objectName"] = transaction.ObjectName; + requestTable["regionHandle"] = transaction.RegionHandle; + + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (user!=null) { + Hashtable responseTable = genericCurrencyXMLRPCRequest(requestTable, "OnMoneyTransfered", user.SimIP); + + if (responseTable!=null && responseTable.ContainsKey("success")) { + //User not online or failed to get object ? + if (!(bool)responseTable["success"]) { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: User {0} can't get the object, rolling back.", transaction.Sender); + if (RollBackTransaction(transaction)) { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed but roll back succeeded.", transactionUUID.ToString()); + } + else { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed and roll back failed as well.", + transactionUUID.ToString()); + } + } + else { + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} finished successfully.", transactionUUID.ToString()); + return true; + } + } + } + return false; + } + return true; + } + } + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed.", transactionUUID.ToString()); + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: exception occurred when transaction {0}: {1}", transactionUUID.ToString(), e.ToString()); + } + + return false; + } + + + + /// + /// Get the user balance. + /// + /// + /// + public XmlRpcResponse handleGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + int balance; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + m_log.InfoFormat("[MONEY RPC]: handleGetBalance: Getting balance for user {0}", clientUUID); + + if (m_sessionDic.ContainsKey(clientUUID) && m_secureSessionDic.ContainsKey(clientUUID)) { + if (m_sessionDic[clientUUID]==sessionID && m_secureSessionDic[clientUUID]==secureID) { + try { + balance = m_moneyDBService.getBalance(clientUUID); + if (balance==-1) // User not found + { + responseData["description"] = "user not found"; + responseData["clientBalance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleGetBalance: Can't get balance for user {0}, Exception {1}", clientUUID, e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handleGetBalance: Session authentication failed when getting balance for user " + clientUUID); + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method, string uri) + { + //m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: to {0}", uri); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!uri.StartsWith("https://")) { + m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file."); + //return null; + } + } + else { + if (!uri.StartsWith("https://") && !uri.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Invalid Region Server URL: {0}", uri); + return null; + } + } + + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + //XmlRpcRequest moneyModuleReq = new XmlRpcRequest(method, arrayParams); + //moneyServResp = moneyModuleReq.Send(uri, MONEYMODULE_REQUEST_TIMEOUT); + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + moneyServResp = moneyModuleReq.certSend(uri, m_clientCert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Unable to connect to Region Server {0}", uri); + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: {0}", ex.ToString()); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + /// + /// Update the client balance.We don't care about the result. + /// + /// + private void UpdateBalance(string userID, string message) + { + //m_log.InfoFormat("[MONEY RPC]: UpdateBalance: ID = {0}, Message = {1}", userID, message); + + string sessionID = string.Empty; + string secureID = string.Empty; + + if (m_sessionDic.ContainsKey(userID) && m_secureSessionDic.ContainsKey(userID)) { + sessionID = m_sessionDic[userID]; + secureID = m_secureSessionDic[userID]; + + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = userID; + requestTable["clientSessionID"] = sessionID; + requestTable["clientSecureSessionID"] = secureID; + requestTable["Balance"] = m_moneyDBService.getBalance(userID); + if (message!="") requestTable["Message"] = message; + + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + genericCurrencyXMLRPCRequest(requestTable, "UpdateBalance", user.SimIP); + m_log.InfoFormat("[MONEY RPC]: UpdateBalance: Sended UpdateBalance Request to {0}", user.SimIP.ToString()); + } + } + } + + + /// + /// RollBack the transaction if user failed to get the object paid + /// + /// + /// + protected bool RollBackTransaction(TransactionData transaction) + { + //m_log.InfoFormat("[MONEY RPC]: RollBackTransaction:"); + + if(m_moneyDBService.withdrawMoney(transaction.TransUUID, transaction.Receiver, transaction.Amount)) { + if(m_moneyDBService.giveMoney(transaction.TransUUID, transaction.Sender, transaction.Amount)) { + m_log.InfoFormat("[MONEY RPC]: RollBackTransaction: Transaction {0} is successfully.", transaction.TransUUID.ToString()); + m_moneyDBService.updateTransactionStatus(transaction.TransUUID, (int)Status.FAILED_STATUS, + "The buyer failed to get the object, roll back the transaction"); + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string senderName = "unknown user"; + string receiverName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + + string snd_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, receiverName, transaction.ObjectName); + string rcv_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, senderName, transaction.ObjectName); + + if (transaction.Sender!=transaction.Receiver) UpdateBalance(transaction.Sender, snd_message); + UpdateBalance(transaction.Receiver, rcv_message); + return true; + } + } + return false; + } + + + // + public XmlRpcResponse handleCancelTransfer(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string secureCode = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("secureCode")) secureCode = (string)requestData["secureCode"]; + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (string.IsNullOrEmpty(secureCode) || string.IsNullOrEmpty(transactionID)) { + m_log.Error("[MONEY RPC]: handleCancelTransfer: secureCode and/or transactionID are empty."); + return response; + } + + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + + try { + m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} wanted to cancel the transaction.", user.Avatar); + if (m_moneyDBService.ValidateTransfer(secureCode, transactionUUID)) { + m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} has canceled the transaction {1}", user.Avatar, transactionID); + m_moneyDBService.updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, + "User canceled the transaction on " + DateTime.UtcNow.ToString()); + responseData["success"] = true; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleCancelTransfer: Exception occurred when transaction {0}: {1}", transactionID, e.ToString()); + } + return response; + } + + + // + public XmlRpcResponse handleGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (m_sessionDic.ContainsKey(clientID) && m_secureSessionDic.ContainsKey(clientID)) { + if (m_sessionDic[clientID]==sessionID && m_secureSessionDic[clientID]==secureID) { + // + if (string.IsNullOrEmpty(transactionID)) { + responseData["description"] = "TransactionID is empty"; + m_log.Error("[MONEY RPC]: handleGetTransaction: TransactionID is empty."); + return response; + } + + try { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null) { + responseData["success"] = true; + responseData["amount"] = transaction.Amount; + responseData["time"] = transaction.Time; + responseData["type"] = transaction.Type; + responseData["sender"] = transaction.Sender.ToString(); + responseData["receiver"] = transaction.Receiver.ToString(); + responseData["description"] = transaction.Description; + } + else { + responseData["description"] = "Invalid Transaction UUID"; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: {0}", e.ToString()); + m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: Can't get transaction information for {0}", transactionUUID.ToString()); + } + return response; + } + } + + responseData["success"] = false; + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // In development + // + + public XmlRpcResponse handleWebLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebLogin:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, login failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (!m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Add(userID, webSessionID); + } + else m_webSessionDic[userID] = webSessionID; + } + + m_log.InfoFormat("[MONEY RPC]: handleWebLogin: User {0} has logged in from web.", userID); + responseData["success"] = true; + return response; + } + + + // + public XmlRpcResponse handleWebLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, log out failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Remove(userID); + } + } + + m_log.InfoFormat("[MONEY RPC]: handleWebLogout: User {0} has logged out from web.", userID); + responseData["success"] = true; + return response; + } + + + /// + /// Get balance method for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int balance = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance: Getting balance for user {0}", userID); + + //perform session check + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + balance = m_moneyDBService.getBalance(userID); + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + responseData["userName"] = user.Avatar; + } + else { + responseData["userName"] = "unknown user"; + } + // + // User not found + if (balance==-1) { + responseData["errorMessage"] = "User not found"; + responseData["balance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["balance"] = balance; + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleWebGetBalance: Can't get balance for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting balance"; + return response; + } + } + } + + m_log.Error("[MONEY RPC]: handleWebLogout: Session authentication failed when getting balance for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get transaction for web pages + /// + /// + /// + public XmlRpcResponse handleWebGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int lastIndex = -1; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + if (requestData.ContainsKey("lastIndex")) lastIndex = (int)requestData["lastIndex"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + int total = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + TransactionData tran = null; + m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction: Getting transation[{0}] for user {1}", lastIndex + 1, userID); + if (total > lastIndex + 2) { + responseData["isEnd"] = false; + } + else { + responseData["isEnd"] = true; + } + + tran = m_moneyDBService.FetchTransaction(userID, startTime, endTime, lastIndex); + if (tran!=null) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(tran.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(tran.Receiver); + if (senderInfo!=null && receiverInfo!=null) { + responseData["senderName"] = senderInfo.Avatar; + responseData["receiverName"] = receiverInfo.Avatar; + } + else { + responseData["senderName"] = "unknown user"; + responseData["receiverName"] = "unknown user"; + } + responseData["success"] = true; + responseData["transactionIndex"] = lastIndex + 1; + responseData["transactionUUID"] = tran.TransUUID.ToString(); + responseData["senderID"] = tran.Sender; + responseData["receiverID"] = tran.Receiver; + responseData["amount"] = tran.Amount; + responseData["type"] = tran.Type; + responseData["time"] = tran.Time; + responseData["status"] = tran.Status; + responseData["description"] = tran.Description; + } + else { + responseData["errorMessage"] = string.Format("Unable to fetch transaction data with the index {0}", lastIndex + 1); + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleWebGetTransaction: Can't get transaction for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting transaction"; + return response; + } + } + } + + m_log.Error("[MONEY RPC]: handleWebGetTransaction: Session authentication failed when getting transaction for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get total number of transactions for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetTransactionNum(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + int it = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + if (it>=0) { + m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum: Get {0} transactions for user {1}", it, userID); + responseData["success"] = true; + responseData["number"] = it; + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handleWebGetTransactionNum: Session authentication failed when getting transaction number for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + } + +} + diff --git a/release/0.9.1/src/OpenSim.Grid.MoneyServer/Program.cs b/release/0.9.1/src/OpenSim.Grid.MoneyServer/Program.cs new file mode 100644 index 0000000..3fbd12d --- /dev/null +++ b/release/0.9.1/src/OpenSim.Grid.MoneyServer/Program.cs @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net.Config; + +namespace OpenSim.Grid.MoneyServer +{ + class Program + { + public static void Main(string[] args) + { + XmlConfigurator.Configure(); + MoneyServerBase app = new MoneyServerBase(); + app.Startup(); + app.Work(); + } + } +} diff --git a/release/0.9.1/src/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs b/release/0.9.1/src/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..407ecee --- /dev/null +++ b/release/0.9.1/src/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Grid.MoneyServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("OpenSim.Grid.MoneyServer")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f554c84a-d8c7-41ea-833d-2483cde29e0f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/release/0.9.1/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs b/release/0.9.1/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs new file mode 100644 index 0000000..d39af60 --- /dev/null +++ b/release/0.9.1/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs @@ -0,0 +1,1903 @@ +// * Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp +// * +// * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ +// * See CONTRIBUTORS.TXT for a full list of copyright holders. +// * +// * Redistribution and use in source and binary forms, with or without +// * modification, are permitted provided that the following conditions are met: +// * * Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * * Redistributions in binary form must reproduce the above copyright +// * notice, this list of conditions and the following disclaimer in the +// * documentation and/or other materials provided with the distribution. +// * * Neither the name of the OpenSim Project nor the +// * names of its contributors may be used to endorse or promote products +// * derived from this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +// * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using Mono.Addins; + +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using NSL.Certificate.Tools; +using NSL.Network.XmlRpc; + + + +[assembly: Addin("DTLNSLMoneyModule", "1.0")] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] + + + +namespace OpenSim.Modules.Currency +{ + // + public enum TransactionType : int + { + None = 0, + // Extend + BirthGift = 900, + AwardPoints = 901, + // One-Time Charges + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + // Recurrent Charges + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + ScheduledFee = 2900, + // Inventory Transactions + GiveInventory = 3000, + // Transfers Between Users + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InvntorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + BuyMoney = 5010, + MoveMoney = 5011, + SendMoney = 5012, + // Group Transactions + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + // Stipend Credits + StipendBasic = 10000 + } + + +/* + // Refer to OpenMetaverse + public enum OpenMetaverse.MoneyTransactionType : int + { + None = 0, + FailSimulatorTimeout = 1, + FailDataserverTimeout = 2, + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + ObjectPublicClaim = 1003, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + GiveInventory = 3000, + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InventorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + ObjectRelease = 8000, + LandRelease = 8001, + ObjectDelete = 8002, + ObjectPublicDecay = 8003, + ObjectPublicDelete = 8004, + LindenAdjustment = 9000, + LindenGrant = 9001, + LindenPenalty = 9002, + EventFee = 9003, + EventPrize = 9004, + StipendBasic = 10000, + StipendDeveloper = 10001, + StipendAlways = 10002, + StipendDaily = 10003, + StipendRating = 10004, + StipendDelta = 10005 + } +*/ + + + // + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")] + public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule + { + #region Constant numbers and members. + + // Constant memebers + private const int MONEYMODULE_REQUEST_TIMEOUT = 10000; + + // Private data members. + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + //private bool m_enabled = true; + private bool m_sellEnabled = false; + private bool m_enable_server = true; // enable Money Server + + private IConfigSource m_config; + + private string m_moneyServURL = string.Empty; + public BaseHttpServer HttpServer; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + private X509Certificate2 m_cert = null; + + private bool m_use_web_settle = false; + private string m_settle_url = ""; + private string m_settle_message = ""; + private bool m_settle_user = false; + + private int m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用 + + + /// + /// Scene dictionary indexed by Region Handle + /// + private Dictionary m_sceneList = new Dictionary(); + + /// + /// To cache the balance data while the money server is not available. + /// + private Dictionary m_moneyServer = new Dictionary(); + + // Events + public event ObjectPaid OnObjectPaid; + + // Price + private int ObjectCount = 0; + private int PriceEnergyUnit = 100; + private int PriceObjectClaim = 10; + private int PricePublicObjectDecay = 4; + private int PricePublicObjectDelete = 4; + private int PriceParcelClaim = 1; + private float PriceParcelClaimFactor = 1.0f; + private int PriceUpload = 0; + private int PriceRentLight = 5; + private float PriceObjectRent = 1.0f; + private float PriceObjectScaleFactor = 10.0f; + private int PriceParcelRent = 1; + private int PriceGroupCreate = 0; + private int TeleportMinPrice = 2; + private float TeleportPriceExponent = 2.0f; + private float EnergyEfficiency = 1.0f; + + #endregion + + + // + public void Initialise(Scene scene, IConfigSource source) + { + Initialise(source); + if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false; + // + AddRegion(scene); + } + + + #region ISharedRegionModule interface + + public void Initialise(IConfigSource source) + { + //m_log.InfoFormat("[MONEY]: Initialise:"); + + // Handle the parameters errors. + if (source==null) return; + + try { + m_config = source; + + // [Economy] section + IConfig economyConfig = m_config.Configs["Economy"]; + + if (economyConfig.GetString("EconomyModule")!=Name) { + //m_enabled = false; + m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is disabled"); + return; + } + else { + m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is enabled"); + } + + m_sellEnabled = economyConfig.GetBoolean("SellEnabled", m_sellEnabled); + m_moneyServURL = economyConfig.GetString("CurrencyServer", m_moneyServURL); + + // クライアント証明書 + m_certFilename = economyConfig.GetString("ClientCertFilename", m_certFilename); + m_certPassword = economyConfig.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename!="") { + m_cert = new X509Certificate2(m_certFilename, m_certPassword); + //m_cert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.InfoFormat("[MONEY]: Issue Authentication of Client. Cert File is " + m_certFilename); + } + + // サーバ認証 + m_checkServerCert = economyConfig.GetBoolean("CheckServerCert", m_checkServerCert); + m_cacertFilename = economyConfig.GetString("CACertFilename", m_cacertFilename); + if (m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.InfoFormat("[MONEY]: Execute Authentication of Server. CA Cert File is " + m_cacertFilename); + } + else { + m_checkServerCert = false; + } + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + + + // Settlement + m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", m_use_web_settle); + m_settle_url = economyConfig.GetString ("SettlementURL", m_settle_url); + m_settle_message = economyConfig.GetString ("SettlementMessage", m_settle_message); + + // Price + PriceEnergyUnit = economyConfig.GetInt ("PriceEnergyUnit", PriceEnergyUnit); + PriceObjectClaim = economyConfig.GetInt ("PriceObjectClaim", PriceObjectClaim); + PricePublicObjectDecay = economyConfig.GetInt ("PricePublicObjectDecay", PricePublicObjectDecay); + PricePublicObjectDelete = economyConfig.GetInt ("PricePublicObjectDelete", PricePublicObjectDelete); + PriceParcelClaim = economyConfig.GetInt ("PriceParcelClaim", PriceParcelClaim); + PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", PriceParcelClaimFactor); + PriceUpload = economyConfig.GetInt ("PriceUpload", PriceUpload); + PriceRentLight = economyConfig.GetInt ("PriceRentLight", PriceRentLight); + PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", PriceObjectRent); + PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", PriceObjectScaleFactor); + PriceParcelRent = economyConfig.GetInt ("PriceParcelRent", PriceParcelRent); + PriceGroupCreate = economyConfig.GetInt ("PriceGroupCreate", PriceGroupCreate); + TeleportMinPrice = economyConfig.GetInt ("TeleportMinPrice", TeleportMinPrice); + TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", TeleportPriceExponent); + EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", EnergyEfficiency); + + // for HG Avatar + string avatar_class = economyConfig.GetString("HGAvatarAs", "HGAvatar").ToLower(); + if (avatar_class=="localavatar") m_hg_avatarClass = (int)AvatarType.LOCAL_AVATAR; + else if (avatar_class=="guestavatar") m_hg_avatarClass = (int)AvatarType.GUEST_AVATAR; + else if (avatar_class=="hgavatar") m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + else if (avatar_class=="foreignavatar") m_hg_avatarClass = (int)AvatarType.FOREIGN_AVATAR; + else m_hg_avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + } + catch { + m_log.ErrorFormat("[MONEY]: Initialise: Faile to read configuration file"); + } + } + + + public void AddRegion(Scene scene) + { + //m_log.InfoFormat("[MONEY]: AddRegion:"); + + if (scene==null) return; + + scene.RegisterModuleInterface(this); // 競合するモジュールの排除 + + lock (m_sceneList) { + if (m_sceneList.Count==0) { + if (m_enable_server) { + HttpServer = new BaseHttpServer(9000); + HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo)); + + HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler); + HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + HttpServer.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + HttpServer.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + + MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler); + MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + } + } + + if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle)) { + m_sceneList[scene.RegionInfo.RegionHandle] = scene; + } + else { + m_sceneList.Add(scene.RegionInfo.RegionHandle, scene); + } + } + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer += MoneyTransferAction; + scene.EventManager.OnValidateLandBuy += ValidateLandBuy; + scene.EventManager.OnLandBuy += processLandBuy; + } + + + public void RemoveRegion(Scene scene) + { + if (scene==null) return; + + lock (m_sceneList) { + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent -= MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer -= MoneyTransferAction; + scene.EventManager.OnValidateLandBuy -= ValidateLandBuy; + scene.EventManager.OnLandBuy -= processLandBuy; + } + } + + + public void RegionLoaded(Scene scene) + { + //m_log.InfoFormat("[MONEY]: RegionLoaded:"); + } + + + public Type ReplaceableInterface + { + //get { return typeof(IMoneyModule); } + get { return null; } + } + + + public bool IsSharedModule + { + get { return true; } + } + + + public string Name + { + get { return "DTLNSLMoneyModule"; } + } + + + public void PostInitialise() + { + //m_log.InfoFormat("[MONEY]: PostInitialise:"); + } + + + public void Close() + { + //m_log.InfoFormat("[MONEY]: Close:"); + } + + #endregion + + + #region IMoneyModule interface. + + // for LSL llGiveMoney() function + public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result) + { + //m_log.InfoFormat("[MONEY]: ObjectGiveMoney: LSL ObjectGiveMoney. UUID = {0}", objectID.ToString()); + + result = string.Empty; + if (!m_sellEnabled) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + + string objName = string.Empty; + string avatarName = string.Empty; + + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + objName = sceneObj.Name; + + Scene scene = GetLocateScene(toID); + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID); + if (account!=null) { + avatarName = account.FirstName + " " + account.LastName; + } + } + + bool ret = false; + string description = String.Format("Object {0} pays {1}", objName, avatarName); + + if (sceneObj.OwnerID==fromID) { + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + if (GetLocateClient(fromID)!=null) { + ret = TransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + else { + ret = ForceTransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + } + + if (!ret) result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return ret; + } + + + // + public int UploadCharge + { + get { return PriceUpload; } + } + + + // + public int GroupCreationCharge + { + get { return PriceGroupCreate; } + } + + + public int GetBalance(UUID agentID) + { + IClientAPI client = GetLocateClient(agentID); + return QueryBalanceFromMoneyServer(client); + } + + + public bool UploadCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public bool AmountCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public void ApplyUploadCharge(UUID agentID, int amount, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)TransactionType.UploadCharge, regionHandle, regionUUID, text); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type) + { + ApplyCharge(agentID, amount, type, string.Empty); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)type, regionHandle, regionUUID, text); + } + + + public bool Transfer(UUID fromID, UUID toID, int regionHandle, int amount, MoneyTransactionType type, string text) + { + return TransferMoney(fromID, toID, amount, (int)type, UUID.Zero, (ulong)regionHandle, UUID.Zero, text); + } + + + public bool Transfer(UUID fromID, UUID toID, UUID objectID, int amount, MoneyTransactionType type, string text) + { + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) return false; + + ulong regionHandle = sceneObj.ParentGroup.Scene.RegionInfo.RegionHandle; + UUID regionUUID = sceneObj.ParentGroup.Scene.RegionInfo.RegionID; + return TransferMoney(fromID, toID, amount, (int)type, objectID, (ulong)regionHandle, regionUUID, text); + } + + + // for 0.8.3 over + public void MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, string text) + { + ForceTransferMoney(fromAgentID, toAgentID, amount, (int)TransactionType.MoveMoney, UUID.Zero, (ulong)0, UUID.Zero, text); + } + + // for 0.9.1 over + public bool MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, MoneyTransactionType type, string text) + { + bool ret = ForceTransferMoney(fromAgentID, toAgentID, amount, (int)type, UUID.Zero, (ulong)0, UUID.Zero, text); + return ret; + } + + #endregion + + + #region MoneyModule event handlers + + // + private void OnNewClient(IClientAPI client) + { + m_log.InfoFormat("[MONEY]: OnNewClient"); + + client.OnEconomyDataRequest += OnEconomyDataRequest; + client.OnLogout += ClientClosed; + + client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + client.OnRequestPayPrice += OnRequestPayPrice; + client.OnObjectBuy += OnObjectBuy; + } + + + public void OnMakeRootAgent(ScenePresence agent) + { + m_log.InfoFormat("[MONEY]: OnMakeRootAgent:"); + + int balance = 0; + IClientAPI client = agent.ControllingClient; + + m_enable_server = LoginMoneyServer(agent, out balance); + client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + + //client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + //client.OnRequestPayPrice += OnRequestPayPrice; + //client.OnObjectBuy += OnObjectBuy; + } + + + // for OnClientClosed event + private void ClientClosed(IClientAPI client) + { + //m_log.InfoFormat("[MONEY]: ClientClosed:"); + + if (m_enable_server && client!=null) { + LogoffMoneyServer(client); + } + } + + + // for OnMakeChildAgent event + private void MakeChildAgent(ScenePresence avatar) + { + //m_log.InfoFormat("[MONEY]: MakeChildAgent:"); + } + + + // for OnMoneyTransfer event + private void MoneyTransferAction(Object sender, EventManager.MoneyTransferArgs moneyEvent) + { + //m_log.InfoFormat("[MONEY]: MoneyTransferAction: type = {0}", moneyEvent.transactiontype); + + if (!m_sellEnabled) return; + + // Check the money transaction is necessary. + if (moneyEvent.sender==moneyEvent.receiver) { + return; + } + + UUID receiver = moneyEvent.receiver; + // Pay for the object. + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + SceneObjectPart sceneObj = GetLocatePrim(moneyEvent.receiver); + if (sceneObj!=null) { + receiver = sceneObj.OwnerID; + } + else { + return; + } + } + + // Before paying for the object, save the object local ID for current transaction. + UUID objectID = UUID.Zero; + ulong regionHandle = 0; + UUID regionUUID = UUID.Zero; + + if (sender is Scene) { + Scene scene = (Scene)sender; + regionHandle = scene.RegionInfo.RegionHandle; + regionUUID = scene.RegionInfo.RegionID; + + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + objectID = scene.GetSceneObjectPart(moneyEvent.receiver).UUID; + } + } + + TransferMoney(moneyEvent.sender, receiver, moneyEvent.amount, moneyEvent.transactiontype, objectID, regionHandle, regionUUID, "OnMoneyTransfer event"); + return; + } + + + // for OnValidateLandBuy event + private void ValidateLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY]: ValidateLandBuy:"); + + IClientAPI senderClient = GetLocateClient(landBuyEvent.agentId); + if (senderClient!=null) { + int balance = QueryBalanceFromMoneyServer(senderClient); + if (balance >= landBuyEvent.parcelPrice) { + lock(landBuyEvent) { + landBuyEvent.economyValidated = true; + } + } + } + return; + } + + + // for LandBuy even + private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY]: processLandBuy:"); + + if (!m_sellEnabled) return; + + lock(landBuyEvent) { + if (landBuyEvent.economyValidated==true && landBuyEvent.transactionID==0) { + landBuyEvent.transactionID = Util.UnixTimeSinceEpoch(); + + ulong parcelID = (ulong)landBuyEvent.parcelLocalID; + UUID regionUUID = UUID.Zero; + if (sender is Scene) regionUUID = ((Scene)sender).RegionInfo.RegionID; + + if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID, + landBuyEvent.parcelPrice, (int)TransactionType.LandSale, regionUUID, parcelID, regionUUID, "Land Purchase")) { + landBuyEvent.amountDebited = landBuyEvent.parcelPrice; + } + } + } + return; + } + + + // for OnObjectBuy event + public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID, + UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice) + { + m_log.InfoFormat("[MONEY]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId); + + // Handle the parameters error. + if (!m_sellEnabled) return; + if (remoteClient==null || salePrice<0) return; + + // Get the balance from money server. + int balance = QueryBalanceFromMoneyServer(remoteClient); + if (balance(); + if (mod!=null) { + UUID receiverId = sceneObj.OwnerID; + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + bool ret = false; + // + if (salePrice>=0) { + if (!string.IsNullOrEmpty(m_moneyServURL)) { + ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice, + (int)TransactionType.PayObject, sceneObj.UUID, regionHandle, regionUUID, "Object Buy"); + } + else if (salePrice==0) { // amount is 0 with No Money Server + ret = true; + } + } + if (ret) { + mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); + } + } + } + else { + remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false); + return; + } + } + return; + } + + + /// + /// Sends the the stored money balance to the client + /// + /// + /// + /// + /// + private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID) + { + m_log.InfoFormat("[MONEY]: OnMoneyBalanceRequest:"); + + if (client.AgentId==agentID && client.SessionId==SessionID) { + int balance = 0; + // + if (m_enable_server) { + balance = QueryBalanceFromMoneyServer(client); + } + + client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + } + else { + client.SendAlertMessage("Unable to send your money balance"); + } + } + + + private void OnRequestPayPrice(IClientAPI client, UUID objectID) + { + m_log.InfoFormat("[MONEY]: OnRequestPayPrice:"); + + Scene scene = GetLocateScene(client.AgentId); + if (scene==null) return; + SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID); + if (sceneObj==null) return; + SceneObjectGroup group = sceneObj.ParentGroup; + SceneObjectPart root = group.RootPart; + + client.SendPayPrice(objectID, root.PayPrice); + } + + + // + //private void OnEconomyDataRequest(UUID agentId) + private void OnEconomyDataRequest(IClientAPI user) + { + //m_log.InfoFormat("[MONEY]: OnEconomyDataRequest:"); + //IClientAPI user = GetLocateClient(agentId); + + if (user!=null) { + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + //Scene s = GetLocateScene(user.AgentId); + Scene s = (Scene)user.Scene; + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, + PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, + PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, + TeleportMinPrice, TeleportPriceExponent); + } + } + } + + #endregion + + + #region MoneyModule XML-RPC Handler + + // "OnMoneyTransfered" RPC from MoneyServer + public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("transactionType") && requestParam.Contains("objectID") && requestParam.Contains("amount")) { + //m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]); + + // Pay for the object. + if ((int)requestParam["transactionType"]==(int)TransactionType.PayObject) { + // Send notify to the client(viewer) for Money Event Trigger. + ObjectPaid handlerOnObjectPaid = OnObjectPaid; + if (handlerOnObjectPaid!=null) { + UUID objectID = UUID.Zero; + UUID.TryParse((string)requestParam["objectID"], out objectID); + handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money() + } + ret = true; + } + } + } + } + } + } + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UpdateBalance" RPC from MoneyServer or Script + public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: BalanceUpdateHandler:"); + + bool ret = false; + + #region Update the balance from money server. + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + // + if (requestParam.Contains("Balance")) { + // Send notify to the client. + string msg = ""; + if (requestParam.Contains("Message")) msg = (string)requestParam["Message"]; + client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"], + 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + // Dialog + if (msg!="") { + Scene scene = (Scene)client.Scene; + IDialogModule dlg = scene.RequestModuleInterface(); + dlg.SendAlertToUser(client.AgentId, msg); + } + ret = true; + } + } + } + } + } + + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY]: BalanceUpdateHandler: Cannot update client balance from MoneyServer"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UserAlert" RPC from Script + public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: UserAlertHandler:"); + + bool ret = false; + + #region confirm the request and show the notice from money server. + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("Description")) + { + string description = (string)requestParam["Description"]; + // Show the notice dialog with money server message. + GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()), + (byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3()); + client.SendInstantMessage(gridMsg); + ret = true; + } + } + } + } + } + // + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + return resp; + } + + + // "GetBalance" RPC from Script + public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: GetBalanceHandler:"); + + bool ret = false; + int balance = -1; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + balance = QueryBalanceFromMoneyServer(client); + } + } + } + } + + // Send the response to caller. + if (balance<0) { + m_log.ErrorFormat("[MONEY]: GetBalanceHandler: GetBalance transaction is failed"); + ret = false; + } + + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + paramTable["balance"] = balance; + resp.Value = paramTable; + + return resp; + } + + + // "AddBankerMoney" RPC from Script + public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: AddBankerMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID bankerUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID); + // + if (bankerUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(bankerUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("amount")) + { + Scene scene = (Scene)client.Scene; + int amount = (int)requestParam["amount"]; + ulong regionHandle = scene.RegionInfo.RegionHandle; + UUID regionUUID = scene.RegionInfo.RegionID; + ret = AddBankerMoney(bankerUUID, amount, regionHandle, regionUUID); + + if (m_use_web_settle && m_settle_user) { + ret = true; + IDialogModule dlg = scene.RequestModuleInterface(); + if (dlg!=null) { + dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url); + } + } + } + } + } + } + } + + if (!ret) m_log.ErrorFormat("[MONEY]: AddBankerMoneyHandler: Add Banker Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["settle"] = false; + paramTable["success"] = ret; + + if (m_use_web_settle && m_settle_user) paramTable["settle"] = true; + resp.Value = paramTable; + + return resp; + } + + + // "SendMoney" RPC from Script + public XmlRpcResponse SendMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: SendMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("agentUUID") && requestParam.Contains("secretAccessCode")) { + UUID agentUUID = UUID.Zero; + UUID.TryParse((string)requestParam["agentUUID"], out agentUUID); + + if (agentUUID!=UUID.Zero) { + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + int type = -1; + if (requestParam.Contains("type")) type = (int)requestParam["type"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY]: SendMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = SendMoneyTo(agentUUID, amount, type, hash); + } + } + else { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("agentUUID")) { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: agentUUID is missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY]: SendMoneyHandler: Send Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + + // "MoveMoney" RPC from Script + public XmlRpcResponse MoveMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: MoveMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if ((requestParam.Contains("fromUUID") || requestParam.Contains("toUUID")) && requestParam.Contains("secretAccessCode")) { + UUID fromUUID = UUID.Zero; + UUID toUUID = UUID.Zero; // UUID.Zero means System + if (requestParam.Contains("fromUUID")) UUID.TryParse((string)requestParam["fromUUID"], out fromUUID); + if (requestParam.Contains("toUUID")) UUID.TryParse((string)requestParam["toUUID"], out toUUID); + + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY]: MoveMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = MoveMoneyFromTo(fromUUID, toUUID, amount, hash); + } + else { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("fromUUID") && !requestParam.Contains("toUUID")) { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: fromUUID and toUUID are missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: Move Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + #endregion + + + #region MoneyModule private help functions + + /// + /// Transfer the money from one user to another. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY]: TransferMoney:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY]: TransferMoney: Client {0} not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Force transfer the money from one user to another. + /// This function does not check sender login. + /// Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY]: ForceTransferMoney:"); + + bool ret = false; + + #region Force send transaction request to money server and parse the resultes. + + if (m_enable_server) { + string objName = string.Empty; + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj!=null)objName = sceneObj.Name; + + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = sender.ToString(); + paramTable["receiverID"] = receiver.ToString(); + paramTable["transactionType"] = type; + paramTable["objectID"] = objectID.ToString(); + paramTable["objectName"] = objName; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["amount"] = amount; + paramTable["description"] = description; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString()); + } + //else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Money Server is not available!!"); + + #endregion + + return ret; + } + + + /// + /// Send the money to avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool SendMoneyTo(UUID avatarID, int amount, int type, string secretCode) + { + //m_log.InfoFormat("[MONEY]: SendMoneyTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + if (type<0) type = (int)TransactionType.ReferBonus; + Hashtable paramTable = new Hashtable(); + paramTable["receiverID"] = avatarID.ToString(); + paramTable["transactionType"] = type; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Bonus to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Move the money from avatar to other avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool MoveMoneyFromTo(UUID senderID, UUID receiverID, int amount, string secretCode) + { + //m_log.InfoFormat("[MONEY]: MoveMoneyFromTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = senderID.ToString(); + paramTable["receiverID"] = receiverID.ToString(); + paramTable["transactionType"] = (int)TransactionType.MoveMoney; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Move Money"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "MoveMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Add the money to banker avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle, UUID regionUUID) + { + //m_log.InfoFormat("[MONEY]: AddBankerMoney:"); + + bool ret = false; + m_settle_user = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["bankerID"] = bankerID.ToString(); + paramTable["transactionType"] = (int)TransactionType.BuyMoney; + paramTable["amount"] = amount; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["description"] = "Add Money to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null) { + if (resultTable.Contains("success") && (bool)resultTable["success"]==true) { + ret = true; + } + else { + if (resultTable.Contains("banker")) { + m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used. + if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used."); + } + else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Fail Message {0}", resultTable["message"]); + } + } + else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not available!!"); + + return ret; + } + + + /// + /// Pay the money of charge. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY]: PayMoneyCharge:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY]: PayMoneyCharge: Client {0} is not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Login the money server when the new client login. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LoginMoneyServer(ScenePresence avatar, out int balance) + { + //m_log.InfoFormat("[MONEY]: LoginMoneyServer:"); + + balance = 0; + bool ret = false; + bool isNpc = avatar.IsNPC; + + IClientAPI client = avatar.ControllingClient; + + #region Send money server the client info for login. + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + Scene scene = (Scene)client.Scene; + string userName = string.Empty; + + // Get the username for the login user. + if (client.Scene is Scene) { + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId); + if (account!=null) { + userName = account.FirstName + " " + account.LastName; + } + } + } + + ////////////////////////////////////////////////////////////// + // User Universal Identifer for Grid Avatar, HG Avatar or NPC + string universalID = string.Empty; + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + int avatarType = (int)AvatarType.LOCAL_AVATAR; + int avatarClass = (int)AvatarType.LOCAL_AVATAR; + + AgentCircuitData agent = scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); + + if (agent!=null) { + universalID = Util.ProduceUserUniversalIdentifier(agent); + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + string tmp; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out tmp); + } + // if serverURL is empty, avatar is a NPC + if (isNpc || String.IsNullOrEmpty(serverURL)) { + avatarType = (int)AvatarType.NPC_AVATAR; + } + // + if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin)!=0 || String.IsNullOrEmpty(userName)) { + avatarType = (int)AvatarType.HG_AVATAR; + } + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // + avatarClass = avatarType; + if (avatarType==(int)AvatarType.NPC_AVATAR) return false; + if (avatarType==(int)AvatarType.HG_AVATAR) avatarClass = m_hg_avatarClass; + + // + // Lognn the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(), + scene.RegionInfo.HttpPort.ToString()); + paramTable["avatarType"] = avatarType.ToString(); + paramTable["avatarClass"] = avatarClass.ToString(); + paramTable["userName"] = userName; + paramTable["universalID"] = universalID; + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + balance = (int)resultTable["clientBalance"]; + m_log.InfoFormat("[MONEY]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL); + ret = true; + } + } + else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString()); + } + else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Money Server is not available!!"); + + #endregion + + // Viewerへ設定を通知する. + if (ret || string.IsNullOrEmpty(m_moneyServURL)) { + OnEconomyDataRequest(client); + } + + return ret; + } + + + /// + /// Log off from the money server. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LogoffMoneyServer(IClientAPI client) + { + //m_log.InfoFormat("[MONEY]: LogoffMoneyServer:"); + + bool ret = false; + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + // Log off from the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout"); + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + } + + return ret; + } + + + // + private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID) + { + //m_log.InfoFormat("[MONEY]: GetTransactionInfo:"); + + EventManager.MoneyTransferArgs args = null; + + if (m_enable_server) { + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + paramTable["transactionID"] = transactionID; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + int amount = (int)resultTable["amount"]; + int type = (int)resultTable["type"]; + string desc = (string)resultTable["description"]; + UUID sender = UUID.Zero; + UUID recver = UUID.Zero; + UUID.TryParse((string)resultTable["sender"], out sender); + UUID.TryParse((string)resultTable["receiver"], out recver); + args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc); + } + else { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]); + } + } + else { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Response"); + } + } + else { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Money Server URL"); + } + + return args; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method) + { + //m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest:"); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!m_moneyServURL.StartsWith("https://")) { + m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file"); + //return null; + } + } + else { + if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL); + return null; + } + } + + // + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL); + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: {0}", ex); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /// Locates a IClientAPI for the client specified + /// + /// + /// + private IClientAPI GetLocateClient(UUID AgentID) + { + IClientAPI client = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID); + if (tPresence!=null && !tPresence.IsChildAgent) { + IClientAPI rclient = tPresence.ControllingClient; + if (rclient!=null) { + client = rclient; + break; + } + } + } + } + } + + return client; + } + + + private Scene GetLocateScene(UUID AgentId) + { + Scene scene = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId); + if (tPresence!=null && !tPresence.IsChildAgent) { + scene = _scene; + break; + } + } + } + } + + return scene; + } + + + private SceneObjectPart GetLocatePrim(UUID objectID) + { + SceneObjectPart sceneObj = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID); + if (part!=null) { + sceneObj = part; + break; + } + } + } + } + + return sceneObj; + } + + #endregion + } + +} diff --git a/release/0.9.1/src/OpenSim.Modules.Currency/NSLCertificateTools.cs b/release/0.9.1/src/OpenSim.Modules.Currency/NSLCertificateTools.cs new file mode 100644 index 0000000..db0008c --- /dev/null +++ b/release/0.9.1/src/OpenSim.Modules.Currency/NSLCertificateTools.cs @@ -0,0 +1,226 @@ +/* + * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp + * + */ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Net; +using System.Net.Security; +using System.Text; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; + +using log4net; + + +namespace NSL.Certificate.Tools +{ + // + public class NSLCertificateVerify + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private X509Chain m_chain = null; + private X509Certificate2 m_cacert = null; + + private Mono.Security.X509.X509Crl m_clientcrl = null; + + + public NSLCertificateVerify() + { + m_chain = null; + m_cacert = null; + m_clientcrl = null; + } + + + public NSLCertificateVerify(string certfile) + { + SetPrivateCA(certfile); + } + + + public NSLCertificateVerify(string certfile, string crlfile) + { + SetPrivateCA (certfile); + SetPrivateCRL(crlfile); + } + + + public void SetPrivateCA(string certfile) + { + try { + m_cacert = new X509Certificate2(certfile); + } + catch (Exception ex) + { + m_cacert = null; + m_log.ErrorFormat("[SET PRIVATE CA]: CA File reading error [{0}]. {1}", certfile, ex); + } + + if (m_cacert!=null) { + m_chain = new X509Chain(); + m_chain.ChainPolicy.ExtraStore.Add(m_cacert); + m_chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + m_chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; + } + } + + + public void SetPrivateCRL(string crlfile) + { + try { + m_clientcrl = Mono.Security.X509.X509Crl.CreateFromFile(crlfile); + } + catch (Exception ex) + { + m_clientcrl = null; + m_log.ErrorFormat("[SET PRIVATE CRL]: CRL File reading error [{0}]. {1}", crlfile, ex); + } + } + + + // + // + // + public bool CheckPrivateChain(X509Certificate2 cert) + { + if (m_chain==null || m_cacert==null) { + return false; + } + + bool ret = m_chain.Build((X509Certificate2)cert); + if (ret) { + return true; + } + + for (int i=0; i tableList = new Dictionary(); + tableList = CheckTables(); + + // + // Balances Table + if (!tableList.ContainsKey(Table_of_Balances)) { + try { + CreateBalancesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating balances table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_Balances].Trim(); + int nVer = getTableVersionNum(version); + balances_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateBalancesTable1(); + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 2: //Rev.2 + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 3: //Rev.3 + UpdateBalancesTable3(); + break; + } + } + + // + // UserInfo Table + if (!tableList.ContainsKey(Table_of_UserInfo)) { + try { + CreateUserInfoTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating userinfo table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_UserInfo].Trim(); + int nVer = getTableVersionNum(version); + userinfo_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateUserInfoTable1(); + UpdateUserInfoTable2(); + break; + case 2: //Rev.2 + UpdateUserInfoTable2(); + break; + } + } + + // + // Transactions Table + if (!tableList.ContainsKey(Table_of_Transactions)) { + try { + CreateTransactionsTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating transactions table: " + e.ToString()); + } + } + // check transactions table version + else { + string version = tableList[Table_of_Transactions].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 2: //Rev.2 + UpdateTransactionsTable2(); + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 3: //Rev.3 + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 4: //Rev.4 + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 5: //Rev.5 + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 6: //Rev.6 + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 7: //Rev.7 + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 8: //Rev.8 + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 9: //Rev.9 + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 10: //Rev.10 + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 11: //Rev.11 + UpdateTransactionsTable11(); + break; + } + } + + // + // TotalSales Table + if (!tableList.ContainsKey(Table_of_TotalSales)) { + try { + CreateTotalSalesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating totalsales table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_TotalSales].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 1: //Rev.1 + UpdateTotalSalesTable1(); + UpdateTotalSalesTable2(); + break; + case 2: //Rev.2 + UpdateTotalSalesTable2(); + break; + } + } + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + throw new Exception("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + } + } + + + private int getTableVersionNum(string version) + { + int nVer = 0; + + Regex _commentPattenRegex = new Regex(@"\w+\.(?\d+)"); + Match m = _commentPattenRegex.Match(version); + if (m.Success) { + string ver = m.Groups["ver"].Value; + nVer = Convert.ToInt32(ver); + } + return nVer; + } + + + + /////////////////////////////////////////////////////////////////////// + // create Tables + + private void CreateBalancesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Balances + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`balance` int(10) NOT NULL,"; + sql += "`status` tinyint(2) DEFAULT NULL,"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.4';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateUserInfoTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_UserInfo + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`simip` varchar(64) NOT NULL,"; + sql += "`avatar` varchar(50) NOT NULL,"; + sql += "`pass` varchar(36) NOT NULL DEFAULT '',"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`class` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`serverurl` varchar(255) NOT NULL DEFAULT '',"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTransactionsTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Transactions + "`("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`sender` varchar(36) NOT NULL,"; + sql += "`receiver` varchar(36) NOT NULL,"; + sql += "`amount` int(10) NOT NULL,"; + sql += "`senderBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`receiverBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`objectUUID` varchar(36) DEFAULT NULL,"; + sql += "`objectName` varchar(255) DEFAULT NULL,"; + sql += "`regionHandle` varchar(36) NOT NULL,"; + sql += "`regionUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`time` int(11) NOT NULL,"; + sql += "`secure` varchar(36) NOT NULL,"; + sql += "`status` tinyint(1) NOT NULL,"; + sql += "`commonName` varchar(128) NOT NULL,"; + sql += "`description` varchar(255) DEFAULT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.12';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTotalSalesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_TotalSales + "` ("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`objectUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`TotalCount` int(10) NOT NULL DEFAULT 0,"; + sql += "`TotalAmount` int(10) NOT NULL DEFAULT 0,"; + sql += "`time` int(11) NOT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + initTotalSalesTable(); + } + + + + /////////////////////////////////////////////////////////////////////// + // update Balances Table + + private void UpdateBalancesTable1() + { + m_log.Info("[MONEY MANAGER]: Converting Balance Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Balances; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT * FROM " + Table_of_Balances; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i=0) { + amount += balance; + updatedb = updateBalance(uuid, amount); + } + else { + updatedb = addUser(uuid, amount, int.Parse(row[i,2]), 0); + } + if (!updatedb) break; + } + } + + // Delete + if (updatedb) { + for (int i=0; i uuid, url, name, pass + bool updatedb = true; + for (int i=0; i + /// update transactions table from Rev.2 to Rev.3 + /// + private void UpdateTransactionsTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`objectUUID` varchar(36) DEFAULT NULL AFTER `amount`),"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.3 to Rev.4 + /// + private void UpdateTransactionsTable3() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`secure` varchar(36) NOT NULL AFTER `time`),"; + sql += "COMMENT = 'Rev.4';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.4 to Rev.5 + /// + private void UpdateTransactionsTable4() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`regionHandle` varchar(36) NOT NULL AFTER `objectUUID`),"; + sql += "COMMENT = 'Rev.5';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.5 to Rev.6 + /// + private void UpdateTransactionsTable5() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`commonName` varchar(128) NOT NULL AFTER `status`),"; + sql += "COMMENT = 'Rev.6';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.6 to Rev.7 + /// + private void UpdateTransactionsTable6() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Transactions; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT UUID,sender,receiver FROM " + Table_of_Transactions; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i + /// update transactions table from Rev.7 to Rev.8 + /// + private void UpdateTransactionsTable7() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `objectName` varchar(255) DEFAULT NULL AFTER `objectUUID`,"; + sql += "COMMENT = 'Rev.8';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.8 to Rev.9 + /// + private void UpdateTransactionsTable8() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `senderBalance` int(10) NOT NULL DEFAULT -1 AFTER `amount`,"; + sql += "ADD `receiverBalance` int(10) NOT NULL DEFAULT -1 AFTER `senderBalance`,"; + sql += "COMMENT = 'Rev.9';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.9 to Rev.10 + /// + private void UpdateTransactionsTable9() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "MODIFY COLUMN `sender` varchar(36) NOT NULL,"; + sql += "MODIFY COLUMN `receiver` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.10';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.10 to Rev.11 + /// change type of BirthGift from 1000 to 900 + /// + private void UpdateTransactionsTable10() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM `" + Table_of_Transactions + "` WHERE type=1000"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + if (resultCount>0) { + sql = "SELECT UUID FROM `" + Table_of_Transactions + "` WHERE type=1000"; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[] row = new string[resultCount]; + while (dbReader.Read()) { + row[l] = dbReader.GetString(0); + l++; + } + dbReader.Close(); + cmd.Dispose(); + + sql = "UPDATE `" + Table_of_Transactions + "` SET type=900 WHERE UUID=?uuid"; + for (int i=0; i + /// update transactions table from Rev.11 to Rev.12 + /// + private void UpdateTransactionsTable11() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `regionUUID` varchar(36) NOT NULL AFTER `regionHandle`,"; + sql += "COMMENT = 'Rev.12';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + // update Total Sales Table + + private void UpdateTotalSalesTable1() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "ADD `time` int(11) NOT NULL AFTER `TotalAmount`,"; + sql += "COMMENT = 'Rev.2';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + deleteTotalSalesTable(); + initTotalSalesTable(); + } + + + private void UpdateTotalSalesTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "MODIFY COLUMN `user` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + // + + private Dictionary CheckTables() + { + Dictionary tableDic = new Dictionary(); + + lock (dbcon) { + string sql = string.Empty; + + sql = "SELECT TABLE_NAME,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?dbname"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?dbname", dbcon.Database); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + while (r.Read()) { + try { + string tableName = (string)r["TABLE_NAME"]; + string comment = (string)r["TABLE_COMMENT"]; + tableDic.Add(tableName, comment); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error checking tables" + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return tableDic; + } + } + + + /// + /// Reconnect to the database + /// + public void Reconnect() + { + m_log.Info("[MONEY MANAGER]: Reconnecting database"); + lock (dbcon) { + try { + dbcon.Close(); + dbcon = new MySqlConnection(connectString); + dbcon.Open(); + m_log.Info("[MONEY MANAGER]: Reconnected database"); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to reconnect to database: " + e.ToString()); + } + } + } + + + + /////////////////////////////////////////////////////////////////////// + // + // balances + // + + /// + /// Get balance from database. returns -1 if failed. + /// + /// + /// + public int getBalance(string userID) + { + if (userID==UUID.Zero.ToString()) return 999999999; // System + + int retValue = -1; + string sql = string.Empty; + + sql = "SELECT balance FROM " + Table_of_Balances + " WHERE user = ?userid"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userid", userID); + + using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { + try { + if (dbReader.Read()) { + retValue = Convert.ToInt32(dbReader["balance"]); + } + } + catch (Exception e) { + m_log.ErrorFormat("[MoneyDB]: MySql failed to fetch balance {0}.", userID); + retValue = -2; + } + dbReader.Close(); + } + cmd.Dispose(); + + return retValue; + } + + + public bool updateBalance(string userID, int amount) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Balances + " SET balance = ?amount WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userID", userID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool addUser(string userID, int balance, int status, int type) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + if (balances_rev>=4) { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`,`type`) VALUES "; + sql += " (?userID,?balance,?status,?type);"; + } + else { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`) VALUES "; + sql += " (?userID,?balance,?status);"; + } + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userID", userID); + cmd.Parameters.AddWithValue("?balance", balance); + cmd.Parameters.AddWithValue("?status", status); + if (balances_rev>=4) { + cmd.Parameters.AddWithValue("?type", type); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + + return bRet; + } + + + /// + /// Here we'll make a withdraw from the sender and update transaction status + /// + /// + /// + /// + /// + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + bool bRet = false; + string sql = string.Empty; + MySqlCommand cmd = null; + + // System + if (senderID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET senderBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET senderBalance = balance - ?amount, "+ Table_of_Transactions + ".status = ?status, balance = balance - ?amount "; + sql += " WHERE UUID = ?tranid AND user = sender AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", senderID); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Give money to the receiver and change the transaction status to success. + /// + /// + /// + /// + /// + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + string sql = string.Empty; + bool bRet = false; + MySqlCommand cmd = null; + + // System + if (receiverID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET receiverBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET receiverBalance = balance + ?amount, " + Table_of_Transactions + ".status = ?status, balance = balance + ?amount "; + sql += " WHERE UUID = ?tranid AND user = receiver AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", receiverID); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // totalsales + // + private void initTotalSalesTable() + { + m_log.Info("[MONEY MANAGER]: Initailising TotalSales Table..."); + string sql = string.Empty; + + sql = "SELECT SQL_CALC_FOUND_ROWS receiver,objectUUID,type,COUNT(*),SUM(amount),MIN(time) FROM "+ Table_of_Transactions; + sql += " WHERE sender != receiver AND status = ?status AND sender != ?system"; + sql += " GROUP BY receiver,objectUUID,type;"; + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); + cmd.Parameters.AddWithValue("?system", UUID.Zero.ToString()); + cmd.ExecuteNonQuery(); + + MySqlCommand cmd2 = new MySqlCommand("SELECT FOUND_ROWS();", dbcon); + int lineCount = int.Parse(cmd2.ExecuteScalar().ToString()); + cmd2.Dispose(); + + if (lineCount<=0) { + cmd.Dispose(); + return; + } + + MySqlDataReader r = cmd.ExecuteReader(); + int l = 0; + string[,] row = new string[lineCount, r.FieldCount]; + while (r.Read()) { + for (int i=0; i 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTotalSale(UUID saleUUID, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_TotalSales; + sql += " SET TotalCount = TotalCount + ?count, TotalAmount = TotalAmount + ?amount, time = ?time "; + sql += " WHERE UUID = ?uuid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?uuid", saleUUID.ToString()); + cmd.Parameters.AddWithValue("?count", count); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?time", tmstamp); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + + } + + + public bool setTotalSale(string userUUID, string objectUUID, int type, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + string uuid = string.Empty; + int dbtm = 0; + + sql = "SELECT UUID,time FROM " + Table_of_TotalSales; + sql += " WHERE user = ?userid AND objectUUID = ?objID AND type = ?type;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userid", userUUID); + cmd.Parameters.AddWithValue("?objID", objectUUID); + cmd.Parameters.AddWithValue("?type", type); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + uuid = (string)r["UUID"]; + dbtm = Convert.ToInt32(r["time"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get sale data from DB failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return false; + } + } + r.Close(); + } + + if (uuid!=string.Empty) { + UUID saleUUID = UUID.Zero; + UUID.TryParse(uuid, out saleUUID); + if (dbtm 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions + " SET status = ?status,description = ?desc WHERE UUID = ?tranid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", status); + cmd.Parameters.AddWithValue("?desc", description); + cmd.Parameters.AddWithValue("?tranid", transactionID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool SetTransExpired(int deadTime) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions; + sql += " SET status = ?failedstatus,description = ?desc WHERE time <= ?deadTime AND status = ?pendingstatus;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?failedstatus", (int)Status.FAILED_STATUS); + cmd.Parameters.AddWithValue("?desc", "expired"); + cmd.Parameters.AddWithValue("?deadTime", deadTime); + cmd.Parameters.AddWithValue("?pendingstatus", (int)Status.PENDING_STATUS); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Validate if the transacion is legal + /// + /// + /// + /// + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + bool bRet = false; + string secure = string.Empty; + string sql = string.Empty; + + sql = "SELECT secure FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + secure = (string)r["secure"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get transaction from DB failed: " + e.ToString()); + } + if (secureCode == secure) bRet = true; + else bRet = false; + } + r.Close(); + } + + cmd.Dispose(); + return bRet; + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + TransactionData transactionData = new TransactionData(); + transactionData.TransUUID = transactionID; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 1: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + + } + r.Close(); + } + + cmd.Dispose(); + return transactionData; + } + + + public TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index, uint retNum) + { + List rows = new List(); + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user) ORDER BY time ASC LIMIT ?index,?num;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + cmd.Parameters.AddWithValue("?index", index); + cmd.Parameters.AddWithValue("?num", retNum); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + for (int i = 0; i < retNum; i++) { + if (r.Read()) { + try { + TransactionData transactionData = new TransactionData(); + string uuid = (string)r["UUID"]; + UUID transUUID; + UUID.TryParse(uuid,out transUUID); + + transactionData.TransUUID = transUUID; + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + // + rows.Add(transactionData); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 2: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + } + r.Close(); + } + + cmd.Dispose(); + return rows.ToArray(); + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + int iRet = -1; + string sql = string.Empty; + + sql = "SELECT COUNT(*) AS number FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user);"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + iRet = Convert.ToInt32(r["number"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to get transaction info: " + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return iRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // userinfo + // + public bool addUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Adding UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + if (userInfo.Avatar==null) return false; + + if (userinfo_rev>=3) { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`,`type`,`class`,`serverurl`) VALUES"; + sql += "(?user,?simip,?avatar,?password,?type,?class,?serverurl);"; + } + else { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`) VALUES"; + sql += "(?user,?simip,?avatar,?password);"; + } + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?avatar", userInfo.Avatar); + cmd.Parameters.AddWithValue("?password", userInfo.PswHash); + if (userinfo_rev>=3) { + cmd.Parameters.AddWithValue("?type", userInfo.Type); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + } + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public UserInfo fetchUserInfo(string userID) + { + //m_log.Error("[MONEY MANAGER]: Fetching UserInfo: " + userID); + + UserInfo userInfo = new UserInfo(); + userInfo.UserID = null; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_UserInfo + " WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userID", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + userInfo.UserID = (string)r["user"]; + userInfo.SimIP = (string)r["simip"]; + userInfo.Avatar = (string)r["avatar"]; + userInfo.PswHash = (string)r["pass"]; + userInfo.Type = Convert.ToInt32(r["type"]); + userInfo.Class = Convert.ToInt32(r["class"]); + userInfo.ServerURL = (string)r["serverurl"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching UserInfo failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + r.Close(); + } + cmd.Dispose(); + + if (userInfo.UserID!=userID) return null; + return userInfo; + } + + + public bool updateUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Updating UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_UserInfo + " SET simip=?simip,pass=?pass,class=?class,serverurl=?serverurl WHERE user=?user;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?pass", userInfo.PswHash); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + } +} diff --git a/release/0.9.1_1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs b/release/0.9.1_1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs new file mode 100644 index 0000000..cd2bae4 --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Threading; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + // This bit of code is from OpenSim.Data.MySQLSuperManager + public class MySQLSuperManager + { + public bool Locked; + private readonly Mutex m_lock = new Mutex(false); + public MySQLMoneyManager Manager; + public string Running; + + public void GetLock() + { + Locked = true; + m_lock.WaitOne(); + } + + public void Release() + { + m_lock.ReleaseMutex(); + Locked = false; + } + } +} diff --git a/release/0.9.1_1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs b/release/0.9.1_1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs new file mode 100644 index 0000000..e73b579 --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs @@ -0,0 +1,237 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public class TransactionData + { + UUID m_uuid; + string m_sender = string.Empty; + string m_receiver = string.Empty; + int m_amount; + int m_senderBalance; + int m_receiverBalance; + int m_type; + int m_time; + int m_status; + string m_objectID = UUID.Zero.ToString(); +// string m_objectID = "00000000-0000-0000-0000-000000000000"; + string m_objectName = string.Empty; + string m_regionHandle = string.Empty; + string m_regionUUID = string.Empty; + string m_secureCode = string.Empty; + string m_commonName = string.Empty; + string m_description = string.Empty; + +/* + public TransactionData(string uuid, string sender, string receiver, + int amount, int time, int status, string description) + { + this.m_uuid = uuid; + this.m_sender = sender; + this.m_receiver = receiver; + this.m_amount = amount; + } +*/ + + public UUID TransUUID + { + get { return m_uuid; } + set { m_uuid = value; } + } + + public string Sender + { + get { return m_sender; } + set { m_sender = value; } + } + + public string Receiver + { + get { return m_receiver; } + set { m_receiver = value; } + } + + public int Amount + { + get { return m_amount; } + set { m_amount = value; } + } + + public int SenderBalance + { + get { return m_senderBalance; } + set { m_senderBalance = value; } + } + + public int ReceiverBalance + { + get { return m_receiverBalance; } + set { m_receiverBalance = value; } + } + + public int Type + { + get { return m_type; } + set { m_type = value; } + } + + public int Time + { + get { return m_time; } + set { m_time = value; } + } + + public int Status + { + get { return m_status; } + set { m_status = value; } + } + + public string Description + { + get { return m_description; } + set { m_description = value; } + } + + public string ObjectUUID + { + get { return m_objectID; } + set { m_objectID = value; } + } + + public string ObjectName + { + get { return m_objectName; } + set { m_objectName = value; } + } + + public string RegionHandle + { + get { return m_regionHandle; } + set { m_regionHandle = value; } + } + + public string RegionUUID + { + get { return m_regionUUID; } + set { m_regionUUID = value; } + } + + public string SecureCode + { + get { return m_secureCode; } + set { m_secureCode = value; } + } + + public string CommonName + { + get { return m_commonName; } + set { m_commonName = value; } + } + } + + + public enum Status + { + SUCCESS_STATUS = 0, + PENDING_STATUS = 1, + FAILED_STATUS = 2, + ERROR_STATUS = 9 + } + + + public enum AvatarType + { + LOCAL_AVATAR = 0, + HG_AVATAR = 1, + NPC_AVATAR = 2, + GUEST_AVATAR = 3, + FOREIGN_AVATAR = 8, + UNKNOWN_AVATAR = 9 + } + + + public class UserInfo + { + string m_userID = string.Empty; + string m_simIP = string.Empty; + string m_avatarName = string.Empty; + string m_passwordHash = string.Empty; + int m_avatarType = (int)AvatarType.LOCAL_AVATAR; + int m_avatarClass = (int)AvatarType.LOCAL_AVATAR; + string m_serverURL = string.Empty; + + public string UserID + { + get { return m_userID; } + set { m_userID = value; } + } + + public string SimIP + { + get { return m_simIP; } + set { m_simIP = value; } + } + + public string Avatar + { + get { return m_avatarName; } + set { m_avatarName = value; } + } + + public string PswHash + { + get { return m_passwordHash; } + set { m_passwordHash = value; } + } + + public int Type + { + get { return m_avatarType; } + set { m_avatarType = value; } + } + + public int Class + { + get { return m_avatarClass; } + set { m_avatarClass = value; } + } + + public string ServerURL + { + get { return m_serverURL; } + set { m_serverURL = value; } + } + } +} diff --git a/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs new file mode 100644 index 0000000..7140c0f --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs @@ -0,0 +1,70 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenMetaverse; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; + + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyDBService + { + int getBalance(string userID); + + bool withdrawMoney(UUID transactionID, string senderID, int amount); + + bool giveMoney(UUID transactionID, string receiverID, int amount); + + bool addTransaction(TransactionData transaction); + + bool addUser(string userID, int balance, int status, int type); + + bool updateTransactionStatus(UUID transactionID, int status, string description); + + bool SetTransExpired(int deadTime); + + bool ValidateTransfer(string secureCode, UUID transactionID); + + TransactionData FetchTransaction(UUID transactionID); + + TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex); + + int getTransactionNum(string userID, int startTime, int endTime); + + bool DoTransfer(UUID transactionUUID); + + bool DoAddMoney(UUID transactionUUID); // Added by Fumi.Iseki + + bool TryAddUserInfo(UserInfo user); + + UserInfo FetchUserInfo(string userID); + } +} diff --git a/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs new file mode 100644 index 0000000..d6e3721 --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; + +using Nini.Config; + + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyServiceCore + { + BaseHttpServer GetHttpServer(); + Dictionary GetSessionDic(); + Dictionary GetSecureSessionDic(); + Dictionary GetWebSessionDic(); + + // + IConfig GetServerConfig(); + IConfig GetCertConfig(); + bool IsCheckClientCert(); + } +} diff --git a/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs new file mode 100644 index 0000000..efa72b4 --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs @@ -0,0 +1,570 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using log4net; +using System.Reflection; +using OpenMetaverse; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyDBService: IMoneyDBService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string m_connect; + //private MySQLMoneyManager m_moneyManager; + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + // DB manager pool + protected Dictionary m_dbconnections = new Dictionary(); // Lock付 + private int m_maxConnections; + + public int m_lastConnect = 0; + + + public MoneyDBService(string connect) + { + m_connect = connect; + Initialise(m_connect,10); + } + + + public MoneyDBService() + { + } + + + public void Initialise(string connectionString, int maxDBConnections) + { + m_connect = connectionString; + m_maxConnections = maxDBConnections; + if (connectionString != string.Empty) { + //m_moneyManager = new MySQLMoneyManager(connectionString); + + //m_log.Info("Creating " + m_maxConnections + " DB connections..."); + for (int i=0; im_maxConnections) { + lockedCons = 0; + System.Threading.Thread.Sleep(1000); // Wait some time before searching them again. + m_log.Debug("WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound."); + } + } + } + + + public int getBalance(string userID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getBalance(userID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.getBalance(userID); + } + catch(Exception e) { + m_log.Error(e.ToString()); + return 0; + } + finally { + dbm.Release(); + } + } + + + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool setTotalSale(TransactionData transaction) + { + if (transaction.Receiver==transaction.Sender) return false; + if (transaction.Sender==UUID.Zero.ToString()) return false; + + MySQLSuperManager dbm = GetLockedConnection(); + + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addTransaction(TransactionData transaction) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.addTransaction(transaction); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.addTransaction(transaction); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addUser(string userID, int balance, int status, int type) + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = UUID.Random(); + transaction.Sender = UUID.Zero.ToString(); + transaction.Receiver = userID; + transaction.Amount = balance; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.ObjectName = string.Empty; + transaction.RegionHandle = string.Empty; + transaction.Type = (int)TransactionType.BirthGift; + transaction.Time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);; + transaction.Status = (int)Status.PENDING_STATUS; + transaction.SecureCode = UUID.Random().ToString(); + transaction.CommonName = string.Empty; + transaction.Description = "addUser " + DateTime.UtcNow.ToString(); + + bool ret = addTransaction(transaction); + if (!ret) return false; + + // + MySQLSuperManager dbm = GetLockedConnection(); + + try { + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + + // + if (ret) ret = giveMoney(transaction.TransUUID, userID, balance); + return ret; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool SetTransExpired(int deadTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.SetTransExpired(deadTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.SetTransExpired(deadTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.FetchTransaction(transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.FetchTransaction(transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex) + { + MySQLSuperManager dbm = GetLockedConnection(); + TransactionData[] arrTransaction; + + uint index = 0; + if (lastIndex>=0) index = Convert.ToUInt32(lastIndex) + 1; + + try { + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + + // + if (arrTransaction.Length > 0) { + return arrTransaction[0]; + } + else { + return null; + } + } + + + public bool DoTransfer(UUID transactionUUID) + { + bool do_trans = false; + + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction != null && transaction.Status == (int)Status.PENDING_STATUS) { + int balance = getBalance(transaction.Sender); + + //check the amount + if (transaction.Amount >= 0 && balance >= transaction.Amount) { + if (withdrawMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver) == -1) { + m_log.ErrorFormat("[MONEY DB]: DoTransfer: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + do_trans = true; + } + else { // give money to receiver failed. 返金処理 + m_log.ErrorFormat("[MONEY DB]: Give money to receiver {0} failed", transaction.Receiver); + //Return money to sender + if (giveMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + m_log.ErrorFormat("[MONEY DB]: give money to receiver {0} failed but return it to sender {1} successfully", + transaction.Receiver, transaction.Sender); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "give money to receiver failed but return it to sender successfully"); + } + else { + m_log.ErrorFormat("[MONEY DB]: FATAL ERROR: Money withdrawn from sender: {0}, but failed to be given to receiver {1}", + transaction.Sender, transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.ERROR_STATUS, "give money to receiver failed, and return it to sender unsuccessfully!!!"); + } + } + } + else { // withdraw money failed + m_log.ErrorFormat("[MONEY DB]: Withdraw money from sender {0} failed", transaction.Sender); + } + } + else { // not enough balance to finish the transaction + m_log.ErrorFormat("[MONEY DB]: Not enough balance for user: {0} to apply the transaction.", transaction.Sender); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + // + if (do_trans) { + setTotalSale(transaction); + } + + return do_trans; + } + + + // by Fumi.Iseki + public bool DoAddMoney(UUID transactionUUID) + { + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction!=null && transaction.Status==(int)Status.PENDING_STATUS) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver)==-1) { + m_log.ErrorFormat("[MONEY DB]: DoAddMoney: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + // + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + setTotalSale(transaction); + return true; + } + else { // give money to receiver failed. + m_log.ErrorFormat("[MONEY DB]: Add money to receiver {0} failed", transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "add money to receiver failed"); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + return false; + } + + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // userinfo + // + + public bool TryAddUserInfo(UserInfo user) + { + MySQLSuperManager dbm = GetLockedConnection(); + + UserInfo userInfo = null; + + try { + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + dbm.Release(); + return false; + } + + try { + if (userInfo!=null) { + //m_log.InfoFormat("[MONEY DB]: Found user \"{0}\", now update information", user.Avatar); + if (dbm.Manager.updateUserInfo(user)) return true; + } + else if (dbm.Manager.addUserInfo(user)) { + //m_log.InfoFormat("[MONEY DB]: Unable to find user \"{0}\", add it to DB successfully", user.Avatar); + return true; + } + m_log.InfoFormat("[MONEY DB]: WARNNING: TryAddUserInfo: Unable to TryAddUserInfo."); + return false; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public UserInfo FetchUserInfo(string userID) + { + UserInfo userInfo = null; + MySQLSuperManager dbm = GetLockedConnection(); + + try { + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + dbm.Manager.Reconnect(); + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return -1; + } + finally { + dbm.Release(); + } + } + } +} diff --git a/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs new file mode 100644 index 0000000..9023c6e --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs @@ -0,0 +1,339 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Security; +using System.Reflection; +using System.Timers; +//using System.Security.Authentication; +//using System.Security.Cryptography; +//using System.Security.Cryptography.X509Certificates; + +using HttpServer; +using Nini.Config; +using log4net; + +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data; + +using NSL.Certificate.Tools; + + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string connectionString = string.Empty; + private uint m_moneyServerPort = 8008; // 8008 is default server port + + private string m_certFilename = ""; + private string m_certPassword = ""; + private string m_cacertFilename = ""; + private string m_clcrlFilename = ""; + private bool m_checkClientCert = false; + + private int DEAD_TIME = 120; + private int MAX_DB_CONNECTION = 10; + + private MoneyXmlRpcModule m_moneyXmlRpcModule; + private MoneyDBService m_moneyDBService; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // クライアント認証用 + + private Dictionary m_sessionDic = new Dictionary(); + private Dictionary m_secureSessionDic = new Dictionary(); + private Dictionary m_webSessionDic = new Dictionary(); + + IConfig m_server_config; + IConfig m_cert_config; + + + public MoneyServerBase() + { + m_console = new LocalConsole("Money "); +// m_console = new CommandConsole("Money "); + MainConsole.Instance = m_console; + } + + + public void Work() + { + //m_console.Notice("Enter help for a list of commands\n"); + + //The timer checks the transactions table every 60 seconds + Timer checkTimer = new Timer(); + checkTimer.Interval = 60*1000; + checkTimer.Enabled = true; + checkTimer.Elapsed += new ElapsedEventHandler(CheckTransaction); + checkTimer.Start(); + + while (true) { + m_console.Prompt(); + } + } + + + /// + /// Check the transactions table, set expired transaction state to failed + /// + private void CheckTransaction(object sender, ElapsedEventArgs e) + { + long ticksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + int unixEpochTime =(int) ((DateTime.UtcNow.Ticks - ticksToEpoch )/10000000); + int deadTime = unixEpochTime - DEAD_TIME; + m_moneyDBService.SetTransExpired(deadTime); + } + + + protected override void StartupSpecific() + { + m_log.Info("[MONEY SERVER]: Setup HTTP Server process"); + + ReadIniConfig(); + + try { + if (m_certFilename!="") { + m_httpServer = new BaseHttpServer(m_moneyServerPort, true, m_certFilename, m_certPassword); + if (m_checkClientCert) { + Type typeBaseHttpServer = typeof(BaseHttpServer); // BaseHttpServer.cs にパッチがあたっていない場合のため + PropertyInfo pinfo = typeBaseHttpServer.GetProperty("CertificateValidationCallback"); + + if (pinfo!=null) { + //m_httpServer.CertificateValidationCallback = (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate; + pinfo.SetValue(m_httpServer, (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate, null); + m_log.Info ("[MONEY SERVER]: Set RemoteCertificateValidationCallback"); + } + else { + m_log.Error("[MONEY SERVER]: StartupSpecific: CheckClientCert is true. But this MoneyServer does not support CheckClientCert!!"); + } + } + } + else { + m_httpServer = new BaseHttpServer(m_moneyServerPort); + } + + SetupMoneyServices(); + m_httpServer.Start(); + base.StartupSpecific(); // OpenSim/Framework/Servers/BaseOpenSimServer.cs + } + + catch (Exception e) { + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Fail to start HTTPS process"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Please Check Certificate File or Password. Exit"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: {0}", e); + Environment.Exit(1); + } + + //TODO : Add some console commands here + } + + + protected void ReadIniConfig() + { + MoneyServerConfigSource moneyConfig = new MoneyServerConfigSource(); + Config = moneyConfig.m_config; // for base.StartupSpecific() + + try { + // [Startup] + IConfig st_config = moneyConfig.m_config.Configs["Startup"]; + string PIDFile = st_config.GetString("PIDFile", ""); + if (PIDFile!="") Create_PIDFile(PIDFile); + + // [MySql] + IConfig db_config = moneyConfig.m_config.Configs["MySql"]; + string sqlserver = db_config.GetString("hostname", "localhost"); + string database = db_config.GetString("database", "OpenSim"); + string username = db_config.GetString("username", "root"); + string password = db_config.GetString("password", "password"); + string pooling = db_config.GetString("pooling", "false"); + string port = db_config.GetString("port", "3306"); + MAX_DB_CONNECTION = db_config.GetInt ("MaxConnection", MAX_DB_CONNECTION); + + connectionString = "Server=" + sqlserver + ";Port=" + port + ";Database=" + database + ";User ID=" + + username + ";Password=" + password + ";Pooling=" + pooling + ";"; + + // [MoneyServer] + m_server_config = moneyConfig.m_config.Configs["MoneyServer"]; + DEAD_TIME = m_server_config.GetInt("ExpiredTime", DEAD_TIME); + m_moneyServerPort = (uint)m_server_config.GetInt("ServerPort", (int)m_moneyServerPort); + + // + // [Certificate] + m_cert_config = moneyConfig.m_config.Configs["Certificate"]; + if (m_cert_config==null) { + m_log.Info("[MONEY SERVER]: [Certificate] section is not found. Using [MoneyServer] section instead"); + m_cert_config = m_server_config; + } + + // HTTPS Server Cert (Server Mode) + // サーバ証明書 + m_certFilename = m_cert_config.GetString("ServerCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ServerCertPassword", m_certPassword); + if (m_certFilename!="") { + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute HTTPS comunication. Cert file is " + m_certFilename); + } + + // クライアント認証 + m_checkClientCert = m_cert_config.GetBoolean("CheckClientCert", m_checkClientCert); + m_cacertFilename = m_cert_config.GetString("CACertFilename", m_cacertFilename); + m_clcrlFilename = m_cert_config.GetString("ClientCrlFilename", m_clcrlFilename); + // + if (m_checkClientCert && m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CA file is " + m_cacertFilename); + } + else { + m_checkClientCert = false; + } + + if (m_checkClientCert) { + if (m_clcrlFilename!="") { + m_certVerify.SetPrivateCRL(m_clcrlFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CRL file is " + m_clcrlFilename); + } + } + } + + catch (Exception) { + m_log.Error("[MONEY SERVER]: ReadIniConfig: Fail to setup configure. Please check MoneyServer.ini. Exit"); + Environment.Exit(1); + } + } + + + // added by skidz + protected void Create_PIDFile(string path) + { + try { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + m_pidFile = path; + } + catch (Exception) { + } + } + + + protected virtual void SetupMoneyServices() + { + m_log.Info("[MONEY SERVER]: Connecting to Money Storage Server"); + + m_moneyDBService = new MoneyDBService(); + m_moneyDBService.Initialise(connectionString, MAX_DB_CONNECTION); + + m_moneyXmlRpcModule = new MoneyXmlRpcModule(); +// m_moneyXmlRpcModule.Initialise(m_version, m_server_config, m_cert_config, m_moneyDBService, this); + m_moneyXmlRpcModule.Initialise(m_version, m_moneyDBService, this); + m_moneyXmlRpcModule.PostInitialise(); + } + + + // + public bool IsCheckClientCert() + { + return m_checkClientCert; + } + + + public IConfig GetServerConfig() + { + return m_server_config; + } + + + public IConfig GetCertConfig() + { + return m_cert_config; + } + + + public BaseHttpServer GetHttpServer() + { + return m_httpServer; + } + + + public Dictionary GetSessionDic() + { + return m_sessionDic; + } + + + public Dictionary GetSecureSessionDic() + { + return m_secureSessionDic; + } + + + public Dictionary GetWebSessionDic() + { + return m_webSessionDic; + } + + } + + + + // + class MoneyServerConfigSource + { + public IniConfigSource m_config; + + public MoneyServerConfigSource() + { + string configPath = Path.Combine(Directory.GetCurrentDirectory(), "MoneyServer.ini"); + if (File.Exists(configPath)) { + m_config = new IniConfigSource(configPath); + } + else { + //TODO: create default configuration. + //m_config = DefaultConfig(); + } + } + + + public void Save(string path) + { + m_config.Save(path); + } + + } +} diff --git a/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs new file mode 100644 index 0000000..675179c --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs @@ -0,0 +1,1758 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Collections; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using OpenSim.Region.Framework.Scenes; + +using NSL.Network.XmlRpc; +using NSL.Certificate.Tools; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyXmlRpcModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private int m_defaultBalance = 1000; + // + private bool m_forceTransfer = false; + private string m_bankerAvatar = ""; + + private bool m_scriptSendMoney = false; + private string m_scriptAccessKey = ""; + private string m_scriptIPaddress = "127.0.0.1"; + + private bool m_hg_enable = false; + private bool m_gst_enable = false; + private int m_hg_defaultBalance = 0; + private int m_gst_defaultBalance = 0; + + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private X509Certificate2 m_clientCert = null; + + private string m_sslCommonName = ""; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用 + + + // Update Balance Messages + private string m_BalanceMessageLandSale = "Paid the Money L${0} for Land."; + private string m_BalanceMessageRcvLandSale = ""; + private string m_BalanceMessageSendGift = "Sent Gift L${0} to {1}."; + private string m_BalanceMessageReceiveGift = "Received Gift L${0} from {1}."; + private string m_BalanceMessagePayCharge = ""; + private string m_BalanceMessageBuyObject = "Bought the Object {2} from {1} by L${0}."; + private string m_BalanceMessageSellObject = "{1} bought the Object {2} by L${0}."; + private string m_BalanceMessageGetMoney = "Got the Money L${0} from {1}."; + private string m_BalanceMessageBuyMoney = "Bought the Money L${0}."; + private string m_BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}."; + private string m_BalanceMessageSendMoney = "Paid the Money L${0} to {1}."; + private string m_BalanceMessageReceiveMoney = "Received L${0} from {1}."; + + private bool m_enableAmountZero = false; + + const int MONEYMODULE_REQUEST_TIMEOUT = 30 * 1000; //30 seconds + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + private IMoneyDBService m_moneyDBService; + private IMoneyServiceCore m_moneyCore; + + protected IConfig m_server_config; + protected IConfig m_cert_config; + + /// + /// Used to notify old regions as to which OpenSim version to upgrade to + /// + //private string m_opensimVersion; + + private Dictionary m_sessionDic; + private Dictionary m_secureSessionDic; + private Dictionary m_webSessionDic; + + protected BaseHttpServer m_httpServer; + + + public MoneyXmlRpcModule() + { + } + + + public void Initialise(string opensimVersion, IMoneyDBService moneyDBService, IMoneyServiceCore moneyCore) + { + //m_opensimVersion = opensimVersion; + m_moneyDBService = moneyDBService; + m_moneyCore = moneyCore; + m_server_config = m_moneyCore.GetServerConfig(); // [MoneyServer] Section + m_cert_config = m_moneyCore.GetCertConfig(); // [Certificate] Section + + //////////////////////////////////////////////////////////////////////// + // [MoneyServer] Section + m_defaultBalance = m_server_config.GetInt("DefaultBalance", m_defaultBalance); + + m_forceTransfer = m_server_config.GetBoolean("EnableForceTransfer", m_forceTransfer); + + string banker = m_server_config.GetString("BankerAvatar", m_bankerAvatar); + m_bankerAvatar = banker.ToLower(); + + m_enableAmountZero = m_server_config.GetBoolean("EnableAmountZero", m_enableAmountZero); + m_scriptSendMoney = m_server_config.GetBoolean("EnableScriptSendMoney", m_scriptSendMoney); + m_scriptAccessKey = m_server_config.GetString("MoneyScriptAccessKey", m_scriptAccessKey); + m_scriptIPaddress = m_server_config.GetString("MoneyScriptIPaddress", m_scriptIPaddress); + + // Hyper Grid Avatar + m_hg_enable = m_server_config.GetBoolean("EnableHGAvatar", m_hg_enable); + m_gst_enable = m_server_config.GetBoolean("EnableGuestAvatar", m_gst_enable); + m_hg_defaultBalance = m_server_config.GetInt("HGAvatarDefaultBalance", m_hg_defaultBalance); + m_gst_defaultBalance = m_server_config.GetInt("GuestAvatarDefaultBalance", m_gst_defaultBalance); + + // Update Balance Messages + m_BalanceMessageLandSale = m_server_config.GetString("BalanceMessageLandSale", m_BalanceMessageLandSale); + m_BalanceMessageRcvLandSale = m_server_config.GetString("BalanceMessageRcvLandSale", m_BalanceMessageRcvLandSale); + m_BalanceMessageSendGift = m_server_config.GetString("BalanceMessageSendGift", m_BalanceMessageSendGift); + m_BalanceMessageReceiveGift = m_server_config.GetString("BalanceMessageReceiveGift", m_BalanceMessageReceiveGift); + m_BalanceMessagePayCharge = m_server_config.GetString("BalanceMessagePayCharge", m_BalanceMessagePayCharge); + m_BalanceMessageBuyObject = m_server_config.GetString("BalanceMessageBuyObject", m_BalanceMessageBuyObject); + m_BalanceMessageSellObject = m_server_config.GetString("BalanceMessageSellObject", m_BalanceMessageSellObject); + m_BalanceMessageGetMoney = m_server_config.GetString("BalanceMessageGetMoney", m_BalanceMessageGetMoney); + m_BalanceMessageBuyMoney = m_server_config.GetString("BalanceMessageBuyMoney", m_BalanceMessageBuyMoney); + m_BalanceMessageRollBack = m_server_config.GetString("BalanceMessageRollBack", m_BalanceMessageRollBack); + m_BalanceMessageSendMoney = m_server_config.GetString("BalanceMessageSendMoney", m_BalanceMessageSendMoney); + m_BalanceMessageReceiveMoney = m_server_config.GetString("BalanceMessageReceiveMoney", m_BalanceMessageReceiveMoney); + + + //////////////////////////////////////////////////////////////////////// + // [Certificate] Section + + // XML RPC to Region Server (Client Mode) + // クライアント証明書 + m_certFilename = m_cert_config.GetString("ClientCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename!="") { + m_clientCert = new X509Certificate2(m_certFilename, m_certPassword); + //m_clientCert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.Info("[MONEY RPC]: Initialise: Issue Authentication of Client. Cert file is " + m_cacertFilename); + } + + // サーバ認証 + m_checkServerCert = m_cert_config.GetBoolean("CheckServerCert", m_checkServerCert); + + // CA + m_cacertFilename = m_cert_config.GetString("CACertFilename", m_cacertFilename); + if (m_checkServerCert && m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + m_log.Info("[MONEY RPC]: Initialise: Execute Authentication of Server. CA file is " + m_cacertFilename); + } + else { + m_checkServerCert = false; + ServicePointManager.ServerCertificateValidationCallback = null; + } + + m_sessionDic = m_moneyCore.GetSessionDic(); + m_secureSessionDic = m_moneyCore.GetSecureSessionDic(); + m_webSessionDic = m_moneyCore.GetWebSessionDic(); + RegisterHandlers(); + } + + + public void PostInitialise() + { + } + + + public void RegisterHandlers() + { + m_httpServer = m_moneyCore.GetHttpServer(); + m_httpServer.AddXmlRPCHandler("ClientLogin", handleClientLogin); + m_httpServer.AddXmlRPCHandler("ClientLogout", handleClientLogout); + m_httpServer.AddXmlRPCHandler("GetBalance", handleGetBalance); + m_httpServer.AddXmlRPCHandler("GetTransaction", handleGetTransaction); + + m_httpServer.AddXmlRPCHandler("CancelTransfer", handleCancelTransfer); + m_httpServer.AddXmlRPCHandler("TransferMoney", handleTransaction); + m_httpServer.AddXmlRPCHandler("ForceTransferMoney", handleForceTransaction); // added + m_httpServer.AddXmlRPCHandler("PayMoneyCharge", handlePayMoneyCharge); // added + m_httpServer.AddXmlRPCHandler("AddBankerMoney", handleAddBankerMoney); // added + m_httpServer.AddXmlRPCHandler("SendMoney", handleScriptTransaction); // added + m_httpServer.AddXmlRPCHandler("MoveMoney", handleScriptTransaction); // added + + // this is from original DTL. not check yet. + m_httpServer.AddXmlRPCHandler("WebLogin", handleWebLogin); + m_httpServer.AddXmlRPCHandler("WebLogout", handleWebLogout); + m_httpServer.AddXmlRPCHandler("WebGetBalance", handleWebGetBalance); + m_httpServer.AddXmlRPCHandler("WebGetTransaction", handleWebGetTransaction); + m_httpServer.AddXmlRPCHandler("WebGetTransactionNum", handleWebGetTransactionNum); + } + + + // + public string GetSSLCommonName(XmlRpcRequest request) + { + if (request.Params.Count>5) { + m_sslCommonName = (string)request.Params[5]; + } + else if (request.Params.Count==5) { + m_sslCommonName = (string)request.Params[4]; + if (m_sslCommonName=="gridproxy") m_sslCommonName = ""; + } + else { + m_sslCommonName = ""; + } + return m_sslCommonName; + } + + + // + public string GetSSLCommonName() + { + return m_sslCommonName; + } + + + /// + /// Get the user balance when user entering a parcel. + /// + /// + /// + public XmlRpcResponse handleClientLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleClientLogin:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + responseData["success"] = false; + responseData["clientBalance"] = 0; + + // Check Client Cert + if (m_moneyCore.IsCheckClientCert()) { + string commonName = GetSSLCommonName(); + if (commonName=="") { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Warnning: Check Client Cert is set, but SSL Common Name is empty."); + responseData["success"] = false; + responseData["description"] = "SSL Common Name is empty"; + return response; + } + else { + m_log.InfoFormat("[MONEY RPC]: handleClientLogin: SSL Common Name is {0}", commonName); + } + + } + + string universalID = string.Empty; + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string simIP = string.Empty; + string userName = string.Empty; + int balance = 0; + int avatarType = (int)AvatarType.UNKNOWN_AVATAR; + int avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + if (requestData.ContainsKey("universalID")) universalID = (string)requestData["universalID"]; + if (requestData.ContainsKey("userName")) userName = (string)requestData["userName"]; + if (requestData.ContainsKey("openSimServIP")) simIP = (string)requestData["openSimServIP"]; + if (requestData.ContainsKey("avatarType")) avatarType = Convert.ToInt32(requestData["avatarType"]); + if (requestData.ContainsKey("avatarClass")) avatarClass = Convert.ToInt32(requestData["avatarClass"]); + + // + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + string securePsw = string.Empty; + // + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out securePsw); + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // Information from DB + UserInfo userInfo = m_moneyDBService.FetchUserInfo(clientUUID); + if (userInfo!=null) { + avatarType = userInfo.Type; // Avatar Type is not updated + if (avatarType ==(int)AvatarType.LOCAL_AVATAR) avatarClass = (int)AvatarType.LOCAL_AVATAR; + if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) avatarClass = userInfo.Class; + if (String.IsNullOrEmpty(userName)) userName = userInfo.Avatar; + } + // + if (avatarType==(int)AvatarType.UNKNOWN_AVATAR) avatarType = avatarClass; + if (String.IsNullOrEmpty(serverURL)) avatarClass = (int)AvatarType.NPC_AVATAR; + + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: Avatar {0} ({1}) is logged on.", userName, clientUUID); + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: Avatar Type is {0} and Avatar Class is {1}", avatarType, avatarClass); + + //if (String.IsNullOrEmpty(serverURL)) { + // responseData["description"] = "Server URL is empty. Avatar is a NPC?"; + // m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + // return response; + //} + + // + // Check Avatar + if (avatarClass==(int)AvatarType.GUEST_AVATAR && !m_gst_enable) { + responseData["description"] = "Avatar is a Guest avatar. But this Money Server does not support Guest avatars."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.HG_AVATAR && !m_hg_enable) { + responseData["description"] = "Avatar is a HG avatar. But this Money Server does not support HG avatars."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.FOREIGN_AVATAR) { + responseData["description"] = "Avatar is a Foreign avatar."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) { + responseData["description"] = "Avatar is a Unknown avatar."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + // NPC + else if (avatarClass==(int)AvatarType.NPC_AVATAR) { + responseData["success"] = true; + responseData["clientBalance"] = 0; + responseData["description"] = "Avatar is a NPC."; + m_log.InfoFormat("[MONEY RPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + + // + //Update the session and secure session dictionary + lock (m_sessionDic) { + if (!m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Add(clientUUID, sessionID); + } + else m_sessionDic[clientUUID] = sessionID; + } + lock (m_secureSessionDic) { + if (!m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Add(clientUUID, secureID); + } + else m_secureSessionDic[clientUUID] = secureID; + } + + // + try { + if (userInfo==null) userInfo = new UserInfo(); + userInfo.UserID = clientUUID; + userInfo.SimIP = simIP; + userInfo.Avatar = userName; + userInfo.PswHash = UUID.Zero.ToString(); + userInfo.Type = avatarType; + userInfo.Class = avatarClass; + userInfo.ServerURL = serverURL; + if (!String.IsNullOrEmpty(securePsw)) userInfo.PswHash = securePsw; + + if (!m_moneyDBService.TryAddUserInfo(userInfo)) { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Unable to refresh information for user \"{0}\" in DB.", userName); + responseData["success"] = true; // for FireStorm + responseData["description"] = "Update or add user information to db failed"; + return response; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Can't update userinfo for user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + return response; + } + + // + try { + balance = m_moneyDBService.getBalance(clientUUID); + + //add user to balances table if not exist. (if balance is -1, it means avatar is not exist at balances table) + if (balance==-1) { + int default_balance = m_defaultBalance; + if (avatarClass==(int)AvatarType.HG_AVATAR) default_balance = m_hg_defaultBalance; + if (avatarClass==(int)AvatarType.GUEST_AVATAR) default_balance = m_gst_defaultBalance; + + if (m_moneyDBService.addUser(clientUUID, default_balance, 0, avatarType)) { + responseData["success"] = true; + responseData["description"] = "add user successfully"; + responseData["clientBalance"] = default_balance; + } + else { + responseData["description"] = "add user failed"; + } + } + //Success + else if (balance >= 0) { + responseData["success"] = true; + responseData["description"] = "get user balance successfully"; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Can't get balance of user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + } + + return response; + } + + + // + public XmlRpcResponse handleClientLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleClientLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + + m_log.InfoFormat("[MONEY RPC]: handleClientLogout: User {0} is logging off.", clientUUID); + try { + lock (m_sessionDic) { + if (m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Remove(clientUUID); + } + } + + lock (m_secureSessionDic) { + if (m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Remove(clientUUID); + } + } + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleClientLogout: Failed to delete user session: " + e.ToString() ); + responseData["success"] = false; + return response; + } + + responseData["success"] = true; + return response; + } + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + /// + /// handle incoming transaction + /// + /// + /// + public XmlRpcResponse handleTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY RPC]: handleTransaction: Transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY RPC]: handleTransaction: Object ID = {0}, Object Name = {1}", objectID, objectName); + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY RPC]: handleTransaction: Transfering money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + rcv_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Add transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleTransaction: Exception occurred while adding transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handleTransaction: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle incoming force transaction. no check senderSessionID and senderSecureSessionID + /// + /// + /// + public XmlRpcResponse handleForceTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleForceTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + // + if (!m_forceTransfer) { + m_log.Error("[MONEY RPC]: handleForceTransaction: Not allowed force transfer of Money."); + m_log.Error("[MONEY RPC]: handleForceTransaction: Set enableForceTransfer at [MoneyServer] to true in MoneyServer.ini"); + responseData["message"] = "not allowed force transfer of Money!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY RPC]: handleForceTransaction: Force transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY RPC]: handleForceTransaction: Object ID = {0}, Object Name = {1}", objectID, objectName); + + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Force receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + snd_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleForceTransaction: Exception occurred while adding force transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle scripted sending money transaction. + /// + /// + /// + public XmlRpcResponse handleScriptTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string receiverID = UUID.Zero.ToString(); + string clientIP = remoteClient.Address.ToString(); + string secretCode = string.Empty; + string description = "Scripted Send Money from/to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (!m_scriptSendMoney || m_scriptAccessKey=="") { + m_log.Error("[MONEY RPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY RPC]: handleScriptTransaction: Set enableScriptSendMoney and MoneyScriptAccessKey at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed set money to avatar!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + if (requestData.ContainsKey("secretAccessCode")) secretCode = (string)requestData["secretAccessCode"]; + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(m_scriptAccessKey + "_" + clientIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(hash + "_" + m_scriptIPaddress)); + hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + + if (secretCode.ToLower()!=hash) { + m_log.Error("[MONEY RPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY RPC]: handleScriptTransaction: Not match Script Access Key."); + responseData["message"] = "not allowed send money to avatar! not match Script Key"; + return response; + } + + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Send money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle = "0"; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo senderInfo = null; + UserInfo receiverInfo = null; + if (transaction.Sender !=UUID.Zero.ToString()) senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (transaction.Receiver!=UUID.Zero.ToString()) receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + + if (senderInfo==null && receiverInfo==null) { + m_log.ErrorFormat("[MONEY RPC]: handleScriptTransaction: Sender and Receiver are not yet in DB, or both of them are System: {0}, {1}", + transaction.Sender, transaction.Receiver); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: ScriptTransaction money finished successfully, now update balance {0}", + transactionUUID.ToString()); + string message = string.Empty; + if (senderInfo!=null) { + if (receiverInfo==null) message = string.Format(m_BalanceMessageSendMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageSendMoney, amount, receiverInfo.Avatar, ""); + UpdateBalance(transaction.Sender, message); + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Sender, message); + } + if (receiverInfo!=null) { + if (senderInfo==null) message = string.Format(m_BalanceMessageReceiveMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageReceiveMoney, amount, senderInfo.Avatar, ""); + UpdateBalance(transaction.Receiver, message); + m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Receiver, message); + } + + + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleScriptTransaction: Add force transaction for user {0} failed.", transaction.Sender); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleScriptTransaction: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle adding money transaction. + /// + /// + /// + public XmlRpcResponse handleAddBankerMoney(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string bankerID = string.Empty; + string regionHandle = "0"; + string regionUUID = UUID.Zero.ToString(); + string description = "Add Money to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("bankerID")) bankerID = (string)requestData["bankerID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + // Check Banker Avatar + if (m_bankerAvatar!=UUID.Zero.ToString() && m_bankerAvatar!=bankerID) { + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Not allowed add money to avatar!!"); + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Set BankerAvatar at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed add money to avatar!"; + responseData["banker"] = false; + return response; + } + responseData["banker"] = true; + + m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Add money to avatar {0}", bankerID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = bankerID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(bankerID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Avatar is not yet in DB {0}", bankerID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoAddMoney(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Adding money finished successfully, now update balance: {0}", + transactionUUID.ToString()); + string message = string.Format(m_BalanceMessageBuyMoney, amount, "SYSTEM", ""); + UpdateBalance(transaction.Receiver, message); + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handleAddBankerMoney: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle pay charge transaction. no check receiver information. + /// + /// + /// + public XmlRpcResponse handlePayMoneyCharge(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = UUID.Zero.ToString(); + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = UUID.Zero.ToString(); + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Pay Charge on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + + m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge: Transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge: Object ID = {0}, Object Name = {1}", objectID, objectName); + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge: Pay from {0}", senderID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle = regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string message = string.Format(m_BalanceMessagePayCharge, amount, "SYSTEM", ""); + responseData["success"] = NotifyTransfer(transactionUUID, message, "", ""); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY RPC]: handlePayMoneyCharge: Pay money transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Exception occurred while pay money transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + // added by Fumi.Iseki + // + /// + /// Continue transaction with no confirm. + /// + /// + /// + public bool NotifyTransfer(UUID transactionUUID, string msg2sender, string msg2receiver, string objectName) + { + //m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: User has accepted the transaction, now continue with the transaction"); + + try { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction Type = {0}", transaction.Type); + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Payment finished successfully, now update balance {0}", transactionUUID.ToString()); + + bool updateSender = true; + bool updateReceiv = true; + if (transaction.Sender==transaction.Receiver) updateSender = false; + //if (transaction.Type==(int)TransactionType.UploadCharge) return true; + if (transaction.Type==(int)TransactionType.UploadCharge) updateReceiv = false; + + if (updateSender) { + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string receiverName = "unknown user"; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + string snd_message = string.Format(msg2sender, transaction.Amount, receiverName, objectName); + UpdateBalance(transaction.Sender, snd_message); + } + if (updateReceiv) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + string senderName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + string rcv_message = string.Format(msg2receiver, transaction.Amount, senderName, objectName); + UpdateBalance(transaction.Receiver, rcv_message); + } + + // Notify to sender + if (transaction.Type==(int)TransactionType.PayObject) { + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Now notify opensim to give object to customer {0} ", transaction.Sender); + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = transaction.Sender; + requestTable["receiverUUID"] = transaction.Receiver; + + if(m_sessionDic.ContainsKey(transaction.Sender)&&m_secureSessionDic.ContainsKey(transaction.Sender)) { + requestTable["clientSessionID"] = m_sessionDic[transaction.Sender]; + requestTable["clientSecureSessionID"] = m_secureSessionDic[transaction.Sender]; + } + else { + requestTable["clientSessionID"] = UUID.Zero.ToString(); + requestTable["clientSecureSessionID"] = UUID.Zero.ToString(); + } + requestTable["transactionType"] = transaction.Type; + requestTable["amount"] = transaction.Amount; + requestTable["objectID"] = transaction.ObjectUUID; + requestTable["objectName"] = transaction.ObjectName; + requestTable["regionHandle"] = transaction.RegionHandle; + + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (user!=null) { + Hashtable responseTable = genericCurrencyXMLRPCRequest(requestTable, "OnMoneyTransfered", user.SimIP); + + if (responseTable!=null && responseTable.ContainsKey("success")) { + //User not online or failed to get object ? + if (!(bool)responseTable["success"]) { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: User {0} can't get the object, rolling back.", transaction.Sender); + if (RollBackTransaction(transaction)) { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed but roll back succeeded.", transactionUUID.ToString()); + } + else { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed and roll back failed as well.", + transactionUUID.ToString()); + } + } + else { + m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} finished successfully.", transactionUUID.ToString()); + return true; + } + } + } + return false; + } + return true; + } + } + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed.", transactionUUID.ToString()); + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: exception occurred when transaction {0}: {1}", transactionUUID.ToString(), e.ToString()); + } + + return false; + } + + + + /// + /// Get the user balance. + /// + /// + /// + public XmlRpcResponse handleGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + int balance; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + m_log.InfoFormat("[MONEY RPC]: handleGetBalance: Getting balance for user {0}", clientUUID); + + if (m_sessionDic.ContainsKey(clientUUID) && m_secureSessionDic.ContainsKey(clientUUID)) { + if (m_sessionDic[clientUUID]==sessionID && m_secureSessionDic[clientUUID]==secureID) { + try { + balance = m_moneyDBService.getBalance(clientUUID); + if (balance==-1) // User not found + { + responseData["description"] = "user not found"; + responseData["clientBalance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleGetBalance: Can't get balance for user {0}, Exception {1}", clientUUID, e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handleGetBalance: Session authentication failed when getting balance for user " + clientUUID); + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method, string uri) + { + //m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: to {0}", uri); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!uri.StartsWith("https://")) { + m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file."); + //return null; + } + } + else { + if (!uri.StartsWith("https://") && !uri.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Invalid Region Server URL: {0}", uri); + return null; + } + } + + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + //XmlRpcRequest moneyModuleReq = new XmlRpcRequest(method, arrayParams); + //moneyServResp = moneyModuleReq.Send(uri, MONEYMODULE_REQUEST_TIMEOUT); + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + moneyServResp = moneyModuleReq.certSend(uri, m_clientCert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Unable to connect to Region Server {0}", uri); + m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: {0}", ex.ToString()); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + /// + /// Update the client balance.We don't care about the result. + /// + /// + private void UpdateBalance(string userID, string message) + { + //m_log.InfoFormat("[MONEY RPC]: UpdateBalance: ID = {0}, Message = {1}", userID, message); + + string sessionID = string.Empty; + string secureID = string.Empty; + + if (m_sessionDic.ContainsKey(userID) && m_secureSessionDic.ContainsKey(userID)) { + sessionID = m_sessionDic[userID]; + secureID = m_secureSessionDic[userID]; + + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = userID; + requestTable["clientSessionID"] = sessionID; + requestTable["clientSecureSessionID"] = secureID; + requestTable["Balance"] = m_moneyDBService.getBalance(userID); + if (message!="") requestTable["Message"] = message; + + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + genericCurrencyXMLRPCRequest(requestTable, "UpdateBalance", user.SimIP); + m_log.InfoFormat("[MONEY RPC]: UpdateBalance: Sended UpdateBalance Request to {0}", user.SimIP.ToString()); + } + } + } + + + /// + /// RollBack the transaction if user failed to get the object paid + /// + /// + /// + protected bool RollBackTransaction(TransactionData transaction) + { + //m_log.InfoFormat("[MONEY RPC]: RollBackTransaction:"); + + if(m_moneyDBService.withdrawMoney(transaction.TransUUID, transaction.Receiver, transaction.Amount)) { + if(m_moneyDBService.giveMoney(transaction.TransUUID, transaction.Sender, transaction.Amount)) { + m_log.InfoFormat("[MONEY RPC]: RollBackTransaction: Transaction {0} is successfully.", transaction.TransUUID.ToString()); + m_moneyDBService.updateTransactionStatus(transaction.TransUUID, (int)Status.FAILED_STATUS, + "The buyer failed to get the object, roll back the transaction"); + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string senderName = "unknown user"; + string receiverName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + + string snd_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, receiverName, transaction.ObjectName); + string rcv_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, senderName, transaction.ObjectName); + + if (transaction.Sender!=transaction.Receiver) UpdateBalance(transaction.Sender, snd_message); + UpdateBalance(transaction.Receiver, rcv_message); + return true; + } + } + return false; + } + + + // + public XmlRpcResponse handleCancelTransfer(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string secureCode = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("secureCode")) secureCode = (string)requestData["secureCode"]; + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (string.IsNullOrEmpty(secureCode) || string.IsNullOrEmpty(transactionID)) { + m_log.Error("[MONEY RPC]: handleCancelTransfer: secureCode and/or transactionID are empty."); + return response; + } + + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + + try { + m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} wanted to cancel the transaction.", user.Avatar); + if (m_moneyDBService.ValidateTransfer(secureCode, transactionUUID)) { + m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} has canceled the transaction {1}", user.Avatar, transactionID); + m_moneyDBService.updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, + "User canceled the transaction on " + DateTime.UtcNow.ToString()); + responseData["success"] = true; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleCancelTransfer: Exception occurred when transaction {0}: {1}", transactionID, e.ToString()); + } + return response; + } + + + // + public XmlRpcResponse handleGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (m_sessionDic.ContainsKey(clientID) && m_secureSessionDic.ContainsKey(clientID)) { + if (m_sessionDic[clientID]==sessionID && m_secureSessionDic[clientID]==secureID) { + // + if (string.IsNullOrEmpty(transactionID)) { + responseData["description"] = "TransactionID is empty"; + m_log.Error("[MONEY RPC]: handleGetTransaction: TransactionID is empty."); + return response; + } + + try { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null) { + responseData["success"] = true; + responseData["amount"] = transaction.Amount; + responseData["time"] = transaction.Time; + responseData["type"] = transaction.Type; + responseData["sender"] = transaction.Sender.ToString(); + responseData["receiver"] = transaction.Receiver.ToString(); + responseData["description"] = transaction.Description; + } + else { + responseData["description"] = "Invalid Transaction UUID"; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: {0}", e.ToString()); + m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: Can't get transaction information for {0}", transactionUUID.ToString()); + } + return response; + } + } + + responseData["success"] = false; + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // In development + // + + public XmlRpcResponse handleWebLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebLogin:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, login failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (!m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Add(userID, webSessionID); + } + else m_webSessionDic[userID] = webSessionID; + } + + m_log.InfoFormat("[MONEY RPC]: handleWebLogin: User {0} has logged in from web.", userID); + responseData["success"] = true; + return response; + } + + + // + public XmlRpcResponse handleWebLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, log out failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Remove(userID); + } + } + + m_log.InfoFormat("[MONEY RPC]: handleWebLogout: User {0} has logged out from web.", userID); + responseData["success"] = true; + return response; + } + + + /// + /// Get balance method for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int balance = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance: Getting balance for user {0}", userID); + + //perform session check + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + balance = m_moneyDBService.getBalance(userID); + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + responseData["userName"] = user.Avatar; + } + else { + responseData["userName"] = "unknown user"; + } + // + // User not found + if (balance==-1) { + responseData["errorMessage"] = "User not found"; + responseData["balance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["balance"] = balance; + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleWebGetBalance: Can't get balance for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting balance"; + return response; + } + } + } + + m_log.Error("[MONEY RPC]: handleWebLogout: Session authentication failed when getting balance for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get transaction for web pages + /// + /// + /// + public XmlRpcResponse handleWebGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int lastIndex = -1; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + if (requestData.ContainsKey("lastIndex")) lastIndex = (int)requestData["lastIndex"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + int total = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + TransactionData tran = null; + m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction: Getting transation[{0}] for user {1}", lastIndex + 1, userID); + if (total > lastIndex + 2) { + responseData["isEnd"] = false; + } + else { + responseData["isEnd"] = true; + } + + tran = m_moneyDBService.FetchTransaction(userID, startTime, endTime, lastIndex); + if (tran!=null) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(tran.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(tran.Receiver); + if (senderInfo!=null && receiverInfo!=null) { + responseData["senderName"] = senderInfo.Avatar; + responseData["receiverName"] = receiverInfo.Avatar; + } + else { + responseData["senderName"] = "unknown user"; + responseData["receiverName"] = "unknown user"; + } + responseData["success"] = true; + responseData["transactionIndex"] = lastIndex + 1; + responseData["transactionUUID"] = tran.TransUUID.ToString(); + responseData["senderID"] = tran.Sender; + responseData["receiverID"] = tran.Receiver; + responseData["amount"] = tran.Amount; + responseData["type"] = tran.Type; + responseData["time"] = tran.Time; + responseData["status"] = tran.Status; + responseData["description"] = tran.Description; + } + else { + responseData["errorMessage"] = string.Format("Unable to fetch transaction data with the index {0}", lastIndex + 1); + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY RPC]: handleWebGetTransaction: Can't get transaction for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting transaction"; + return response; + } + } + } + + m_log.Error("[MONEY RPC]: handleWebGetTransaction: Session authentication failed when getting transaction for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get total number of transactions for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetTransactionNum(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + int it = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + if (it>=0) { + m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum: Get {0} transactions for user {1}", it, userID); + responseData["success"] = true; + responseData["number"] = it; + } + return response; + } + } + + m_log.Error("[MONEY RPC]: handleWebGetTransactionNum: Session authentication failed when getting transaction number for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + } + +} + diff --git a/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/Program.cs b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/Program.cs new file mode 100644 index 0000000..3fbd12d --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Grid.MoneyServer/Program.cs @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net.Config; + +namespace OpenSim.Grid.MoneyServer +{ + class Program + { + public static void Main(string[] args) + { + XmlConfigurator.Configure(); + MoneyServerBase app = new MoneyServerBase(); + app.Startup(); + app.Work(); + } + } +} diff --git a/release/0.9.1_1/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs b/release/0.9.1_1/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs new file mode 100644 index 0000000..72f808b --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs @@ -0,0 +1,1903 @@ +// * Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp +// * +// * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ +// * See CONTRIBUTORS.TXT for a full list of copyright holders. +// * +// * Redistribution and use in source and binary forms, with or without +// * modification, are permitted provided that the following conditions are met: +// * * Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * * Redistributions in binary form must reproduce the above copyright +// * notice, this list of conditions and the following disclaimer in the +// * documentation and/or other materials provided with the distribution. +// * * Neither the name of the OpenSim Project nor the +// * names of its contributors may be used to endorse or promote products +// * derived from this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +// * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using Mono.Addins; + +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using NSL.Certificate.Tools; +using NSL.Network.XmlRpc; + + + +[assembly: Addin("DTLNSLMoneyModule", "1.0")] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] + + + +namespace OpenSim.Modules.Currency +{ + // + public enum TransactionType : int + { + None = 0, + // Extend + BirthGift = 900, + AwardPoints = 901, + // One-Time Charges + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + // Recurrent Charges + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + ScheduledFee = 2900, + // Inventory Transactions + GiveInventory = 3000, + // Transfers Between Users + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InvntorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + BuyMoney = 5010, + MoveMoney = 5011, + SendMoney = 5012, + // Group Transactions + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + // Stipend Credits + StipendBasic = 10000 + } + + +/* + // Refer to OpenMetaverse + public enum OpenMetaverse.MoneyTransactionType : int + { + None = 0, + FailSimulatorTimeout = 1, + FailDataserverTimeout = 2, + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + ObjectPublicClaim = 1003, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + GiveInventory = 3000, + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InventorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + ObjectRelease = 8000, + LandRelease = 8001, + ObjectDelete = 8002, + ObjectPublicDecay = 8003, + ObjectPublicDelete = 8004, + LindenAdjustment = 9000, + LindenGrant = 9001, + LindenPenalty = 9002, + EventFee = 9003, + EventPrize = 9004, + StipendBasic = 10000, + StipendDeveloper = 10001, + StipendAlways = 10002, + StipendDaily = 10003, + StipendRating = 10004, + StipendDelta = 10005 + } +*/ + + + // + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")] + public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule + { + #region Constant numbers and members. + + // Constant memebers + private const int MONEYMODULE_REQUEST_TIMEOUT = 10000; + + // Private data members. + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + //private bool m_enabled = true; + private bool m_sellEnabled = false; + private bool m_enable_server = true; // enable Money Server + + private IConfigSource m_config; + + private string m_moneyServURL = string.Empty; + public BaseHttpServer HttpServer; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + private X509Certificate2 m_cert = null; + + private bool m_use_web_settle = false; + private string m_settle_url = ""; + private string m_settle_message = ""; + private bool m_settle_user = false; + + private int m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用 + + + /// + /// Scene dictionary indexed by Region Handle + /// + private Dictionary m_sceneList = new Dictionary(); + + /// + /// To cache the balance data while the money server is not available. + /// + private Dictionary m_moneyServer = new Dictionary(); + + // Events + public event ObjectPaid OnObjectPaid; + + // Price + private int ObjectCount = 0; + private int PriceEnergyUnit = 100; + private int PriceObjectClaim = 10; + private int PricePublicObjectDecay = 4; + private int PricePublicObjectDelete = 4; + private int PriceParcelClaim = 1; + private float PriceParcelClaimFactor = 1.0f; + private int PriceUpload = 0; + private int PriceRentLight = 5; + private float PriceObjectRent = 1.0f; + private float PriceObjectScaleFactor = 10.0f; + private int PriceParcelRent = 1; + private int PriceGroupCreate = 0; + private int TeleportMinPrice = 2; + private float TeleportPriceExponent = 2.0f; + private float EnergyEfficiency = 1.0f; + + #endregion + + + // + public void Initialise(Scene scene, IConfigSource source) + { + Initialise(source); + if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false; + // + AddRegion(scene); + } + + + #region ISharedRegionModule interface + + public void Initialise(IConfigSource source) + { + //m_log.InfoFormat("[MONEY]: Initialise:"); + + // Handle the parameters errors. + if (source==null) return; + + try { + m_config = source; + + // [Economy] section + IConfig economyConfig = m_config.Configs["Economy"]; + + if (economyConfig.GetString("EconomyModule")!=Name) { + //m_enabled = false; + m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is disabled"); + return; + } + else { + m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is enabled"); + } + + m_sellEnabled = economyConfig.GetBoolean("SellEnabled", m_sellEnabled); + m_moneyServURL = economyConfig.GetString("CurrencyServer", m_moneyServURL); + + // クライアント証明書 + m_certFilename = economyConfig.GetString("ClientCertFilename", m_certFilename); + m_certPassword = economyConfig.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename!="") { + m_cert = new X509Certificate2(m_certFilename, m_certPassword); + //m_cert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.InfoFormat("[MONEY]: Issue Authentication of Client. Cert File is " + m_certFilename); + } + + // サーバ認証 + m_checkServerCert = economyConfig.GetBoolean("CheckServerCert", m_checkServerCert); + m_cacertFilename = economyConfig.GetString("CACertFilename", m_cacertFilename); + if (m_cacertFilename!="") { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.InfoFormat("[MONEY]: Execute Authentication of Server. CA Cert File is " + m_cacertFilename); + } + else { + m_checkServerCert = false; + } + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + + + // Settlement + m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", m_use_web_settle); + m_settle_url = economyConfig.GetString ("SettlementURL", m_settle_url); + m_settle_message = economyConfig.GetString ("SettlementMessage", m_settle_message); + + // Price + PriceEnergyUnit = economyConfig.GetInt ("PriceEnergyUnit", PriceEnergyUnit); + PriceObjectClaim = economyConfig.GetInt ("PriceObjectClaim", PriceObjectClaim); + PricePublicObjectDecay = economyConfig.GetInt ("PricePublicObjectDecay", PricePublicObjectDecay); + PricePublicObjectDelete = economyConfig.GetInt ("PricePublicObjectDelete", PricePublicObjectDelete); + PriceParcelClaim = economyConfig.GetInt ("PriceParcelClaim", PriceParcelClaim); + PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", PriceParcelClaimFactor); + PriceUpload = economyConfig.GetInt ("PriceUpload", PriceUpload); + PriceRentLight = economyConfig.GetInt ("PriceRentLight", PriceRentLight); + PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", PriceObjectRent); + PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", PriceObjectScaleFactor); + PriceParcelRent = economyConfig.GetInt ("PriceParcelRent", PriceParcelRent); + PriceGroupCreate = economyConfig.GetInt ("PriceGroupCreate", PriceGroupCreate); + TeleportMinPrice = economyConfig.GetInt ("TeleportMinPrice", TeleportMinPrice); + TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", TeleportPriceExponent); + EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", EnergyEfficiency); + + // for HG Avatar + string avatar_class = economyConfig.GetString("HGAvatarAs", "HGAvatar").ToLower(); + if (avatar_class=="localavatar") m_hg_avatarClass = (int)AvatarType.LOCAL_AVATAR; + else if (avatar_class=="guestavatar") m_hg_avatarClass = (int)AvatarType.GUEST_AVATAR; + else if (avatar_class=="hgavatar") m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + else if (avatar_class=="foreignavatar") m_hg_avatarClass = (int)AvatarType.FOREIGN_AVATAR; + else m_hg_avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + } + catch { + m_log.ErrorFormat("[MONEY]: Initialise: Faile to read configuration file"); + } + } + + + public void AddRegion(Scene scene) + { + //m_log.InfoFormat("[MONEY]: AddRegion:"); + + if (scene==null) return; + + scene.RegisterModuleInterface(this); // 競合するモジュールの排除 + + lock (m_sceneList) { + if (m_sceneList.Count==0) { + if (m_enable_server) { + HttpServer = new BaseHttpServer(9000); + HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo)); + + HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler); + HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + HttpServer.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + HttpServer.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + + MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler); + MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + } + } + + if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle)) { + m_sceneList[scene.RegionInfo.RegionHandle] = scene; + } + else { + m_sceneList.Add(scene.RegionInfo.RegionHandle, scene); + } + } + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer += MoneyTransferAction; + scene.EventManager.OnValidateLandBuy += ValidateLandBuy; + scene.EventManager.OnLandBuy += processLandBuy; + } + + + public void RemoveRegion(Scene scene) + { + if (scene==null) return; + + lock (m_sceneList) { + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent -= MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer -= MoneyTransferAction; + scene.EventManager.OnValidateLandBuy -= ValidateLandBuy; + scene.EventManager.OnLandBuy -= processLandBuy; + } + } + + + public void RegionLoaded(Scene scene) + { + //m_log.InfoFormat("[MONEY]: RegionLoaded:"); + } + + + public Type ReplaceableInterface + { + //get { return typeof(IMoneyModule); } + get { return null; } + } + + + public bool IsSharedModule + { + get { return true; } + } + + + public string Name + { + get { return "DTLNSLMoneyModule"; } + } + + + public void PostInitialise() + { + //m_log.InfoFormat("[MONEY]: PostInitialise:"); + } + + + public void Close() + { + //m_log.InfoFormat("[MONEY]: Close:"); + } + + #endregion + + + #region IMoneyModule interface. + + // for LSL llGiveMoney() function + public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result) + { + //m_log.InfoFormat("[MONEY]: ObjectGiveMoney: LSL ObjectGiveMoney. UUID = {0}", objectID.ToString()); + + result = string.Empty; + if (!m_sellEnabled) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + + string objName = string.Empty; + string avatarName = string.Empty; + + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + objName = sceneObj.Name; + + Scene scene = GetLocateScene(toID); + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID); + if (account!=null) { + avatarName = account.FirstName + " " + account.LastName; + } + } + + bool ret = false; + string description = String.Format("Object {0} pays {1}", objName, avatarName); + + if (sceneObj.OwnerID==fromID) { + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + if (GetLocateClient(fromID)!=null) { + ret = TransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + else { + ret = ForceTransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + } + + if (!ret) result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return ret; + } + + + // + public int UploadCharge + { + get { return PriceUpload; } + } + + + // + public int GroupCreationCharge + { + get { return PriceGroupCreate; } + } + + + public int GetBalance(UUID agentID) + { + IClientAPI client = GetLocateClient(agentID); + return QueryBalanceFromMoneyServer(client); + } + + + public bool UploadCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public bool AmountCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public void ApplyUploadCharge(UUID agentID, int amount, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)TransactionType.UploadCharge, regionHandle, regionUUID, text); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type) + { + ApplyCharge(agentID, amount, type, string.Empty); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)type, regionHandle, regionUUID, text); + } + + + public bool Transfer(UUID fromID, UUID toID, int regionHandle, int amount, MoneyTransactionType type, string text) + { + return TransferMoney(fromID, toID, amount, (int)type, UUID.Zero, (ulong)regionHandle, UUID.Zero, text); + } + + + public bool Transfer(UUID fromID, UUID toID, UUID objectID, int amount, MoneyTransactionType type, string text) + { + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) return false; + + ulong regionHandle = sceneObj.ParentGroup.Scene.RegionInfo.RegionHandle; + UUID regionUUID = sceneObj.ParentGroup.Scene.RegionInfo.RegionID; + return TransferMoney(fromID, toID, amount, (int)type, objectID, (ulong)regionHandle, regionUUID, text); + } + + + // for 0.8.3 over + public void MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, string text) + { + ForceTransferMoney(fromAgentID, toAgentID, amount, (int)TransactionType.MoveMoney, UUID.Zero, (ulong)0, UUID.Zero, text); + } + + // for 0.9.1 over + public bool MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, MoneyTransactionType type, string text) + { + bool ret = ForceTransferMoney(fromAgentID, toAgentID, amount, (int)type, UUID.Zero, (ulong)0, UUID.Zero, text); + return ret; + } + + #endregion + + + #region MoneyModule event handlers + + // + private void OnNewClient(IClientAPI client) + { + m_log.InfoFormat("[MONEY]: OnNewClient"); + + client.OnEconomyDataRequest += OnEconomyDataRequest; + client.OnLogout += ClientClosed; + + client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + client.OnRequestPayPrice += OnRequestPayPrice; + client.OnObjectBuy += OnObjectBuy; + } + + + public void OnMakeRootAgent(ScenePresence agent) + { + m_log.InfoFormat("[MONEY]: OnMakeRootAgent:"); + + int balance = 0; + IClientAPI client = agent.ControllingClient; + + m_enable_server = LoginMoneyServer(agent, out balance); + client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + + //client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + //client.OnRequestPayPrice += OnRequestPayPrice; + //client.OnObjectBuy += OnObjectBuy; + } + + + // for OnClientClosed event + private void ClientClosed(IClientAPI client) + { + //m_log.InfoFormat("[MONEY]: ClientClosed:"); + + if (m_enable_server && client!=null) { + LogoffMoneyServer(client); + } + } + + + // for OnMakeChildAgent event + private void MakeChildAgent(ScenePresence avatar) + { + //m_log.InfoFormat("[MONEY]: MakeChildAgent:"); + } + + + // for OnMoneyTransfer event + private void MoneyTransferAction(Object sender, EventManager.MoneyTransferArgs moneyEvent) + { + //m_log.InfoFormat("[MONEY]: MoneyTransferAction: type = {0}", moneyEvent.transactiontype); + + if (!m_sellEnabled) return; + + // Check the money transaction is necessary. + if (moneyEvent.sender==moneyEvent.receiver) { + return; + } + + UUID receiver = moneyEvent.receiver; + // Pay for the object. + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + SceneObjectPart sceneObj = GetLocatePrim(moneyEvent.receiver); + if (sceneObj!=null) { + receiver = sceneObj.OwnerID; + } + else { + return; + } + } + + // Before paying for the object, save the object local ID for current transaction. + UUID objectID = UUID.Zero; + ulong regionHandle = 0; + UUID regionUUID = UUID.Zero; + + if (sender is Scene) { + Scene scene = (Scene)sender; + regionHandle = scene.RegionInfo.RegionHandle; + regionUUID = scene.RegionInfo.RegionID; + + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + objectID = scene.GetSceneObjectPart(moneyEvent.receiver).UUID; + } + } + + TransferMoney(moneyEvent.sender, receiver, moneyEvent.amount, moneyEvent.transactiontype, objectID, regionHandle, regionUUID, "OnMoneyTransfer event"); + return; + } + + + // for OnValidateLandBuy event + private void ValidateLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY]: ValidateLandBuy:"); + + IClientAPI senderClient = GetLocateClient(landBuyEvent.agentId); + if (senderClient!=null) { + int balance = QueryBalanceFromMoneyServer(senderClient); + if (balance >= landBuyEvent.parcelPrice) { + lock(landBuyEvent) { + landBuyEvent.economyValidated = true; + } + } + } + return; + } + + + // for LandBuy even + private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY]: processLandBuy:"); + + if (!m_sellEnabled) return; + + lock(landBuyEvent) { + if (landBuyEvent.economyValidated==true && landBuyEvent.transactionID==0) { + landBuyEvent.transactionID = Util.UnixTimeSinceEpoch(); + + ulong parcelID = (ulong)landBuyEvent.parcelLocalID; + UUID regionUUID = UUID.Zero; + if (sender is Scene) regionUUID = ((Scene)sender).RegionInfo.RegionID; + + if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID, + landBuyEvent.parcelPrice, (int)TransactionType.LandSale, regionUUID, parcelID, regionUUID, "Land Purchase")) { + landBuyEvent.amountDebited = landBuyEvent.parcelPrice; + } + } + } + return; + } + + + // for OnObjectBuy event + public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID, + UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice) + { + m_log.InfoFormat("[MONEY]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId); + + // Handle the parameters error. + if (!m_sellEnabled) return; + if (remoteClient==null || salePrice<0) return; + + // Get the balance from money server. + int balance = QueryBalanceFromMoneyServer(remoteClient); + if (balance(); + if (mod!=null) { + UUID receiverId = sceneObj.OwnerID; + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + bool ret = false; + // + if (salePrice>=0) { + if (!string.IsNullOrEmpty(m_moneyServURL)) { + ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice, + (int)TransactionType.PayObject, sceneObj.UUID, regionHandle, regionUUID, "Object Buy"); + } + else if (salePrice==0) { // amount is 0 with No Money Server + ret = true; + } + } + if (ret) { + mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); + } + } + } + else { + remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false); + return; + } + } + return; + } + + + /// + /// Sends the the stored money balance to the client + /// + /// + /// + /// + /// + private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID) + { + m_log.InfoFormat("[MONEY]: OnMoneyBalanceRequest:"); + + if (client.AgentId==agentID && client.SessionId==SessionID) { + int balance = 0; + // + if (m_enable_server) { + balance = QueryBalanceFromMoneyServer(client); + } + + client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + } + else { + client.SendAlertMessage("Unable to send your money balance"); + } + } + + + private void OnRequestPayPrice(IClientAPI client, UUID objectID) + { + m_log.InfoFormat("[MONEY]: OnRequestPayPrice:"); + + Scene scene = GetLocateScene(client.AgentId); + if (scene==null) return; + SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID); + if (sceneObj==null) return; + SceneObjectGroup group = sceneObj.ParentGroup; + SceneObjectPart root = group.RootPart; + + client.SendPayPrice(objectID, root.PayPrice); + } + + + // + //private void OnEconomyDataRequest(UUID agentId) + private void OnEconomyDataRequest(IClientAPI user) + { + //m_log.InfoFormat("[MONEY]: OnEconomyDataRequest:"); + //IClientAPI user = GetLocateClient(agentId); + + if (user!=null) { + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + //Scene s = GetLocateScene(user.AgentId); + Scene s = (Scene)user.Scene; + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, + PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, + PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, + TeleportMinPrice, TeleportPriceExponent); + } + } + } + + #endregion + + + #region MoneyModule XML-RPC Handler + + // "OnMoneyTransfered" RPC from MoneyServer + public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("transactionType") && requestParam.Contains("objectID") && requestParam.Contains("amount")) { + //m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]); + + // Pay for the object. + if ((int)requestParam["transactionType"]==(int)TransactionType.PayObject) { + // Send notify to the client(viewer) for Money Event Trigger. + ObjectPaid handlerOnObjectPaid = OnObjectPaid; + if (handlerOnObjectPaid!=null) { + UUID objectID = UUID.Zero; + UUID.TryParse((string)requestParam["objectID"], out objectID); + handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money() + } + ret = true; + } + } + } + } + } + } + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UpdateBalance" RPC from MoneyServer or Script + public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: BalanceUpdateHandler:"); + + bool ret = false; + + #region Update the balance from money server. + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + // + if (requestParam.Contains("Balance")) { + // Send notify to the client. + string msg = ""; + if (requestParam.Contains("Message")) msg = (string)requestParam["Message"]; + client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"], + 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + // Dialog + if (msg!="") { + Scene scene = (Scene)client.Scene; + IDialogModule dlg = scene.RequestModuleInterface(); + dlg.SendAlertToUser(client.AgentId, msg); + } + ret = true; + } + } + } + } + } + + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY]: BalanceUpdateHandler: Cannot update client balance from MoneyServer"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UserAlert" RPC from Script + public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: UserAlertHandler:"); + + bool ret = false; + + #region confirm the request and show the notice from money server. + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("Description")) + { + string description = (string)requestParam["Description"]; + // Show the notice dialog with money server message. + GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()), + (byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3()); + client.SendInstantMessage(gridMsg); + ret = true; + } + } + } + } + } + // + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + return resp; + } + + + // "GetBalance" RPC from Script + public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: GetBalanceHandler:"); + + bool ret = false; + int balance = -1; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + balance = QueryBalanceFromMoneyServer(client); + } + } + } + } + + // Send the response to caller. + if (balance<0) { + m_log.ErrorFormat("[MONEY]: GetBalanceHandler: GetBalance transaction is failed"); + ret = false; + } + + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + paramTable["balance"] = balance; + resp.Value = paramTable; + + return resp; + } + + + // "AddBankerMoney" RPC from Script + public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: AddBankerMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID bankerUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID); + // + if (bankerUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(bankerUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("amount")) + { + Scene scene = (Scene)client.Scene; + int amount = (int)requestParam["amount"]; + ulong regionHandle = scene.RegionInfo.RegionHandle; + UUID regionUUID = scene.RegionInfo.RegionID; + ret = AddBankerMoney(bankerUUID, amount, regionHandle, regionUUID); + + if (m_use_web_settle && m_settle_user) { + ret = true; + IDialogModule dlg = scene.RequestModuleInterface(); + if (dlg!=null) { + dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url); + } + } + } + } + } + } + } + + if (!ret) m_log.ErrorFormat("[MONEY]: AddBankerMoneyHandler: Add Banker Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["settle"] = false; + paramTable["success"] = ret; + + if (m_use_web_settle && m_settle_user) paramTable["settle"] = true; + resp.Value = paramTable; + + return resp; + } + + + // "SendMoney" RPC from Script + public XmlRpcResponse SendMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: SendMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("agentUUID") && requestParam.Contains("secretAccessCode")) { + UUID agentUUID = UUID.Zero; + UUID.TryParse((string)requestParam["agentUUID"], out agentUUID); + + if (agentUUID!=UUID.Zero) { + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + int type = -1; + if (requestParam.Contains("type")) type = (int)requestParam["type"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY]: SendMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = SendMoneyTo(agentUUID, amount, type, hash); + } + } + else { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("agentUUID")) { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: agentUUID is missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY]: SendMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY]: SendMoneyHandler: Send Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + + // "MoveMoney" RPC from Script + public XmlRpcResponse MoveMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY]: MoveMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if ((requestParam.Contains("fromUUID") || requestParam.Contains("toUUID")) && requestParam.Contains("secretAccessCode")) { + UUID fromUUID = UUID.Zero; + UUID toUUID = UUID.Zero; // UUID.Zero means System + if (requestParam.Contains("fromUUID")) UUID.TryParse((string)requestParam["fromUUID"], out fromUUID); + if (requestParam.Contains("toUUID")) UUID.TryParse((string)requestParam["toUUID"], out toUUID); + + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY]: MoveMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = MoveMoneyFromTo(fromUUID, toUUID, amount, hash); + } + else { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("fromUUID") && !requestParam.Contains("toUUID")) { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: fromUUID and toUUID are missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: Move Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + #endregion + + + #region MoneyModule private help functions + + /// + /// Transfer the money from one user to another. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY]: TransferMoney:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY]: TransferMoney: Client {0} not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Force transfer the money from one user to another. + /// This function does not check sender login. + /// Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY]: ForceTransferMoney:"); + + bool ret = false; + + #region Force send transaction request to money server and parse the resultes. + + if (m_enable_server) { + string objName = string.Empty; + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj!=null)objName = sceneObj.Name; + + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = sender.ToString(); + paramTable["receiverID"] = receiver.ToString(); + paramTable["transactionType"] = type; + paramTable["objectID"] = objectID.ToString(); + paramTable["objectName"] = objName; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["amount"] = amount; + paramTable["description"] = description; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString()); + } + //else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Money Server is not available!!"); + + #endregion + + return ret; + } + + + /// + /// Send the money to avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool SendMoneyTo(UUID avatarID, int amount, int type, string secretCode) + { + //m_log.InfoFormat("[MONEY]: SendMoneyTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + if (type<0) type = (int)TransactionType.ReferBonus; + Hashtable paramTable = new Hashtable(); + paramTable["receiverID"] = avatarID.ToString(); + paramTable["transactionType"] = type; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Bonus to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Move the money from avatar to other avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool MoveMoneyFromTo(UUID senderID, UUID receiverID, int amount, string secretCode) + { + //m_log.InfoFormat("[MONEY]: MoveMoneyFromTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = senderID.ToString(); + paramTable["receiverID"] = receiverID.ToString(); + paramTable["transactionType"] = (int)TransactionType.MoveMoney; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Move Money"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "MoveMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Add the money to banker avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle, UUID regionUUID) + { + //m_log.InfoFormat("[MONEY]: AddBankerMoney:"); + + bool ret = false; + m_settle_user = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["bankerID"] = bankerID.ToString(); + paramTable["transactionType"] = (int)TransactionType.BuyMoney; + paramTable["amount"] = amount; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["description"] = "Add Money to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null) { + if (resultTable.Contains("success") && (bool)resultTable["success"]==true) { + ret = true; + } + else { + if (resultTable.Contains("banker")) { + m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used. + if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used."); + } + else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Fail Message {0}", resultTable["message"]); + } + } + else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not available!!"); + + return ret; + } + + + /// + /// Pay the money of charge. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY]: PayMoneyCharge:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY]: PayMoneyCharge: Client {0} is not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Login the money server when the new client login. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LoginMoneyServer(ScenePresence avatar, out int balance) + { + //m_log.InfoFormat("[MONEY]: LoginMoneyServer:"); + + balance = 0; + bool ret = false; + bool isNpc = avatar.IsNPC; + + IClientAPI client = avatar.ControllingClient; + + #region Send money server the client info for login. + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + Scene scene = (Scene)client.Scene; + string userName = string.Empty; + + // Get the username for the login user. + if (client.Scene is Scene) { + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId); + if (account!=null) { + userName = account.FirstName + " " + account.LastName; + } + } + } + + ////////////////////////////////////////////////////////////// + // User Universal Identifer for Grid Avatar, HG Avatar or NPC + string universalID = string.Empty; + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + int avatarType = (int)AvatarType.LOCAL_AVATAR; + int avatarClass = (int)AvatarType.LOCAL_AVATAR; + + AgentCircuitData agent = scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); + + if (agent!=null) { + universalID = Util.ProduceUserUniversalIdentifier(agent); + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + string tmp; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out tmp); + } + // if serverURL is empty, avatar is a NPC + if (isNpc || String.IsNullOrEmpty(serverURL)) { + avatarType = (int)AvatarType.NPC_AVATAR; + } + // + if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin)!=0 || String.IsNullOrEmpty(userName)) { + avatarType = (int)AvatarType.HG_AVATAR; + } + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // + avatarClass = avatarType; + if (avatarType==(int)AvatarType.NPC_AVATAR) return false; + if (avatarType==(int)AvatarType.HG_AVATAR) avatarClass = m_hg_avatarClass; + + // + // Login the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(), + scene.RegionInfo.HttpPort.ToString()); + paramTable["avatarType"] = avatarType.ToString(); + paramTable["avatarClass"] = avatarClass.ToString(); + paramTable["userName"] = userName; + paramTable["universalID"] = universalID; + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + balance = (int)resultTable["clientBalance"]; + m_log.InfoFormat("[MONEY]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL); + ret = true; + } + } + else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString()); + } + else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Money Server is not available!!"); + + #endregion + + // Viewerへ設定を通知する. + if (ret || string.IsNullOrEmpty(m_moneyServURL)) { + OnEconomyDataRequest(client); + } + + return ret; + } + + + /// + /// Log off from the money server. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LogoffMoneyServer(IClientAPI client) + { + //m_log.InfoFormat("[MONEY]: LogoffMoneyServer:"); + + bool ret = false; + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + // Log off from the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout"); + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + } + + return ret; + } + + + // + private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID) + { + //m_log.InfoFormat("[MONEY]: GetTransactionInfo:"); + + EventManager.MoneyTransferArgs args = null; + + if (m_enable_server) { + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + paramTable["transactionID"] = transactionID; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + int amount = (int)resultTable["amount"]; + int type = (int)resultTable["type"]; + string desc = (string)resultTable["description"]; + UUID sender = UUID.Zero; + UUID recver = UUID.Zero; + UUID.TryParse((string)resultTable["sender"], out sender); + UUID.TryParse((string)resultTable["receiver"], out recver); + args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc); + } + else { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]); + } + } + else { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Response"); + } + } + else { + m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Money Server URL"); + } + + return args; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method) + { + //m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest:"); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!m_moneyServURL.StartsWith("https://")) { + m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file"); + //return null; + } + } + else { + if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL); + return null; + } + } + + // + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL); + m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: {0}", ex); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /// Locates a IClientAPI for the client specified + /// + /// + /// + private IClientAPI GetLocateClient(UUID AgentID) + { + IClientAPI client = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID); + if (tPresence!=null && !tPresence.IsChildAgent) { + IClientAPI rclient = tPresence.ControllingClient; + if (rclient!=null) { + client = rclient; + break; + } + } + } + } + } + + return client; + } + + + private Scene GetLocateScene(UUID AgentId) + { + Scene scene = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId); + if (tPresence!=null && !tPresence.IsChildAgent) { + scene = _scene; + break; + } + } + } + } + + return scene; + } + + + private SceneObjectPart GetLocatePrim(UUID objectID) + { + SceneObjectPart sceneObj = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID); + if (part!=null) { + sceneObj = part; + break; + } + } + } + } + + return sceneObj; + } + + #endregion + } + +} diff --git a/release/0.9.1_1/src/OpenSim.Modules.Currency/NSLCertificateTools.cs b/release/0.9.1_1/src/OpenSim.Modules.Currency/NSLCertificateTools.cs new file mode 100644 index 0000000..6365c8f --- /dev/null +++ b/release/0.9.1_1/src/OpenSim.Modules.Currency/NSLCertificateTools.cs @@ -0,0 +1,226 @@ +/* + * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp + * + */ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Net; +using System.Net.Security; +using System.Text; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; + +using log4net; + + +namespace NSL.Certificate.Tools +{ + // + public class NSLCertificateVerify + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private X509Chain m_chain = null; + private X509Certificate2 m_cacert = null; + + private Mono.Security.X509.X509Crl m_clientcrl = null; + + + public NSLCertificateVerify() + { + m_chain = null; + m_cacert = null; + m_clientcrl = null; + } + + + public NSLCertificateVerify(string certfile) + { + SetPrivateCA(certfile); + } + + + public NSLCertificateVerify(string certfile, string crlfile) + { + SetPrivateCA (certfile); + SetPrivateCRL(crlfile); + } + + + public void SetPrivateCA(string certfile) + { + try { + m_cacert = new X509Certificate2(certfile); + } + catch (Exception ex) + { + m_cacert = null; + m_log.ErrorFormat("[SET PRIVATE CA]: CA File reading error [{0}]. {1}", certfile, ex); + } + + if (m_cacert!=null) { + m_chain = new X509Chain(); + m_chain.ChainPolicy.ExtraStore.Add(m_cacert); + m_chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + m_chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; + } + } + + + public void SetPrivateCRL(string crlfile) + { + try { + m_clientcrl = Mono.Security.X509.X509Crl.CreateFromFile(crlfile); + } + catch (Exception ex) + { + m_clientcrl = null; + m_log.ErrorFormat("[SET PRIVATE CRL]: CRL File reading error [{0}]. {1}", crlfile, ex); + } + } + + + // + // + // + public bool CheckPrivateChain(X509Certificate2 cert) + { + if (m_chain==null || m_cacert==null) { + return false; + } + + bool ret = m_chain.Build((X509Certificate2)cert); + if (ret) { + return true; + } + + for (int i=0; i tableList = new Dictionary(); + tableList = CheckTables(); + + // + // Balances Table + if (!tableList.ContainsKey(Table_of_Balances)) { + try { + CreateBalancesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating balances table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_Balances].Trim(); + int nVer = getTableVersionNum(version); + balances_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateBalancesTable1(); + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 2: //Rev.2 + UpdateBalancesTable2(); + UpdateBalancesTable3(); + break; + case 3: //Rev.3 + UpdateBalancesTable3(); + break; + } + } + + // + // UserInfo Table + if (!tableList.ContainsKey(Table_of_UserInfo)) { + try { + CreateUserInfoTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating userinfo table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_UserInfo].Trim(); + int nVer = getTableVersionNum(version); + userinfo_rev = nVer; + switch (nVer) { + case 1: //Rev.1 + UpdateUserInfoTable1(); + UpdateUserInfoTable2(); + break; + case 2: //Rev.2 + UpdateUserInfoTable2(); + break; + } + } + + // + // Transactions Table + if (!tableList.ContainsKey(Table_of_Transactions)) { + try { + CreateTransactionsTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating transactions table: " + e.ToString()); + } + } + // check transactions table version + else { + string version = tableList[Table_of_Transactions].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 2: //Rev.2 + UpdateTransactionsTable2(); + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 3: //Rev.3 + UpdateTransactionsTable3(); + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 4: //Rev.4 + UpdateTransactionsTable4(); + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 5: //Rev.5 + UpdateTransactionsTable5(); + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 6: //Rev.6 + UpdateTransactionsTable6(); + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 7: //Rev.7 + UpdateTransactionsTable7(); + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 8: //Rev.8 + UpdateTransactionsTable8(); + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 9: //Rev.9 + UpdateTransactionsTable9(); + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 10: //Rev.10 + UpdateTransactionsTable10(); + UpdateTransactionsTable11(); + break; + case 11: //Rev.11 + UpdateTransactionsTable11(); + break; + } + } + + // + // TotalSales Table + if (!tableList.ContainsKey(Table_of_TotalSales)) { + try { + CreateTotalSalesTable(); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error creating totalsales table: " + e.ToString()); + } + } + else { + string version = tableList[Table_of_TotalSales].Trim(); + int nVer = getTableVersionNum(version); + switch (nVer) { + case 1: //Rev.1 + UpdateTotalSalesTable1(); + UpdateTotalSalesTable2(); + break; + case 2: //Rev.2 + UpdateTotalSalesTable2(); + break; + } + } + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + throw new Exception("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString()); + } + } + + + private int getTableVersionNum(string version) + { + int nVer = 0; + + Regex _commentPattenRegex = new Regex(@"\w+\.(?\d+)"); + Match m = _commentPattenRegex.Match(version); + if (m.Success) { + string ver = m.Groups["ver"].Value; + nVer = Convert.ToInt32(ver); + } + return nVer; + } + + + + /////////////////////////////////////////////////////////////////////// + // create Tables + + private void CreateBalancesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Balances + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`balance` int(10) NOT NULL,"; + sql += "`status` tinyint(2) DEFAULT NULL,"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.4';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateUserInfoTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_UserInfo + "` ("; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`simip` varchar(64) NOT NULL,"; + sql += "`avatar` varchar(50) NOT NULL,"; + sql += "`pass` varchar(36) NOT NULL DEFAULT '',"; + sql += "`type` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`class` tinyint(2) NOT NULL DEFAULT 0,"; + sql += "`serverurl` varchar(255) NOT NULL DEFAULT '',"; + sql += "PRIMARY KEY(`user`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTransactionsTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_Transactions + "`("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`sender` varchar(36) NOT NULL,"; + sql += "`receiver` varchar(36) NOT NULL,"; + sql += "`amount` int(10) NOT NULL,"; + sql += "`senderBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`receiverBalance` int(10) NOT NULL DEFAULT -1,"; + sql += "`objectUUID` varchar(36) DEFAULT NULL,"; + sql += "`objectName` varchar(255) DEFAULT NULL,"; + sql += "`regionHandle` varchar(36) NOT NULL,"; + sql += "`regionUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`time` int(11) NOT NULL,"; + sql += "`secure` varchar(36) NOT NULL,"; + sql += "`status` tinyint(1) NOT NULL,"; + sql += "`commonName` varchar(128) NOT NULL,"; + sql += "`description` varchar(255) DEFAULT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.12';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + private void CreateTotalSalesTable() + { + string sql = string.Empty; + + sql = "CREATE TABLE `" + Table_of_TotalSales + "` ("; + sql += "`UUID` varchar(36) NOT NULL,"; + sql += "`user` varchar(36) NOT NULL,"; + sql += "`objectUUID` varchar(36) NOT NULL,"; + sql += "`type` int(10) NOT NULL,"; + sql += "`TotalCount` int(10) NOT NULL DEFAULT 0,"; + sql += "`TotalAmount` int(10) NOT NULL DEFAULT 0,"; + sql += "`time` int(11) NOT NULL,"; + sql += "PRIMARY KEY(`UUID`))"; + sql += "Engine=InnoDB DEFAULT CHARSET=utf8 "; + /////////////////////////////////////////////// + sql += "COMMENT='Rev.3';"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + initTotalSalesTable(); + } + + + + /////////////////////////////////////////////////////////////////////// + // update Balances Table + + private void UpdateBalancesTable1() + { + m_log.Info("[MONEY MANAGER]: Converting Balance Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Balances; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT * FROM " + Table_of_Balances; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i=0) { + amount += balance; + updatedb = updateBalance(uuid, amount); + } + else { + updatedb = addUser(uuid, amount, int.Parse(row[i,2]), 0); + } + if (!updatedb) break; + } + } + + // Delete + if (updatedb) { + for (int i=0; i uuid, url, name, pass + bool updatedb = true; + for (int i=0; i + /// update transactions table from Rev.2 to Rev.3 + /// + private void UpdateTransactionsTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`objectUUID` varchar(36) DEFAULT NULL AFTER `amount`),"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.3 to Rev.4 + /// + private void UpdateTransactionsTable3() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`secure` varchar(36) NOT NULL AFTER `time`),"; + sql += "COMMENT = 'Rev.4';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.4 to Rev.5 + /// + private void UpdateTransactionsTable4() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`regionHandle` varchar(36) NOT NULL AFTER `objectUUID`),"; + sql += "COMMENT = 'Rev.5';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.5 to Rev.6 + /// + private void UpdateTransactionsTable5() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD(`commonName` varchar(128) NOT NULL AFTER `status`),"; + sql += "COMMENT = 'Rev.6';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.6 to Rev.7 + /// + private void UpdateTransactionsTable6() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM " + Table_of_Transactions; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + sql = "SELECT UUID,sender,receiver FROM " + Table_of_Transactions; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[,] row = new string[resultCount, dbReader.FieldCount]; + while (dbReader.Read()) { + for (int i=0; i + /// update transactions table from Rev.7 to Rev.8 + /// + private void UpdateTransactionsTable7() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `objectName` varchar(255) DEFAULT NULL AFTER `objectUUID`,"; + sql += "COMMENT = 'Rev.8';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.8 to Rev.9 + /// + private void UpdateTransactionsTable8() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `senderBalance` int(10) NOT NULL DEFAULT -1 AFTER `amount`,"; + sql += "ADD `receiverBalance` int(10) NOT NULL DEFAULT -1 AFTER `senderBalance`,"; + sql += "COMMENT = 'Rev.9';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.9 to Rev.10 + /// + private void UpdateTransactionsTable9() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "MODIFY COLUMN `sender` varchar(36) NOT NULL,"; + sql += "MODIFY COLUMN `receiver` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.10';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /// + /// update transactions table from Rev.10 to Rev.11 + /// change type of BirthGift from 1000 to 900 + /// + private void UpdateTransactionsTable10() + { + //m_log.Info("[MONEY MANAGER]: Converting Transaction Table..."); + string sql = string.Empty; + + sql = "SELECT COUNT(*) FROM `" + Table_of_Transactions + "` WHERE type=1000"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + int resultCount = int.Parse(cmd.ExecuteScalar().ToString()); + cmd.Dispose(); + + if (resultCount>0) { + sql = "SELECT UUID FROM `" + Table_of_Transactions + "` WHERE type=1000"; + cmd = new MySqlCommand(sql, dbcon); + MySqlDataReader dbReader = cmd.ExecuteReader(); + + int l = 0; + string[] row = new string[resultCount]; + while (dbReader.Read()) { + row[l] = dbReader.GetString(0); + l++; + } + dbReader.Close(); + cmd.Dispose(); + + sql = "UPDATE `" + Table_of_Transactions + "` SET type=900 WHERE UUID=?uuid"; + for (int i=0; i + /// update transactions table from Rev.11 to Rev.12 + /// + private void UpdateTransactionsTable11() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_Transactions + "` "; + sql += "ADD `regionUUID` varchar(36) NOT NULL AFTER `regionHandle`,"; + sql += "COMMENT = 'Rev.12';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + // update Total Sales Table + + private void UpdateTotalSalesTable1() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "ADD `time` int(11) NOT NULL AFTER `TotalAmount`,"; + sql += "COMMENT = 'Rev.2';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + + deleteTotalSalesTable(); + initTotalSalesTable(); + } + + + private void UpdateTotalSalesTable2() + { + string sql = string.Empty; + + sql = "BEGIN;"; + sql += "ALTER TABLE `" + Table_of_TotalSales + "` "; + sql += "MODIFY COLUMN `user` varchar(36) NOT NULL,"; + sql += "COMMENT = 'Rev.3';"; + sql += "COMMIT;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.ExecuteNonQuery(); + cmd.Dispose(); + } + + + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + // + + private Dictionary CheckTables() + { + Dictionary tableDic = new Dictionary(); + + lock (dbcon) { + string sql = string.Empty; + + sql = "SELECT TABLE_NAME,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?dbname"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?dbname", dbcon.Database); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + while (r.Read()) { + try { + string tableName = (string)r["TABLE_NAME"]; + string comment = (string)r["TABLE_COMMENT"]; + tableDic.Add(tableName, comment); + } + catch (Exception e) { + throw new Exception("[MONEY MANAGER]: Error checking tables" + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return tableDic; + } + } + + + /// + /// Reconnect to the database + /// + public void Reconnect() + { + m_log.Info("[MONEY MANAGER]: Reconnecting database"); + lock (dbcon) { + try { + dbcon.Close(); + dbcon = new MySqlConnection(connectString); + dbcon.Open(); + m_log.Info("[MONEY MANAGER]: Reconnected database"); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to reconnect to database: " + e.ToString()); + } + } + } + + + + /////////////////////////////////////////////////////////////////////// + // + // balances + // + + /// + /// Get balance from database. returns -1 if failed. + /// + /// + /// + public int getBalance(string userID) + { + if (userID==UUID.Zero.ToString()) return 999999999; // System + + int retValue = -1; + string sql = string.Empty; + + sql = "SELECT balance FROM " + Table_of_Balances + " WHERE user = ?userid"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userid", userID); + + using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { + try { + if (dbReader.Read()) { + retValue = Convert.ToInt32(dbReader["balance"]); + } + } +#pragma warning disable CS0168 // The variable 'e' is declared but never +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception e) { + m_log.ErrorFormat("[MoneyDB]: MySql failed to fetch balance {0}.", userID); + retValue = -2; + } +#pragma warning restore CA1031 // Do not catch general exception types +#pragma warning restore CS0168 // The variable 'e' is declared but never + + dbReader.Close(); + } + cmd.Dispose(); + + return retValue; + } + + + public bool updateBalance(string userID, int amount) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Balances + " SET balance = ?amount WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userID", userID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool addUser(string userID, int balance, int status, int type) + { + if (userID==UUID.Zero.ToString()) return true; // System + + bool bRet = false; + string sql = string.Empty; + + if (balances_rev>=4) { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`,`type`) VALUES "; + sql += " (?userID,?balance,?status,?type);"; + } + else { + sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`) VALUES "; + sql += " (?userID,?balance,?status);"; + } + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userID", userID); + cmd.Parameters.AddWithValue("?balance", balance); + cmd.Parameters.AddWithValue("?status", status); + if (balances_rev>=4) { + cmd.Parameters.AddWithValue("?type", type); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + cmd.Dispose(); + + return bRet; + } + + + /// + /// Here we'll make a withdraw from the sender and update transaction status + /// + /// + /// + /// + /// + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + bool bRet = false; + string sql = string.Empty; + MySqlCommand cmd = null; + + // System + if (senderID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET senderBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET senderBalance = balance - ?amount, "+ Table_of_Transactions + ".status = ?status, balance = balance - ?amount "; + sql += " WHERE UUID = ?tranid AND user = sender AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", senderID); + cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Give money to the receiver and change the transaction status to success. + /// + /// + /// + /// + /// + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + string sql = string.Empty; + bool bRet = false; + MySqlCommand cmd = null; + + // System + if (receiverID==UUID.Zero.ToString()) { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions; + sql += " SET receiverBalance = 0, status = ?status WHERE UUID = ?tranid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + else { + sql = "BEGIN;"; + sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances; + sql += " SET receiverBalance = balance + ?amount, " + Table_of_Transactions + ".status = ?status, balance = balance + ?amount "; + sql += " WHERE UUID = ?tranid AND user = receiver AND user = ?userid;"; + sql += "COMMIT;"; + + cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?userid", receiverID); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success + cmd.Parameters.AddWithValue("?tranid", transactionID.ToString()); + } + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // totalsales + // + private void initTotalSalesTable() + { + m_log.Info("[MONEY MANAGER]: Initailising TotalSales Table..."); + string sql = string.Empty; + + sql = "SELECT SQL_CALC_FOUND_ROWS receiver,objectUUID,type,COUNT(*),SUM(amount),MIN(time) FROM "+ Table_of_Transactions; + sql += " WHERE sender != receiver AND status = ?status AND sender != ?system"; + sql += " GROUP BY receiver,objectUUID,type;"; + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); + cmd.Parameters.AddWithValue("?system", UUID.Zero.ToString()); + cmd.ExecuteNonQuery(); + + MySqlCommand cmd2 = new MySqlCommand("SELECT FOUND_ROWS();", dbcon); + int lineCount = int.Parse(cmd2.ExecuteScalar().ToString()); + cmd2.Dispose(); + + if (lineCount<=0) { + cmd.Dispose(); + return; + } + + MySqlDataReader r = cmd.ExecuteReader(); + int l = 0; + string[,] row = new string[lineCount, r.FieldCount]; + while (r.Read()) { + for (int i=0; i 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTotalSale(UUID saleUUID, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_TotalSales; + sql += " SET TotalCount = TotalCount + ?count, TotalAmount = TotalAmount + ?amount, time = ?time "; + sql += " WHERE UUID = ?uuid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?uuid", saleUUID.ToString()); + cmd.Parameters.AddWithValue("?count", count); + cmd.Parameters.AddWithValue("?amount", amount); + cmd.Parameters.AddWithValue("?time", tmstamp); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + + } + + + public bool setTotalSale(string userUUID, string objectUUID, int type, int count, int amount, int tmstamp) + { + bool bRet = false; + string sql = string.Empty; + string uuid = string.Empty; + int dbtm = 0; + + sql = "SELECT UUID,time FROM " + Table_of_TotalSales; + sql += " WHERE user = ?userid AND objectUUID = ?objID AND type = ?type;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?userid", userUUID); + cmd.Parameters.AddWithValue("?objID", objectUUID); + cmd.Parameters.AddWithValue("?type", type); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + uuid = (string)r["UUID"]; + dbtm = Convert.ToInt32(r["time"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get sale data from DB failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return false; + } + } + r.Close(); + } + + if (uuid!=string.Empty) { + UUID saleUUID = UUID.Zero; + UUID.TryParse(uuid, out saleUUID); + if (dbtm 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions + " SET status = ?status,description = ?desc WHERE UUID = ?tranid;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?status", status); + cmd.Parameters.AddWithValue("?desc", description); + cmd.Parameters.AddWithValue("?tranid", transactionID); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public bool SetTransExpired(int deadTime) + { + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_Transactions; + sql += " SET status = ?failedstatus,description = ?desc WHERE time <= ?deadTime AND status = ?pendingstatus;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?failedstatus", (int)Status.FAILED_STATUS); + cmd.Parameters.AddWithValue("?desc", "expired"); + cmd.Parameters.AddWithValue("?deadTime", deadTime); + cmd.Parameters.AddWithValue("?pendingstatus", (int)Status.PENDING_STATUS); + + if (cmd.ExecuteNonQuery() > 0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + /// + /// Validate if the transacion is legal + /// + /// + /// + /// + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + bool bRet = false; + string secure = string.Empty; + string sql = string.Empty; + + sql = "SELECT secure FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + secure = (string)r["secure"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Get transaction from DB failed: " + e.ToString()); + } + if (secureCode == secure) bRet = true; + else bRet = false; + } + r.Close(); + } + + cmd.Dispose(); + return bRet; + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + TransactionData transactionData = new TransactionData(); + transactionData.TransUUID = transactionID; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE UUID = ?transID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?transID", transactionID.ToString()); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 1: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + + } + r.Close(); + } + + cmd.Dispose(); + return transactionData; + } + + + public TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index, uint retNum) + { + List rows = new List(); + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user) ORDER BY time ASC LIMIT ?index,?num;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + cmd.Parameters.AddWithValue("?index", index); + cmd.Parameters.AddWithValue("?num", retNum); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + for (int i = 0; i < retNum; i++) { + if (r.Read()) { + try { + TransactionData transactionData = new TransactionData(); + string uuid = (string)r["UUID"]; + UUID transUUID; + UUID.TryParse(uuid,out transUUID); + + transactionData.TransUUID = transUUID; + transactionData.Sender = (string)r["sender"]; + transactionData.Receiver = (string)r["receiver"]; + transactionData.Amount = Convert.ToInt32(r["amount"]); + transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]); + transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]); + transactionData.Type = Convert.ToInt32(r["type"]); + transactionData.Time = Convert.ToInt32(r["time"]); + transactionData.Status = Convert.ToInt32(r["status"]); + transactionData.CommonName = (string)r["commonName"]; + transactionData.RegionHandle = (string)r["regionHandle"]; + transactionData.RegionUUID = (string)r["regionUUID"]; + // + if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString(); + else transactionData.ObjectUUID = (string)r["objectUUID"]; + if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty; + else transactionData.ObjectName = (string)r["objectName"]; + if (r["description"] is System.DBNull) transactionData.Description = string.Empty; + else transactionData.Description = (string)r["description"]; + // + rows.Add(transactionData); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching transaction failed 2: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + } + r.Close(); + } + + cmd.Dispose(); + return rows.ToArray(); + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + int iRet = -1; + string sql = string.Empty; + + sql = "SELECT COUNT(*) AS number FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end "; + sql += "AND (sender=?user OR receiver=?user);"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + + cmd.Parameters.AddWithValue("?start", startTime); + cmd.Parameters.AddWithValue("?end", endTime); + cmd.Parameters.AddWithValue("?user", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if(r.Read()) { + try { + iRet = Convert.ToInt32(r["number"]); + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Unable to get transaction info: " + e.ToString()); + } + } + r.Close(); + } + + cmd.Dispose(); + return iRet; + } + + + + /////////////////////////////////////////////////////////////////////// + // + // userinfo + // + public bool addUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Adding UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + if (userInfo.Avatar==null) return false; + + if (userinfo_rev>=3) { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`,`type`,`class`,`serverurl`) VALUES"; + sql += "(?user,?simip,?avatar,?password,?type,?class,?serverurl);"; + } + else { + sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`) VALUES"; + sql += "(?user,?simip,?avatar,?password);"; + } + + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?avatar", userInfo.Avatar); + cmd.Parameters.AddWithValue("?password", userInfo.PswHash); + if (userinfo_rev>=3) { + cmd.Parameters.AddWithValue("?type", userInfo.Type); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + } + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + + public UserInfo fetchUserInfo(string userID) + { + //m_log.Error("[MONEY MANAGER]: Fetching UserInfo: " + userID); + + UserInfo userInfo = new UserInfo(); + userInfo.UserID = null; + string sql = string.Empty; + + sql = "SELECT * FROM " + Table_of_UserInfo + " WHERE user = ?userID;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?userID", userID); + + using (MySqlDataReader r = cmd.ExecuteReader()) { + if (r.Read()) { + try { + userInfo.UserID = (string)r["user"]; + userInfo.SimIP = (string)r["simip"]; + userInfo.Avatar = (string)r["avatar"]; + userInfo.PswHash = (string)r["pass"]; + userInfo.Type = Convert.ToInt32(r["type"]); + userInfo.Class = Convert.ToInt32(r["class"]); + userInfo.ServerURL = (string)r["serverurl"]; + } + catch (Exception e) { + m_log.Error("[MONEY MANAGER]: Fetching UserInfo failed: " + e.ToString()); + r.Close(); + cmd.Dispose(); + return null; + } + } + r.Close(); + } + cmd.Dispose(); + + if (userInfo.UserID!=userID) return null; + return userInfo; + } + + + public bool updateUserInfo(UserInfo userInfo) + { + //m_log.Error("[MONEY MANAGER]: Updating UserInfo: " + userInfo.UserID); + + bool bRet = false; + string sql = string.Empty; + + sql = "UPDATE " + Table_of_UserInfo + " SET simip=?simip,pass=?pass,class=?class,serverurl=?serverurl WHERE user=?user;"; + MySqlCommand cmd = new MySqlCommand(sql, dbcon); + cmd.Parameters.AddWithValue("?simip", userInfo.SimIP); + cmd.Parameters.AddWithValue("?pass", userInfo.PswHash); + cmd.Parameters.AddWithValue("?class", userInfo.Class); + cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL); + cmd.Parameters.AddWithValue("?user", userInfo.UserID); + + if (cmd.ExecuteNonQuery()>0) bRet = true; + + cmd.Dispose(); + return bRet; + } + + } +} diff --git a/release/0.9.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs b/release/0.9.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs new file mode 100644 index 0000000..26974c8 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs @@ -0,0 +1,53 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + // This bit of code is from OpenSim.Data.MySQLSuperManager + public class MySQLSuperManager + { + public bool Locked; + private readonly Mutex m_lock = new Mutex(false); + public MySQLMoneyManager Manager; + public string Running; + + public void GetLock() + { + Locked = true; + m_lock.WaitOne(); + } + + public void Release() + { + m_lock.ReleaseMutex(); + Locked = false; + } + } +} diff --git a/release/0.9.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs b/release/0.9.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs new file mode 100644 index 0000000..abb0fd1 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs @@ -0,0 +1,237 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + + +namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper +{ + public class TransactionData + { + UUID m_uuid; + string m_sender = string.Empty; + string m_receiver = string.Empty; + int m_amount; + int m_senderBalance; + int m_receiverBalance; + int m_type; + int m_time; + int m_status; + string m_objectID = UUID.Zero.ToString(); +// string m_objectID = "00000000-0000-0000-0000-000000000000"; + string m_objectName = string.Empty; + string m_regionHandle = string.Empty; + string m_regionUUID = string.Empty; + string m_secureCode = string.Empty; + string m_commonName = string.Empty; + string m_description = string.Empty; + +/* + public TransactionData(string uuid, string sender, string receiver, + int amount, int time, int status, string description) + { + this.m_uuid = uuid; + this.m_sender = sender; + this.m_receiver = receiver; + this.m_amount = amount; + } +*/ + + public UUID TransUUID + { + get { return m_uuid; } + set { m_uuid = value; } + } + + public string Sender + { + get { return m_sender; } + set { m_sender = value; } + } + + public string Receiver + { + get { return m_receiver; } + set { m_receiver = value; } + } + + public int Amount + { + get { return m_amount; } + set { m_amount = value; } + } + + public int SenderBalance + { + get { return m_senderBalance; } + set { m_senderBalance = value; } + } + + public int ReceiverBalance + { + get { return m_receiverBalance; } + set { m_receiverBalance = value; } + } + + public int Type + { + get { return m_type; } + set { m_type = value; } + } + + public int Time + { + get { return m_time; } + set { m_time = value; } + } + + public int Status + { + get { return m_status; } + set { m_status = value; } + } + + public string Description + { + get { return m_description; } + set { m_description = value; } + } + + public string ObjectUUID + { + get { return m_objectID; } + set { m_objectID = value; } + } + + public string ObjectName + { + get { return m_objectName; } + set { m_objectName = value; } + } + + public string RegionHandle + { + get { return m_regionHandle; } + set { m_regionHandle = value; } + } + + public string RegionUUID + { + get { return m_regionUUID; } + set { m_regionUUID = value; } + } + + public string SecureCode + { + get { return m_secureCode; } + set { m_secureCode = value; } + } + + public string CommonName + { + get { return m_commonName; } + set { m_commonName = value; } + } + } + + + public enum Status + { + SUCCESS_STATUS = 0, + PENDING_STATUS = 1, + FAILED_STATUS = 2, + ERROR_STATUS = 9 + } + + + public enum AvatarType + { + LOCAL_AVATAR = 0, + HG_AVATAR = 1, + NPC_AVATAR = 2, + GUEST_AVATAR = 3, + FOREIGN_AVATAR = 8, + UNKNOWN_AVATAR = 9 + } + + + public class UserInfo + { + string m_userID = string.Empty; + string m_simIP = string.Empty; + string m_avatarName = string.Empty; + string m_passwordHash = string.Empty; + int m_avatarType = (int)AvatarType.LOCAL_AVATAR; + int m_avatarClass = (int)AvatarType.LOCAL_AVATAR; + string m_serverURL = string.Empty; + + public string UserID + { + get { return m_userID; } + set { m_userID = value; } + } + + public string SimIP + { + get { return m_simIP; } + set { m_simIP = value; } + } + + public string Avatar + { + get { return m_avatarName; } + set { m_avatarName = value; } + } + + public string PswHash + { + get { return m_passwordHash; } + set { m_passwordHash = value; } + } + + public int Type + { + get { return m_avatarType; } + set { m_avatarType = value; } + } + + public int Class + { + get { return m_avatarClass; } + set { m_avatarClass = value; } + } + + public string ServerURL + { + get { return m_serverURL; } + set { m_serverURL = value; } + } + } +} diff --git a/release/0.9.2/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs b/release/0.9.2/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs new file mode 100644 index 0000000..2043719 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Grid.MoneyServer/IMoneyDBService.cs @@ -0,0 +1,77 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma warning disable IDE1006 + +#pragma warning disable S1128 // Unused "using" should be removed +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +#pragma warning restore S1128 // Unused "using" should be removed + + +namespace OpenSim.Grid.MoneyServer +{ + /// + /// IMoney DB Service + /// + public interface IMoneyDBService + { + int getBalance(string userID); + + bool withdrawMoney(UUID transactionID, string senderID, int amount); + + bool giveMoney(UUID transactionID, string receiverID, int amount); + + bool addTransaction(TransactionData transaction); + + bool addUser(string userID, int balance, int status, int type); + + bool updateTransactionStatus(UUID transactionID, int status, string description); + + bool SetTransExpired(int deadTime); + + bool ValidateTransfer(string secureCode, UUID transactionID); + + TransactionData FetchTransaction(UUID transactionID); + + TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex); + + int getTransactionNum(string userID, int startTime, int endTime); + + bool DoTransfer(UUID transactionUUID); + + bool DoAddMoney(UUID transactionUUID); // Added by Fumi.Iseki + + bool TryAddUserInfo(UserInfo user); + + UserInfo FetchUserInfo(string userID); + + } +} diff --git a/release/0.9.2/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs b/release/0.9.2/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs new file mode 100644 index 0000000..7f84903 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Text; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; + +using Nini.Config; + + +namespace OpenSim.Grid.MoneyServer +{ + public interface IMoneyServiceCore + { + BaseHttpServer GetHttpServer(); + Dictionary GetSessionDic(); + Dictionary GetSecureSessionDic(); + Dictionary GetWebSessionDic(); + + // + IConfig GetServerConfig(); + IConfig GetCertConfig(); + bool IsCheckClientCert(); + } +} diff --git a/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs b/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs new file mode 100644 index 0000000..07fa789 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyDBService.cs @@ -0,0 +1,584 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using log4net; +using System.Reflection; +using OpenMetaverse; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyDBService: IMoneyDBService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string m_connect; + //private MySQLMoneyManager m_moneyManager; + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + // DB manager pool + protected Dictionary m_dbconnections = new Dictionary(); // with Lock + private int m_maxConnections; + + public int m_lastConnect = 0; + + + public MoneyDBService(string connect) + { + m_connect = connect; + Initialise(m_connect,10); + } + + + public MoneyDBService() + { + } + + + public void Initialise(string connectionString, int maxDBConnections) + { + m_connect = connectionString; + m_maxConnections = maxDBConnections; + if (connectionString != string.Empty) { + //m_moneyManager = new MySQLMoneyManager(connectionString); + + //m_log.Info("Creating " + m_maxConnections + " DB connections..."); + for (int i=0; im_maxConnections) { + lockedCons = 0; + System.Threading.Thread.Sleep(1000); // Wait some time before searching them again. + m_log.Debug("WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound."); + } + } + } + + + public int getBalance(string userID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getBalance(userID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.getBalance(userID); + } + catch(Exception e) { + m_log.Error(e.ToString()); + return 0; + } + finally { + dbm.Release(); + } + } + + + public bool withdrawMoney(UUID transactionID, string senderID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.withdrawMoney(transactionID, senderID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool giveMoney(UUID transactionID, string receiverID, int amount) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.giveMoney(transactionID, receiverID, amount); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool setTotalSale(TransactionData transaction) + { + if (transaction.Receiver==transaction.Sender) return false; + if (transaction.Sender==UUID.Zero.ToString()) return false; + + MySQLSuperManager dbm = GetLockedConnection(); + + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addTransaction(TransactionData transaction) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.addTransaction(transaction); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.addTransaction(transaction); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool addUser(string userID, int balance, int status, int type) + { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = UUID.Random(); + transaction.Sender = UUID.Zero.ToString(); + transaction.Receiver = userID; + transaction.Amount = balance; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.ObjectName = string.Empty; + transaction.RegionHandle = string.Empty; + transaction.Type = (int)TransactionType.BirthGift; + transaction.Time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);; + transaction.Status = (int)Status.PENDING_STATUS; + transaction.SecureCode = UUID.Random().ToString(); + transaction.CommonName = string.Empty; + transaction.Description = "addUser " + DateTime.UtcNow.ToString(); + + bool ret = addTransaction(transaction); + if (!ret) return false; + + // + MySQLSuperManager dbm = GetLockedConnection(); + + try { + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + + // + if (ret) ret = giveMoney(transaction.TransUUID, userID, balance); + return ret; + } + + + public bool updateTransactionStatus(UUID transactionID, int status, string description) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.updateTransactionStatus(transactionID, status, description); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool SetTransExpired(int deadTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.SetTransExpired(deadTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.SetTransExpired(deadTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public bool ValidateTransfer(string secureCode, UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.ValidateTransfer(secureCode, transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(UUID transactionID) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.FetchTransaction(transactionID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.FetchTransaction(transactionID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex) + { + MySQLSuperManager dbm = GetLockedConnection(); + TransactionData[] arrTransaction; + + uint index = 0; + if (lastIndex>=0) index = Convert.ToUInt32(lastIndex) + 1; + + try { + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + + // + if (arrTransaction.Length > 0) { + return arrTransaction[0]; + } + else { + return null; + } + } + + + public bool DoTransfer(UUID transactionUUID) + { + bool do_trans = false; + + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction != null && transaction.Status == (int)Status.PENDING_STATUS) { + int balance = getBalance(transaction.Sender); + + //check the amount + if (transaction.Amount >= 0 && balance >= transaction.Amount) { + if (withdrawMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver) == -1) { + m_log.ErrorFormat("[MONEY DB]: DoTransfer: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + do_trans = true; + } + else { // give money to receiver failed. Refund Processing + m_log.ErrorFormat("[MONEY DB]: Give money to receiver {0} failed", transaction.Receiver); + //Return money to sender + if (giveMoney(transactionUUID, transaction.Sender, transaction.Amount)) { + m_log.ErrorFormat("[MONEY DB]: give money to receiver {0} failed but return it to sender {1} successfully", + transaction.Receiver, transaction.Sender); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "give money to receiver failed but return it to sender successfully"); + } + else { + m_log.ErrorFormat("[MONEY DB]: FATAL ERROR: Money withdrawn from sender: {0}, but failed to be given to receiver {1}", + transaction.Sender, transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.ERROR_STATUS, "give money to receiver failed, and return it to sender unsuccessfully!!!"); + } + } + } + else { // withdraw money failed + m_log.ErrorFormat("[MONEY DB]: Withdraw money from sender {0} failed", transaction.Sender); + } + } + else { // not enough balance to finish the transaction + m_log.ErrorFormat("[MONEY DB]: Not enough balance for user: {0} to apply the transaction.", transaction.Sender); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + // + if (do_trans) { + setTotalSale(transaction); + } + + return do_trans; + } + + + // by Fumi.Iseki + public bool DoAddMoney(UUID transactionUUID) + { + TransactionData transaction = new TransactionData(); + transaction = FetchTransaction(transactionUUID); + + if (transaction!=null && transaction.Status==(int)Status.PENDING_STATUS) { + //If receiver not found, add it to DB. + if (getBalance(transaction.Receiver)==-1) { + m_log.ErrorFormat("[MONEY DB]: DoAddMoney: Receiver not found in balances DB. {0}", transaction.Receiver); + return false; + } + // + if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) { + setTotalSale(transaction); + return true; + } + else { // give money to receiver failed. + m_log.ErrorFormat("[MONEY DB]: Add money to receiver {0} failed", transaction.Receiver); + updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "add money to receiver failed"); + } + } + else { // Can not fetch the transaction or it has expired + m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString()); + } + + return false; + } + + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // userinfo + // + + public bool TryAddUserInfo(UserInfo user) + { + MySQLSuperManager dbm = GetLockedConnection(); + + UserInfo userInfo = null; + + try { + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(user.UserID); + } + catch (Exception e) { + m_log.Error(e.ToString()); + dbm.Release(); + return false; + } + + try { + if (userInfo!=null) { + //m_log.InfoFormat("[MONEY DB]: Found user \"{0}\", now update information", user.Avatar); + if (dbm.Manager.updateUserInfo(user)) return true; + } + else if (dbm.Manager.addUserInfo(user)) { + //m_log.InfoFormat("[MONEY DB]: Unable to find user \"{0}\", add it to DB successfully", user.Avatar); + return true; + } + m_log.InfoFormat("[MONEY DB]: WARNNING: TryAddUserInfo: Unable to TryAddUserInfo."); + return false; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return false; + } + finally { + dbm.Release(); + } + } + + + public UserInfo FetchUserInfo(string userID) + { + UserInfo userInfo = null; + MySQLSuperManager dbm = GetLockedConnection(); + + try { + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + userInfo = dbm.Manager.fetchUserInfo(userID); + return userInfo; + } + catch (Exception e) { + m_log.Error(e.ToString()); + return null; + } + finally { + dbm.Release(); + } + } + + + public int getTransactionNum(string userID, int startTime, int endTime) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try { + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (MySql.Data.MySqlClient.MySqlException e) { + m_log.Info(e.ToString()); + dbm.Manager.Reconnect(); + return dbm.Manager.getTransactionNum(userID,startTime,endTime); + } + catch (Exception e) { + m_log.Error(e.ToString()); + return -1; + } + finally { + dbm.Release(); + } + } + } +} diff --git a/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs b/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs new file mode 100644 index 0000000..deddd76 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyServerBase.cs @@ -0,0 +1,407 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma warning disable S1128 // Unused "using" should be removed +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Net; +using System.Net.Security; +using System.Reflection; +using System.Timers; +using OpenSim.Framework.Servers.HttpServer; +using Nini.Config; +using log4net; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Data; +using NSL.Certificate.Tools; + +using System.Threading; +using System.Security.Cryptography.X509Certificates; +using log4net.Appender; +using log4net.Core; +using log4net.Repository; +using OpenMetaverse; +using Timer = System.Timers.Timer; +#pragma warning restore S1128 // Unused "using" should be removed + + +/// +/// OpenSim Grid MoneyServer +/// +namespace OpenSim.Grid.MoneyServer +{ + /// + /// class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore + /// Manni internal class + /// + internal class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string connectionString = string.Empty; + private uint m_moneyServerPort = 8008; // 8008 is default server port + + private string m_certFilename = ""; + private string m_certPassword = ""; + private string m_cacertFilename = ""; + private string m_clcrlFilename = ""; + private bool m_checkClientCert = false; + + private int DEAD_TIME = 120; + private int MAX_DB_CONNECTION = 10; + +#pragma warning disable S1450 // Private fields only used as local variables in methods should become local variables + private MoneyXmlRpcModule m_moneyXmlRpcModule; +#pragma warning restore S1450 // Private fields only used as local variables in methods should become local variables + private MoneyDBService m_moneyDBService; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // Client Certificate + +#pragma warning disable S2933 // Fields that are only assigned in the constructor should be "readonly" + private Dictionary m_sessionDic = new Dictionary(); + private Dictionary m_secureSessionDic = new Dictionary(); + private Dictionary m_webSessionDic = new Dictionary(); +#pragma warning restore S2933 // Fields that are only assigned in the constructor should be "readonly" + + IConfig m_server_config; + IConfig m_cert_config; + + + /// + /// Money Server Base + /// + public MoneyServerBase() + { + m_console = new LocalConsole("MoneyServer "); + MainConsole.Instance = m_console; + } + + + /// + /// Work + /// + public void Work() + { + //The timer checks the transactions table every 60 seconds + Timer checkTimer = new Timer + { + Interval = 60 * 1000, + Enabled = true + }; + checkTimer.Elapsed += new ElapsedEventHandler(CheckTransaction); + checkTimer.Start(); + + while (true) { + m_console.Prompt(); + } + } + + + /// + /// Check the transactions table, set expired transaction state to failed + /// + private void CheckTransaction(object sender, ElapsedEventArgs e) + { + long ticksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + int unixEpochTime = (int)((DateTime.UtcNow.Ticks - ticksToEpoch)/10000000); + int deadTime = unixEpochTime - DEAD_TIME; + m_moneyDBService.SetTransExpired(deadTime); + } + + + /// + /// Startup Specific + /// + protected override void StartupSpecific() + { + m_log.Info("[MONEY SERVER]: Setup HTTP Server process"); + + ReadIniConfig(); + + try { + if (m_certFilename != "") { + m_httpServer = new BaseHttpServer(m_moneyServerPort, true, m_certFilename, m_certPassword); + m_httpServer.CertificateValidationCallback = null; + // + if (m_checkClientCert) { + m_httpServer.CertificateValidationCallback = (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate; + m_log.Info("[MONEY SERVER]: Set RemoteCertificateValidationCallback"); + + /* + Type typeBaseHttpServer = typeof(BaseHttpServer); // BaseHttpServer.cs にパッチがあたっていない場合のため + PropertyInfo pinfo = typeBaseHttpServer.GetProperty("CertificateValidationCallback"); + + if (pinfo!=null) { + pinfo.SetValue(m_httpServer, (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate, null); + m_log.Info ("[MONEY SERVER]: Set RemoteCertificateValidationCallback"); + } + else { + m_log.Error("[MONEY SERVER]: StartupSpecific: CheckClientCert is true. But this MoneyServer does not support CheckClientCert!!"); + } + */ + } + } + else { + m_httpServer = new BaseHttpServer(m_moneyServerPort); + } + + SetupMoneyServices(); + m_httpServer.Start(); + base.StartupSpecific(); // OpenSim/Framework/Servers/BaseOpenSimServer.cs + } + + catch (Exception e) { + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Fail to start HTTPS process"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Please Check Certificate File or Password. Exit"); + m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: {0}", e); + Environment.Exit(1); + } + } + + + /// + /// Read Ini Config + /// + protected void ReadIniConfig() + { + MoneyServerConfigSource moneyConfig = new MoneyServerConfigSource(); + Config = moneyConfig.m_config; + + try { + // [Startup] + IConfig st_config = moneyConfig.m_config.Configs["Startup"]; + string PIDFile = st_config.GetString("PIDFile", ""); + if (PIDFile != "") Create_PIDFile(PIDFile); + + // [MySql] + IConfig db_config = moneyConfig.m_config.Configs["MySql"]; + string sqlserver = db_config.GetString("hostname", "localhost"); + string database = db_config.GetString("database", "OpenSim"); + string username = db_config.GetString("username", "root"); + string password = db_config.GetString("password", "password"); + string pooling = db_config.GetString("pooling", "false"); + string port = db_config.GetString("port", "3306"); + MAX_DB_CONNECTION = db_config.GetInt ("MaxConnection", MAX_DB_CONNECTION); + + connectionString = "Server=" + sqlserver + ";Port=" + port + ";Database=" + database + ";User ID=" + + username + ";Password=" + password + ";Pooling=" + pooling + ";"; + + // [MoneyServer] + m_server_config = moneyConfig.m_config.Configs["MoneyServer"]; + DEAD_TIME = m_server_config.GetInt("ExpiredTime", DEAD_TIME); + m_moneyServerPort = (uint)m_server_config.GetInt("ServerPort", (int)m_moneyServerPort); + + // + // [Certificate] + m_cert_config = moneyConfig.m_config.Configs["Certificate"]; + if (m_cert_config == null) { + m_log.Info("[MONEY SERVER]: [Certificate] section is not found. Using [MoneyServer] section instead"); + m_cert_config = m_server_config; + } + + // HTTPS Server Cert (Server Mode) // サーバ証明書 + m_certFilename = m_cert_config.GetString("ServerCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ServerCertPassword", m_certPassword); + if (m_certFilename != "") { + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute HTTPS comunication. Server Cert file is " + m_certFilename); + } + + // Client Certificate + m_checkClientCert = m_cert_config.GetBoolean("CheckClientCert", m_checkClientCert); + m_cacertFilename = m_cert_config.GetString ("CACertFilename", m_cacertFilename); + m_clcrlFilename = m_cert_config.GetString ("ClientCrlFilename", m_clcrlFilename); + // + if (m_checkClientCert && (m_cacertFilename != "")) { + m_certVerify.SetPrivateCA(m_cacertFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CA file is " + m_cacertFilename); + } + else { + m_checkClientCert = false; + } + + if (m_checkClientCert) { + if (m_clcrlFilename != "") { + m_certVerify.SetPrivateCRL(m_clcrlFilename); + m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CRL file is " + m_clcrlFilename); + } + } + } + + catch (Exception) + { + m_log.Error("[MONEY SERVER]: ReadIniConfig: Fail to setup configure. Please check MoneyServer.ini. Exit"); + Environment.Exit(1); + } + } + + + /// + /// Create PID File added by skidz + /// + protected void Create_PIDFile(string path) + { + try { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + m_pidFile = path; + } +#pragma warning disable S2486 // Generic exceptions should not be ignored +#pragma warning disable CA1031 // Do not catch general exception types +#pragma warning disable S108 // Nested blocks of code should not be left empty + catch (Exception) { } +#pragma warning restore S108 // Nested blocks of code should not be left empty +#pragma warning restore CA1031 // Do not catch general exception types +#pragma warning restore S2486 // Generic exceptions should not be ignored + } + + + /// + /// Setup Money Services + /// + protected virtual void SetupMoneyServices() + { + m_log.Info("[MONEY SERVER]: Connecting to Money Storage Server"); + + m_moneyDBService = new MoneyDBService(); + m_moneyDBService.Initialise(connectionString, MAX_DB_CONNECTION); + + m_moneyXmlRpcModule = new MoneyXmlRpcModule(); + m_moneyXmlRpcModule.Initialise(m_version, m_moneyDBService, this); + m_moneyXmlRpcModule.PostInitialise(); + } + + + /// + /// Is Check Client Cert + /// + public bool IsCheckClientCert() + { + return m_checkClientCert; + } + + + /// + /// Get Server Config + /// + public IConfig GetServerConfig() + { + return m_server_config; + } + + + /// + /// Get Cert Config + /// + public IConfig GetCertConfig() + { + return m_cert_config; + } + + + /// + /// Get Http Server + /// + public BaseHttpServer GetHttpServer() + { + return m_httpServer; + } + + + /// + /// Get Session Dic + /// + public Dictionary GetSessionDic() + { + return m_sessionDic; + } + + /// + /// Get Secure Session Dic + /// + public Dictionary GetSecureSessionDic() + { + return m_secureSessionDic; + } + + + /// + /// Get Web Session Dic + /// + public Dictionary GetWebSessionDic() + { + return m_webSessionDic; + } + + } + + + + /// + /// class Money Server Config Source + /// + class MoneyServerConfigSource + { + /// + /// Ini Config Source + /// + public IniConfigSource m_config; + + /// + /// Money Server Config Source + /// + public MoneyServerConfigSource() + { + string configPath = Path.Combine(Directory.GetCurrentDirectory(), "MoneyServer.ini"); + if (File.Exists(configPath)) + { + m_config = new IniConfigSource(configPath); + } +#pragma warning disable S108 // Nested blocks of code should not be left empty + else { } +#pragma warning restore S108 // Nested blocks of code should not be left empty + } + + + /// + /// Save config + /// + public void Save(string path) + { + m_config.Save(path); + } + + } +} diff --git a/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs b/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs new file mode 100644 index 0000000..bb957cb --- /dev/null +++ b/release/0.9.2/src/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs @@ -0,0 +1,1807 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Collections; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using OpenSim.Modules.Currency; +using OpenSim.Region.Framework.Scenes; + +using NSL.Network.XmlRpc; +using NSL.Certificate.Tools; + + +namespace OpenSim.Grid.MoneyServer +{ + class MoneyXmlRpcModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private int m_defaultBalance = 1000; + // + private bool m_forceTransfer = false; + private string m_bankerAvatar = ""; + + private bool m_scriptSendMoney = false; + private string m_scriptAccessKey = ""; + private string m_scriptIPaddress = "127.0.0.1"; + + private bool m_hg_enable = false; + private bool m_gst_enable = false; + private int m_hg_defaultBalance = 0; + private int m_gst_defaultBalance = 0; + + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + + private string m_certFilename = ""; + private string m_certPassword = ""; + //private X509Certificate2 m_clientCert = null; + + private string m_sslCommonName = ""; + + /// + /// For server authentication + /// + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); + + /// + /// Update Balance Messages + /// + private string m_BalanceMessageLandSale = "Paid the Money L${0} for Land."; + private string m_BalanceMessageRcvLandSale = ""; + private string m_BalanceMessageSendGift = "Sent Gift L${0} to {1}."; + private string m_BalanceMessageReceiveGift = "Received Gift L${0} from {1}."; + private string m_BalanceMessagePayCharge = ""; + private string m_BalanceMessageBuyObject = "Bought the Object {2} from {1} by L${0}."; + private string m_BalanceMessageSellObject = "{1} bought the Object {2} by L${0}."; + private string m_BalanceMessageGetMoney = "Got the Money L${0} from {1}."; + private string m_BalanceMessageBuyMoney = "Bought the Money L${0}."; + private string m_BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}."; + private string m_BalanceMessageSendMoney = "Paid the Money L${0} to {1}."; + private string m_BalanceMessageReceiveMoney = "Received L${0} from {1}."; + + private bool m_enableAmountZero = false; + + const int MONEYMODULE_REQUEST_TIMEOUT = 30 * 1000; //30 seconds + private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + + private IMoneyDBService m_moneyDBService; + private IMoneyServiceCore m_moneyCore; + + protected IConfig m_server_config; + protected IConfig m_cert_config; + + /// + /// Used to notify old regions as to which OpenSim version to upgrade to + /// + //private string m_opensimVersion; + + private Dictionary m_sessionDic; + private Dictionary m_secureSessionDic; + private Dictionary m_webSessionDic; + + protected BaseHttpServer m_httpServer; + + + public MoneyXmlRpcModule() + { + } + + + public void Initialise(string opensimVersion, IMoneyDBService moneyDBService, IMoneyServiceCore moneyCore) + { + //m_opensimVersion = opensimVersion; + m_moneyDBService = moneyDBService; + m_moneyCore = moneyCore; + m_server_config = m_moneyCore.GetServerConfig(); // [MoneyServer] Section + m_cert_config = m_moneyCore.GetCertConfig(); // [Certificate] Section + + //////////////////////////////////////////////////////////////////////// + // [MoneyServer] Section + m_defaultBalance = m_server_config.GetInt("DefaultBalance", m_defaultBalance); + + m_forceTransfer = m_server_config.GetBoolean("EnableForceTransfer", m_forceTransfer); + + string banker = m_server_config.GetString("BankerAvatar", m_bankerAvatar); + m_bankerAvatar = banker.ToLower(); + + m_enableAmountZero = m_server_config.GetBoolean("EnableAmountZero", m_enableAmountZero); + m_scriptSendMoney = m_server_config.GetBoolean("EnableScriptSendMoney", m_scriptSendMoney); + m_scriptAccessKey = m_server_config.GetString ("MoneyScriptAccessKey", m_scriptAccessKey); + m_scriptIPaddress = m_server_config.GetString ("MoneyScriptIPaddress", m_scriptIPaddress); + + // Hyper Grid Avatar + m_hg_enable = m_server_config.GetBoolean("EnableHGAvatar", m_hg_enable); + m_gst_enable = m_server_config.GetBoolean("EnableGuestAvatar", m_gst_enable); + m_hg_defaultBalance = m_server_config.GetInt("HGAvatarDefaultBalance", m_hg_defaultBalance); + m_gst_defaultBalance = m_server_config.GetInt("GuestAvatarDefaultBalance", m_gst_defaultBalance); + + // Update Balance Messages + m_BalanceMessageLandSale = m_server_config.GetString("BalanceMessageLandSale", m_BalanceMessageLandSale); + m_BalanceMessageRcvLandSale = m_server_config.GetString("BalanceMessageRcvLandSale", m_BalanceMessageRcvLandSale); + m_BalanceMessageSendGift = m_server_config.GetString("BalanceMessageSendGift", m_BalanceMessageSendGift); + m_BalanceMessageReceiveGift = m_server_config.GetString("BalanceMessageReceiveGift", m_BalanceMessageReceiveGift); + m_BalanceMessagePayCharge = m_server_config.GetString("BalanceMessagePayCharge", m_BalanceMessagePayCharge); + m_BalanceMessageBuyObject = m_server_config.GetString("BalanceMessageBuyObject", m_BalanceMessageBuyObject); + m_BalanceMessageSellObject = m_server_config.GetString("BalanceMessageSellObject", m_BalanceMessageSellObject); + m_BalanceMessageGetMoney = m_server_config.GetString("BalanceMessageGetMoney", m_BalanceMessageGetMoney); + m_BalanceMessageBuyMoney = m_server_config.GetString("BalanceMessageBuyMoney", m_BalanceMessageBuyMoney); + m_BalanceMessageRollBack = m_server_config.GetString("BalanceMessageRollBack", m_BalanceMessageRollBack); + m_BalanceMessageSendMoney = m_server_config.GetString("BalanceMessageSendMoney", m_BalanceMessageSendMoney); + m_BalanceMessageReceiveMoney = m_server_config.GetString("BalanceMessageReceiveMoney", m_BalanceMessageReceiveMoney); + + //////////////////////////////////////////////////////////////////////// + // [Certificate] Section + + // XML RPC to Region Server (Client Mode) + // Client Certificate + m_certFilename = m_cert_config.GetString("ClientCertFilename", m_certFilename); + m_certPassword = m_cert_config.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename != "") { + m_certVerify.SetPrivateCert(m_certFilename, m_certPassword); + //m_clientCert = new X509Certificate2(m_certFilename, m_certPassword); + //m_clientCert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.Info("[MONEY XMLRPC]: Initialise: Issue Authentication of Client. Cert file is " + m_certFilename); + } + + // Server Authentication + // CA : MoneyServer が XMLRPC のWebサーバのサーバ証明書をチェックするための設定 + m_checkServerCert = m_cert_config.GetBoolean("CheckServerCert", m_checkServerCert); + m_cacertFilename = m_cert_config.GetString ("CACertFilename", m_cacertFilename); + + if (m_cacertFilename != "") { + m_certVerify.SetPrivateCA(m_cacertFilename); + } + else { + m_checkServerCert = false; + } + + if (m_checkServerCert) { + m_log.Info("[MONEY XMLRPC]: Initialise: Execute Authentication of Server. CA file is " + m_cacertFilename); + } + else { + m_log.Info("[MONEY XMLRPC]: Initialise: No check XMLRPC Server or CACertFilename is empty. CheckServerCert is false."); + } + + //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + //ServicePointManager.UseNagleAlgorithm = false; + //ServicePointManager.Expect100Continue = false; + + m_sessionDic = m_moneyCore.GetSessionDic(); + m_secureSessionDic = m_moneyCore.GetSecureSessionDic(); + m_webSessionDic = m_moneyCore.GetWebSessionDic(); + RegisterHandlers(); + } + + + public void PostInitialise() + { + } + + + public void RegisterHandlers() + { + m_httpServer = m_moneyCore.GetHttpServer(); + m_httpServer.AddXmlRPCHandler("ClientLogin", handleClientLogin); + m_httpServer.AddXmlRPCHandler("ClientLogout", handleClientLogout); + m_httpServer.AddXmlRPCHandler("GetBalance", handleGetBalance); + m_httpServer.AddXmlRPCHandler("GetTransaction", handleGetTransaction); + + m_httpServer.AddXmlRPCHandler("CancelTransfer", handleCancelTransfer); + m_httpServer.AddXmlRPCHandler("TransferMoney", handleTransaction); + m_httpServer.AddXmlRPCHandler("ForceTransferMoney", handleForceTransaction); // added + m_httpServer.AddXmlRPCHandler("PayMoneyCharge", handlePayMoneyCharge); // added + m_httpServer.AddXmlRPCHandler("AddBankerMoney", handleAddBankerMoney); // added + m_httpServer.AddXmlRPCHandler("SendMoney", handleScriptTransaction); // added + m_httpServer.AddXmlRPCHandler("MoveMoney", handleScriptTransaction); // added + + // this is from original DTL. not check yet. + m_httpServer.AddXmlRPCHandler("WebLogin", handleWebLogin); + m_httpServer.AddXmlRPCHandler("WebLogout", handleWebLogout); + m_httpServer.AddXmlRPCHandler("WebGetBalance", handleWebGetBalance); + m_httpServer.AddXmlRPCHandler("WebGetTransaction", handleWebGetTransaction); + m_httpServer.AddXmlRPCHandler("WebGetTransactionNum", handleWebGetTransactionNum); + + // Land Buy Test + m_httpServer.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func); + m_httpServer.AddXmlRPCHandler("buyLandPrep", landBuy_func); + + // Currency Buy Test + m_httpServer.AddXmlRPCHandler("getCurrencyQuote", quote_func); + m_httpServer.AddXmlRPCHandler("buyCurrency", buy_func); + } + + + private XmlRpcResponse buy_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient buyCurrency."); + throw new NotImplementedException(); + } + + + private XmlRpcResponse quote_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient getCurrencyQuote."); + throw new NotImplementedException(); + } + + + private XmlRpcResponse landBuy_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient buyLandPrep."); + throw new NotImplementedException(); + } + + + private XmlRpcResponse preflightBuyLandPrep_func(XmlRpcRequest request, IPEndPoint client) + { + m_log.InfoFormat("[MONEY XMLRPC]: handleClient preflightBuyLandPrep."); + throw new NotImplementedException(); + } + + + // + public string GetSSLCommonName(XmlRpcRequest request) + { + if (request.Params.Count>5) { + m_sslCommonName = (string)request.Params[5]; + } + else if (request.Params.Count==5) { + m_sslCommonName = (string)request.Params[4]; + if (m_sslCommonName=="gridproxy") m_sslCommonName = ""; + } + else { + m_sslCommonName = ""; + } + return m_sslCommonName; + } + + + // + public string GetSSLCommonName() + { + return m_sslCommonName; + } + + + /// + /// Get the user balance when user entering a parcel. + /// + /// + /// + public XmlRpcResponse handleClientLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogin: Start."); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + responseData["success"] = false; + responseData["clientBalance"] = 0; + + // Check Client Cert + if (m_moneyCore.IsCheckClientCert()) { + string commonName = GetSSLCommonName(); + if (commonName=="") { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Warnning: Check Client Cert is set, but SSL Common Name is empty."); + responseData["success"] = false; + responseData["description"] = "SSL Common Name is empty"; + return response; + } + else { + if (commonName=="SSLCN:unknownName") { + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogin: SSL Common Name is \"{0}\", but this name is ignored.", commonName); + } + else { + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogin: SSL Common Name is \"{0}\"", commonName); + } + } + } + + string universalID = string.Empty; + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string simIP = string.Empty; + string userName = string.Empty; + int balance = 0; + int avatarType = (int)AvatarType.UNKNOWN_AVATAR; + int avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + if (requestData.ContainsKey("universalID")) universalID = (string)requestData["universalID"]; + if (requestData.ContainsKey("userName")) userName = (string)requestData["userName"]; + if (requestData.ContainsKey("openSimServIP")) simIP = (string)requestData["openSimServIP"]; + if (requestData.ContainsKey("avatarType")) avatarType = Convert.ToInt32(requestData["avatarType"]); + if (requestData.ContainsKey("avatarClass")) avatarClass = Convert.ToInt32(requestData["avatarClass"]); + + // + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + string securePsw = string.Empty; + // + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out securePsw); + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // Information from DB + UserInfo userInfo = m_moneyDBService.FetchUserInfo(clientUUID); + if (userInfo!=null) { + avatarType = userInfo.Type; // Avatar Type is not updated + if (avatarType ==(int)AvatarType.LOCAL_AVATAR) avatarClass = (int)AvatarType.LOCAL_AVATAR; + if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) avatarClass = userInfo.Class; + if (String.IsNullOrEmpty(userName)) userName = userInfo.Avatar; + } + // + if (avatarType==(int)AvatarType.UNKNOWN_AVATAR) avatarType = avatarClass; + if (String.IsNullOrEmpty(serverURL)) avatarClass = (int)AvatarType.NPC_AVATAR; + + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: Avatar {0} ({1}) is logged on.", userName, clientUUID); + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: Avatar Type is {0} and Avatar Class is {1}", avatarType, avatarClass); + + //if (String.IsNullOrEmpty(serverURL)) { + // responseData["description"] = "Server URL is empty. Avatar is a NPC?"; + // m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + // return response; + //} + + // + // Check Avatar + if (avatarClass==(int)AvatarType.GUEST_AVATAR && !m_gst_enable) { + responseData["description"] = "Avatar is a Guest avatar. But this Money Server does not support Guest avatars."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.HG_AVATAR && !m_hg_enable) { + responseData["description"] = "Avatar is a HG avatar. But this Money Server does not support HG avatars."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.FOREIGN_AVATAR) { + responseData["description"] = "Avatar is a Foreign avatar."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + else if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) { + responseData["description"] = "Avatar is a Unknown avatar."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + // NPC + else if (avatarClass==(int)AvatarType.NPC_AVATAR) { + responseData["success"] = true; + responseData["clientBalance"] = 0; + responseData["description"] = "Avatar is a NPC."; + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogon: {0}", responseData["description"]); + return response; + } + + // + //Update the session and secure session dictionary + lock (m_sessionDic) { + if (!m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Add(clientUUID, sessionID); + } + else m_sessionDic[clientUUID] = sessionID; + } + lock (m_secureSessionDic) { + if (!m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Add(clientUUID, secureID); + } + else m_secureSessionDic[clientUUID] = secureID; + } + + // + try { + if (userInfo==null) userInfo = new UserInfo(); + userInfo.UserID = clientUUID; + userInfo.SimIP = simIP; + userInfo.Avatar = userName; + userInfo.PswHash = UUID.Zero.ToString(); + userInfo.Type = avatarType; + userInfo.Class = avatarClass; + userInfo.ServerURL = serverURL; + if (!String.IsNullOrEmpty(securePsw)) userInfo.PswHash = securePsw; + + if (!m_moneyDBService.TryAddUserInfo(userInfo)) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Unable to refresh information for user \"{0}\" in DB.", userName); + responseData["success"] = true; // for FireStorm + responseData["description"] = "Update or add user information to db failed"; + return response; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Can't update userinfo for user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + return response; + } + + // + try { + balance = m_moneyDBService.getBalance(clientUUID); + + //add user to balances table if not exist. (if balance is -1, it means avatar is not exist at balances table) + if (balance==-1) { + int default_balance = m_defaultBalance; + if (avatarClass==(int)AvatarType.HG_AVATAR) default_balance = m_hg_defaultBalance; + if (avatarClass==(int)AvatarType.GUEST_AVATAR) default_balance = m_gst_defaultBalance; + + if (m_moneyDBService.addUser(clientUUID, default_balance, 0, avatarType)) { + responseData["success"] = true; + responseData["description"] = "add user successfully"; + responseData["clientBalance"] = default_balance; + } + else { + responseData["description"] = "add user failed"; + } + } + //Success + else if (balance >= 0) { + responseData["success"] = true; + responseData["description"] = "get user balance successfully"; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleClientLogin: Can't get balance of user {0}: {1}", clientUUID, e.ToString()); + responseData["description"] = "Exception occured" + e.ToString(); + } + + return response; + } + + + // + public XmlRpcResponse handleClientLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogout:"); + + //GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleClientLogout: User {0} is logging off.", clientUUID); + try { + lock (m_sessionDic) { + if (m_sessionDic.ContainsKey(clientUUID)) { + m_sessionDic.Remove(clientUUID); + } + } + + lock (m_secureSessionDic) { + if (m_secureSessionDic.ContainsKey(clientUUID)) { + m_secureSessionDic.Remove(clientUUID); + } + } + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleClientLogout: Failed to delete user session: " + e.ToString() ); + responseData["success"] = false; + return response; + } + + responseData["success"] = true; + return response; + } + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + /// + /// handle incoming transaction + /// + /// + /// + public XmlRpcResponse handleTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction: Transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction: Object ID = {0}, Object Name = {1}", objectID, objectName); + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY XMLRPC]: handleTransaction: Transfering money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleTransaction: Receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + rcv_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleTransaction: Add transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleTransaction: Exception occurred while adding transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handleTransaction: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle incoming force transaction. no check senderSessionID and senderSecureSessionID + /// + /// + /// + public XmlRpcResponse handleForceTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleForceTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = string.Empty; + string objectID = string.Empty; + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Newly added on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + // + if (!m_forceTransfer) { + m_log.Error("[MONEY XMLRPC]: handleForceTransaction: Not allowed force transfer of Money."); + m_log.Error("[MONEY XMLRPC]: handleForceTransaction: Set enableForceTransfer at [MoneyServer] to true in MoneyServer.ini"); + responseData["message"] = "not allowed force transfer of Money!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleForceTransaction: Force transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY XMLRPC]: handleForceTransaction: Object ID = {0}, Object Name = {1}", objectID, objectName); + + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleForceTransaction: Force receive User is not yet in DB {0}", receiverID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string snd_message = ""; + string rcv_message = ""; + + if (transaction.Type==(int)TransactionType.Gift) { + snd_message = m_BalanceMessageSendGift; + rcv_message = m_BalanceMessageReceiveGift; + } + else if (transaction.Type==(int)TransactionType.LandSale) { + snd_message = m_BalanceMessageLandSale; + snd_message = m_BalanceMessageRcvLandSale; + } + else if (transaction.Type==(int)TransactionType.PayObject) { + snd_message = m_BalanceMessageBuyObject; + rcv_message = m_BalanceMessageSellObject; + } + else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney + rcv_message = m_BalanceMessageGetMoney; + } + + responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleForceTransaction: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleForceTransaction: Exception occurred while adding force transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle scripted sending money transaction. + /// + /// + /// + public XmlRpcResponse handleScriptTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string receiverID = UUID.Zero.ToString(); + string clientIP = remoteClient.Address.ToString(); + string secretCode = string.Empty; + string description = "Scripted Send Money from/to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (!m_scriptSendMoney || m_scriptAccessKey=="") { + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Set enableScriptSendMoney and MoneyScriptAccessKey at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed set money to avatar!"; + return response; + } + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("transactionType")) transactionType= Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + if (requestData.ContainsKey("secretAccessCode")) secretCode = (string)requestData["secretAccessCode"]; + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(m_scriptAccessKey + "_" + clientIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(hash + "_" + m_scriptIPaddress)); + hash = BitConverter.ToString(code).ToLower().Replace("-", ""); + + if (secretCode.ToLower()!=hash) { + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Not allowed send money to avatar!!"); + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Not match Script Access Key."); + responseData["message"] = "not allowed send money to avatar! not match Script Key"; + return response; + } + + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: Send money from {0} to {1}", senderID, receiverID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle= "0"; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo senderInfo = null; + UserInfo receiverInfo = null; + if (transaction.Sender !=UUID.Zero.ToString()) senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (transaction.Receiver!=UUID.Zero.ToString()) receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + + if (senderInfo==null && receiverInfo==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleScriptTransaction: Sender and Receiver are not yet in DB, or both of them are System: {0}, {1}", + transaction.Sender, transaction.Receiver); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: ScriptTransaction money finished successfully, now update balance {0}", + transactionUUID.ToString()); + string message = string.Empty; + if (senderInfo!=null) { + if (receiverInfo==null) message = string.Format(m_BalanceMessageSendMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageSendMoney, amount, receiverInfo.Avatar, ""); + UpdateBalance(transaction.Sender, message); + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Sender, message); + } + if (receiverInfo!=null) { + if (senderInfo==null) message = string.Format(m_BalanceMessageReceiveMoney, amount, "SYSTEM", ""); + else message = string.Format(m_BalanceMessageReceiveMoney, amount, senderInfo.Avatar, ""); + UpdateBalance(transaction.Receiver, message); + m_log.InfoFormat("[MONEY XMLRPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Receiver, message); + } + + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleScriptTransaction: Add force transaction for user {0} failed.", transaction.Sender); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleScriptTransaction: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle adding money transaction. + /// + /// + /// + public XmlRpcResponse handleAddBankerMoney(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleAddBankerMoney:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = UUID.Zero.ToString(); + string bankerID = string.Empty; + string regionHandle = "0"; + string regionUUID = UUID.Zero.ToString(); + string description = "Add Money to Avatar on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("bankerID")) bankerID = (string)requestData["bankerID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + // Check Banker Avatar + if (m_bankerAvatar!=UUID.Zero.ToString() && m_bankerAvatar!=bankerID) { + m_log.Error("[MONEY XMLRPC]: handleAddBankerMoney: Not allowed add money to avatar!!"); + m_log.Error("[MONEY XMLRPC]: handleAddBankerMoney: Set BankerAvatar at [MoneyServer] in MoneyServer.ini"); + responseData["message"] = "not allowed add money to avatar!"; + responseData["banker"] = false; + return response; + } + responseData["banker"] = true; + + m_log.InfoFormat("[MONEY XMLRPC]: handleAddBankerMoney: Add money to avatar {0}", bankerID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = bankerID; + transaction.Amount = amount; + transaction.ObjectUUID = UUID.Zero.ToString(); + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + UserInfo rcvr = m_moneyDBService.FetchUserInfo(bankerID); + if (rcvr==null) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleAddBankerMoney: Avatar is not yet in DB {0}", bankerID); + return response; + } + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + if (m_moneyDBService.DoAddMoney(transactionUUID)) { + transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY XMLRPC]: handleAddBankerMoney: Adding money finished successfully, now update balance: {0}", + transactionUUID.ToString()); + string message = string.Format(m_BalanceMessageBuyMoney, amount, "SYSTEM", ""); + UpdateBalance(transaction.Receiver, message); + responseData["success"] = true; + } + } + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 add + } + return response; + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handleAddBankerMoney: Add force transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handleAddBankerMoney: Exception occurred while adding money transaction: " + e.ToString()); + } + return response; + } + + + // + // added by Fumi.Iseki + // + /// + /// handle pay charge transaction. no check receiver information. + /// + /// + /// + public XmlRpcResponse handlePayMoneyCharge(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + int amount = 0; + int transactionType = 0; + string senderID = string.Empty; + string receiverID = UUID.Zero.ToString(); + string senderSessionID = string.Empty; + string senderSecureSessionID = string.Empty; + string objectID = UUID.Zero.ToString(); + string objectName = string.Empty; + string regionHandle = string.Empty; + string regionUUID = string.Empty; + string description = "Pay Charge on"; + + responseData["success"] = false; + UUID transactionUUID = UUID.Random(); + + if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"]; + if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"]; + if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"]; + if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]); + if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"]; + if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"]; + if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]); + if (requestData.ContainsKey("description")) description = (string)requestData["description"]; + + if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"]; + if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"]; + if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Transfering money from {0} to {1}, Amount = {2}", senderID, receiverID, amount); + m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Object ID = {0}, Object Name = {1}", objectID, objectName); + + if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) { + if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) { + m_log.InfoFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Pay from {0}", senderID); + int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000); + try { + TransactionData transaction = new TransactionData(); + transaction.TransUUID = transactionUUID; + transaction.Sender = senderID; + transaction.Receiver = receiverID; + transaction.Amount = amount; + transaction.ObjectUUID = objectID; + transaction.ObjectName = objectName; + transaction.RegionHandle= regionHandle; + transaction.RegionUUID = regionUUID; + transaction.Type = transactionType; + transaction.Time = time; + transaction.SecureCode = UUID.Random().ToString(); + transaction.Status = (int)Status.PENDING_STATUS; + transaction.CommonName = GetSSLCommonName(); + transaction.Description = description + " " + DateTime.UtcNow.ToString(); + + bool result = m_moneyDBService.addTransaction(transaction); + if (result) { + UserInfo user = m_moneyDBService.FetchUserInfo(senderID); + if (user!=null) { + if (amount>0 || (m_enableAmountZero&&amount==0)) { + string message = string.Format(m_BalanceMessagePayCharge, amount, "SYSTEM", ""); + responseData["success"] = NotifyTransfer(transactionUUID, message, "", ""); + } + else if (amount==0) { + responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki + } + return response; + } + } + else { // add transaction failed + m_log.ErrorFormat("[MONEY XMLRPC]: handlePayMoneyCharge: Pay money transaction for user {0} failed.", senderID); + } + return response; + } + catch (Exception e) { + m_log.Error("[MONEY XMLRPC]: handlePayMoneyCharge: Exception occurred while pay money transaction: " + e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handlePayMoneyCharge: Session authentication failure for sender " + senderID); + responseData["message"] = "Session check failure, please re-login later!"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // + // added by Fumi.Iseki + // + /// + /// Continue transaction with no confirm. + /// + /// + /// + public bool NotifyTransfer(UUID transactionUUID, string msg2sender, string msg2receiver, string objectName) + { + //m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: User has accepted the transaction, now continue with the transaction"); + + try { + if (m_moneyDBService.DoTransfer(transactionUUID)) { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) { + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction Type = {0}", transaction.Type); + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Payment finished successfully, now update balance {0}", transactionUUID.ToString()); + + bool updateSender = true; + bool updateReceiv = true; + if (transaction.Sender==transaction.Receiver) updateSender = false; + //if (transaction.Type==(int)TransactionType.UploadCharge) return true; + if (transaction.Type==(int)TransactionType.UploadCharge) updateReceiv = false; + + if (updateSender) { + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string receiverName = "unknown user"; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + string snd_message = string.Format(msg2sender, transaction.Amount, receiverName, objectName); + UpdateBalance(transaction.Sender, snd_message); + } + if (updateReceiv) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + string senderName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + string rcv_message = string.Format(msg2receiver, transaction.Amount, senderName, objectName); + UpdateBalance(transaction.Receiver, rcv_message); + } + + // Notify to sender + if (transaction.Type==(int)TransactionType.PayObject) { + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Now notify opensim to give object to customer {0} ", transaction.Sender); + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = transaction.Sender; + requestTable["receiverUUID"] = transaction.Receiver; + + if(m_sessionDic.ContainsKey(transaction.Sender)&&m_secureSessionDic.ContainsKey(transaction.Sender)) { + requestTable["clientSessionID"] = m_sessionDic[transaction.Sender]; + requestTable["clientSecureSessionID"] = m_secureSessionDic[transaction.Sender]; + } + else { + requestTable["clientSessionID"] = UUID.Zero.ToString(); + requestTable["clientSecureSessionID"] = UUID.Zero.ToString(); + } + requestTable["transactionType"] = transaction.Type; + requestTable["amount"] = transaction.Amount; + requestTable["objectID"] = transaction.ObjectUUID; + requestTable["objectName"] = transaction.ObjectName; + requestTable["regionHandle"] = transaction.RegionHandle; + + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + if (user!=null) { + Hashtable responseTable = genericCurrencyXMLRPCRequest(requestTable, "OnMoneyTransfered", user.SimIP); + + if (responseTable!=null && responseTable.ContainsKey("success")) { + //User not online or failed to get object ? + if (!(bool)responseTable["success"]) { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: User {0} can't get the object, rolling back.", transaction.Sender); + if (RollBackTransaction(transaction)) { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} failed but roll back succeeded.", transactionUUID.ToString()); + } + else { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} failed and roll back failed as well.", + transactionUUID.ToString()); + } + } + else { + m_log.InfoFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} finished successfully.", transactionUUID.ToString()); + return true; + } + } + } + return false; + } + return true; + } + } + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: Transaction {0} failed.", transactionUUID.ToString()); + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: NotifyTransfer: exception occurred when transaction {0}: {1}", transactionUUID.ToString(), e.ToString()); + } + + return false; + } + + + /// + /// Get the user balance. + /// + /// + /// + public XmlRpcResponse handleGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientUUID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + int balance; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleGetBalance: Getting balance for user {0}", clientUUID); + + if (m_sessionDic.ContainsKey(clientUUID) && m_secureSessionDic.ContainsKey(clientUUID)) { + if (m_sessionDic[clientUUID]==sessionID && m_secureSessionDic[clientUUID]==secureID) { + try { + balance = m_moneyDBService.getBalance(clientUUID); + if (balance==-1) // User not found + { + responseData["description"] = "user not found"; + responseData["clientBalance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["clientBalance"] = balance; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleGetBalance: Can't get balance for user {0}, Exception {1}", clientUUID, e.ToString()); + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handleGetBalance: Session authentication failed when getting balance for user " + clientUUID); + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method, string uri) + { + //m_log.InfoFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: to {0}", uri); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!uri.StartsWith("https://")) { + m_log.InfoFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file."); + //return null; + } + } + else { + if (!uri.StartsWith("https://") && !uri.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: Invalid Region Server URL: {0}", uri); + return null; + } + } + + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + //moneyServResp = moneyModuleReq.certSend(uri, m_clientCert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + moneyServResp = moneyModuleReq.certSend(uri, m_certVerify, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: Unable to connect to Region Server {0}", uri); + m_log.ErrorFormat("[MONEY XMLRPC]: genericCurrencyXMLRPCRequest: {0}", ex.ToString()); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + /// + /// Update the client balance.We don't care about the result. + /// + /// + private void UpdateBalance(string userID, string message) + { + //m_log.InfoFormat("[MONEY XMLRPC]: UpdateBalance: ID = {0}, Message = {1}", userID, message); + + string sessionID = string.Empty; + string secureID = string.Empty; + + if (m_sessionDic.ContainsKey(userID) && m_secureSessionDic.ContainsKey(userID)) { + sessionID = m_sessionDic[userID]; + secureID = m_secureSessionDic[userID]; + + Hashtable requestTable = new Hashtable(); + requestTable["clientUUID"] = userID; + requestTable["clientSessionID"] = sessionID; + requestTable["clientSecureSessionID"] = secureID; + requestTable["Balance"] = m_moneyDBService.getBalance(userID); + if (message!="") requestTable["Message"] = message; + + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + genericCurrencyXMLRPCRequest(requestTable, "UpdateBalance", user.SimIP); + m_log.InfoFormat("[MONEY XMLRPC]: UpdateBalance: Sended UpdateBalance Request to {0}", user.SimIP.ToString()); + } + } + } + + + /// + /// RollBack the transaction if user failed to get the object paid + /// + /// + /// + protected bool RollBackTransaction(TransactionData transaction) + { + //m_log.InfoFormat("[MONEY XMLRPC]: RollBackTransaction:"); + + if(m_moneyDBService.withdrawMoney(transaction.TransUUID, transaction.Receiver, transaction.Amount)) { + if(m_moneyDBService.giveMoney(transaction.TransUUID, transaction.Sender, transaction.Amount)) { + m_log.InfoFormat("[MONEY XMLRPC]: RollBackTransaction: Transaction {0} is successfully.", transaction.TransUUID.ToString()); + m_moneyDBService.updateTransactionStatus(transaction.TransUUID, (int)Status.FAILED_STATUS, + "The buyer failed to get the object, roll back the transaction"); + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver); + string senderName = "unknown user"; + string receiverName = "unknown user"; + if (senderInfo!=null) senderName = senderInfo.Avatar; + if (receiverInfo!=null) receiverName = receiverInfo.Avatar; + + string snd_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, receiverName, transaction.ObjectName); + string rcv_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, senderName, transaction.ObjectName); + + if (transaction.Sender!=transaction.Receiver) UpdateBalance(transaction.Sender, snd_message); + UpdateBalance(transaction.Receiver, rcv_message); + return true; + } + } + return false; + } + + + // + public XmlRpcResponse handleCancelTransfer(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleCancelTransfer:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string secureCode = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("secureCode")) secureCode = (string)requestData["secureCode"]; + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (string.IsNullOrEmpty(secureCode) || string.IsNullOrEmpty(transactionID)) { + m_log.Error("[MONEY XMLRPC]: handleCancelTransfer: secureCode and/or transactionID are empty."); + return response; + } + + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender); + + try { + m_log.InfoFormat("[MONEY XMLRPC]: handleCancelTransfer: User {0} wanted to cancel the transaction.", user.Avatar); + if (m_moneyDBService.ValidateTransfer(secureCode, transactionUUID)) { + m_log.InfoFormat("[MONEY XMLRPC]: handleCancelTransfer: User {0} has canceled the transaction {1}", user.Avatar, transactionID); + m_moneyDBService.updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, + "User canceled the transaction on " + DateTime.UtcNow.ToString()); + responseData["success"] = true; + } + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleCancelTransfer: Exception occurred when transaction {0}: {1}", transactionID, e.ToString()); + } + return response; + } + + + // + public XmlRpcResponse handleGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string clientID = string.Empty; + string sessionID = string.Empty; + string secureID = string.Empty; + string transactionID = string.Empty; + UUID transactionUUID = UUID.Zero; + + responseData["success"] = false; + + if (requestData.ContainsKey("clientUUID")) clientID = (string)requestData["clientUUID"]; + if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"]; + if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"]; + + if (requestData.ContainsKey("transactionID")) { + transactionID = (string)requestData["transactionID"]; + UUID.TryParse(transactionID, out transactionUUID); + } + + if (m_sessionDic.ContainsKey(clientID) && m_secureSessionDic.ContainsKey(clientID)) { + if (m_sessionDic[clientID]==sessionID && m_secureSessionDic[clientID]==secureID) { + // + if (string.IsNullOrEmpty(transactionID)) { + responseData["description"] = "TransactionID is empty"; + m_log.Error("[MONEY XMLRPC]: handleGetTransaction: TransactionID is empty."); + return response; + } + + try { + TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID); + if (transaction!=null) { + responseData["success"] = true; + responseData["amount"] = transaction.Amount; + responseData["time"] = transaction.Time; + responseData["type"] = transaction.Type; + responseData["sender"] = transaction.Sender.ToString(); + responseData["receiver"] = transaction.Receiver.ToString(); + responseData["description"] = transaction.Description; + } + else { + responseData["description"] = "Invalid Transaction UUID"; + } + + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleGetTransaction: {0}", e.ToString()); + m_log.ErrorFormat("[MONEY XMLRPC]: handleGetTransaction: Can't get transaction information for {0}", transactionUUID.ToString()); + } + return response; + } + } + + responseData["success"] = false; + responseData["description"] = "Session check failure, please re-login"; + return response; + } + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // In development + // + + public XmlRpcResponse handleWebLogin(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogin: Start."); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, login failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (!m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Add(userID, webSessionID); + } + else m_webSessionDic[userID] = webSessionID; + } + + m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogin: User {0} has logged in from web.", userID); + responseData["success"] = true; + return response; + } + + + // + public XmlRpcResponse handleWebLogout(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogout:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) { + responseData["errorMessage"] = "userID or sessionID can`t be empty, log out failed!"; + return response; + } + + //Update the web session dictionary + lock (m_webSessionDic) { + if (m_webSessionDic.ContainsKey(userID)) { + m_webSessionDic.Remove(userID); + } + } + + m_log.InfoFormat("[MONEY XMLRPC]: handleWebLogout: User {0} has logged out from web.", userID); + responseData["success"] = true; + return response; + } + + + /// + /// Get balance method for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetBalance(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetBalance:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int balance = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + + m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetBalance: Getting balance for user {0}", userID); + + //perform session check + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + balance = m_moneyDBService.getBalance(userID); + UserInfo user = m_moneyDBService.FetchUserInfo(userID); + if (user!=null) { + responseData["userName"] = user.Avatar; + } + else { + responseData["userName"] = "unknown user"; + } + // + // User not found + if (balance==-1) { + responseData["errorMessage"] = "User not found"; + responseData["balance"] = 0; + } + else if (balance >= 0) { + responseData["success"] = true; + responseData["balance"] = balance; + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleWebGetBalance: Can't get balance for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting balance"; + return response; + } + } + } + + m_log.Error("[MONEY XMLRPC]: handleWebLogout: Session authentication failed when getting balance for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get transaction for web pages + /// + /// + /// + public XmlRpcResponse handleWebGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransaction:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int lastIndex = -1; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + if (requestData.ContainsKey("lastIndex")) lastIndex = (int)requestData["lastIndex"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + try { + int total = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + TransactionData tran = null; + m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransaction: Getting transation[{0}] for user {1}", lastIndex + 1, userID); + if (total > lastIndex + 2) { + responseData["isEnd"] = false; + } + else { + responseData["isEnd"] = true; + } + + tran = m_moneyDBService.FetchTransaction(userID, startTime, endTime, lastIndex); + if (tran!=null) { + UserInfo senderInfo = m_moneyDBService.FetchUserInfo(tran.Sender); + UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(tran.Receiver); + if (senderInfo!=null && receiverInfo!=null) { + responseData["senderName"] = senderInfo.Avatar; + responseData["receiverName"] = receiverInfo.Avatar; + } + else { + responseData["senderName"] = "unknown user"; + responseData["receiverName"] = "unknown user"; + } + responseData["success"] = true; + responseData["transactionIndex"] = lastIndex + 1; + responseData["transactionUUID"] = tran.TransUUID.ToString(); + responseData["senderID"] = tran.Sender; + responseData["receiverID"] = tran.Receiver; + responseData["amount"] = tran.Amount; + responseData["type"] = tran.Type; + responseData["time"] = tran.Time; + responseData["status"] = tran.Status; + responseData["description"] = tran.Description; + } + else { + responseData["errorMessage"] = string.Format("Unable to fetch transaction data with the index {0}", lastIndex + 1); + } + return response; + } + catch (Exception e) { + m_log.ErrorFormat("[MONEY XMLRPC]: handleWebGetTransaction: Can't get transaction for user {0}, Exception {1}", userID, e.ToString()); + responseData["errorMessage"] = "Exception occurred when getting transaction"; + return response; + } + } + } + + m_log.Error("[MONEY XMLRPC]: handleWebGetTransaction: Session authentication failed when getting transaction for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + + + /// + /// Get total number of transactions for web pages. + /// + /// + /// + public XmlRpcResponse handleWebGetTransactionNum(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransactionNum:"); + + GetSSLCommonName(request); + + Hashtable requestData = (Hashtable)request.Params[0]; + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + string userID = string.Empty; + string webSessionID = string.Empty; + int startTime = 0; + int endTime = 0; + + responseData["success"] = false; + + if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"]; + if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"]; + if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"]; + if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"]; + + if (m_webSessionDic.ContainsKey(userID)) { + if (m_webSessionDic[userID]==webSessionID) { + int it = m_moneyDBService.getTransactionNum(userID, startTime, endTime); + if (it>=0) { + m_log.InfoFormat("[MONEY XMLRPC]: handleWebGetTransactionNum: Get {0} transactions for user {1}", it, userID); + responseData["success"] = true; + responseData["number"] = it; + } + return response; + } + } + + m_log.Error("[MONEY XMLRPC]: handleWebGetTransactionNum: Session authentication failed when getting transaction number for user " + userID); + responseData["errorMessage"] = "Session check failure, please re-login"; + return response; + } + } + +} + diff --git a/release/0.9.2/src/OpenSim.Grid.MoneyServer/Program.cs b/release/0.9.2/src/OpenSim.Grid.MoneyServer/Program.cs new file mode 100644 index 0000000..3fbd12d --- /dev/null +++ b/release/0.9.2/src/OpenSim.Grid.MoneyServer/Program.cs @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net.Config; + +namespace OpenSim.Grid.MoneyServer +{ + class Program + { + public static void Main(string[] args) + { + XmlConfigurator.Configure(); + MoneyServerBase app = new MoneyServerBase(); + app.Startup(); + app.Work(); + } + } +} diff --git a/release/0.9.2/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs b/release/0.9.2/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs new file mode 100644 index 0000000..f86ff16 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs @@ -0,0 +1,1920 @@ +// * Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp +// * +// * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/ +// * See CONTRIBUTORS.TXT for a full list of copyright holders. +// * +// * Redistribution and use in source and binary forms, with or without +// * modification, are permitted provided that the following conditions are met: +// * * Redistributions of source code must retain the above copyright +// * notice, this list of conditions and the following disclaimer. +// * * Redistributions in binary form must reproduce the above copyright +// * notice, this list of conditions and the following disclaimer in the +// * documentation and/or other materials provided with the distribution. +// * * Neither the name of the OpenSim Project nor the +// * names of its contributors may be used to endorse or promote products +// * derived from this software without specific prior written permission. +// * +// * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +// * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES +// * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using Mono.Addins; + +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using OpenSim.Data.MySQL.MySQLMoneyDataWrapper; +using NSL.Certificate.Tools; +using NSL.Network.XmlRpc; + + + +[assembly: Addin("DTLNSLMoneyModule", "1.0")] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] + + + +namespace OpenSim.Modules.Currency +{ + /// + /// Transaction Type + /// + public enum TransactionType : int + { + None = 0, + // Extend + BirthGift = 900, + AwardPoints = 901, + // One-Time Charges + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + // Recurrent Charges + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + ScheduledFee = 2900, + // Inventory Transactions + GiveInventory = 3000, + // Transfers Between Users + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InvntorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + BuyMoney = 5010, + MoveMoney = 5011, + SendMoney = 5012, + // Group Transactions + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + // Stipend Credits + StipendBasic = 10000 + } + + +/* + // Refer to OpenMetaverse + public enum OpenMetaverse.MoneyTransactionType : int + { + None = 0, + FailSimulatorTimeout = 1, + FailDataserverTimeout = 2, + ObjectClaim = 1000, + LandClaim = 1001, + GroupCreate = 1002, + ObjectPublicClaim = 1003, + GroupJoin = 1004, + TeleportCharge = 1100, + UploadCharge = 1101, + LandAuction = 1102, + ClassifiedCharge = 1103, + ObjectTax = 2000, + LandTax = 2001, + LightTax = 2002, + ParcelDirFee = 2003, + GroupTax = 2004, + ClassifiedRenew = 2005, + GiveInventory = 3000, + ObjectSale = 5000, + Gift = 5001, + LandSale = 5002, + ReferBonus = 5003, + InventorySale = 5004, + RefundPurchase = 5005, + LandPassSale = 5006, + DwellBonus = 5007, + PayObject = 5008, + ObjectPays = 5009, + GroupLandDeed = 6001, + GroupObjectDeed = 6002, + GroupLiability = 6003, + GroupDividend = 6004, + GroupMembershipDues = 6005, + ObjectRelease = 8000, + LandRelease = 8001, + ObjectDelete = 8002, + ObjectPublicDecay = 8003, + ObjectPublicDelete = 8004, + LindenAdjustment = 9000, + LindenGrant = 9001, + LindenPenalty = 9002, + EventFee = 9003, + EventPrize = 9004, + StipendBasic = 10000, + StipendDeveloper = 10001, + StipendAlways = 10002, + StipendDaily = 10003, + StipendRating = 10004, + StipendDelta = 10005 + } +*/ + + + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")] + public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule + { + #region Constant numbers and members. + + // Constant memebers + private const int MONEYMODULE_REQUEST_TIMEOUT = 10000; + + // Private data members. + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + //private bool m_enabled = true; + private bool m_sellEnabled = false; + private bool m_enable_server = true; // enable Money Server + + private IConfigSource m_config; + + private string m_moneyServURL = string.Empty; + public BaseHttpServer HttpServer; + + private string m_certFilename = ""; + private string m_certPassword = ""; + private bool m_checkServerCert = false; + private string m_cacertFilename = ""; + //private X509Certificate2 m_cert = null; + + private bool m_use_web_settle = false; + private string m_settle_url = ""; + private string m_settle_message = ""; + private bool m_settle_user = false; + + private int m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + + private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // For server authentication + + + /// + /// Scene dictionary indexed by Region Handle + /// + private Dictionary m_sceneList = new Dictionary(); + + /// + /// To cache the balance data while the money server is not available. + /// + private Dictionary m_moneyServer = new Dictionary(); + + // Events + public event ObjectPaid OnObjectPaid; + + // Price + private int ObjectCount = 0; + private int PriceEnergyUnit = 100; + private int PriceObjectClaim = 10; + private int PricePublicObjectDecay = 4; + private int PricePublicObjectDelete = 4; + private int PriceParcelClaim = 1; + private float PriceParcelClaimFactor = 1.0f; + private int PriceUpload = 0; + private int PriceRentLight = 5; + private float PriceObjectRent = 1.0f; + private float PriceObjectScaleFactor = 10.0f; + private int PriceParcelRent = 1; + private int PriceGroupCreate = 0; + private int TeleportMinPrice = 2; + private float TeleportPriceExponent = 2.0f; + private float EnergyEfficiency = 1.0f; + + #endregion + + + /// + /// Initialise + /// + /// + /// + public void Initialise(Scene scene, IConfigSource source) + { + Initialise(source); + if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false; + // + AddRegion(scene); + } + + + #region ISharedRegionModule interface + + public void Initialise(IConfigSource source) + { + //m_log.InfoFormat("[MONEY MODULE]: Initialise:"); + + // Handle the parameters errors. + if (source==null) return; + + try { + m_config = source; + + // [Economy] section + IConfig economyConfig = m_config.Configs["Economy"]; + + if (economyConfig.GetString("EconomyModule")!=Name && economyConfig.GetString("economymodule")!=Name) { + //m_enabled = false; + m_log.InfoFormat("[MONEY MODULE]: Initialise: The DTL/NSL MoneyModule is disabled"); + return; + } + else { + m_log.InfoFormat("[MONEY MODULE]: Initialise: The DTL/NSL MoneyModule is enabled"); + } + + m_sellEnabled = economyConfig.GetBoolean("SellEnabled", m_sellEnabled); + m_moneyServURL = economyConfig.GetString("CurrencyServer", m_moneyServURL); + + // Client Certification // クライアント証明書 + m_certFilename = economyConfig.GetString("ClientCertFilename", m_certFilename); + m_certPassword = economyConfig.GetString("ClientCertPassword", m_certPassword); + if (m_certFilename!="") { + m_certVerify.SetPrivateCert(m_certFilename, m_certPassword); + //m_cert = new X509Certificate2(m_certFilename, m_certPassword); + //m_cert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet); + m_log.Info("[MONEY MODULE]: Initialise: Issue Authentication of Client. Cert File is " + m_certFilename); + } + + // Server Authentication // MoneyServer のサーバ証明書のチェック + m_checkServerCert = economyConfig.GetBoolean("CheckServerCert", m_checkServerCert); + m_cacertFilename = economyConfig.GetString ("CACertFilename", m_cacertFilename); + + if (m_cacertFilename != "") { + m_certVerify.SetPrivateCA(m_cacertFilename); + } + else { + m_checkServerCert = false; + } + + if (m_checkServerCert) { + m_log.Info("[MONEY MODULE]: Initialise: Execute Authentication of Server. CA Cert File is " + m_cacertFilename); + } + else { + m_log.Info("[MONEY MODULE]: Initialise: No check Money Server or CACertFilename is empty. CheckServerCert is false."); + } + + //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate); + //ServicePointManager.UseNagleAlgorithm = false; + //ServicePointManager.Expect100Continue = false; + + // Settlement + m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", m_use_web_settle); + m_settle_url = economyConfig.GetString ("SettlementURL", m_settle_url); + m_settle_message = economyConfig.GetString ("SettlementMessage", m_settle_message); + + // Price + PriceEnergyUnit = economyConfig.GetInt ("PriceEnergyUnit", PriceEnergyUnit); + PriceObjectClaim = economyConfig.GetInt ("PriceObjectClaim", PriceObjectClaim); + PricePublicObjectDecay = economyConfig.GetInt ("PricePublicObjectDecay", PricePublicObjectDecay); + PricePublicObjectDelete = economyConfig.GetInt ("PricePublicObjectDelete", PricePublicObjectDelete); + PriceParcelClaim = economyConfig.GetInt ("PriceParcelClaim", PriceParcelClaim); + PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", PriceParcelClaimFactor); + PriceUpload = economyConfig.GetInt ("PriceUpload", PriceUpload); + PriceRentLight = economyConfig.GetInt ("PriceRentLight", PriceRentLight); + PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", PriceObjectRent); + PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", PriceObjectScaleFactor); + PriceParcelRent = economyConfig.GetInt ("PriceParcelRent", PriceParcelRent); + PriceGroupCreate = economyConfig.GetInt ("PriceGroupCreate", PriceGroupCreate); + TeleportMinPrice = economyConfig.GetInt ("TeleportMinPrice", TeleportMinPrice); + TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", TeleportPriceExponent); + EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", EnergyEfficiency); + + // for HG Avatar + string avatar_class = economyConfig.GetString("HGAvatarAs", "HGAvatar").ToLower(); + if (avatar_class=="localavatar") m_hg_avatarClass = (int)AvatarType.LOCAL_AVATAR; + else if (avatar_class=="guestavatar") m_hg_avatarClass = (int)AvatarType.GUEST_AVATAR; + else if (avatar_class=="hgavatar") m_hg_avatarClass = (int)AvatarType.HG_AVATAR; + else if (avatar_class=="foreignavatar") m_hg_avatarClass = (int)AvatarType.FOREIGN_AVATAR; + else m_hg_avatarClass = (int)AvatarType.UNKNOWN_AVATAR; + + } + catch { + m_log.ErrorFormat("[MONEY MODULE]: Initialise: Faile to read configuration file"); + } + } + + + public void AddRegion(Scene scene) + { + //m_log.InfoFormat("[MONEY MODULE]: AddRegion:"); + + if (scene==null) return; + + scene.RegisterModuleInterface(this); // 競合するモジュールの排除 + + lock (m_sceneList) { + if (m_sceneList.Count==0) { + if (m_enable_server) { + HttpServer = new BaseHttpServer(9000); + HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo)); + + HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler); + HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + HttpServer.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + HttpServer.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + + MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler); + MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler); + MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler); + MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added + MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added + MainServer.Instance.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added + } + } + + if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle)) { + m_sceneList[scene.RegionInfo.RegionHandle] = scene; + } + else { + m_sceneList.Add(scene.RegionInfo.RegionHandle, scene); + } + } + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer += MoneyTransferAction; + scene.EventManager.OnValidateLandBuy += ValidateLandBuy; + scene.EventManager.OnLandBuy += processLandBuy; + } + + + public void RemoveRegion(Scene scene) + { + if (scene==null) return; + + lock (m_sceneList) { + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent -= MakeChildAgent; + + // for OpenSim + scene.EventManager.OnMoneyTransfer -= MoneyTransferAction; + scene.EventManager.OnValidateLandBuy -= ValidateLandBuy; + scene.EventManager.OnLandBuy -= processLandBuy; + } + } + + + public void RegionLoaded(Scene scene) + { + //m_log.InfoFormat("[MONEY MODULE]: RegionLoaded:"); + } + + + public Type ReplaceableInterface + { + //get { return typeof(IMoneyModule); } + get { return null; } + } + + + public bool IsSharedModule + { + get { return true; } + } + + + public string Name + { + get { return "DTLNSLMoneyModule"; } + } + + + public void PostInitialise() + { + //m_log.InfoFormat("[MONEY MODULE]: PostInitialise:"); + } + + + public void Close() + { + //m_log.InfoFormat("[MONEY MODULE]: Close:"); + } + + #endregion + + + #region IMoneyModule interface. + + // for LSL llGiveMoney() function + public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result) + { + //m_log.InfoFormat("[MONEY MODULE]: ObjectGiveMoney: LSL ObjectGiveMoney. UUID = {0}", objectID.ToString()); + + result = string.Empty; + if (!m_sellEnabled) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + + string objName = string.Empty; + string avatarName = string.Empty; + + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) { + result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return false; + } + objName = sceneObj.Name; + + Scene scene = GetLocateScene(toID); + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID); + if (account!=null) { + avatarName = account.FirstName + " " + account.LastName; + } + } + + bool ret = false; + string description = String.Format("Object {0} pays {1}", objName, avatarName); + + if (sceneObj.OwnerID==fromID) { + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + if (GetLocateClient(fromID)!=null) { + ret = TransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + else { + ret = ForceTransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description); + } + } + + if (!ret) result = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + return ret; + } + + + // + public int UploadCharge + { + get { return PriceUpload; } + } + + + // + public int GroupCreationCharge + { + get { return PriceGroupCreate; } + } + + + public int GetBalance(UUID agentID) + { + IClientAPI client = GetLocateClient(agentID); + return QueryBalanceFromMoneyServer(client); + } + + + public bool UploadCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public bool AmountCovered(UUID agentID, int amount) + { + IClientAPI client = GetLocateClient(agentID); + + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + int balance = QueryBalanceFromMoneyServer(client); + if (balance>=amount) return true; + } + return false; + } + + + public void ApplyUploadCharge(UUID agentID, int amount, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)TransactionType.UploadCharge, regionHandle, regionUUID, text); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type) + { + ApplyCharge(agentID, amount, type, string.Empty); + } + + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string text) + { + ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle; + UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID; + PayMoneyCharge(agentID, amount, (int)type, regionHandle, regionUUID, text); + } + + + public bool Transfer(UUID fromID, UUID toID, int regionHandle, int amount, MoneyTransactionType type, string text) + { + return TransferMoney(fromID, toID, amount, (int)type, UUID.Zero, (ulong)regionHandle, UUID.Zero, text); + } + + + public bool Transfer(UUID fromID, UUID toID, UUID objectID, int amount, MoneyTransactionType type, string text) + { + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj==null) return false; + + ulong regionHandle = sceneObj.ParentGroup.Scene.RegionInfo.RegionHandle; + UUID regionUUID = sceneObj.ParentGroup.Scene.RegionInfo.RegionID; + return TransferMoney(fromID, toID, amount, (int)type, objectID, (ulong)regionHandle, regionUUID, text); + } + + + // for 0.8.3 over + public void MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, string text) + { + ForceTransferMoney(fromAgentID, toAgentID, amount, (int)TransactionType.MoveMoney, UUID.Zero, (ulong)0, UUID.Zero, text); + } + + // for 0.9.1 over + public bool MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, MoneyTransactionType type, string text) + { + bool ret = ForceTransferMoney(fromAgentID, toAgentID, amount, (int)type, UUID.Zero, (ulong)0, UUID.Zero, text); + return ret; + } + + #endregion + + + #region MoneyModule event handlers + + // + private void OnNewClient(IClientAPI client) + { + //m_log.InfoFormat("[MONEY MODULE]: OnNewClient"); + + client.OnEconomyDataRequest += OnEconomyDataRequest; + client.OnLogout += ClientClosed; + + client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + client.OnRequestPayPrice += OnRequestPayPrice; + client.OnObjectBuy += OnObjectBuy; + } + + + public void OnMakeRootAgent(ScenePresence agent) + { + //m_log.InfoFormat("[MONEY MODULE]: OnMakeRootAgent:"); + + int balance = 0; + IClientAPI client = agent.ControllingClient; + + m_enable_server = LoginMoneyServer(agent, out balance); + client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + + //client.OnMoneyBalanceRequest += OnMoneyBalanceRequest; + //client.OnRequestPayPrice += OnRequestPayPrice; + //client.OnObjectBuy += OnObjectBuy; + } + + + // for OnClientClosed event + private void ClientClosed(IClientAPI client) + { + //m_log.InfoFormat("[MONEY MODULE]: ClientClosed:"); + + if (m_enable_server && client!=null) { + LogoffMoneyServer(client); + } + } + + + // for OnMakeChildAgent event + private void MakeChildAgent(ScenePresence avatar) + { + //m_log.InfoFormat("[MONEY MODULE]: MakeChildAgent:"); + } + + + // for OnMoneyTransfer event + private void MoneyTransferAction(Object sender, EventManager.MoneyTransferArgs moneyEvent) + { + //m_log.InfoFormat("[MONEY MODULE]: MoneyTransferAction: type = {0}", moneyEvent.transactiontype); + + if (!m_sellEnabled) return; + + // Check the money transaction is necessary. + if (moneyEvent.sender==moneyEvent.receiver) { + return; + } + + UUID receiver = moneyEvent.receiver; + // Pay for the object. + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + SceneObjectPart sceneObj = GetLocatePrim(moneyEvent.receiver); + if (sceneObj!=null) { + receiver = sceneObj.OwnerID; + } + else { + return; + } + } + + // Before paying for the object, save the object local ID for current transaction. + UUID objectID = UUID.Zero; + ulong regionHandle = 0; + UUID regionUUID = UUID.Zero; + + if (sender is Scene) { + Scene scene = (Scene)sender; + regionHandle = scene.RegionInfo.RegionHandle; + regionUUID = scene.RegionInfo.RegionID; + + if (moneyEvent.transactiontype==(int)TransactionType.PayObject) { + objectID = scene.GetSceneObjectPart(moneyEvent.receiver).UUID; + } + } + + TransferMoney(moneyEvent.sender, receiver, moneyEvent.amount, moneyEvent.transactiontype, objectID, regionHandle, regionUUID, "OnMoneyTransfer event"); + return; + } + + + // for OnValidateLandBuy event + private void ValidateLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY MODULE]: ValidateLandBuy:"); + + IClientAPI senderClient = GetLocateClient(landBuyEvent.agentId); + if (senderClient!=null) { + int balance = QueryBalanceFromMoneyServer(senderClient); + if (balance >= landBuyEvent.parcelPrice) { + lock(landBuyEvent) { + landBuyEvent.economyValidated = true; + } + } + } + return; + } + + + // for LandBuy even + private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent) + { + //m_log.InfoFormat("[MONEY MODULE]: processLandBuy:"); + + if (!m_sellEnabled) return; + + lock(landBuyEvent) { + if (landBuyEvent.economyValidated==true && landBuyEvent.transactionID==0) { + landBuyEvent.transactionID = Util.UnixTimeSinceEpoch(); + + ulong parcelID = (ulong)landBuyEvent.parcelLocalID; + UUID regionUUID = UUID.Zero; + if (sender is Scene) regionUUID = ((Scene)sender).RegionInfo.RegionID; + + if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID, + landBuyEvent.parcelPrice, (int)TransactionType.LandSale, regionUUID, parcelID, regionUUID, "Land Purchase")) { + landBuyEvent.amountDebited = landBuyEvent.parcelPrice; + } + } + } + return; + } + + + // for OnObjectBuy event + public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID, + UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice) + { + m_log.InfoFormat("[MONEY MODULE]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId); + + // Handle the parameters error. + if (!m_sellEnabled) return; + if (remoteClient==null || salePrice<0) return; + + // Get the balance from money server. + int balance = QueryBalanceFromMoneyServer(remoteClient); + if (balance(); + if (mod!=null) { + UUID receiverId = sceneObj.OwnerID; + ulong regionHandle = sceneObj.RegionHandle; + UUID regionUUID = sceneObj.RegionID; + bool ret = false; + // + if (salePrice>=0) { + if (!string.IsNullOrEmpty(m_moneyServURL)) { + ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice, + (int)TransactionType.PayObject, sceneObj.UUID, regionHandle, regionUUID, "Object Buy"); + } + else if (salePrice==0) { // amount is 0 with No Money Server + ret = true; + } + } + if (ret) { + mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); + } + } + } + else { + remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false); + return; + } + } + return; + } + + + /// + /// Sends the the stored money balance to the client + /// + /// + /// + /// + /// + private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID) + { + m_log.InfoFormat("[MONEY MODULE]: OnMoneyBalanceRequest:"); + + if (client.AgentId==agentID && client.SessionId==SessionID) { + int balance = 0; + // + if (m_enable_server) { + balance = QueryBalanceFromMoneyServer(client); + } + + client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + } + else { + client.SendAlertMessage("Unable to send your money balance"); + } + } + + + private void OnRequestPayPrice(IClientAPI client, UUID objectID) + { + m_log.InfoFormat("[MONEY MODULE]: OnRequestPayPrice:"); + + Scene scene = GetLocateScene(client.AgentId); + if (scene==null) return; + SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID); + if (sceneObj==null) return; + SceneObjectGroup group = sceneObj.ParentGroup; + SceneObjectPart root = group.RootPart; + + client.SendPayPrice(objectID, root.PayPrice); + } + + + // + //private void OnEconomyDataRequest(UUID agentId) + private void OnEconomyDataRequest(IClientAPI user) + { + //m_log.InfoFormat("[MONEY MODULE]: OnEconomyDataRequest:"); + //IClientAPI user = GetLocateClient(agentId); + + if (user!=null) { + if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) { + //Scene s = GetLocateScene(user.AgentId); + Scene s = (Scene)user.Scene; + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, + PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, + PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, + TeleportMinPrice, TeleportPriceExponent); + } + } + } + + #endregion + + + #region MoneyModule XML-RPC Handler + + // "OnMoneyTransfered" RPC from MoneyServer + public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + m_log.InfoFormat("[MONEY MODULE]: OnMoneyTransferedHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("transactionType") && requestParam.Contains("objectID") && requestParam.Contains("amount")) { + //m_log.InfoFormat("[MONEY MODULE]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]); + + // Pay for the object. + if ((int)requestParam["transactionType"]==(int)TransactionType.PayObject) { + // Send notify to the client(viewer) for Money Event Trigger. + ObjectPaid handlerOnObjectPaid = OnObjectPaid; + if (handlerOnObjectPaid!=null) { + UUID objectID = UUID.Zero; + UUID.TryParse((string)requestParam["objectID"], out objectID); + handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money() + } + ret = true; + } + } + } + } + } + } + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY MODULE]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UpdateBalance" RPC from MoneyServer or Script + public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: BalanceUpdateHandler:"); + + bool ret = false; + + #region Update the balance from money server. + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + // + if (requestParam.Contains("Balance")) { + // Send notify to the client. + string msg = ""; + if (requestParam.Contains("Message")) msg = (string)requestParam["Message"]; + client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"], + 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); + // Dialog + if (msg!="") { + Scene scene = (Scene)client.Scene; + IDialogModule dlg = scene.RequestModuleInterface(); + dlg.SendAlertToUser(client.AgentId, msg); + } + ret = true; + } + } + } + } + } + + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + if (!ret) { + m_log.ErrorFormat("[MONEY MODULE]: BalanceUpdateHandler: Cannot update client balance from MoneyServer"); + } + resp.Value = paramTable; + + return resp; + } + + + // "UserAlert" RPC from Script + public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: UserAlertHandler:"); + + bool ret = false; + + #region confirm the request and show the notice from money server. + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("Description")) + { + string description = (string)requestParam["Description"]; + // Show the notice dialog with money server message. + GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()), + (byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3()); + client.SendInstantMessage(gridMsg); + ret = true; + } + } + } + } + } + // + #endregion + + // Send the response to money server. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + return resp; + } + + + // "GetBalance" RPC from Script + public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: GetBalanceHandler:"); + + bool ret = false; + int balance = -1; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID clientUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out clientUUID); + // + if (clientUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(clientUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + balance = QueryBalanceFromMoneyServer(client); + } + } + } + } + + // Send the response to caller. + if (balance<0) { + m_log.ErrorFormat("[MONEY MODULE]: GetBalanceHandler: GetBalance transaction is failed"); + ret = false; + } + + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + paramTable["balance"] = balance; + resp.Value = paramTable; + + return resp; + } + + + // "AddBankerMoney" RPC from Script + public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: AddBankerMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + + if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) { + UUID bankerUUID = UUID.Zero; + UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID); + // + if (bankerUUID!=UUID.Zero) { + IClientAPI client = GetLocateClient(bankerUUID); + string sessionid = (string)requestParam["clientSessionID"]; + string secureid = (string)requestParam["clientSecureSessionID"]; + if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) { + if (requestParam.Contains("amount")) + { + Scene scene = (Scene)client.Scene; + int amount = (int)requestParam["amount"]; + ulong regionHandle = scene.RegionInfo.RegionHandle; + UUID regionUUID = scene.RegionInfo.RegionID; + ret = AddBankerMoney(bankerUUID, amount, regionHandle, regionUUID); + + if (m_use_web_settle && m_settle_user) { + ret = true; + IDialogModule dlg = scene.RequestModuleInterface(); + if (dlg!=null) { + dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url); + } + } + } + } + } + } + } + + if (!ret) m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoneyHandler: Add Banker Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["settle"] = false; + paramTable["success"] = ret; + + if (m_use_web_settle && m_settle_user) paramTable["settle"] = true; + resp.Value = paramTable; + + return resp; + } + + + // "SendMoney" RPC from Script + public XmlRpcResponse SendMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: SendMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) { + Hashtable requestParam = (Hashtable)request.Params[0]; + if (requestParam.Contains("agentUUID") && requestParam.Contains("secretAccessCode")) { + UUID agentUUID = UUID.Zero; + UUID.TryParse((string)requestParam["agentUUID"], out agentUUID); + + if (agentUUID!=UUID.Zero) { + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + int type = -1; + if (requestParam.Contains("type")) type = (int)requestParam["type"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY MODULE]: SendMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = SendMoneyTo(agentUUID, amount, type, hash); + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("agentUUID")) { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: agentUUID is missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY MODULE]: SendMoneyHandler: Send Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + + // "MoveMoney" RPC from Script + public XmlRpcResponse MoveMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient) + { + //m_log.InfoFormat("[MONEY MODULE]: MoveMoneyHandler:"); + + bool ret = false; + + if (request.Params.Count>0) + { + Hashtable requestParam = (Hashtable)request.Params[0]; + if ((requestParam.Contains("fromUUID") || requestParam.Contains("toUUID")) && requestParam.Contains("secretAccessCode")) { + UUID fromUUID = UUID.Zero; + UUID toUUID = UUID.Zero; // UUID.Zero means System + if (requestParam.Contains("fromUUID")) UUID.TryParse((string)requestParam["fromUUID"], out fromUUID); + if (requestParam.Contains("toUUID")) UUID.TryParse((string)requestParam["toUUID"], out toUUID); + + if (requestParam.Contains("amount")) { + int amount = (int)requestParam["amount"]; + string secretCode = (string)requestParam["secretAccessCode"]; + string scriptIP = remoteClient.Address.ToString(); + + MD5 md5 = MD5.Create(); + byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP)); + string hash = BitConverter.ToString(code).ToLower().Replace("-",""); + //m_log.InfoFormat("[MONEY MODULE]: MoveMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash); + ret = MoveMoneyFromTo(fromUUID, toUUID, amount, hash); + } + else { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: amount is missed"); + } + } + else { + if (!requestParam.Contains("fromUUID") && !requestParam.Contains("toUUID")) { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: fromUUID and toUUID are missed"); + } + if (!requestParam.Contains("secretAccessCode")) { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: secretAccessCode is missed"); + } + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: Params count is under 0"); + } + + if (!ret) m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyHandler: Move Money transaction is failed"); + + // Send the response to caller. + XmlRpcResponse resp = new XmlRpcResponse(); + Hashtable paramTable = new Hashtable(); + paramTable["success"] = ret; + + resp.Value = paramTable; + + return resp; + } + + #endregion + + + #region MoneyModule private help functions + + /// + /// Transfer the money from one user to another. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY MODULE]: TransferMoney:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY MODULE]: TransferMoney: Client {0} not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Force transfer the money from one user to another. + /// This function does not check sender login. + /// Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY MODULE]: ForceTransferMoney:"); + + bool ret = false; + + #region Force send transaction request to money server and parse the resultes. + + if (m_enable_server) { + string objName = string.Empty; + SceneObjectPart sceneObj = GetLocatePrim(objectID); + if (sceneObj!=null)objName = sceneObj.Name; + + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = sender.ToString(); + paramTable["receiverID"] = receiver.ToString(); + paramTable["transactionType"] = type; + paramTable["objectID"] = objectID.ToString(); + paramTable["objectName"] = objName; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["amount"] = amount; + paramTable["description"] = description; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + else m_log.ErrorFormat("[MONEY MODULE]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString()); + } + //else m_log.ErrorFormat("[MONEY MODULE]: ForceTransferMoney: Money Server is not available!!"); + + #endregion + + return ret; + } + + + /// + /// Send the money to avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool SendMoneyTo(UUID avatarID, int amount, int type, string secretCode) + { + //m_log.InfoFormat("[MONEY MODULE]: SendMoneyTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + if (type<0) type = (int)TransactionType.ReferBonus; + Hashtable paramTable = new Hashtable(); + paramTable["receiverID"] = avatarID.ToString(); + paramTable["transactionType"] = type; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Bonus to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY MODULE]: SendMoneyTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Move the money from avatar to other avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool MoveMoneyFromTo(UUID senderID, UUID receiverID, int amount, string secretCode) + { + //m_log.InfoFormat("[MONEY MODULE]: MoveMoneyFromTo:"); + + bool ret = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["senderID"] = senderID.ToString(); + paramTable["receiverID"] = receiverID.ToString(); + paramTable["transactionType"] = (int)TransactionType.MoveMoney; + paramTable["amount"] = amount; + paramTable["secretAccessCode"] = secretCode; + paramTable["description"] = "Move Money"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "MoveMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Fail Message is {0}", resultTable["message"]); + } + else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY MODULE]: MoveMoneyFromTo: Money Server is not available!!"); + + return ret; + } + + + /// + /// Add the money to banker avatar. Need to notify money server to update. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle, UUID regionUUID) + { + //m_log.InfoFormat("[MONEY MODULE]: AddBankerMoney:"); + + bool ret = false; + m_settle_user = false; + + if (m_enable_server) { + // Fill parameters for money transfer XML-RPC. + Hashtable paramTable = new Hashtable(); + paramTable["bankerID"] = bankerID.ToString(); + paramTable["transactionType"] = (int)TransactionType.BuyMoney; + paramTable["amount"] = amount; + paramTable["regionHandle"] = regionHandle.ToString(); + paramTable["regionUUID"] = regionUUID.ToString(); + paramTable["description"] = "Add Money to Avatar"; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney"); + + // Handle the return values from Money Server. + if (resultTable!=null) { + if (resultTable.Contains("success") && (bool)resultTable["success"]==true) { + ret = true; + } + else { + if (resultTable.Contains("banker")) { + m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used. + if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used."); + } + else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Fail Message {0}", resultTable["message"]); + } + } + else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Money Server is not responce"); + } + //else m_log.ErrorFormat("[MONEY MODULE]: AddBankerMoney: Money Server is not available!!"); + + return ret; + } + + + /// + /// Pay the money of charge. + /// + /// + /// The amount of money. + /// + /// + /// return true, if successfully. + /// + private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, UUID regionUUID, string description) + { + //m_log.InfoFormat("[MONEY MODULE]: PayMoneyCharge:"); + + bool ret = false; + IClientAPI senderClient = GetLocateClient(sender); + + // Handle the illegal transaction. + // receiverClient could be null. + if (senderClient==null) { + m_log.InfoFormat("[MONEY MODULE]: PayMoneyCharge: Client {0} is not found", sender.ToString()); + return false; + } + + if (QueryBalanceFromMoneyServer(senderClient) + /// Login the money server when the new client login. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LoginMoneyServer(ScenePresence avatar, out int balance) + { + //m_log.InfoFormat("[MONEY MODULE]: LoginMoneyServer:"); + + balance = 0; + bool ret = false; + bool isNpc = avatar.IsNPC; + + IClientAPI client = avatar.ControllingClient; + + #region Send money server the client info for login. + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + Scene scene = (Scene)client.Scene; + string userName = string.Empty; + + // Get the username for the login user. + if (client.Scene is Scene) { + if (scene!=null) { + UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId); + if (account!=null) { + userName = account.FirstName + " " + account.LastName; + } + } + } + + ////////////////////////////////////////////////////////////// + // User Universal Identifer for Grid Avatar, HG Avatar or NPC + string universalID = string.Empty; + string firstName = string.Empty; + string lastName = string.Empty; + string serverURL = string.Empty; + int avatarType = (int)AvatarType.LOCAL_AVATAR; + int avatarClass = (int)AvatarType.LOCAL_AVATAR; + + AgentCircuitData agent = scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); + + if (agent!=null) { + universalID = Util.ProduceUserUniversalIdentifier(agent); + if (!String.IsNullOrEmpty(universalID)) { + UUID uuid; + string tmp; + Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out tmp); + } + // if serverURL is empty, avatar is a NPC + if (isNpc || String.IsNullOrEmpty(serverURL)) { + avatarType = (int)AvatarType.NPC_AVATAR; + } + // + if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin)!=0 || String.IsNullOrEmpty(userName)) { + avatarType = (int)AvatarType.HG_AVATAR; + } + } + if (String.IsNullOrEmpty(userName)) { + userName = firstName + " " + lastName; + } + + // + avatarClass = avatarType; + if (avatarType==(int)AvatarType.NPC_AVATAR) return false; + if (avatarType==(int)AvatarType.HG_AVATAR) avatarClass = m_hg_avatarClass; + + // + // Login the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(), + scene.RegionInfo.HttpPort.ToString()); + paramTable["avatarType"] = avatarType.ToString(); + paramTable["avatarClass"] = avatarClass.ToString(); + paramTable["userName"] = userName; + paramTable["universalID"] = universalID; + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + balance = (int)resultTable["clientBalance"]; + m_log.InfoFormat("[MONEY MODULE]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL); + ret = true; + } + } + else m_log.ErrorFormat("[MONEY MODULE]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString()); + } + else m_log.ErrorFormat("[MONEY MODULE]: LoginMoneyServer: Money Server is not available!! Server URL is Null or empty!!"); + + #endregion + + // Viewerへ設定を通知する. + if (ret || string.IsNullOrEmpty(m_moneyServURL)) { + OnEconomyDataRequest(client); + } + + return ret; + } + + + /// + /// Log off from the money server. + /// + /// + /// Indicate user ID of the new client. + /// + /// + /// return true, if successfully. + /// + private bool LogoffMoneyServer(IClientAPI client) + { + //m_log.InfoFormat("[MONEY MODULE]: LogoffMoneyServer:"); + + bool ret = false; + + if (!string.IsNullOrEmpty(m_moneyServURL)) { + // Log off from the Money Server. + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout"); + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + ret = true; + } + } + } + + return ret; + } + + + // + private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID) + { + //m_log.InfoFormat("[MONEY MODULE]: GetTransactionInfo:"); + + EventManager.MoneyTransferArgs args = null; + + if (m_enable_server) { + Hashtable paramTable = new Hashtable(); + paramTable["clientUUID"] = client.AgentId.ToString(); + paramTable["clientSessionID"] = client.SessionId.ToString(); + paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString(); + paramTable["transactionID"] = transactionID; + + // Generate the request for transfer. + Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction"); + + // Handle the return result + if (resultTable!=null && resultTable.Contains("success")) { + if ((bool)resultTable["success"]==true) { + int amount = (int)resultTable["amount"]; + int type = (int)resultTable["type"]; + string desc = (string)resultTable["description"]; + UUID sender = UUID.Zero; + UUID recver = UUID.Zero; + UUID.TryParse((string)resultTable["sender"], out sender); + UUID.TryParse((string)resultTable["receiver"], out recver); + args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc); + } + else { + m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]); + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: Invalid Response"); + } + } + else { + m_log.ErrorFormat("[MONEY MODULE]: GetTransactionInfo: Invalid Money Server URL"); + } + + return args; + } + + + /// + /// Generic XMLRPC client abstraction + /// + /// Hashtable containing parameters to the method + /// Method to invoke + /// Hashtable with success=>bool and other values + private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method) + { + //m_log.InfoFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest:"); + + if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null; + + if (m_checkServerCert) { + if (!m_moneyServURL.StartsWith("https://")) { + m_log.InfoFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file"); + //return null; + } + } + else { + if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://")) { + m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL); + return null; + } + } + + // + ArrayList arrayParams = new ArrayList(); + arrayParams.Add(reqParams); + XmlRpcResponse moneyServResp = null; + try { + NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams); + //moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_certVerify, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL); + m_log.ErrorFormat("[MONEY MODULE]: genericCurrencyXMLRPCRequest: {0}", ex); + + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + if (moneyServResp==null || moneyServResp.IsFault) { + Hashtable ErrorHash = new Hashtable(); + ErrorHash["success"] = false; + ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable"; + ErrorHash["errorURI"] = ""; + return ErrorHash; + } + + Hashtable moneyRespData = (Hashtable)moneyServResp.Value; + return moneyRespData; + } + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /// Locates a IClientAPI for the client specified + /// + /// + /// + private IClientAPI GetLocateClient(UUID AgentID) + { + IClientAPI client = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID); + if (tPresence!=null && !tPresence.IsChildAgent) { + IClientAPI rclient = tPresence.ControllingClient; + if (rclient!=null) { + client = rclient; + break; + } + } + } + } + } + + return client; + } + + + private Scene GetLocateScene(UUID AgentId) + { + Scene scene = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId); + if (tPresence!=null && !tPresence.IsChildAgent) { + scene = _scene; + break; + } + } + } + } + + return scene; + } + + + private SceneObjectPart GetLocatePrim(UUID objectID) + { + SceneObjectPart sceneObj = null; + + lock (m_sceneList) { + if (m_sceneList.Count>0) { + foreach (Scene _scene in m_sceneList.Values) { + SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID); + if (part!=null) { + sceneObj = part; + break; + } + } + } + } + + return sceneObj; + } + + #endregion + } + +} diff --git a/release/0.9.2/src/OpenSim.Modules.Currency/NSLCertificateTools.cs b/release/0.9.2/src/OpenSim.Modules.Currency/NSLCertificateTools.cs new file mode 100644 index 0000000..b0c3034 --- /dev/null +++ b/release/0.9.2/src/OpenSim.Modules.Currency/NSLCertificateTools.cs @@ -0,0 +1,291 @@ +/* + * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp + * + */ + +#pragma warning disable S1128 // Unused "using" should be removed +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using System.Net; +using System.Net.Security; +using System.Text; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using log4net; +#pragma warning restore S1128 // Unused "using" should be removed + + +namespace NSL.Certificate.Tools +{ + /// + /// class NSL Certificate Verify + /// + public class NSLCertificateVerify + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private X509Chain m_chain = null; + private X509Certificate2 m_cacert = null; + private X509Certificate2 m_mycert = null; + + private Mono.Security.X509.X509Crl m_clientcrl = null; + + + /// + /// NSL Certificate Verify + /// + public NSLCertificateVerify() + { + m_chain = null; + m_cacert = null; + m_clientcrl = null; + } + + + /// + /// NSL Certificate Verify + /// + /// + public NSLCertificateVerify(string certfile) + { + SetPrivateCA(certfile); + } + + + /// + /// NSL Certificate Verify + /// + /// + /// + public NSLCertificateVerify(string certfile, string crlfile) + { + SetPrivateCA (certfile); + SetPrivateCRL(crlfile); + } + + + /// + /// Set Private Certificate + /// + /// + /// + public void SetPrivateCert(string certfile, string passwd) + { + try { + m_mycert = new X509Certificate2(certfile, passwd); + } + catch (Exception ex) { + m_mycert = null; + m_log.ErrorFormat("[SET PRIVATE CERT]: Cert File setting error [{0}]. {1}", certfile, ex); + } + } + + + /// + /// Get Private Certificate + /// + public X509Certificate2 GetPrivateCert() + { + return m_mycert; + } + + + /// + /// Set Private CA + /// + /// + public void SetPrivateCA(string certfile) + { + try { + m_cacert = new X509Certificate2(certfile); + } + catch (Exception ex) { + m_cacert = null; + m_log.ErrorFormat("[SET PRIVATE CA]: CA File reading error [{0}]. {1}", certfile, ex); + } + + if (m_cacert!=null) { + m_chain = new X509Chain(); + m_chain.ChainPolicy.ExtraStore.Add(m_cacert); + m_chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + m_chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; + } + } + + + // + public void SetPrivateCRL(string crlfile) + { + try { + m_clientcrl = Mono.Security.X509.X509Crl.CreateFromFile(crlfile); + } + catch (Exception ex) { + m_clientcrl = null; + m_log.ErrorFormat("[SET PRIVATE CRL]: CRL File reading error [{0}]. {1}", crlfile, ex); + } + } + + + /// + /// Check Private Chain + /// + /// + /// + public bool CheckPrivateChain(X509Certificate2 cert) + { + if (m_chain==null || m_cacert==null) { + return false; + } + + bool ret = m_chain.Build((X509Certificate2)cert); + if (ret) { + return true; + } + + for (int i=0; i + /// Validate Server Certificate Callback Function + /// + /// + /// + /// + /// + /// + public bool ValidateServerCertificate(object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Policy is ({0})", sslPolicyErrors); + + if (obj is HttpWebRequest) { + HttpWebRequest Request = (HttpWebRequest)obj; + string noVerify = Request.Headers.Get("NoVerifyCert"); + if ((noVerify != null) && (noVerify.ToLower() == "true")) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: No Verify Server Certificate."); + return true; + } + } + + X509Certificate2 certificate2 = new X509Certificate2(certificate); + string commonname = certificate2.GetNameInfo(X509NameType.SimpleName, false); + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Common Name is \"{0}\"", commonname); + + /* + // RemoteCertificateNotAvailableはエラーとする. + if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable)==SslPolicyErrors.RemoteCertificateNotAvailable) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Policy Error! {0}", sslPolicyErrors); + return false; + } + */ + + // None, ChainErrors Error except for. // None, ChainErrors 以外は全てエラーとする. + if ((sslPolicyErrors != SslPolicyErrors.None) && (sslPolicyErrors != SslPolicyErrors.RemoteCertificateChainErrors)) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Policy Error! {0}", sslPolicyErrors); + return false; + } + + bool valid = CheckPrivateChain(certificate2); + if (valid) { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Valid Server Certification for \"{0}\"", commonname); + } + else { + m_log.InfoFormat("[NSL SERVER CERT VERIFY]: ValidateServerCertificate: Failed to Verify Server Certification for \"{0}\"", commonname); + } + return valid; + } + + + /// + /// Validate Client Certificate Callback Function + /// + /// + /// + /// + /// + /// + public bool ValidateClientCertificate(object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Start."); + + if (certificate==null) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Client does not have a Certificate!"); + return false; + } + + X509Certificate2 certificate2 = new X509Certificate2(certificate); + string commonname = certificate2.GetNameInfo(X509NameType.SimpleName, false); + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Common Name is \"{0}\"", commonname); + + // None, ChainErrors 以外は全てエラーとする. + if (sslPolicyErrors!=SslPolicyErrors.None && sslPolicyErrors!=SslPolicyErrors.RemoteCertificateChainErrors) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: ValidateClientCertificate: Policy Error! {0}", sslPolicyErrors); + return false; + } + + // check CRL + if (m_clientcrl!=null) { + Mono.Security.X509.X509Certificate monocert = new Mono.Security.X509.X509Certificate(certificate.GetRawCertData()); + Mono.Security.X509.X509Crl.X509CrlEntry entry = m_clientcrl.GetCrlEntry(monocert); + if (entry!=null) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: Common Name \"{0}\" was revoked at {1}", commonname, entry.RevocationDate.ToString()); + return false; + } + } + + bool valid = CheckPrivateChain(certificate2); + if (valid) { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: Valid Client Certification for \"{0}\"", commonname); + } + else { + m_log.InfoFormat("[NSL CLIENT CERT VERIFY]: Failed to Verify Client Certification for \"{0}\"", commonname); + } + return valid; + } + } + + +/* + /// + /// class NSL Certificate Policy + /// + public class NSLCertificatePolicy : ICertificatePolicy + { + /// + /// Check Validation Result + /// + /// + /// + /// + /// + /// + public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) + { + if (certificateProblem == 0 || // normal // 正常 + certificateProblem == -2146762487 || // Not trusted // 信頼されてない + certificateProblem == -2146762495 || // Expired // 期限切れ + certificateProblem == -2146762481) { // Incorrect name // 名前不正 + return true; + } + else { + return false; + } + } + } +*/ +} diff --git a/release/0.9.2/src/OpenSim.Modules.Currency/NSLXmlRpc.cs b/release/0.9.2/src/OpenSim.Modules.Currency/NSLXmlRpc.cs new file mode 100644 index 0000000..025236a --- /dev/null +++ b/release/0.9.2/src/OpenSim.Modules.Currency/NSLXmlRpc.cs @@ -0,0 +1,115 @@ +/* + * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp + * + */ + + +using System; +using System.Collections; +using System.IO; +using System.Xml; +using System.Net; +using System.Text; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using log4net; +using Nwc.XmlRpc; + +using System.Net.Security; +using NSL.Certificate.Tools; + + +namespace NSL.Network.XmlRpc +{ + public class NSLXmlRpcRequest : XmlRpcRequest + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Encoding _encoding = new UTF8Encoding(); + private XmlRpcRequestSerializer _serializer = new XmlRpcRequestSerializer(); + private XmlRpcResponseDeserializer _deserializer = new XmlRpcResponseDeserializer(); + + + public NSLXmlRpcRequest() + { + _params = new ArrayList(); + } + + + public NSLXmlRpcRequest(String methodName, IList parameters) + { + MethodName = methodName; + _params = parameters; + } + + + //public XmlRpcResponse certSend(String url, X509Certificate2 myClientCert, bool checkServerCert, Int32 timeout) + public XmlRpcResponse certSend(String url, NSLCertificateVerify certVerify, bool checkServerCert, Int32 timeout) + { + m_log.InfoFormat("[MONEY NSL XMLRPC]: XmlRpcResponse certSend: connect to {0}", url); + +//#pragma warning disable SYSLIB0014 // Use HttpClient instead of WebRequest.Create. + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); +//#pragma warning restore SYSLIB0014 + if (request==null) { + throw new XmlRpcException(XmlRpcErrorCodes.TRANSPORT_ERROR, XmlRpcErrorCodes.TRANSPORT_ERROR_MSG +": Could not create request with " + url); + } + + X509Certificate2 clientCert = null; + + request.Method = "POST"; + request.ContentType = "text/xml"; + request.AllowWriteStreamBuffering = true; + request.Timeout = timeout; + request.UserAgent = "NSLXmlRpcRequest"; + + if (certVerify != null) { + clientCert = certVerify.GetPrivateCert(); + if (clientCert != null) request.ClientCertificates.Add(clientCert); // Own certificate // 自身の証明書 + request.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(certVerify.ValidateServerCertificate); + } + else { + checkServerCert = false; + } + // + if (!checkServerCert) { + request.Headers.Add("NoVerifyCert", "true"); // Do not verify the certificate of the other party // 相手の証明書を検証しない + } + + // + Stream stream = null; + try { + stream = request.GetRequestStream(); + } +#pragma warning disable CS0168 + catch (Exception ex) { +#pragma warning restore CS0168 + m_log.ErrorFormat("[MONEY NSL XMLRPC]: GetRequestStream Error: {0}", ex); + stream = null; + } + if (stream==null) return null; + + // + XmlTextWriter xml = new XmlTextWriter(stream, _encoding); + _serializer.Serialize(xml, this); + xml.Flush(); + xml.Close(); + + HttpWebResponse response = null; + try { + response = (HttpWebResponse)request.GetResponse(); + } + catch (Exception ex) { + m_log.ErrorFormat("[MONEY NSL XMLRPC]: XmlRpcResponse certSend: GetResponse Error: {0}", ex.ToString()); + } + StreamReader input = new StreamReader(response.GetResponseStream()); + + string inputXml = input.ReadToEnd(); + XmlRpcResponse resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); + + input.Close(); + response.Close(); + return resp; + } + } +} diff --git a/runprebuild.bat b/runprebuild.bat new file mode 100755 index 0000000..603267f --- /dev/null +++ b/runprebuild.bat @@ -0,0 +1,61 @@ +@echo OFF + +..\bin\Prebuild.exe /target vs2015 + +setlocal ENABLEEXTENSIONS +set VALUE_NAME=MSBuildToolsPath + +if "%PROCESSOR_ARCHITECTURE%"=="x86" set PROGRAMS=%ProgramFiles% +if defined ProgramFiles(x86) set PROGRAMS=%ProgramFiles(x86)% + +rem Try to find VS2019 +for %%e in (Enterprise Professional Community) do ( + if exist "%PROGRAMS%\Microsoft Visual Studio\2019\%%e\MSBuild\Current\Bin\MSBuild.exe" ( + + set ValueValue="%PROGRAMS%\Microsoft Visual Studio\2019\%%e\MSBuild\Current\Bin\MSBuild" + goto :found + ) +) + +rem try find vs2017 +for %%e in (Enterprise Professional Community) do ( + if exist "%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe" ( + + set ValueValue="%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild" + goto :found + ) +) + +rem We have to use grep or find to locate the correct line, because reg query spits +rem out 4 lines before Windows 7 but 2 lines after Windows 7. +rem We use grep if it's on the path; otherwise we use the built-in find command +rem from Windows. (We must use grep on Cygwin because it overrides the "find" command.) + +for %%X in (grep.exe) do (set FOUNDGREP=%%~$PATH:X) +if defined FOUNDGREP ( + set FINDCMD=grep +) else ( + set FINDCMD=find +) + +rem try vs2015 +FOR /F "usebackq tokens=1-3" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v %VALUE_NAME% 2^>nul ^| %FINDCMD% "%VALUE_NAME%"`) DO ( + set ValueValue=%%C\msbuild + goto :found +) + +@echo msbuild for at least VS2015 not found, please install a (Community) edition of VS2017 or VS2015 +@echo Not creating compile.bat +if exist "compile.bat" ( + del compile.bat + ) +goto :done + +:found + @echo Found msbuild at %ValueValue% + @echo Creating compile.bat +rem To compile in debug mode + @echo %ValueValue% opensim.sln > compile.bat +rem To compile in release mode comment line (add rem to start) above and uncomment next (remove rem) +rem @echo %ValueValue% /P:Config=Release opensim.sln > compile.bat +:done diff --git a/runprebuild.net.bat b/runprebuild.net.bat new file mode 100755 index 0000000..162d76b --- /dev/null +++ b/runprebuild.net.bat @@ -0,0 +1,18 @@ +@echo OFF + +dotnet ..\bin\prebuild.dll /target vs2022 /targetframework net6_0 /excludedir = "obj | bin" /file prebuild.net.xml + + @echo Creating compile.bat +rem To compile in debug mode + @echo dotnet build --configuration Release OpenSim.Currency.sln > compile.bat +rem To compile in release mode comment line (add rem to start) above and uncomment next (remove rem) +rem @echo dotnet build --configuration Debug OpenSim.sln > compile.bat +:done +if exist "..\bin\addin-db-002" ( + del /F/Q/S ..\bin\addin-db-002 > NUL + rmdir /Q/S ..\bin\addin-db-002 + ) +if exist "..\bin\addin-db-004" ( + del /F/Q/S ..\bin\addin-db-004 > NUL + rmdir /Q/S ..\bin\addin-db-004 + ) diff --git a/runprebuild.net.sh b/runprebuild.net.sh new file mode 100755 index 0000000..d80ef02 --- /dev/null +++ b/runprebuild.net.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# +echo y | dotnet ../bin/prebuild.dll /file prebuild.net.xml /clean + +dotnet ../bin/prebuild.dll /target vs2022 /targetframework net6_0 /excludedir = "obj | bin" /file prebuild.net.xml + diff --git a/runprebuild.sh b/runprebuild.sh new file mode 100755 index 0000000..086f7e9 --- /dev/null +++ b/runprebuild.sh @@ -0,0 +1,4 @@ +#mono ../bin/Prebuild.exe /target vs2008 /targetframework v3_5 /conditionals NET_3_5 +#mono ../bin/Prebuild.exe /target vs2010 +mono ../bin/Prebuild.exe /target vs2015 +