
By default system is disabled (src/config/core.h). This follows the iRO implementation VIP System. More information can be found on the iRO Wiki. All settings also have individual configs. Official VIP scripts will be implemented later. Big thanks to lighta and Cydh for support and debugging.
718 lines
26 KiB
C
718 lines
26 KiB
C
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
|
|
// For more information, see LICENCE in the main folder
|
|
|
|
#include "../common/malloc.h"
|
|
#include "../common/mmo.h"
|
|
#include "../common/showmsg.h"
|
|
#include "../common/sql.h"
|
|
#include "../common/strlib.h"
|
|
#include "../common/timer.h"
|
|
#include "../config/core.h"
|
|
#include "account.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/// global defines
|
|
#define ACCOUNT_SQL_DB_VERSION 20110114
|
|
|
|
/// internal structure
|
|
typedef struct AccountDB_SQL
|
|
{
|
|
AccountDB vtable; // public interface
|
|
|
|
Sql* accounts; // SQL accounts storage
|
|
|
|
// global sql settings
|
|
char global_db_hostname[32];
|
|
uint16 global_db_port;
|
|
char global_db_username[32];
|
|
char global_db_password[32];
|
|
char global_db_database[32];
|
|
char global_codepage[32];
|
|
// local sql settings
|
|
char db_hostname[32];
|
|
uint16 db_port;
|
|
char db_username[32];
|
|
char db_password[32];
|
|
char db_database[32];
|
|
char codepage[32];
|
|
// other settings
|
|
bool case_sensitive;
|
|
char account_db[32];
|
|
char accreg_db[32];
|
|
|
|
} AccountDB_SQL;
|
|
|
|
/// internal structure
|
|
typedef struct AccountDBIterator_SQL
|
|
{
|
|
AccountDBIterator vtable; // public interface
|
|
|
|
AccountDB_SQL* db;
|
|
int last_account_id;
|
|
} AccountDBIterator_SQL;
|
|
|
|
/// internal functions
|
|
static bool account_db_sql_init(AccountDB* self);
|
|
static void account_db_sql_destroy(AccountDB* self);
|
|
static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen);
|
|
static bool account_db_sql_set_property(AccountDB* self, const char* option, const char* value);
|
|
static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc);
|
|
static bool account_db_sql_remove(AccountDB* self, const int account_id);
|
|
static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc);
|
|
static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id);
|
|
static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid);
|
|
static AccountDBIterator* account_db_sql_iterator(AccountDB* self);
|
|
static void account_db_sql_iter_destroy(AccountDBIterator* self);
|
|
static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc);
|
|
|
|
static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id);
|
|
static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new);
|
|
|
|
/// public constructor
|
|
AccountDB* account_db_sql(void)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)aCalloc(1, sizeof(AccountDB_SQL));
|
|
|
|
// set up the vtable
|
|
db->vtable.init = &account_db_sql_init;
|
|
db->vtable.destroy = &account_db_sql_destroy;
|
|
db->vtable.get_property = &account_db_sql_get_property;
|
|
db->vtable.set_property = &account_db_sql_set_property;
|
|
db->vtable.save = &account_db_sql_save;
|
|
db->vtable.create = &account_db_sql_create;
|
|
db->vtable.remove = &account_db_sql_remove;
|
|
db->vtable.load_num = &account_db_sql_load_num;
|
|
db->vtable.load_str = &account_db_sql_load_str;
|
|
db->vtable.iterator = &account_db_sql_iterator;
|
|
|
|
// initialize to default values
|
|
db->accounts = NULL;
|
|
// global sql settings
|
|
safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname));
|
|
db->global_db_port = 3306;
|
|
safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username));
|
|
safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password));
|
|
safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database));
|
|
safestrncpy(db->global_codepage, "", sizeof(db->global_codepage));
|
|
// local sql settings
|
|
safestrncpy(db->db_hostname, "", sizeof(db->db_hostname));
|
|
db->db_port = 3306;
|
|
safestrncpy(db->db_username, "", sizeof(db->db_username));
|
|
safestrncpy(db->db_password, "", sizeof(db->db_password));
|
|
safestrncpy(db->db_database, "", sizeof(db->db_database));
|
|
safestrncpy(db->codepage, "", sizeof(db->codepage));
|
|
// other settings
|
|
db->case_sensitive = false;
|
|
safestrncpy(db->account_db, "login", sizeof(db->account_db));
|
|
safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db));
|
|
|
|
return &db->vtable;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
/// establishes database connection
|
|
static bool account_db_sql_init(AccountDB* self)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
Sql* sql_handle;
|
|
const char* username;
|
|
const char* password;
|
|
const char* hostname;
|
|
uint16 port;
|
|
const char* database;
|
|
const char* codepage;
|
|
|
|
db->accounts = Sql_Malloc();
|
|
sql_handle = db->accounts;
|
|
|
|
if( db->db_hostname[0] != '\0' )
|
|
{// local settings
|
|
username = db->db_username;
|
|
password = db->db_password;
|
|
hostname = db->db_hostname;
|
|
port = db->db_port;
|
|
database = db->db_database;
|
|
codepage = db->codepage;
|
|
}
|
|
else
|
|
{// global settings
|
|
username = db->global_db_username;
|
|
password = db->global_db_password;
|
|
hostname = db->global_db_hostname;
|
|
port = db->global_db_port;
|
|
database = db->global_db_database;
|
|
codepage = db->global_codepage;
|
|
}
|
|
|
|
if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
Sql_Free(db->accounts);
|
|
db->accounts = NULL;
|
|
return false;
|
|
}
|
|
|
|
if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
|
|
Sql_ShowDebug(sql_handle);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// disconnects from database
|
|
static void account_db_sql_destroy(AccountDB* self)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
|
|
Sql_Free(db->accounts);
|
|
db->accounts = NULL;
|
|
aFree(db);
|
|
}
|
|
|
|
/// Gets a property from this database.
|
|
static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
const char* signature;
|
|
|
|
signature = "engine.";
|
|
if( strncmpi(key, signature, strlen(signature)) == 0 )
|
|
{
|
|
key += strlen(signature);
|
|
if( strcmpi(key, "name") == 0 )
|
|
safesnprintf(buf, buflen, "sql");
|
|
else
|
|
if( strcmpi(key, "version") == 0 )
|
|
safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION);
|
|
else
|
|
if( strcmpi(key, "comment") == 0 )
|
|
safesnprintf(buf, buflen, "SQL Account Database");
|
|
else
|
|
return false;// not found
|
|
return true;
|
|
}
|
|
|
|
signature = "sql.";
|
|
if( strncmpi(key, signature, strlen(signature)) == 0 )
|
|
{
|
|
key += strlen(signature);
|
|
if( strcmpi(key, "db_hostname") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->global_db_hostname);
|
|
else
|
|
if( strcmpi(key, "db_port") == 0 )
|
|
safesnprintf(buf, buflen, "%d", db->global_db_port);
|
|
else
|
|
if( strcmpi(key, "db_username") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->global_db_username);
|
|
else
|
|
if( strcmpi(key, "db_password") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->global_db_password);
|
|
else
|
|
if( strcmpi(key, "db_database") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->global_db_database);
|
|
else
|
|
if( strcmpi(key, "codepage") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->global_codepage);
|
|
else
|
|
return false;// not found
|
|
return true;
|
|
}
|
|
|
|
signature = "account.sql.";
|
|
if( strncmpi(key, signature, strlen(signature)) == 0 )
|
|
{
|
|
key += strlen(signature);
|
|
if( strcmpi(key, "db_hostname") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->db_hostname);
|
|
else
|
|
if( strcmpi(key, "db_port") == 0 )
|
|
safesnprintf(buf, buflen, "%d", db->db_port);
|
|
else
|
|
if( strcmpi(key, "db_username") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->db_username);
|
|
else
|
|
if( strcmpi(key, "db_password") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->db_password);
|
|
else
|
|
if( strcmpi(key, "db_database") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->db_database);
|
|
else
|
|
if( strcmpi(key, "codepage") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->codepage);
|
|
else
|
|
if( strcmpi(key, "case_sensitive") == 0 )
|
|
safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0));
|
|
else
|
|
if( strcmpi(key, "account_db") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->account_db);
|
|
else
|
|
if( strcmpi(key, "accreg_db") == 0 )
|
|
safesnprintf(buf, buflen, "%s", db->accreg_db);
|
|
else
|
|
return false;// not found
|
|
return true;
|
|
}
|
|
|
|
return false;// not found
|
|
}
|
|
|
|
/// if the option is supported, adjusts the internal state
|
|
static bool account_db_sql_set_property(AccountDB* self, const char* key, const char* value)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
const char* signature;
|
|
|
|
|
|
signature = "sql.";
|
|
if( strncmp(key, signature, strlen(signature)) == 0 )
|
|
{
|
|
key += strlen(signature);
|
|
if( strcmpi(key, "db_hostname") == 0 )
|
|
safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname));
|
|
else
|
|
if( strcmpi(key, "db_port") == 0 )
|
|
db->global_db_port = (uint16)strtoul(value, NULL, 10);
|
|
else
|
|
if( strcmpi(key, "db_username") == 0 )
|
|
safestrncpy(db->global_db_username, value, sizeof(db->global_db_username));
|
|
else
|
|
if( strcmpi(key, "db_password") == 0 )
|
|
safestrncpy(db->global_db_password, value, sizeof(db->global_db_password));
|
|
else
|
|
if( strcmpi(key, "db_database") == 0 )
|
|
safestrncpy(db->global_db_database, value, sizeof(db->global_db_database));
|
|
else
|
|
if( strcmpi(key, "codepage") == 0 )
|
|
safestrncpy(db->global_codepage, value, sizeof(db->global_codepage));
|
|
else
|
|
return false;// not found
|
|
return true;
|
|
}
|
|
|
|
signature = "account.sql.";
|
|
if( strncmp(key, signature, strlen(signature)) == 0 )
|
|
{
|
|
key += strlen(signature);
|
|
if( strcmpi(key, "db_hostname") == 0 )
|
|
safestrncpy(db->db_hostname, value, sizeof(db->db_hostname));
|
|
else
|
|
if( strcmpi(key, "db_port") == 0 )
|
|
db->db_port = (uint16)strtoul(value, NULL, 10);
|
|
else
|
|
if( strcmpi(key, "db_username") == 0 )
|
|
safestrncpy(db->db_username, value, sizeof(db->db_username));
|
|
else
|
|
if( strcmpi(key, "db_password") == 0 )
|
|
safestrncpy(db->db_password, value, sizeof(db->db_password));
|
|
else
|
|
if( strcmpi(key, "db_database") == 0 )
|
|
safestrncpy(db->db_database, value, sizeof(db->db_database));
|
|
else
|
|
if( strcmpi(key, "codepage") == 0 )
|
|
safestrncpy(db->codepage, value, sizeof(db->codepage));
|
|
else
|
|
if( strcmpi(key, "case_sensitive") == 0 )
|
|
db->case_sensitive = config_switch(value);
|
|
else
|
|
if( strcmpi(key, "account_db") == 0 )
|
|
safestrncpy(db->account_db, value, sizeof(db->account_db));
|
|
else
|
|
if( strcmpi(key, "accreg_db") == 0 )
|
|
safestrncpy(db->accreg_db, value, sizeof(db->accreg_db));
|
|
else
|
|
return false;// not found
|
|
return true;
|
|
}
|
|
|
|
return false;// not found
|
|
}
|
|
|
|
/// create a new account entry
|
|
/// If acc->account_id is -1, the account id will be auto-generated,
|
|
/// and its value will be written to acc->account_id if everything succeeds.
|
|
static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
Sql* sql_handle = db->accounts;
|
|
|
|
// decide on the account id to assign
|
|
int account_id;
|
|
if( acc->account_id != -1 )
|
|
{// caller specifies it manually
|
|
account_id = acc->account_id;
|
|
}
|
|
else
|
|
{// ask the database
|
|
char* data;
|
|
size_t len;
|
|
|
|
if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db) )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
return false;
|
|
}
|
|
if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
Sql_FreeResult(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
Sql_GetData(sql_handle, 0, &data, &len);
|
|
account_id = ( data != NULL ) ? atoi(data) : 0;
|
|
Sql_FreeResult(sql_handle);
|
|
|
|
if( account_id < START_ACCOUNT_NUM )
|
|
account_id = START_ACCOUNT_NUM;
|
|
|
|
}
|
|
|
|
// zero value is prohibited
|
|
if( account_id == 0 )
|
|
return false;
|
|
|
|
// absolute maximum
|
|
if( account_id > END_ACCOUNT_NUM )
|
|
return false;
|
|
|
|
// insert the data into the database
|
|
acc->account_id = account_id;
|
|
return mmo_auth_tosql(db, acc, true);
|
|
}
|
|
|
|
/// delete an existing account entry + its regs
|
|
static bool account_db_sql_remove(AccountDB* self, const int account_id)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
Sql* sql_handle = db->accounts;
|
|
bool result = false;
|
|
|
|
if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION")
|
|
|| SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id)
|
|
|| SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id) )
|
|
Sql_ShowDebug(sql_handle);
|
|
else
|
|
result = true;
|
|
|
|
result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") );
|
|
|
|
return result;
|
|
}
|
|
|
|
/// update an existing account with the provided new data (both account and regs)
|
|
static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
return mmo_auth_tosql(db, acc, false);
|
|
}
|
|
|
|
/// retrieve data from db and store it in the provided data structure
|
|
static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
return mmo_auth_fromsql(db, acc, account_id);
|
|
}
|
|
|
|
/// retrieve data from db and store it in the provided data structure
|
|
static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
Sql* sql_handle = db->accounts;
|
|
char esc_userid[2*NAME_LENGTH+1];
|
|
int account_id;
|
|
char* data;
|
|
|
|
Sql_EscapeString(sql_handle, esc_userid, userid);
|
|
|
|
// get the list of account IDs for this user ID
|
|
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'",
|
|
db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid) )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
if( Sql_NumRows(sql_handle) > 1 )
|
|
{// serious problem - duplicit account
|
|
ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid);
|
|
Sql_FreeResult(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
|
|
{// no such entry
|
|
Sql_FreeResult(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
Sql_GetData(sql_handle, 0, &data, NULL);
|
|
account_id = atoi(data);
|
|
|
|
return account_db_sql_load_num(self, acc, account_id);
|
|
}
|
|
|
|
|
|
/// Returns a new forward iterator.
|
|
static AccountDBIterator* account_db_sql_iterator(AccountDB* self)
|
|
{
|
|
AccountDB_SQL* db = (AccountDB_SQL*)self;
|
|
AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)aCalloc(1, sizeof(AccountDBIterator_SQL));
|
|
|
|
// set up the vtable
|
|
iter->vtable.destroy = &account_db_sql_iter_destroy;
|
|
iter->vtable.next = &account_db_sql_iter_next;
|
|
|
|
// fill data
|
|
iter->db = db;
|
|
iter->last_account_id = -1;
|
|
|
|
return &iter->vtable;
|
|
}
|
|
|
|
|
|
/// Destroys this iterator, releasing all allocated memory (including itself).
|
|
static void account_db_sql_iter_destroy(AccountDBIterator* self)
|
|
{
|
|
AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self;
|
|
aFree(iter);
|
|
}
|
|
|
|
|
|
/// Fetches the next account in the database.
|
|
static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc)
|
|
{
|
|
AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self;
|
|
AccountDB_SQL* db = (AccountDB_SQL*)iter->db;
|
|
Sql* sql_handle = db->accounts;
|
|
char* data;
|
|
|
|
// get next account ID
|
|
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1",
|
|
db->account_db, iter->last_account_id) )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
if( SQL_SUCCESS == Sql_NextRow(sql_handle) &&
|
|
SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) &&
|
|
data != NULL )
|
|
{// get account data
|
|
int account_id;
|
|
account_id = atoi(data);
|
|
if( mmo_auth_fromsql(db, acc, account_id) )
|
|
{
|
|
iter->last_account_id = account_id;
|
|
Sql_FreeResult(sql_handle);
|
|
return true;
|
|
}
|
|
}
|
|
Sql_FreeResult(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
|
|
static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id)
|
|
{
|
|
Sql* sql_handle = db->accounts;
|
|
char* data;
|
|
int i = 0;
|
|
|
|
// retrieve login entry for the specified account
|
|
if( SQL_ERROR == Sql_Query(sql_handle,
|
|
#ifdef VIP_ENABLE
|
|
"SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change`, `bank_vault`, `vip_time`, `old_group` FROM `%s` WHERE `account_id` = %d",
|
|
#else
|
|
"SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change`, `bank_vault` FROM `%s` WHERE `account_id` = %d",
|
|
#endif
|
|
db->account_db, account_id )
|
|
) {
|
|
Sql_ShowDebug(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
|
|
{// no such entry
|
|
Sql_FreeResult(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
Sql_GetData(sql_handle, 0, &data, NULL); acc->account_id = atoi(data);
|
|
Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->userid, data, sizeof(acc->userid));
|
|
Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass));
|
|
Sql_GetData(sql_handle, 3, &data, NULL); acc->sex = data[0];
|
|
Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email));
|
|
Sql_GetData(sql_handle, 5, &data, NULL); acc->group_id = atoi(data);
|
|
Sql_GetData(sql_handle, 6, &data, NULL); acc->state = strtoul(data, NULL, 10);
|
|
Sql_GetData(sql_handle, 7, &data, NULL); acc->unban_time = atol(data);
|
|
Sql_GetData(sql_handle, 8, &data, NULL); acc->expiration_time = atol(data);
|
|
Sql_GetData(sql_handle, 9, &data, NULL); acc->logincount = strtoul(data, NULL, 10);
|
|
Sql_GetData(sql_handle, 10, &data, NULL); safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin));
|
|
Sql_GetData(sql_handle, 11, &data, NULL); safestrncpy(acc->last_ip, data, sizeof(acc->last_ip));
|
|
Sql_GetData(sql_handle, 12, &data, NULL); safestrncpy(acc->birthdate, data, sizeof(acc->birthdate));
|
|
Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = atoi(data);
|
|
Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode));
|
|
Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data);
|
|
Sql_GetData(sql_handle, 16, &data, NULL); acc->bank_vault = atoi(data);
|
|
#ifdef VIP_ENABLE
|
|
Sql_GetData(sql_handle, 17, &data, NULL); acc->vip_time = atol(data);
|
|
Sql_GetData(sql_handle, 18, &data, NULL); acc->old_group = atoi(data);
|
|
#endif
|
|
Sql_FreeResult(sql_handle);
|
|
|
|
// retrieve account regs for the specified user
|
|
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
return false;
|
|
}
|
|
|
|
acc->account_reg2_num = (int)Sql_NumRows(sql_handle);
|
|
|
|
while( SQL_SUCCESS == Sql_NextRow(sql_handle) )
|
|
{
|
|
char* data;
|
|
Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str));
|
|
Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value));
|
|
++i;
|
|
}
|
|
Sql_FreeResult(sql_handle);
|
|
|
|
if( i != acc->account_reg2_num )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new)
|
|
{
|
|
Sql* sql_handle = db->accounts;
|
|
SqlStmt* stmt = SqlStmt_Malloc(sql_handle);
|
|
bool result = false;
|
|
int i;
|
|
|
|
// try
|
|
do
|
|
{
|
|
|
|
if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
break;
|
|
}
|
|
|
|
if( is_new )
|
|
{// insert into account table
|
|
if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
|
|
#ifdef VIP_ENABLE
|
|
"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`, `bank_vault`, `vip_time`, `old_group` ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
#else
|
|
"INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`, `bank_vault`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
#endif
|
|
db->account_db)
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_INT, (void*)&acc->bank_vault, sizeof(acc->bank_vault))
|
|
#ifdef VIP_ENABLE
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 17, SQLDT_LONG, (void*)&acc->vip_time, sizeof(acc->vip_time))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 18, SQLDT_INT, (void*)&acc->old_group, sizeof(acc->old_group))
|
|
#endif
|
|
|| SQL_SUCCESS != SqlStmt_Execute(stmt)
|
|
) {
|
|
SqlStmt_ShowDebug(stmt);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{// update account table
|
|
if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
|
|
#ifdef VIP_ENABLE
|
|
"UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=?, `bank_vault`=?, `vip_time`=?, `old_group`=? WHERE `account_id` = '%d'",
|
|
#else
|
|
"UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=?, `bank_vault`=? WHERE `account_id` = '%d'",
|
|
#endif
|
|
db->account_db, acc->account_id)
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_INT, (void*)&acc->bank_vault, sizeof(acc->bank_vault))
|
|
#ifdef VIP_ENABLE
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_LONG, (void*)&acc->vip_time, sizeof(acc->vip_time))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 17, SQLDT_INT, (void*)&acc->old_group, sizeof(acc->old_group))
|
|
#endif
|
|
|| SQL_SUCCESS != SqlStmt_Execute(stmt)
|
|
) {
|
|
SqlStmt_ShowDebug(stmt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// remove old account regs
|
|
if( SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
|
|
{
|
|
Sql_ShowDebug(sql_handle);
|
|
break;
|
|
}
|
|
// insert new account regs
|
|
if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id) )
|
|
{
|
|
SqlStmt_ShowDebug(stmt);
|
|
break;
|
|
}
|
|
for( i = 0; i < acc->account_reg2_num; ++i )
|
|
{
|
|
if( SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str))
|
|
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value))
|
|
|| SQL_SUCCESS != SqlStmt_Execute(stmt)
|
|
) {
|
|
SqlStmt_ShowDebug(stmt);
|
|
break;
|
|
}
|
|
}
|
|
if( i < acc->account_reg2_num )
|
|
{
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
// if we got this far, everything was successful
|
|
result = true;
|
|
|
|
} while(0);
|
|
// finally
|
|
|
|
result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") );
|
|
SqlStmt_Free(stmt);
|
|
|
|
return result;
|
|
}
|