account_sql.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/malloc.h"
  4. #include "../common/mmo.h"
  5. #include "../common/showmsg.h"
  6. #include "../common/sql.h"
  7. #include "../common/strlib.h"
  8. #include "../common/timer.h"
  9. #include "../config/core.h"
  10. #include "account.h"
  11. #include <stdlib.h>
  12. #include <string.h>
  13. /// global defines
  14. #define ACCOUNT_SQL_DB_VERSION 20110114
  15. /// internal structure
  16. typedef struct AccountDB_SQL
  17. {
  18. AccountDB vtable; // public interface
  19. Sql* accounts; // SQL accounts storage
  20. // global sql settings
  21. char global_db_hostname[32];
  22. uint16 global_db_port;
  23. char global_db_username[32];
  24. char global_db_password[32];
  25. char global_db_database[32];
  26. char global_codepage[32];
  27. // local sql settings
  28. char db_hostname[64]; // Doubled for long hostnames (bugreport:8003)
  29. uint16 db_port;
  30. char db_username[32];
  31. char db_password[32];
  32. char db_database[32];
  33. char codepage[32];
  34. // other settings
  35. bool case_sensitive;
  36. char account_db[32];
  37. char accreg_db[32];
  38. } AccountDB_SQL;
  39. /// internal structure
  40. typedef struct AccountDBIterator_SQL
  41. {
  42. AccountDBIterator vtable; // public interface
  43. AccountDB_SQL* db;
  44. int last_account_id;
  45. } AccountDBIterator_SQL;
  46. /// internal functions
  47. static bool account_db_sql_init(AccountDB* self);
  48. static void account_db_sql_destroy(AccountDB* self);
  49. static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen);
  50. static bool account_db_sql_set_property(AccountDB* self, const char* option, const char* value);
  51. static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc);
  52. static bool account_db_sql_remove(AccountDB* self, const int account_id);
  53. static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc);
  54. static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id);
  55. static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid);
  56. static AccountDBIterator* account_db_sql_iterator(AccountDB* self);
  57. static void account_db_sql_iter_destroy(AccountDBIterator* self);
  58. static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc);
  59. static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id);
  60. static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new);
  61. /// public constructor
  62. AccountDB* account_db_sql(void)
  63. {
  64. AccountDB_SQL* db = (AccountDB_SQL*)aCalloc(1, sizeof(AccountDB_SQL));
  65. // set up the vtable
  66. db->vtable.init = &account_db_sql_init;
  67. db->vtable.destroy = &account_db_sql_destroy;
  68. db->vtable.get_property = &account_db_sql_get_property;
  69. db->vtable.set_property = &account_db_sql_set_property;
  70. db->vtable.save = &account_db_sql_save;
  71. db->vtable.create = &account_db_sql_create;
  72. db->vtable.remove = &account_db_sql_remove;
  73. db->vtable.load_num = &account_db_sql_load_num;
  74. db->vtable.load_str = &account_db_sql_load_str;
  75. db->vtable.iterator = &account_db_sql_iterator;
  76. // initialize to default values
  77. db->accounts = NULL;
  78. // global sql settings
  79. safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname));
  80. db->global_db_port = 3306;
  81. safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username));
  82. safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password));
  83. safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database));
  84. safestrncpy(db->global_codepage, "", sizeof(db->global_codepage));
  85. // local sql settings
  86. safestrncpy(db->db_hostname, "", sizeof(db->db_hostname));
  87. db->db_port = 3306;
  88. safestrncpy(db->db_username, "", sizeof(db->db_username));
  89. safestrncpy(db->db_password, "", sizeof(db->db_password));
  90. safestrncpy(db->db_database, "", sizeof(db->db_database));
  91. safestrncpy(db->codepage, "", sizeof(db->codepage));
  92. // other settings
  93. db->case_sensitive = false;
  94. safestrncpy(db->account_db, "login", sizeof(db->account_db));
  95. safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db));
  96. return &db->vtable;
  97. }
  98. /* ------------------------------------------------------------------------- */
  99. /// establishes database connection
  100. static bool account_db_sql_init(AccountDB* self)
  101. {
  102. AccountDB_SQL* db = (AccountDB_SQL*)self;
  103. Sql* sql_handle;
  104. const char* username;
  105. const char* password;
  106. const char* hostname;
  107. uint16 port;
  108. const char* database;
  109. const char* codepage;
  110. db->accounts = Sql_Malloc();
  111. sql_handle = db->accounts;
  112. if( db->db_hostname[0] != '\0' )
  113. {// local settings
  114. username = db->db_username;
  115. password = db->db_password;
  116. hostname = db->db_hostname;
  117. port = db->db_port;
  118. database = db->db_database;
  119. codepage = db->codepage;
  120. }
  121. else
  122. {// global settings
  123. username = db->global_db_username;
  124. password = db->global_db_password;
  125. hostname = db->global_db_hostname;
  126. port = db->global_db_port;
  127. database = db->global_db_database;
  128. codepage = db->global_codepage;
  129. }
  130. if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
  131. {
  132. Sql_ShowDebug(sql_handle);
  133. Sql_Free(db->accounts);
  134. db->accounts = NULL;
  135. return false;
  136. }
  137. if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) )
  138. Sql_ShowDebug(sql_handle);
  139. return true;
  140. }
  141. /// disconnects from database
  142. static void account_db_sql_destroy(AccountDB* self)
  143. {
  144. AccountDB_SQL* db = (AccountDB_SQL*)self;
  145. Sql_Free(db->accounts);
  146. db->accounts = NULL;
  147. aFree(db);
  148. }
  149. /// Gets a property from this database.
  150. static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen)
  151. {
  152. AccountDB_SQL* db = (AccountDB_SQL*)self;
  153. const char* signature;
  154. signature = "engine.";
  155. if( strncmpi(key, signature, strlen(signature)) == 0 )
  156. {
  157. key += strlen(signature);
  158. if( strcmpi(key, "name") == 0 )
  159. safesnprintf(buf, buflen, "sql");
  160. else
  161. if( strcmpi(key, "version") == 0 )
  162. safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION);
  163. else
  164. if( strcmpi(key, "comment") == 0 )
  165. safesnprintf(buf, buflen, "SQL Account Database");
  166. else
  167. return false;// not found
  168. return true;
  169. }
  170. signature = "sql.";
  171. if( strncmpi(key, signature, strlen(signature)) == 0 )
  172. {
  173. key += strlen(signature);
  174. if( strcmpi(key, "db_hostname") == 0 )
  175. safesnprintf(buf, buflen, "%s", db->global_db_hostname);
  176. else
  177. if( strcmpi(key, "db_port") == 0 )
  178. safesnprintf(buf, buflen, "%d", db->global_db_port);
  179. else
  180. if( strcmpi(key, "db_username") == 0 )
  181. safesnprintf(buf, buflen, "%s", db->global_db_username);
  182. else
  183. if( strcmpi(key, "db_password") == 0 )
  184. safesnprintf(buf, buflen, "%s", db->global_db_password);
  185. else
  186. if( strcmpi(key, "db_database") == 0 )
  187. safesnprintf(buf, buflen, "%s", db->global_db_database);
  188. else
  189. if( strcmpi(key, "codepage") == 0 )
  190. safesnprintf(buf, buflen, "%s", db->global_codepage);
  191. else
  192. return false;// not found
  193. return true;
  194. }
  195. signature = "account.sql.";
  196. if( strncmpi(key, signature, strlen(signature)) == 0 )
  197. {
  198. key += strlen(signature);
  199. if( strcmpi(key, "db_hostname") == 0 )
  200. safesnprintf(buf, buflen, "%s", db->db_hostname);
  201. else
  202. if( strcmpi(key, "db_port") == 0 )
  203. safesnprintf(buf, buflen, "%d", db->db_port);
  204. else
  205. if( strcmpi(key, "db_username") == 0 )
  206. safesnprintf(buf, buflen, "%s", db->db_username);
  207. else
  208. if( strcmpi(key, "db_password") == 0 )
  209. safesnprintf(buf, buflen, "%s", db->db_password);
  210. else
  211. if( strcmpi(key, "db_database") == 0 )
  212. safesnprintf(buf, buflen, "%s", db->db_database);
  213. else
  214. if( strcmpi(key, "codepage") == 0 )
  215. safesnprintf(buf, buflen, "%s", db->codepage);
  216. else
  217. if( strcmpi(key, "case_sensitive") == 0 )
  218. safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0));
  219. else
  220. if( strcmpi(key, "account_db") == 0 )
  221. safesnprintf(buf, buflen, "%s", db->account_db);
  222. else
  223. if( strcmpi(key, "accreg_db") == 0 )
  224. safesnprintf(buf, buflen, "%s", db->accreg_db);
  225. else
  226. return false;// not found
  227. return true;
  228. }
  229. return false;// not found
  230. }
  231. /// if the option is supported, adjusts the internal state
  232. static bool account_db_sql_set_property(AccountDB* self, const char* key, const char* value)
  233. {
  234. AccountDB_SQL* db = (AccountDB_SQL*)self;
  235. const char* signature;
  236. signature = "sql.";
  237. if( strncmp(key, signature, strlen(signature)) == 0 )
  238. {
  239. key += strlen(signature);
  240. if( strcmpi(key, "db_hostname") == 0 )
  241. safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname));
  242. else
  243. if( strcmpi(key, "db_port") == 0 )
  244. db->global_db_port = (uint16)strtoul(value, NULL, 10);
  245. else
  246. if( strcmpi(key, "db_username") == 0 )
  247. safestrncpy(db->global_db_username, value, sizeof(db->global_db_username));
  248. else
  249. if( strcmpi(key, "db_password") == 0 )
  250. safestrncpy(db->global_db_password, value, sizeof(db->global_db_password));
  251. else
  252. if( strcmpi(key, "db_database") == 0 )
  253. safestrncpy(db->global_db_database, value, sizeof(db->global_db_database));
  254. else
  255. if( strcmpi(key, "codepage") == 0 )
  256. safestrncpy(db->global_codepage, value, sizeof(db->global_codepage));
  257. else
  258. return false;// not found
  259. return true;
  260. }
  261. signature = "account.sql.";
  262. if( strncmp(key, signature, strlen(signature)) == 0 )
  263. {
  264. key += strlen(signature);
  265. if( strcmpi(key, "db_hostname") == 0 )
  266. safestrncpy(db->db_hostname, value, sizeof(db->db_hostname));
  267. else
  268. if( strcmpi(key, "db_port") == 0 )
  269. db->db_port = (uint16)strtoul(value, NULL, 10);
  270. else
  271. if( strcmpi(key, "db_username") == 0 )
  272. safestrncpy(db->db_username, value, sizeof(db->db_username));
  273. else
  274. if( strcmpi(key, "db_password") == 0 )
  275. safestrncpy(db->db_password, value, sizeof(db->db_password));
  276. else
  277. if( strcmpi(key, "db_database") == 0 )
  278. safestrncpy(db->db_database, value, sizeof(db->db_database));
  279. else
  280. if( strcmpi(key, "codepage") == 0 )
  281. safestrncpy(db->codepage, value, sizeof(db->codepage));
  282. else
  283. if( strcmpi(key, "case_sensitive") == 0 )
  284. db->case_sensitive = config_switch(value);
  285. else
  286. if( strcmpi(key, "account_db") == 0 )
  287. safestrncpy(db->account_db, value, sizeof(db->account_db));
  288. else
  289. if( strcmpi(key, "accreg_db") == 0 )
  290. safestrncpy(db->accreg_db, value, sizeof(db->accreg_db));
  291. else
  292. return false;// not found
  293. return true;
  294. }
  295. return false;// not found
  296. }
  297. /// create a new account entry
  298. /// If acc->account_id is -1, the account id will be auto-generated,
  299. /// and its value will be written to acc->account_id if everything succeeds.
  300. static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc)
  301. {
  302. AccountDB_SQL* db = (AccountDB_SQL*)self;
  303. Sql* sql_handle = db->accounts;
  304. // decide on the account id to assign
  305. int account_id;
  306. if( acc->account_id != -1 )
  307. {// caller specifies it manually
  308. account_id = acc->account_id;
  309. }
  310. else
  311. {// ask the database
  312. char* data;
  313. size_t len;
  314. if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db) )
  315. {
  316. Sql_ShowDebug(sql_handle);
  317. return false;
  318. }
  319. if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  320. {
  321. Sql_ShowDebug(sql_handle);
  322. Sql_FreeResult(sql_handle);
  323. return false;
  324. }
  325. Sql_GetData(sql_handle, 0, &data, &len);
  326. account_id = ( data != NULL ) ? atoi(data) : 0;
  327. Sql_FreeResult(sql_handle);
  328. if( account_id < START_ACCOUNT_NUM )
  329. account_id = START_ACCOUNT_NUM;
  330. }
  331. // zero value is prohibited
  332. if( account_id == 0 )
  333. return false;
  334. // absolute maximum
  335. if( account_id > END_ACCOUNT_NUM )
  336. return false;
  337. // insert the data into the database
  338. acc->account_id = account_id;
  339. return mmo_auth_tosql(db, acc, true);
  340. }
  341. /// delete an existing account entry + its regs
  342. static bool account_db_sql_remove(AccountDB* self, const int account_id)
  343. {
  344. AccountDB_SQL* db = (AccountDB_SQL*)self;
  345. Sql* sql_handle = db->accounts;
  346. bool result = false;
  347. if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION")
  348. || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id)
  349. || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id) )
  350. Sql_ShowDebug(sql_handle);
  351. else
  352. result = true;
  353. result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") );
  354. return result;
  355. }
  356. /// update an existing account with the provided new data (both account and regs)
  357. static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc)
  358. {
  359. AccountDB_SQL* db = (AccountDB_SQL*)self;
  360. return mmo_auth_tosql(db, acc, false);
  361. }
  362. /// retrieve data from db and store it in the provided data structure
  363. static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id)
  364. {
  365. AccountDB_SQL* db = (AccountDB_SQL*)self;
  366. return mmo_auth_fromsql(db, acc, account_id);
  367. }
  368. /// retrieve data from db and store it in the provided data structure
  369. static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid)
  370. {
  371. AccountDB_SQL* db = (AccountDB_SQL*)self;
  372. Sql* sql_handle = db->accounts;
  373. char esc_userid[2*NAME_LENGTH+1];
  374. int account_id;
  375. char* data;
  376. Sql_EscapeString(sql_handle, esc_userid, userid);
  377. // get the list of account IDs for this user ID
  378. if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'",
  379. db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid) )
  380. {
  381. Sql_ShowDebug(sql_handle);
  382. return false;
  383. }
  384. if( Sql_NumRows(sql_handle) > 1 )
  385. {// serious problem - duplicit account
  386. ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid);
  387. Sql_FreeResult(sql_handle);
  388. return false;
  389. }
  390. if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  391. {// no such entry
  392. Sql_FreeResult(sql_handle);
  393. return false;
  394. }
  395. Sql_GetData(sql_handle, 0, &data, NULL);
  396. account_id = atoi(data);
  397. return account_db_sql_load_num(self, acc, account_id);
  398. }
  399. /// Returns a new forward iterator.
  400. static AccountDBIterator* account_db_sql_iterator(AccountDB* self)
  401. {
  402. AccountDB_SQL* db = (AccountDB_SQL*)self;
  403. AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)aCalloc(1, sizeof(AccountDBIterator_SQL));
  404. // set up the vtable
  405. iter->vtable.destroy = &account_db_sql_iter_destroy;
  406. iter->vtable.next = &account_db_sql_iter_next;
  407. // fill data
  408. iter->db = db;
  409. iter->last_account_id = -1;
  410. return &iter->vtable;
  411. }
  412. /// Destroys this iterator, releasing all allocated memory (including itself).
  413. static void account_db_sql_iter_destroy(AccountDBIterator* self)
  414. {
  415. AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self;
  416. aFree(iter);
  417. }
  418. /// Fetches the next account in the database.
  419. static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc)
  420. {
  421. AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self;
  422. AccountDB_SQL* db = (AccountDB_SQL*)iter->db;
  423. Sql* sql_handle = db->accounts;
  424. char* data;
  425. // get next account ID
  426. if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1",
  427. db->account_db, iter->last_account_id) )
  428. {
  429. Sql_ShowDebug(sql_handle);
  430. return false;
  431. }
  432. if( SQL_SUCCESS == Sql_NextRow(sql_handle) &&
  433. SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) &&
  434. data != NULL )
  435. {// get account data
  436. int account_id;
  437. account_id = atoi(data);
  438. if( mmo_auth_fromsql(db, acc, account_id) )
  439. {
  440. iter->last_account_id = account_id;
  441. Sql_FreeResult(sql_handle);
  442. return true;
  443. }
  444. }
  445. Sql_FreeResult(sql_handle);
  446. return false;
  447. }
  448. static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id)
  449. {
  450. Sql* sql_handle = db->accounts;
  451. char* data;
  452. int i = 0;
  453. // retrieve login entry for the specified account
  454. if( SQL_ERROR == Sql_Query(sql_handle,
  455. #ifdef VIP_ENABLE
  456. "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",
  457. #else
  458. "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",
  459. #endif
  460. db->account_db, account_id )
  461. ) {
  462. Sql_ShowDebug(sql_handle);
  463. return false;
  464. }
  465. if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
  466. {// no such entry
  467. Sql_FreeResult(sql_handle);
  468. return false;
  469. }
  470. Sql_GetData(sql_handle, 0, &data, NULL); acc->account_id = atoi(data);
  471. Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->userid, data, sizeof(acc->userid));
  472. Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass));
  473. Sql_GetData(sql_handle, 3, &data, NULL); acc->sex = data[0];
  474. Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email));
  475. Sql_GetData(sql_handle, 5, &data, NULL); acc->group_id = atoi(data);
  476. Sql_GetData(sql_handle, 6, &data, NULL); acc->state = strtoul(data, NULL, 10);
  477. Sql_GetData(sql_handle, 7, &data, NULL); acc->unban_time = atol(data);
  478. Sql_GetData(sql_handle, 8, &data, NULL); acc->expiration_time = atol(data);
  479. Sql_GetData(sql_handle, 9, &data, NULL); acc->logincount = strtoul(data, NULL, 10);
  480. Sql_GetData(sql_handle, 10, &data, NULL); safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin));
  481. Sql_GetData(sql_handle, 11, &data, NULL); safestrncpy(acc->last_ip, data, sizeof(acc->last_ip));
  482. Sql_GetData(sql_handle, 12, &data, NULL); safestrncpy(acc->birthdate, data, sizeof(acc->birthdate));
  483. Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = atoi(data);
  484. Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode));
  485. Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data);
  486. Sql_GetData(sql_handle, 16, &data, NULL); acc->bank_vault = atoi(data);
  487. #ifdef VIP_ENABLE
  488. Sql_GetData(sql_handle, 17, &data, NULL); acc->vip_time = atol(data);
  489. Sql_GetData(sql_handle, 18, &data, NULL); acc->old_group = atoi(data);
  490. #endif
  491. Sql_FreeResult(sql_handle);
  492. // retrieve account regs for the specified user
  493. 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) )
  494. {
  495. Sql_ShowDebug(sql_handle);
  496. return false;
  497. }
  498. acc->account_reg2_num = (int)Sql_NumRows(sql_handle);
  499. while( SQL_SUCCESS == Sql_NextRow(sql_handle) )
  500. {
  501. char* data;
  502. Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str));
  503. Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value));
  504. ++i;
  505. }
  506. Sql_FreeResult(sql_handle);
  507. if( i != acc->account_reg2_num )
  508. return false;
  509. return true;
  510. }
  511. static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new)
  512. {
  513. Sql* sql_handle = db->accounts;
  514. SqlStmt* stmt = SqlStmt_Malloc(sql_handle);
  515. bool result = false;
  516. int i;
  517. // try
  518. do
  519. {
  520. if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") )
  521. {
  522. Sql_ShowDebug(sql_handle);
  523. break;
  524. }
  525. if( is_new )
  526. {// insert into account table
  527. if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
  528. #ifdef VIP_ENABLE
  529. "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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
  530. #else
  531. "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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
  532. #endif
  533. db->account_db)
  534. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id))
  535. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid))
  536. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass))
  537. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex))
  538. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email))
  539. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id))
  540. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state))
  541. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time))
  542. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time))
  543. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount))
  544. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin))
  545. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip))
  546. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate))
  547. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots))
  548. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode))
  549. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change))
  550. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_INT, (void*)&acc->bank_vault, sizeof(acc->bank_vault))
  551. #ifdef VIP_ENABLE
  552. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 17, SQLDT_LONG, (void*)&acc->vip_time, sizeof(acc->vip_time))
  553. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 18, SQLDT_INT, (void*)&acc->old_group, sizeof(acc->old_group))
  554. #endif
  555. || SQL_SUCCESS != SqlStmt_Execute(stmt)
  556. ) {
  557. SqlStmt_ShowDebug(stmt);
  558. break;
  559. }
  560. }
  561. else
  562. {// update account table
  563. if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
  564. #ifdef VIP_ENABLE
  565. "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'",
  566. #else
  567. "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'",
  568. #endif
  569. db->account_db, acc->account_id)
  570. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid))
  571. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass))
  572. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex))
  573. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email))
  574. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id))
  575. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state))
  576. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time))
  577. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time))
  578. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount))
  579. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin))
  580. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip))
  581. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate))
  582. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots))
  583. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode))
  584. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change))
  585. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_INT, (void*)&acc->bank_vault, sizeof(acc->bank_vault))
  586. #ifdef VIP_ENABLE
  587. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_LONG, (void*)&acc->vip_time, sizeof(acc->vip_time))
  588. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 17, SQLDT_INT, (void*)&acc->old_group, sizeof(acc->old_group))
  589. #endif
  590. || SQL_SUCCESS != SqlStmt_Execute(stmt)
  591. ) {
  592. SqlStmt_ShowDebug(stmt);
  593. break;
  594. }
  595. }
  596. // remove old account regs
  597. if( SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) )
  598. {
  599. Sql_ShowDebug(sql_handle);
  600. break;
  601. }
  602. // insert new account regs
  603. if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id) )
  604. {
  605. SqlStmt_ShowDebug(stmt);
  606. break;
  607. }
  608. for( i = 0; i < acc->account_reg2_num; ++i )
  609. {
  610. if( SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str))
  611. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value))
  612. || SQL_SUCCESS != SqlStmt_Execute(stmt)
  613. ) {
  614. SqlStmt_ShowDebug(stmt);
  615. break;
  616. }
  617. }
  618. if( i < acc->account_reg2_num )
  619. {
  620. result = false;
  621. break;
  622. }
  623. // if we got this far, everything was successful
  624. result = true;
  625. } while(0);
  626. // finally
  627. result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") );
  628. SqlStmt_Free(stmt);
  629. return result;
  630. }