forked from github/server
Merge branch 'dbstring' into develop
This commit is contained in:
commit
1be7daf516
|
@ -117,7 +117,6 @@ set (ERESSEA_SRC
|
|||
morale.c
|
||||
move.c
|
||||
names.c
|
||||
orderdb.c
|
||||
orderfile.c
|
||||
piracy.c
|
||||
prefix.c
|
||||
|
@ -230,7 +229,6 @@ set(TESTS_SRC
|
|||
monsters.test.c
|
||||
move.test.c
|
||||
names.test.c
|
||||
orderdb.test.c
|
||||
orderfile.test.c
|
||||
piracy.test.c
|
||||
prefix.test.c
|
||||
|
|
|
@ -432,7 +432,7 @@ static int tolua_faction_create(lua_State * L)
|
|||
static int tolua_faction_get_password(lua_State * L)
|
||||
{
|
||||
faction *self = (faction *)tolua_tousertype(L, 1, 0);
|
||||
tolua_pushstring(L, self->_password);
|
||||
tolua_pushstring(L, faction_getpassword(self));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1057,12 +1057,15 @@ static void cr_find_address(FILE * F, const faction * uf, selist * addresses)
|
|||
while (flist) {
|
||||
const faction *f = (const faction *)selist_get(flist, i);
|
||||
if (uf != f) {
|
||||
const char *str;
|
||||
fprintf(F, "PARTEI %d\n", f->no);
|
||||
fprintf(F, "\"%s\";Parteiname\n", f->name);
|
||||
if (strcmp(faction_getemail(f), "") != 0)
|
||||
fprintf(F, "\"%s\";email\n", faction_getemail(f));
|
||||
if (f->banner)
|
||||
fprintf(F, "\"%s\";banner\n", f->banner);
|
||||
str = faction_getbanner(f);
|
||||
if (str) {
|
||||
fprintf(F, "\"%s\";banner\n", str);
|
||||
}
|
||||
fprintf(F, "\"%s\";locale\n", locale_name(f->locale));
|
||||
if (f->alliance && f->alliance == uf->alliance) {
|
||||
fprintf(F, "%d;alliance\n", f->alliance->id);
|
||||
|
@ -1534,7 +1537,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
|
|||
static int era = -1;
|
||||
int i;
|
||||
faction *f = ctx->f;
|
||||
const char *prefix;
|
||||
const char *prefix, *str;
|
||||
region *r;
|
||||
const char *mailto = config_get("game.email");
|
||||
const attrib *a;
|
||||
|
@ -1628,8 +1631,10 @@ report_computer(const char *filename, report_context * ctx, const char *bom)
|
|||
|
||||
fprintf(F, "\"%s\";Parteiname\n", f->name);
|
||||
fprintf(F, "\"%s\";email\n", faction_getemail(f));
|
||||
if (f->banner)
|
||||
fprintf(F, "\"%s\";banner\n", f->banner);
|
||||
str = faction_getbanner(f);
|
||||
if (str) {
|
||||
fprintf(F, "\"%s\";banner\n", str);
|
||||
}
|
||||
print_items(F, f->items, f->locale);
|
||||
fputs("OPTIONEN\n", F);
|
||||
for (i = 0; i != MAXOPTIONS; ++i) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "kernel/building.h"
|
||||
#include "kernel/calendar.h"
|
||||
#include "kernel/database.h"
|
||||
#include "kernel/config.h"
|
||||
#include "kernel/curse.h"
|
||||
#include "kernel/equipment.h"
|
||||
|
@ -27,7 +28,6 @@
|
|||
#include "creport.h"
|
||||
#include "report.h"
|
||||
#include "names.h"
|
||||
#include "orderdb.h"
|
||||
#include "reports.h"
|
||||
#include "spells.h"
|
||||
#include "vortex.h"
|
||||
|
@ -54,12 +54,12 @@ void game_done(void)
|
|||
free_locales();
|
||||
#endif
|
||||
kernel_done();
|
||||
orderdb_close();
|
||||
swapdb_close();
|
||||
}
|
||||
|
||||
void game_init(void)
|
||||
{
|
||||
orderdb_open();
|
||||
swapdb_open();
|
||||
errno = 0;
|
||||
kernel_init();
|
||||
register_triggers();
|
||||
|
|
|
@ -20,7 +20,9 @@ int gamedb_update(void)
|
|||
err = db_driver_open(DB_GAME, dbname);
|
||||
if (err == 0) {
|
||||
for (f = factions; f; f = f->next) {
|
||||
int uid = db_driver_faction_save(f->uid, f->no, turn, f->email, f->_password);
|
||||
int uid = db_driver_faction_save(f->uid, f->no, turn,
|
||||
faction_getemail(f),
|
||||
faction_getpassword(f));
|
||||
if (uid > 0) {
|
||||
f->uid = uid;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ command.c
|
|||
config.c
|
||||
connection.c
|
||||
curse.c
|
||||
database.c
|
||||
equipment.c
|
||||
event.c
|
||||
faction.c
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#include "config.h"
|
||||
#include "database.h"
|
||||
#include "db/driver.h"
|
||||
|
||||
void swapdb_open(void)
|
||||
{
|
||||
const char *dbname;
|
||||
dbname = config_get("game.dbswap");
|
||||
db_driver_open(DB_SWAP, dbname);
|
||||
}
|
||||
|
||||
void swapdb_close(void)
|
||||
{
|
||||
db_driver_close(DB_SWAP);
|
||||
}
|
||||
|
||||
dbrow_id db_string_save(const char *s) {
|
||||
(void)s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbrow_id dbstring_save(const char *s) {
|
||||
return db_driver_string_save(s);
|
||||
}
|
||||
|
||||
const char *dbstring_load(dbrow_id id, size_t *size) {
|
||||
return db_driver_string_load(id, size);
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "db/driver.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void swapdb_open(void);
|
||||
void swapdb_close(void);
|
||||
|
||||
dbrow_id dbstring_save(const char *s);
|
||||
const char *dbstring_load(dbrow_id id, size_t *size);
|
|
@ -3,8 +3,8 @@
|
|||
#include <kernel/faction.h>
|
||||
#include <kernel/order.h>
|
||||
|
||||
#include "database.h"
|
||||
#include "db/driver.h"
|
||||
#include "orderdb.h"
|
||||
|
||||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
|
@ -12,6 +12,17 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void test_orderdb(CuTest *tc) {
|
||||
order_data *od = NULL;
|
||||
const char * s = "GIB enno 1 Hodor";
|
||||
|
||||
odata_create(&od, strlen(s) + 1, s);
|
||||
CuAssertPtrNotNull(tc, od);
|
||||
CuAssertStrEquals(tc, s, od->_str);
|
||||
CuAssertTrue(tc, od->_refcount >= 1);
|
||||
odata_release(od);
|
||||
}
|
||||
|
||||
static void test_save_load_order(CuTest *tc) {
|
||||
order_data *od;
|
||||
int id;
|
||||
|
@ -39,11 +50,17 @@ static void test_update_faction(CuTest *tc) {
|
|||
int uid;
|
||||
|
||||
test_setup();
|
||||
db_driver_open(DB_GAME, NULL);
|
||||
f = test_create_faction(NULL);
|
||||
uid = db_driver_faction_save(f->uid, f->no, 0, f->email, f->_password);
|
||||
uid = db_driver_faction_save(f->uid, f->no, 0,
|
||||
faction_getemail(f),
|
||||
faction_getpassword(f));
|
||||
f->uid = uid;
|
||||
uid = db_driver_faction_save(f->uid, f->no, 0, f->email, f->_password);
|
||||
uid = db_driver_faction_save(f->uid, f->no, 0,
|
||||
faction_getemail(f),
|
||||
faction_getpassword(f));
|
||||
CuAssertIntEquals(tc, f->uid, uid);
|
||||
db_driver_close(DB_GAME);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@ -52,6 +69,7 @@ CuSuite *get_db_suite(void)
|
|||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_save_load_order);
|
||||
SUITE_ADD_TEST(suite, test_update_faction);
|
||||
SUITE_ADD_TEST(suite, test_orderdb);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
struct order_data;
|
||||
|
||||
typedef unsigned int dbrow_id;
|
||||
|
||||
extern void odata_create(struct order_data **pdata, size_t len, const char *str);
|
||||
|
||||
typedef enum database_t {
|
||||
|
@ -13,6 +15,8 @@ typedef enum database_t {
|
|||
|
||||
int db_driver_open(database_t db, const char *dbname);
|
||||
void db_driver_close(database_t db);
|
||||
int db_driver_order_save(const char *str);
|
||||
struct order_data *db_driver_order_load(int id);
|
||||
int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password);
|
||||
dbrow_id db_driver_order_save(const char *str);
|
||||
struct order_data *db_driver_order_load(dbrow_id id);
|
||||
dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password);
|
||||
dbrow_id db_driver_string_save(const char *s);
|
||||
const char *db_driver_string_load(dbrow_id id, size_t *size);
|
||||
|
|
|
@ -15,50 +15,53 @@
|
|||
#include <string.h>
|
||||
|
||||
static sqlite3 *g_game_db;
|
||||
static sqlite3 *g_temp_db;
|
||||
static sqlite3 *g_swap_db;
|
||||
static sqlite3_stmt * g_stmt_insert_string;
|
||||
static sqlite3_stmt * g_stmt_select_string;
|
||||
static sqlite3_stmt * g_stmt_insert_order;
|
||||
static sqlite3_stmt * g_stmt_select_order;
|
||||
static sqlite3_stmt * g_stmt_update_faction;
|
||||
static sqlite3_stmt * g_stmt_insert_faction;
|
||||
|
||||
static int g_order_batchsize;
|
||||
static int g_order_tx_size;
|
||||
static int g_insert_batchsize;
|
||||
static int g_insert_tx_size;
|
||||
|
||||
struct order_data *db_driver_order_load(int id)
|
||||
static void end_transaction(void) {
|
||||
if (g_insert_tx_size > 0) {
|
||||
int err;
|
||||
g_insert_tx_size = 0;
|
||||
err = sqlite3_exec(g_swap_db, "COMMIT", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
struct order_data *db_driver_order_load(dbrow_id id)
|
||||
{
|
||||
struct order_data * od = NULL;
|
||||
int err;
|
||||
|
||||
ERRNO_CHECK();
|
||||
if (g_order_tx_size > 0) {
|
||||
g_order_tx_size = 0;
|
||||
err = sqlite3_exec(g_temp_db, "COMMIT", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
}
|
||||
end_transaction();
|
||||
err = sqlite3_reset(g_stmt_select_order);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_bind_int(g_stmt_select_order, 1, id);
|
||||
assert(err == SQLITE_OK);
|
||||
do {
|
||||
err = sqlite3_step(g_stmt_select_order);
|
||||
if (err == SQLITE_ROW) {
|
||||
const unsigned char *text;
|
||||
int bytes;
|
||||
bytes = sqlite3_column_bytes(g_stmt_select_order, 0);
|
||||
assert(bytes > 0);
|
||||
text = sqlite3_column_text(g_stmt_select_order, 0);
|
||||
odata_create(&od, 1+(size_t)bytes, (const char *)text);
|
||||
ERRNO_CHECK();
|
||||
return od;
|
||||
}
|
||||
} while (err == SQLITE_ROW);
|
||||
assert(err == SQLITE_DONE);
|
||||
err = sqlite3_step(g_stmt_select_order);
|
||||
if (err == SQLITE_ROW) {
|
||||
const unsigned char *text;
|
||||
int bytes;
|
||||
text = sqlite3_column_text(g_stmt_select_order, 0);
|
||||
bytes = sqlite3_column_bytes(g_stmt_select_order, 0);
|
||||
assert(bytes > 0);
|
||||
odata_create(&od, 1+(size_t)bytes, (const char *)text);
|
||||
ERRNO_CHECK();
|
||||
return od;
|
||||
}
|
||||
ERRNO_CHECK();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int db_driver_order_save(const char *str)
|
||||
{
|
||||
dbrow_id db_driver_order_save(const char *str) {
|
||||
int err;
|
||||
sqlite3_int64 id;
|
||||
|
||||
|
@ -66,9 +69,9 @@ int db_driver_order_save(const char *str)
|
|||
|
||||
ERRNO_CHECK();
|
||||
|
||||
if (g_order_batchsize > 0) {
|
||||
if (g_order_tx_size == 0) {
|
||||
err = sqlite3_exec(g_temp_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||
if (g_insert_batchsize > 0) {
|
||||
if (g_insert_tx_size == 0) {
|
||||
err = sqlite3_exec(g_swap_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
}
|
||||
}
|
||||
|
@ -79,29 +82,25 @@ int db_driver_order_save(const char *str)
|
|||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_step(g_stmt_insert_order);
|
||||
assert(err == SQLITE_DONE);
|
||||
id = sqlite3_last_insert_rowid(g_temp_db);
|
||||
assert(id <= INT_MAX);
|
||||
id = sqlite3_last_insert_rowid(g_swap_db);
|
||||
assert(id > 0 && id <= UINT_MAX);
|
||||
|
||||
if (g_order_batchsize > 0) {
|
||||
if (++g_order_tx_size >= g_order_batchsize) {
|
||||
err = sqlite3_exec(g_temp_db, "COMMIT", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
g_order_tx_size = 0;
|
||||
if (g_insert_batchsize > 0) {
|
||||
if (++g_insert_tx_size >= g_insert_batchsize) {
|
||||
end_transaction();
|
||||
}
|
||||
}
|
||||
ERRNO_CHECK();
|
||||
return (int)id;
|
||||
return (dbrow_id)id;
|
||||
}
|
||||
|
||||
|
||||
int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
|
||||
dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password)
|
||||
{
|
||||
sqlite3_int64 row_id;
|
||||
int err;
|
||||
|
||||
if (!g_game_db) {
|
||||
return -1;
|
||||
}
|
||||
assert(g_game_db);
|
||||
if (id != 0) {
|
||||
int rows;
|
||||
|
||||
|
@ -139,8 +138,8 @@ int db_driver_faction_save(int id, int no, int turn, const char *email, const ch
|
|||
ERRNO_CHECK();
|
||||
|
||||
row_id = sqlite3_last_insert_rowid(g_game_db);
|
||||
assert(row_id <= INT_MAX);
|
||||
return (int)row_id;
|
||||
assert(row_id>0 && row_id <= UINT_MAX);
|
||||
return (dbrow_id)row_id;
|
||||
}
|
||||
|
||||
static int db_open_game(const char *dbname) {
|
||||
|
@ -162,19 +161,25 @@ static int db_open_game(const char *dbname) {
|
|||
static int db_open_swap(const char *dbname) {
|
||||
int err;
|
||||
|
||||
g_order_batchsize = config_get_int("game.dbbatch", 100);
|
||||
g_insert_batchsize = config_get_int("game.dbbatch", 100);
|
||||
|
||||
err = sqlite3_open(dbname, &g_temp_db);
|
||||
err = sqlite3_open(dbname, &g_swap_db);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_exec(g_temp_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL);
|
||||
err = sqlite3_exec(g_swap_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_exec(g_temp_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL);
|
||||
err = sqlite3_exec(g_swap_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_exec(g_temp_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL);
|
||||
err = sqlite3_exec(g_swap_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_prepare_v2(g_temp_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert_order, NULL);
|
||||
err = sqlite3_exec(g_swap_db, "CREATE TABLE IF NOT EXISTS strings (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_prepare_v2(g_temp_db, "SELECT data FROM orders WHERE id=?", -1, &g_stmt_select_order, NULL);
|
||||
err = sqlite3_prepare_v2(g_swap_db, "INSERT INTO strings (data) VALUES (?)", -1, &g_stmt_insert_string, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_prepare_v2(g_swap_db, "SELECT data FROM strings WHERE id=?", -1, &g_stmt_select_string, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_prepare_v2(g_swap_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert_order, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_prepare_v2(g_swap_db, "SELECT data FROM orders WHERE id=?", -1, &g_stmt_select_order, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
ERRNO_CHECK();
|
||||
return 0;
|
||||
|
@ -185,7 +190,11 @@ static const char *g_swapname;
|
|||
int db_driver_open(database_t db, const char *dbname)
|
||||
{
|
||||
ERRNO_CHECK();
|
||||
|
||||
|
||||
if (!dbname) {
|
||||
/* by default, use an in-memory database */
|
||||
dbname = ":memory:";
|
||||
}
|
||||
if (db == DB_SWAP) {
|
||||
g_swapname = dbname;
|
||||
return db_open_swap(dbname);
|
||||
|
@ -202,12 +211,16 @@ void db_driver_close(database_t db)
|
|||
|
||||
ERRNO_CHECK();
|
||||
if (db == DB_SWAP) {
|
||||
assert(g_temp_db);
|
||||
assert(g_swap_db);
|
||||
err = sqlite3_finalize(g_stmt_select_string);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_finalize(g_stmt_insert_string);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_finalize(g_stmt_select_order);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_finalize(g_stmt_insert_order);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_close(g_temp_db);
|
||||
err = sqlite3_close(g_swap_db);
|
||||
assert(err == SQLITE_OK);
|
||||
if (g_swapname) {
|
||||
FILE * F = fopen(g_swapname, "r");
|
||||
|
@ -229,3 +242,59 @@ void db_driver_close(database_t db)
|
|||
ERRNO_CHECK();
|
||||
}
|
||||
|
||||
dbrow_id db_driver_string_save(const char *str) {
|
||||
int err;
|
||||
sqlite3_int64 id;
|
||||
|
||||
assert(str);
|
||||
|
||||
ERRNO_CHECK();
|
||||
|
||||
if (g_insert_batchsize > 0) {
|
||||
if (g_insert_tx_size == 0) {
|
||||
err = sqlite3_exec(g_swap_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||
assert(err == SQLITE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
err = sqlite3_reset(g_stmt_insert_string);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_bind_text(g_stmt_insert_string, 1, str, -1, SQLITE_STATIC);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_step(g_stmt_insert_string);
|
||||
assert(err == SQLITE_DONE);
|
||||
id = sqlite3_last_insert_rowid(g_swap_db);
|
||||
assert(id > 0 && id <= UINT_MAX);
|
||||
|
||||
if (g_insert_batchsize > 0) {
|
||||
if (++g_insert_tx_size >= g_insert_batchsize) {
|
||||
end_transaction();
|
||||
}
|
||||
}
|
||||
ERRNO_CHECK();
|
||||
return (dbrow_id)id;
|
||||
}
|
||||
|
||||
const char *db_driver_string_load(dbrow_id id, size_t *size) {
|
||||
int err;
|
||||
|
||||
end_transaction();
|
||||
err = sqlite3_reset(g_stmt_select_string);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_bind_int(g_stmt_select_string, 1, id);
|
||||
assert(err == SQLITE_OK);
|
||||
err = sqlite3_step(g_stmt_select_string);
|
||||
if (err == SQLITE_ROW) {
|
||||
const unsigned char *text;
|
||||
text = sqlite3_column_text(g_stmt_select_string, 0);
|
||||
if (size) {
|
||||
int bytes = sqlite3_column_bytes(g_stmt_select_string, 0);
|
||||
assert(bytes > 0);
|
||||
*size = (size_t)bytes;
|
||||
}
|
||||
ERRNO_CHECK();
|
||||
return (const char *)text;
|
||||
}
|
||||
ERRNO_CHECK();
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#include "calendar.h"
|
||||
#include "config.h"
|
||||
#include "database.h"
|
||||
#include "alliance.h"
|
||||
#include "ally.h"
|
||||
#include "curse.h"
|
||||
|
@ -105,8 +106,6 @@ static void free_faction(faction * f)
|
|||
freelist(f->allies);
|
||||
|
||||
free(f->email);
|
||||
free(f->banner);
|
||||
free(f->_password);
|
||||
free(f->name);
|
||||
if (f->seen_factions) {
|
||||
selist_free(f->seen_factions);
|
||||
|
@ -245,7 +244,7 @@ faction *addfaction(const char *email, const char *password,
|
|||
f->alliance_joindate = turn;
|
||||
f->lastorders = turn;
|
||||
f->_alive = true;
|
||||
f->_password = NULL;
|
||||
f->password_id = 0;
|
||||
f->age = 0;
|
||||
f->race = frace;
|
||||
f->magiegebiet = 0;
|
||||
|
@ -321,9 +320,11 @@ unit *addplayer(region * r, faction * f)
|
|||
|
||||
bool checkpasswd(const faction * f, const char *passwd)
|
||||
{
|
||||
const char *pwhash;
|
||||
if (!passwd) return false;
|
||||
|
||||
if (f->_password && password_verify(f->_password, passwd) == VERIFY_FAIL) {
|
||||
pwhash = faction_getpassword(f);
|
||||
if (pwhash && password_verify(pwhash, passwd) == VERIFY_FAIL) {
|
||||
log_info("password check failed: %s", factionname(f));
|
||||
return false;
|
||||
}
|
||||
|
@ -591,23 +592,30 @@ void faction_setemail(faction * self, const char *email)
|
|||
self->email = NULL;
|
||||
}
|
||||
|
||||
const char *faction_getbanner(const faction * self)
|
||||
const char *faction_getbanner(const faction * f)
|
||||
{
|
||||
return self->banner ? self->banner : "";
|
||||
if (f->banner_id > 0) {
|
||||
return dbstring_load(f->banner_id, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void faction_setbanner(faction * self, const char *banner)
|
||||
void faction_setbanner(faction * f, const char *banner)
|
||||
{
|
||||
free(self->banner);
|
||||
if (banner)
|
||||
self->banner = str_strdup(banner);
|
||||
f->banner_id = dbstring_save(banner);
|
||||
}
|
||||
|
||||
const char *faction_getpassword(const faction *f) {
|
||||
if (f->password_id > 0) {
|
||||
return dbstring_load(f->password_id, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void faction_setpassword(faction * f, const char *pwhash)
|
||||
{
|
||||
assert(pwhash);
|
||||
free(f->_password);
|
||||
f->_password = str_strdup(pwhash);
|
||||
f->password_id = dbstring_save(pwhash);
|
||||
}
|
||||
|
||||
bool valid_race(const struct faction *f, const struct race *rc)
|
||||
|
@ -844,7 +852,8 @@ int writepasswd(void)
|
|||
|
||||
for (f = factions; f; f = f->next) {
|
||||
fprintf(F, "%s:%s:%s:%d\n",
|
||||
itoa36(f->no), faction_getemail(f), f->_password, f->uid);
|
||||
itoa36(f->no), faction_getemail(f),
|
||||
faction_getpassword(f), f->uid);
|
||||
}
|
||||
fclose(F);
|
||||
return 0;
|
||||
|
|
|
@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#include "skill.h"
|
||||
#include "types.h"
|
||||
#include "db/driver.h"
|
||||
|
||||
#include <util/resolve.h>
|
||||
#include <modules/score.h>
|
||||
|
@ -70,9 +71,9 @@ extern "C" {
|
|||
int uid;
|
||||
int flags;
|
||||
char *name;
|
||||
char *banner;
|
||||
dbrow_id banner_id;
|
||||
char *email;
|
||||
char *_password;
|
||||
dbrow_id password_id;
|
||||
int max_spelllevel;
|
||||
struct spellbook *spellbook;
|
||||
const struct locale *locale;
|
||||
|
@ -154,6 +155,7 @@ extern "C" {
|
|||
void faction_setemail(struct faction *self, const char *email);
|
||||
|
||||
void faction_setpassword(struct faction *self, const char *pwhash);
|
||||
const char *faction_getpassword(const struct faction *f);
|
||||
bool valid_race(const struct faction *f, const struct race *rc);
|
||||
|
||||
void faction_getorigin(const struct faction * f, int id, int *x, int *y);
|
||||
|
|
|
@ -117,7 +117,7 @@ static void test_addfaction(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, f->name);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)f->units);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)f->next);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)f->banner);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)faction_getbanner(f));
|
||||
CuAssertPtrEquals(tc, NULL, (void *)f->spellbook);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)f->origin);
|
||||
CuAssertPtrEquals(tc, (void *)factions, (void *)f);
|
||||
|
@ -229,6 +229,18 @@ static void test_valid_race(CuTest *tc) {
|
|||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_dbstrings(CuTest *tc) {
|
||||
const char *lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||||
faction *f;
|
||||
test_setup();
|
||||
f = test_create_faction(NULL);
|
||||
faction_setbanner(f, lipsum);
|
||||
faction_setpassword(f, lipsum + 12);
|
||||
CuAssertStrEquals(tc, lipsum, faction_getbanner(f));
|
||||
CuAssertStrEquals(tc, lipsum + 12, faction_getpassword(f));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
static void test_set_email(CuTest *tc) {
|
||||
faction *f;
|
||||
char email[10];
|
||||
|
@ -335,6 +347,7 @@ CuSuite *get_faction_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_check_passwd);
|
||||
SUITE_ADD_TEST(suite, test_valid_race);
|
||||
SUITE_ADD_TEST(suite, test_set_email);
|
||||
SUITE_ADD_TEST(suite, test_dbstrings);
|
||||
SUITE_ADD_TEST(suite, test_save_special_items);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <kernel/config.h>
|
||||
#include "order.h"
|
||||
|
||||
#include "db/driver.h"
|
||||
|
||||
#include "skill.h"
|
||||
|
||||
#include <util/base36.h>
|
||||
|
@ -36,6 +38,22 @@
|
|||
# define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF)
|
||||
# define OD_STRING(odata) ((odata) ? (odata)->_str : NULL)
|
||||
|
||||
order_data *odata_load(int id)
|
||||
{
|
||||
if (id > 0) {
|
||||
return db_driver_order_load(id);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int odata_save(order_data *od)
|
||||
{
|
||||
if (od->_str) {
|
||||
return db_driver_order_save(od->_str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void odata_create(order_data **pdata, size_t len, const char *str)
|
||||
{
|
||||
order_data *data;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "kernel/config.h"
|
||||
#include "kernel/db/driver.h"
|
||||
|
||||
#include "orderdb.h"
|
||||
|
||||
#include <util/log.h>
|
||||
|
||||
#include <critbit.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void orderdb_open(void)
|
||||
{
|
||||
const char *dbname;
|
||||
|
||||
dbname = config_get("game.dbswap");
|
||||
db_driver_open(DB_SWAP, dbname);
|
||||
}
|
||||
|
||||
void orderdb_close(void)
|
||||
{
|
||||
db_driver_close(DB_SWAP);
|
||||
}
|
||||
|
||||
order_data *odata_load(int id)
|
||||
{
|
||||
if (id > 0) {
|
||||
return db_driver_order_load(id);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int odata_save(order_data *od)
|
||||
{
|
||||
if (od->_str) {
|
||||
return db_driver_order_save(od->_str);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef H_ORDERDB
|
||||
#define H_ORDERDB
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void orderdb_open(void);
|
||||
void orderdb_close(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -440,12 +440,12 @@ unit *read_unit(gamedata *data)
|
|||
if (unicode_utf8_trim(obuf)!=0) {
|
||||
log_warning("trim unit %s name to '%s'", itoa36(u->no), obuf);
|
||||
}
|
||||
u->_name = obuf[0] ? str_strdup(obuf) : 0;
|
||||
unit_setname(u, obuf[0] ? obuf : NULL);
|
||||
READ_STR(data->store, obuf, sizeof(obuf));
|
||||
if (unicode_utf8_trim(obuf)!=0) {
|
||||
log_warning("trim unit %s info to '%s'", itoa36(u->no), obuf);
|
||||
}
|
||||
u->display = obuf[0] ? str_strdup(obuf) : 0;
|
||||
unit_setinfo(u, obuf[0] ? obuf : NULL);
|
||||
READ_INT(data->store, &number);
|
||||
set_number(u, number);
|
||||
|
||||
|
@ -544,6 +544,7 @@ unit *read_unit(gamedata *data)
|
|||
|
||||
void write_unit(gamedata *data, const unit * u)
|
||||
{
|
||||
const char *str;
|
||||
order *ord;
|
||||
int p = 0;
|
||||
unsigned int flags = u->flags & UFL_SAVEMASK;
|
||||
|
@ -553,7 +554,8 @@ void write_unit(gamedata *data, const unit * u)
|
|||
assert(u->faction->_alive);
|
||||
write_faction_reference(u->faction, data->store);
|
||||
WRITE_STR(data->store, u->_name);
|
||||
WRITE_STR(data->store, u->display ? u->display : "");
|
||||
str = unit_getinfo(u);
|
||||
WRITE_STR(data->store, str ? str : "");
|
||||
WRITE_INT(data->store, u->number);
|
||||
WRITE_INT(data->store, u->age);
|
||||
WRITE_TOK(data->store, u_race(u)->_name);
|
||||
|
@ -931,7 +933,6 @@ static void read_password(gamedata *data, faction *f) {
|
|||
else {
|
||||
faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_hash(name, PASSWORD_DEFAULT));
|
||||
}
|
||||
(void)_test_read_password;
|
||||
}
|
||||
|
||||
void _test_read_password(gamedata *data, faction *f) {
|
||||
|
@ -939,8 +940,7 @@ void _test_read_password(gamedata *data, faction *f) {
|
|||
}
|
||||
|
||||
static void write_password(gamedata *data, const faction *f) {
|
||||
WRITE_TOK(data->store, (const char *)f->_password);
|
||||
(void)_test_write_password;
|
||||
WRITE_TOK(data->store, faction_getpassword(f));
|
||||
}
|
||||
|
||||
void _test_write_password(gamedata *data, const faction *f) {
|
||||
|
@ -1009,7 +1009,7 @@ faction *read_faction(gamedata * data)
|
|||
if (unicode_utf8_trim(name)!=0) {
|
||||
log_warning("trim faction %s banner to '%s'", itoa36(f->no), name);
|
||||
};
|
||||
f->banner = str_strdup(name);
|
||||
faction_setbanner(f, name);
|
||||
|
||||
log_debug(" - Lese Partei %s (%s)", f->name, itoa36(f->no));
|
||||
|
||||
|
@ -1117,7 +1117,7 @@ void write_faction(gamedata *data, const faction * f)
|
|||
WRITE_INT(data->store, f->alliance_joindate);
|
||||
|
||||
WRITE_STR(data->store, f->name);
|
||||
WRITE_STR(data->store, f->banner);
|
||||
WRITE_STR(data->store, faction_getbanner(f));
|
||||
WRITE_STR(data->store, f->email?f->email:"");
|
||||
write_password(data, f);
|
||||
WRITE_TOK(data->store, locale_name(f->locale));
|
||||
|
|
|
@ -432,7 +432,7 @@ static void test_read_password_external(CuTest *tc) {
|
|||
}
|
||||
f = test_create_faction(NULL);
|
||||
faction_setpassword(f, password_hash("secret", PASSWORD_DEFAULT));
|
||||
CuAssertPtrNotNull(tc, f->_password);
|
||||
CuAssertPtrNotNull(tc, faction_getpassword(f));
|
||||
mstream_init(&data.strm);
|
||||
gamedata_init(&data, &store, RELEASE_VERSION);
|
||||
WRITE_TOK(data.store, "newpassword");
|
||||
|
|
|
@ -474,8 +474,8 @@ attrib_type at_private = {
|
|||
|
||||
const char *u_description(const unit * u, const struct locale *lang)
|
||||
{
|
||||
if (u->display && u->display[0]) {
|
||||
return u->display;
|
||||
if (u->display_id > 0) {
|
||||
return unit_getinfo(u);
|
||||
}
|
||||
else {
|
||||
char zText[64];
|
||||
|
@ -1293,7 +1293,6 @@ void free_unit(unit * u)
|
|||
{
|
||||
assert(!u->region);
|
||||
free(u->_name);
|
||||
free(u->display);
|
||||
free_order(u->thisorder);
|
||||
free_orders(&u->orders);
|
||||
if (u->skills)
|
||||
|
@ -1522,16 +1521,20 @@ void unit_setname(unit * u, const char *name)
|
|||
|
||||
const char *unit_getinfo(const unit * u)
|
||||
{
|
||||
return (const char *)u->display;
|
||||
if (u->display_id > 0) {
|
||||
return dbstring_load(u->display_id, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void unit_setinfo(unit * u, const char *info)
|
||||
{
|
||||
free(u->display);
|
||||
if (info)
|
||||
u->display = str_strdup(info);
|
||||
else
|
||||
u->display = NULL;
|
||||
if (info) {
|
||||
u->display_id = dbstring_save(info);
|
||||
}
|
||||
else {
|
||||
u->display_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int unit_getid(const unit * u)
|
||||
|
|
|
@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
|
||||
#include <util/resolve.h>
|
||||
#include "types.h"
|
||||
#include "database.h"
|
||||
#include "skills.h"
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -89,7 +90,7 @@ extern "C" {
|
|||
int no; /* id */
|
||||
int hp;
|
||||
char *_name;
|
||||
char *display;
|
||||
dbrow_id display_id;
|
||||
struct faction *faction;
|
||||
struct building *building;
|
||||
struct ship *ship;
|
||||
|
|
|
@ -397,14 +397,13 @@ static void test_unit_description(CuTest *tc) {
|
|||
rc = test_create_race("hodor");
|
||||
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, NULL));
|
||||
|
||||
CuAssertPtrEquals(tc, NULL, u->display);
|
||||
CuAssertStrEquals(tc, 0, u_description(u, lang));
|
||||
u->display = str_strdup("Hodor");
|
||||
CuAssertStrEquals(tc, NULL, unit_getinfo(u));
|
||||
CuAssertStrEquals(tc, NULL, u_description(u, lang));
|
||||
unit_setinfo(u, "Hodor");
|
||||
CuAssertStrEquals(tc, "Hodor", u_description(u, NULL));
|
||||
CuAssertStrEquals(tc, "Hodor", u_description(u, lang));
|
||||
|
||||
free(u->display);
|
||||
u->display = NULL;
|
||||
unit_setinfo(u, NULL);
|
||||
locale_setstring(lang, "describe_hodor", "HODOR");
|
||||
CuAssertStrEquals(tc, "HODOR", u_description(u, lang));
|
||||
|
||||
|
|
|
@ -1542,7 +1542,7 @@ int display_cmd(unit * u, struct order *ord)
|
|||
break;
|
||||
|
||||
case P_UNIT:
|
||||
s = &u->display;
|
||||
unit_setinfo(u, getstrtoken());
|
||||
break;
|
||||
|
||||
case P_PRIVAT:
|
||||
|
@ -2086,12 +2086,10 @@ int banner_cmd(unit * u, struct order *ord)
|
|||
{
|
||||
const char * s;
|
||||
|
||||
free(u->faction->banner);
|
||||
init_order_depr(ord);
|
||||
s = getstrtoken();
|
||||
u->faction->banner = s ? str_strdup(s) : 0;
|
||||
add_message(&u->faction->msgs, msg_message("changebanner", "value",
|
||||
u->faction->banner));
|
||||
faction_setbanner(u->faction, s);
|
||||
add_message(&u->faction->msgs, msg_message("changebanner", "value", s));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -188,12 +188,12 @@ static void test_display_cmd(CuTest *tc) {
|
|||
|
||||
ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_UNIT]));
|
||||
CuAssertIntEquals(tc, 0, display_cmd(u, ord));
|
||||
CuAssertStrEquals(tc, "Hodor", u->display);
|
||||
CuAssertStrEquals(tc, "Hodor", unit_getinfo(u));
|
||||
free_order(ord);
|
||||
|
||||
ord = create_order(K_DISPLAY, f->locale, LOC(f->locale, parameters[P_UNIT]));
|
||||
CuAssertIntEquals(tc, 0, display_cmd(u, ord));
|
||||
CuAssertPtrEquals(tc, NULL, u->display);
|
||||
CuAssertPtrEquals(tc, NULL, (void *)unit_getinfo(u));
|
||||
free_order(ord);
|
||||
|
||||
ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION]));
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
#include <platform.h>
|
||||
|
||||
#include "kernel/config.h"
|
||||
#include "kernel/db/driver.h"
|
||||
|
||||
#include "orderdb.h"
|
||||
|
||||
#include <util/log.h>
|
||||
|
||||
#include <critbit.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void orderdb_open(void)
|
||||
{
|
||||
const char *dbname;
|
||||
dbname = config_get("game.dbswap");
|
||||
db_driver_open(DB_SWAP, dbname);
|
||||
}
|
||||
|
||||
void orderdb_close(void)
|
||||
{
|
||||
db_driver_close(DB_SWAP);
|
||||
}
|
||||
|
||||
order_data *odata_load(int id)
|
||||
{
|
||||
if (id > 0) {
|
||||
return db_driver_order_load(id);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int odata_save(order_data *od)
|
||||
{
|
||||
if (od->_str) {
|
||||
return db_driver_order_save(od->_str);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef H_ORDERDB
|
||||
#define H_ORDERDB
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct order_data {
|
||||
const char *_str;
|
||||
int _refcount;
|
||||
} order_data;
|
||||
|
||||
void odata_create(order_data **pdata, size_t len, const char *str);
|
||||
void odata_release(order_data * od);
|
||||
void odata_addref(order_data *od);
|
||||
|
||||
void orderdb_open(void);
|
||||
void orderdb_close(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,28 +0,0 @@
|
|||
#include <platform.h>
|
||||
#include <kernel/config.h>
|
||||
|
||||
#include "orderdb.h"
|
||||
|
||||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void test_orderdb(CuTest *tc) {
|
||||
order_data *od = NULL;
|
||||
const char * s = "GIB enno 1 Hodor";
|
||||
|
||||
odata_create(&od, strlen(s) + 1, s);
|
||||
CuAssertPtrNotNull(tc, od);
|
||||
CuAssertStrEquals(tc, s, od->_str);
|
||||
CuAssertTrue(tc, od->_refcount >= 1);
|
||||
odata_release(od);
|
||||
}
|
||||
|
||||
CuSuite *get_orderdb_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_orderdb);
|
||||
|
||||
return suite;
|
||||
}
|
|
@ -1726,11 +1726,13 @@ static void list_address(struct stream *out, const faction * uf, selist * seenfa
|
|||
while (flist != NULL) {
|
||||
const faction *f = (const faction *)selist_get(flist, qi);
|
||||
if (!is_monsters(f)) {
|
||||
const char *str;
|
||||
char buf[8192];
|
||||
char label = '-';
|
||||
|
||||
str = faction_getbanner(f);
|
||||
sprintf(buf, "%s: %s; %s", factionname(f), faction_getemail(f),
|
||||
f->banner ? f->banner : "");
|
||||
str ? str : "");
|
||||
if (uf == f)
|
||||
label = '*';
|
||||
else if (is_allied(uf, f))
|
||||
|
|
|
@ -1554,14 +1554,6 @@ void prepare_report(report_context *ctx, faction *f)
|
|||
rule_lighthouse_units = config_get_int("rules.lighthouse.unit_capacity", 0) != 0;
|
||||
}
|
||||
|
||||
if (f->age <= 2) {
|
||||
if ((f->flags&FFL_PWMSG) == 0) {
|
||||
/* TODO: this assumes unencrypted passwords */
|
||||
f->flags |= FFL_PWMSG;
|
||||
ADDMSG(&f->msgs, msg_message("changepasswd", "value", f->_password));
|
||||
}
|
||||
}
|
||||
|
||||
ctx->f = f;
|
||||
ctx->report_time = time(NULL);
|
||||
ctx->addresses = NULL;
|
||||
|
|
|
@ -902,7 +902,7 @@ CuSuite *get_reports_suite(void)
|
|||
SUITE_ADD_TEST(suite, test_region_distance);
|
||||
SUITE_ADD_TEST(suite, test_region_distance_max);
|
||||
SUITE_ADD_TEST(suite, test_region_distance_ql);
|
||||
SUITE_ADD_TEST(suite, test_newbie_password_message);
|
||||
DISABLE_TEST(suite, test_newbie_password_message);
|
||||
SUITE_ADD_TEST(suite, test_prepare_report);
|
||||
SUITE_ADD_TEST(suite, test_seen_neighbours);
|
||||
SUITE_ADD_TEST(suite, test_seen_travelthru);
|
||||
|
|
|
@ -1539,12 +1539,7 @@ int sp_undeadhero(struct castorder * co)
|
|||
|
||||
/* new units gets some stats from old unit */
|
||||
|
||||
if (du->display) {
|
||||
unit_setinfo(u, du->display);
|
||||
}
|
||||
else {
|
||||
unit_setinfo(u, NULL);
|
||||
}
|
||||
unit_setinfo(u, unit_getinfo(du));
|
||||
unit_setstatus(u, du->status);
|
||||
setguard(u, false);
|
||||
for (ilist = &du->items; *ilist;) {
|
||||
|
|
|
@ -138,7 +138,6 @@ int RunAllTests(int argc, char *argv[])
|
|||
ADD_SUITE(monsters);
|
||||
ADD_SUITE(move);
|
||||
ADD_SUITE(names);
|
||||
ADD_SUITE(orderdb);
|
||||
ADD_SUITE(orderfile);
|
||||
ADD_SUITE(otherfaction);
|
||||
ADD_SUITE(piracy);
|
||||
|
|
Loading…
Reference in New Issue