From 60a426c0742b3e7d8c5b557c7578df6eeeea377b Mon Sep 17 00:00:00 2001 From: brianluau Date: Wed, 5 Dec 2012 02:53:33 +0000 Subject: - Undid r16968: SVN Replaced with source:/trunk/src/@16966 (tid:74924). [16969:16991/trunk/src/] will be re-committed in the next 24 hours. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16992 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/char.c | 8167 +++++------ src/char/char.h | 19 +- src/char/int_auction.c | 754 +- src/char/int_elemental.c | 266 +- src/char/int_guild.c | 3072 +++-- src/char/int_guild.h | 26 +- src/char/int_homun.c | 469 +- src/char/int_homun.h | 4 +- src/char/int_mail.c | 721 +- src/char/int_mail.h | 4 +- src/char/int_mercenary.c | 266 +- src/char/int_party.c | 1367 +- src/char/int_party.h | 12 +- src/char/int_pet.c | 505 +- src/char/int_quest.c | 250 +- src/char/int_storage.c | 352 +- src/char/int_storage.h | 2 +- src/char/inter.c | 2022 ++- src/char/inter.h | 4 +- src/common/atomic.h | 139 +- src/common/cbasetypes.h | 147 +- src/common/conf.c | 147 +- src/common/core.c | 447 +- src/common/core.h | 29 +- src/common/db.c | 3246 +++-- src/common/db.h | 1041 +- src/common/des.c | 316 +- src/common/des.h | 12 +- src/common/ers.c | 316 +- src/common/ers.h | 106 +- src/common/evdp.h | 130 +- src/common/evdp_epoll.c | 356 +- src/common/grfio.c | 1205 +- src/common/grfio.h | 14 +- src/common/malloc.c | 1006 +- src/common/malloc.h | 58 +- src/common/mapindex.c | 251 +- src/common/mapindex.h | 10 +- src/common/md5calc.c | 362 +- src/common/md5calc.h | 6 +- src/common/mempool.c | 899 +- src/common/mempool.h | 62 +- src/common/mmo.h | 929 +- src/common/mutex.c | 256 +- src/common/mutex.h | 50 +- src/common/netbuffer.c | 349 +- src/common/netbuffer.h | 78 +- src/common/network.c | 1809 ++- src/common/network.h | 220 +- src/common/nullpo.c | 96 +- src/common/nullpo.h | 30 +- src/common/raconf.c | 1037 +- src/common/raconf.h | 34 +- src/common/random.c | 36 +- src/common/showmsg.c | 1351 +- src/common/showmsg.h | 104 +- src/common/socket.c | 1983 +-- src/common/socket.h | 75 +- src/common/spinlock.h | 108 +- src/common/sql.c | 1216 +- src/common/sql.h | 139 +- src/common/strlib.c | 1729 +-- src/common/strlib.h | 119 +- src/common/thread.c | 384 +- src/common/thread.h | 62 +- src/common/timer.c | 479 +- src/common/timer.h | 32 +- src/common/utils.c | 403 +- src/common/utils.h | 8 +- src/common/winapi.h | 6 +- src/config/const.h | 74 +- src/login/account.h | 227 +- src/login/account_sql.c | 1123 +- src/login/ipban.h | 2 +- src/login/ipban_sql.c | 340 +- src/login/login.c | 3198 ++--- src/login/login.h | 123 +- src/login/loginlog.h | 4 +- src/login/loginlog_sql.c | 241 +- src/map/atcommand.c | 14104 +++++++++---------- src/map/atcommand.h | 28 +- src/map/battle.c | 10900 +++++++-------- src/map/battle.h | 850 +- src/map/battleground.c | 329 +- src/map/battleground.h | 26 +- src/map/buyingstore.c | 804 +- src/map/buyingstore.h | 32 +- src/map/chat.c | 570 +- src/map/chat.h | 50 +- src/map/chrif.c | 2531 ++-- src/map/chrif.h | 38 +- src/map/clif.c | 21226 ++++++++++++++-------------- src/map/clif.h | 842 +- src/map/date.c | 66 +- src/map/duel.c | 248 +- src/map/duel.h | 20 +- src/map/elemental.c | 1458 +- src/map/elemental.h | 56 +- src/map/guild.c | 2853 ++-- src/map/guild.h | 26 +- src/map/homunculus.c | 2062 ++- src/map/homunculus.h | 110 +- src/map/instance.c | 631 +- src/map/instance.h | 32 +- src/map/intif.c | 3021 ++-- src/map/intif.h | 20 +- src/map/itemdb.c | 2238 +-- src/map/itemdb.h | 226 +- src/map/log.c | 878 +- src/map/log.h | 107 +- src/map/mail.c | 226 +- src/map/mail.h | 2 +- src/map/map.c | 5622 ++++---- src/map/map.h | 967 +- src/map/mapreg.h | 6 +- src/map/mapreg_sql.c | 311 +- src/map/mercenary.c | 640 +- src/map/mercenary.h | 58 +- src/map/mob.c | 7791 +++++------ src/map/mob.h | 359 +- src/map/npc.c | 6196 +++++---- src/map/npc.h | 219 +- src/map/npc_chat.c | 568 +- src/map/party.c | 1823 +-- src/map/party.h | 52 +- src/map/path.c | 686 +- src/map/path.h | 10 +- src/map/pc.c | 16190 +++++++++++----------- src/map/pc.h | 1190 +- src/map/pc_groups.c | 657 +- src/map/pc_groups.h | 92 +- src/map/pet.c | 2286 ++-- src/map/pet.h | 140 +- src/map/quest.c | 516 +- src/map/quest.h | 26 +- src/map/script.c | 26313 ++++++++++++++++++----------------- src/map/script.h | 238 +- src/map/searchstore.c | 593 +- src/map/searchstore.h | 77 +- src/map/skill.c | 33496 ++++++++++++++++++++++----------------------- src/map/skill.h | 3268 ++--- src/map/status.c | 20396 ++++++++++++++------------- src/map/status.h | 3129 ++--- src/map/storage.c | 922 +- src/map/storage.h | 4 +- src/map/trade.c | 1014 +- src/map/trade.h | 4 +- src/map/unit.c | 4228 +++--- src/map/unit.h | 104 +- src/map/vending.c | 654 +- src/map/vending.h | 24 +- src/test/test_spinlock.c | 160 +- src/tool/mapcache.c | 484 +- 153 files changed, 127650 insertions(+), 127514 deletions(-) (limited to 'src') diff --git a/src/char/char.c b/src/char/char.c index dc1dd6a72..234a91b79 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -30,9 +30,9 @@ #include // private declarations -#define CHAR_CONF_NAME "conf/char_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" -#define SQL_CONF_NAME "conf/inter_athena.conf" +#define CHAR_CONF_NAME "conf/char_athena.conf" +#define LAN_CONF_NAME "conf/subnet_athena.conf" +#define SQL_CONF_NAME "conf/inter_athena.conf" char char_db[256] = "char"; char scdata_db[256] = "sc_data"; @@ -68,18 +68,18 @@ char ragsrvinfo_db[256] = "ragsrvinfo"; // show loading/saving messages int save_log = 1; -static DBMap *char_db_; // int char_id -> struct mmo_charstatus* +static DBMap* char_db_; // int char_id -> struct mmo_charstatus* char db_path[1024] = "db"; int db_use_sqldbs; struct mmo_map_server { - int fd; - uint32 ip; - uint16 port; - int users; - unsigned short map[MAX_MAP_PER_SERVER]; + int fd; + uint32 ip; + uint16 port; + int users; + unsigned short map[MAX_MAP_PER_SERVER]; } server[MAX_MAP_SERVERS]; int login_fd=-1, char_fd=-1; @@ -109,28 +109,28 @@ int char_per_account = 0; //Maximum chars per account (default unlimited) [Siriu int char_del_level = 0; //From which level u can delete character [Lupus] int char_del_delay = 86400; -int log_char = 1; // loggin char or not [devil] -int log_inter = 1; // loggin inter or not [devil] +int log_char = 1; // loggin char or not [devil] +int log_inter = 1; // loggin inter or not [devil] // Advanced subnet check [LuzZza] struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; + uint32 mask; + uint32 char_ip; + uint32 map_ip; } subnet[16]; int subnet_count = 0; struct char_session_data { - bool auth; // whether the session is authed or not - int account_id, login_id1, login_id2, sex; - int found_char[MAX_CHARS]; // ids of chars on this account - char email[40]; // e-mail (default: a@a.com) by [Yor] - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int group_id; // permission - uint32 version; - uint8 clienttype; - char new_name[NAME_LENGTH]; - char birthdate[10+1]; // YYYY-MM-DD + bool auth; // whether the session is authed or not + int account_id, login_id1, login_id2, sex; + int found_char[MAX_CHARS]; // ids of chars on this account + char email[40]; // e-mail (default: a@a.com) by [Yor] + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + int group_id; // permission + uint32 version; + uint8 clienttype; + char new_name[NAME_LENGTH]; + char birthdate[10+1]; // YYYY-MM-DD }; int max_connect_user = 0; @@ -167,32 +167,32 @@ int console = 0; #define AUTH_TIMEOUT 30000 struct auth_node { - int account_id; - int char_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - int sex; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int group_id; - unsigned changing_mapservers : 1; + int account_id; + int char_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + int sex; + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + int group_id; + unsigned changing_mapservers : 1; }; -static DBMap *auth_db; // int account_id -> struct auth_node* +static DBMap* auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- // Online User Database //----------------------------------------------------- struct online_char_data { - int account_id; - int char_id; - int fd; - int waiting_disconnect; - short server; // -2: unknown server, -1: not connected, 0+: id of server + int account_id; + int char_id; + int fd; + int waiting_disconnect; + short server; // -2: unknown server, -1: not connected, 0+: id of server }; -static DBMap *online_char_db; // int account_id -> struct online_char_data* +static DBMap* online_char_db; // int account_id -> struct online_char_data* static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data); int delete_char_sql(int char_id); @@ -201,129 +201,137 @@ int delete_char_sql(int char_id); */ static DBData create_online_char_data(DBKey key, va_list args) { - struct online_char_data *character; - CREATE(character, struct online_char_data, 1); - character->account_id = key.i; - character->char_id = -1; - character->server = -1; - character->fd = -1; - character->waiting_disconnect = INVALID_TIMER; - return db_ptr2data(character); + struct online_char_data* character; + CREATE(character, struct online_char_data, 1); + character->account_id = key.i; + character->char_id = -1; + character->server = -1; + character->fd = -1; + character->waiting_disconnect = INVALID_TIMER; + return db_ptr2data(character); } void set_char_charselect(int account_id) { - struct online_char_data *character; + struct online_char_data* character; - character = (struct online_char_data *)idb_ensure(online_char_db, account_id, create_online_char_data); + character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); - if (character->server > -1) - if (server[character->server].users > 0) // Prevent this value from going negative. - server[character->server].users--; + if( character->server > -1 ) + if( server[character->server].users > 0 ) // Prevent this value from going negative. + server[character->server].users--; - character->char_id = -1; - character->server = -1; + character->char_id = -1; + character->server = -1; - if (character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } + if(character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } - if (login_fd > 0 && !session[login_fd]->flag.eof) { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + if (login_fd > 0 && !session[login_fd]->flag.eof) + { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272b; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } void set_char_online(int map_id, int char_id, int account_id) { - struct online_char_data *character; - struct mmo_charstatus *cp; - - //Update DB - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id)) - Sql_ShowDebug(sql_handle); - - //Check to see for online conflicts - character = (struct online_char_data *)idb_ensure(online_char_db, account_id, create_online_char_data); - if (character->char_id != -1 && character->server > -1 && character->server != map_id) { - ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, map_id, account_id, char_id); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - - //Update state data - character->char_id = char_id; - character->server = map_id; - - if (character->server > -1) - server[character->server].users++; - - //Get rid of disconnect timer - if (character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. - cp = (struct mmo_charstatus *)idb_get(char_db_,char_id); - inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); - - //Notify login server - if (login_fd > 0 && !session[login_fd]->flag.eof) { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + struct online_char_data* character; + struct mmo_charstatus *cp; + + //Update DB + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + + //Check to see for online conflicts + character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); + if( character->char_id != -1 && character->server > -1 && character->server != map_id ) + { + ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, map_id, account_id, char_id); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + + //Update state data + character->char_id = char_id; + character->server = map_id; + + if( character->server > -1 ) + server[character->server].users++; + + //Get rid of disconnect timer + if(character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + + //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. + cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); + inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); + + //Notify login server + if (login_fd > 0 && !session[login_fd]->flag.eof) + { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272b; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } void set_char_offline(int char_id, int account_id) { - struct online_char_data *character; - - if (char_id == -1) { - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id)) - Sql_ShowDebug(sql_handle); - } else { - struct mmo_charstatus *cp = (struct mmo_charstatus *)idb_get(char_db_,char_id); - inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); - if (cp) - idb_remove(char_db_,char_id); - - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id)) - Sql_ShowDebug(sql_handle); - } - - if ((character = (struct online_char_data *)idb_get(online_char_db, account_id)) != NULL) { - //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] - if (character->server > -1) - if (server[character->server].users > 0) // Prevent this value from going negative. - server[character->server].users--; - - if (character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - if (character->char_id == char_id) { - character->char_id = -1; - character->server = -1; - } - - //FIXME? Why Kevin free'd the online information when the char was effectively in the map-server? - } - - //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. - if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272c; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + struct online_char_data* character; + + if ( char_id == -1 ) + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id) ) + Sql_ShowDebug(sql_handle); + } + else + { + struct mmo_charstatus* cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); + inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); + if (cp) + idb_remove(char_db_,char_id); + + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + } + + if ((character = (struct online_char_data*)idb_get(online_char_db, account_id)) != NULL) + { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] + if( character->server > -1 ) + if( server[character->server].users > 0 ) // Prevent this value from going negative. + server[character->server].users--; + + if(character->waiting_disconnect != INVALID_TIMER){ + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + + if(character->char_id == char_id) + { + character->char_id = -1; + character->server = -1; + } + + //FIXME? Why Kevin free'd the online information when the char was effectively in the map-server? + } + + //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. + if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) + { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272c; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } /** @@ -331,18 +339,18 @@ void set_char_offline(int char_id, int account_id) */ static int char_db_setoffline(DBKey key, DBData *data, va_list ap) { - struct online_char_data *character = (struct online_char_data *)db_data2ptr(data); - int server = va_arg(ap, int); - if (server == -1) { - character->char_id = -1; - character->server = -1; - if (character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - } else if (character->server == server) - character->server = -2; //In some map server that we aren't connected to. - return 0; + struct online_char_data* character = (struct online_char_data*)db_data2ptr(data); + int server = va_arg(ap, int); + if (server == -1) { + character->char_id = -1; + character->server = -1; + if(character->waiting_disconnect != INVALID_TIMER){ + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + } else if (character->server == server) + character->server = -2; //In some map server that we aren't connected to. + return 0; } /** @@ -350,48 +358,48 @@ static int char_db_setoffline(DBKey key, DBData *data, va_list ap) */ static int char_db_kickoffline(DBKey key, DBData *data, va_list ap) { - struct online_char_data *character = (struct online_char_data *)db_data2ptr(data); - int server_id = va_arg(ap, int); + struct online_char_data* character = (struct online_char_data*)db_data2ptr(data); + int server_id = va_arg(ap, int); - if (server_id > -1 && character->server != server_id) - return 0; + if (server_id > -1 && character->server != server_id) + return 0; - //Kick out any connected characters, and set them offline as appropriate. - if (character->server > -1) - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); - else if (character->waiting_disconnect == INVALID_TIMER) - set_char_offline(character->char_id, character->account_id); - else - return 0; // fail + //Kick out any connected characters, and set them offline as appropriate. + if (character->server > -1) + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); + else if (character->waiting_disconnect == INVALID_TIMER) + set_char_offline(character->char_id, character->account_id); + else + return 0; // fail - return 1; + return 1; } void set_all_offline(int id) { - if (id < 0) - ShowNotice("Sending all users offline.\n"); - else - ShowNotice("Sending users of map-server %d offline.\n",id); - online_char_db->foreach(online_char_db,char_db_kickoffline,id); - - if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) - return; - //Tell login-server to also mark all our characters as offline. - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2737; - WFIFOSET(login_fd,2); + if (id < 0) + ShowNotice("Sending all users offline.\n"); + else + ShowNotice("Sending users of map-server %d offline.\n",id); + online_char_db->foreach(online_char_db,char_db_kickoffline,id); + + if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) + return; + //Tell login-server to also mark all our characters as offline. + WFIFOHEAD(login_fd,2); + WFIFOW(login_fd,0) = 0x2737; + WFIFOSET(login_fd,2); } void set_all_offline_sql(void) { - //Set all players to 'OFFLINE' - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db)) - Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db)) - Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db)) - Sql_ShowDebug(sql_handle); + //Set all players to 'OFFLINE' + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db) ) + Sql_ShowDebug(sql_handle); } /** @@ -399,920 +407,949 @@ void set_all_offline_sql(void) */ static DBData create_charstatus(DBKey key, va_list args) { - struct mmo_charstatus *cp; - cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); - cp->char_id = key.i; - return db_ptr2data(cp); + struct mmo_charstatus *cp; + cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); + cp->char_id = key.i; + return db_ptr2data(cp); } int inventory_to_sql(const struct item items[], int max, int id); -int mmo_char_tosql(int char_id, struct mmo_charstatus *p) +int mmo_char_tosql(int char_id, struct mmo_charstatus* p) { - int i = 0; - int count = 0; - int diff = 0; - char save_status[128]; //For displaying save information. [Skotlex] - struct mmo_charstatus *cp; - int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. - StringBuf buf; - - if (char_id!=p->char_id) return 0; - - cp = idb_ensure(char_db_, char_id, create_charstatus); - - StringBuf_Init(&buf); - memset(save_status, 0, sizeof(save_status)); - - //map inventory data - if (memcmp(p->inventory, cp->inventory, sizeof(p->inventory))) { - if (!inventory_to_sql(p->inventory, MAX_INVENTORY, p->char_id)) - strcat(save_status, " inventory"); - else - errors++; - } - - //map cart data - if (memcmp(p->cart, cp->cart, sizeof(p->cart))) { - if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) - strcat(save_status, " cart"); - else - errors++; - } - - //map storage data - if (memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items))) { - if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) - strcat(save_status, " storage"); - else - errors++; - } - - if ( - (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || - (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || - (p->zeny != cp->zeny) || - (p->last_point.map != cp->last_point.map) || - (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || - (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || - (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || - (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || - (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || - (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || - (p->option != cp->option) || - (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || - (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || - (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || - (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || - (p->rename != cp->rename) || (p->robe != cp->robe) - ) { - //Save status - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," - "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," - "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," - "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," - "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d'," - "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," - "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," - "`delete_date`='%lu',`robe`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->base_level, p->job_level, - p->base_exp, p->job_exp, p->zeny, - p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, - mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, - mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, - (unsigned long)p->delete_date, // FIXME: platform-dependent size - p->robe, - p->account_id, p->char_id)) { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status"); - } - - //Values that will seldom change (to speed up saving) - if ( - (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || - (p->class_ != cp->class_) || - (p->partner_id != cp->partner_id) || (p->father != cp->father) || - (p->mother != cp->mother) || (p->child != cp->child) || - (p->karma != cp->karma) || (p->manner != cp->manner) || - (p->fame != cp->fame) - ) { - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," - "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," - "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," - "`karma`='%d',`manner`='%d', `fame`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->class_, - p->hair, p->hair_color, p->clothes_color, - p->partner_id, p->father, p->mother, p->child, - p->karma, p->manner, p->fame, - p->account_id, p->char_id)) { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status2"); - } - - /* Mercenary Owner */ - if ((p->mer_id != cp->mer_id) || - (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || - (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || - (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith)) { - if (mercenary_owner_tosql(char_id, p)) - strcat(save_status, " mercenary"); - else - errors++; - } - - //memo points - if (memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point))) { - char esc_mapname[NAME_LENGTH*2+1]; - - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id)) { - Sql_ShowDebug(sql_handle); - errors++; - } - - //insert here. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); - for (i = 0, count = 0; i < MAX_MEMOPOINTS; ++i) { - if (p->memo_point[i].map) { - if (count) - StringBuf_AppendStr(&buf, ","); - Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); - StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); - ++count; - } - } - if (count) { - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " memo"); - } - - //FIXME: is this neccessary? [ultramage] - for (i=0; iskill[i].lv != 0) && (p->skill[i].id == 0)) - p->skill[i].id = i; // Fix skill tree - - - //skills - if (memcmp(p->skill, cp->skill, sizeof(p->skill))) { - //`skill` (`char_id`, `id`, `lv`) - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id)) { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); - //insert here. - for (i = 0, count = 0; i < MAX_SKILL; ++i) { - if (p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY) { - if (p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0) - continue; - if (p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0) - continue; - if (count) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); - ++count; - } - } - if (count) { - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - strcat(save_status, " skills"); - } - - diff = 0; - for (i = 0; i < MAX_FRIENDS; i++) { - if (p->friends[i].char_id != cp->friends[i].char_id || - p->friends[i].account_id != cp->friends[i].account_id) { - diff = 1; - break; - } - } - - if (diff == 1) { - //Save friends - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id)) { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); - for (i = 0, count = 0; i < MAX_FRIENDS; ++i) { - if (p->friends[i].char_id > 0) { - if (count) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); - count++; - } - } - if (count) { - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " friends"); - } + int i = 0; + int count = 0; + int diff = 0; + char save_status[128]; //For displaying save information. [Skotlex] + struct mmo_charstatus *cp; + int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. + StringBuf buf; + + if (char_id!=p->char_id) return 0; + + cp = idb_ensure(char_db_, char_id, create_charstatus); + + StringBuf_Init(&buf); + memset(save_status, 0, sizeof(save_status)); + + //map inventory data + if( memcmp(p->inventory, cp->inventory, sizeof(p->inventory)) ) { + if (!inventory_to_sql(p->inventory, MAX_INVENTORY, p->char_id)) + strcat(save_status, " inventory"); + else + errors++; + } + + //map cart data + if( memcmp(p->cart, cp->cart, sizeof(p->cart)) ) { + if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) + strcat(save_status, " cart"); + else + errors++; + } + + //map storage data + if( memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items)) ) { + if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) + strcat(save_status, " storage"); + else + errors++; + } + + if ( + (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || + (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || + (p->zeny != cp->zeny) || + (p->last_point.map != cp->last_point.map) || + (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || + (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || + (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || + (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || + (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || + (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || + (p->option != cp->option) || + (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || + (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || + (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || + (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || + (p->rename != cp->rename) || (p->robe != cp->robe) + ) + { //Save status + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," + "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," + "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," + "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," + "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d'," + "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," + "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," + "`delete_date`='%lu',`robe`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->base_level, p->job_level, + p->base_exp, p->job_exp, p->zeny, + p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, + p->str, p->agi, p->vit, p->int_, p->dex, p->luk, + p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id, + p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, + mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, + mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, + (unsigned long)p->delete_date, // FIXME: platform-dependent size + p->robe, + p->account_id, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status"); + } + + //Values that will seldom change (to speed up saving) + if ( + (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || + (p->class_ != cp->class_) || + (p->partner_id != cp->partner_id) || (p->father != cp->father) || + (p->mother != cp->mother) || (p->child != cp->child) || + (p->karma != cp->karma) || (p->manner != cp->manner) || + (p->fame != cp->fame) + ) + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," + "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," + "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," + "`karma`='%d',`manner`='%d', `fame`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->class_, + p->hair, p->hair_color, p->clothes_color, + p->partner_id, p->father, p->mother, p->child, + p->karma, p->manner, p->fame, + p->account_id, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status2"); + } + + /* Mercenary Owner */ + if( (p->mer_id != cp->mer_id) || + (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || + (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || + (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith) ) + { + if (mercenary_owner_tosql(char_id, p)) + strcat(save_status, " mercenary"); + else + errors++; + } + + //memo points + if( memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point)) ) + { + char esc_mapname[NAME_LENGTH*2+1]; + + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + + //insert here. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); + for( i = 0, count = 0; i < MAX_MEMOPOINTS; ++i ) + { + if( p->memo_point[i].map ) + { + if( count ) + StringBuf_AppendStr(&buf, ","); + Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); + StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); + ++count; + } + } + if( count ) + { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " memo"); + } + + //FIXME: is this neccessary? [ultramage] + for(i=0;iskill[i].lv != 0) && (p->skill[i].id == 0)) + p->skill[i].id = i; // Fix skill tree + + + //skills + if( memcmp(p->skill, cp->skill, sizeof(p->skill)) ) + { + //`skill` (`char_id`, `id`, `lv`) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); + //insert here. + for( i = 0, count = 0; i < MAX_SKILL; ++i ) + { + if( p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY ) + { + if( p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0 ) + continue; + if( p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0 ) + continue; + if( count ) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); + ++count; + } + } + if( count ) + { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + strcat(save_status, " skills"); + } + + diff = 0; + for(i = 0; i < MAX_FRIENDS; i++){ + if(p->friends[i].char_id != cp->friends[i].char_id || + p->friends[i].account_id != cp->friends[i].account_id){ + diff = 1; + break; + } + } + + if(diff == 1) + { //Save friends + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); + for( i = 0, count = 0; i < MAX_FRIENDS; ++i ) + { + if( p->friends[i].char_id > 0 ) + { + if( count ) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); + count++; + } + } + if( count ) + { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " friends"); + } #ifdef HOTKEY_SAVING - // hotkeys - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); - diff = 0; - for (i = 0; i < ARRAYLENGTH(p->hotkeys); i++) { - if (memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) { - if (diff) - StringBuf_AppendStr(&buf, ",");// not the first hotkey - StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); - diff = 1; - } - } - if (diff) { - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " hotkeys"); - } + // hotkeys + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); + diff = 0; + for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){ + if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) + { + if( diff ) + StringBuf_AppendStr(&buf, ",");// not the first hotkey + StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); + diff = 1; + } + } + if(diff) { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " hotkeys"); + } #endif - StringBuf_Destroy(&buf); - if (save_status[0]!='\0' && save_log) - ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); - if (!errors) - memcpy(cp, p, sizeof(struct mmo_charstatus)); - return 0; + StringBuf_Destroy(&buf); + if (save_status[0]!='\0' && save_log) + ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); + if (!errors) + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 0; } /// Saves an array of 'item' entries into the specified table. int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) { - StringBuf buf; - SqlStmt *stmt; - int i; - int j; - const char *tablename; - const char *selectoption; - struct item item; // temp storage variable - bool *flag; // bit array for inventory matching - bool found; - int errors = 0; - - switch (tableswitch) { - case TABLE_INVENTORY: - tablename = inventory_db; - selectoption = "char_id"; - break; - case TABLE_CART: - tablename = cart_db; - selectoption = "char_id"; - break; - case TABLE_STORAGE: - tablename = storage_db; - selectoption = "account_id"; - break; - case TABLE_GUILD_STORAGE: - tablename = guild_storage_db; - selectoption = "guild_id"; - break; - default: - ShowError("Invalid table name!\n"); - return 1; - } - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); - - stmt = SqlStmt_Malloc(sql_handle); - if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_Execute(stmt)) { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - for (j = 0; j < MAX_SLOTS; ++j) - SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - // bit array indicating which inventory items have already been matched - flag = (bool *) aCalloc(max, sizeof(bool)); - - while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { - found = false; - // search for the presence of the item in the char's inventory - for (i = 0; i < max; ++i) { - // skip empty and already matched entries - if (items[i].nameid == 0 || flag[i]) - continue; - - if (items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]); - if (j == MAX_SLOTS && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time) - ; //Do nothing. - else { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", - tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if (!found) { - // Item not present in inventory, remove it. - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id)) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for (i = 0; i < max; ++i) { - // skip empty and already matched entries - if (items[i].nameid == 0 || flag[i]) - continue; - - if (found) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); - StringBuf_AppendStr(&buf, ")"); - } - - if (found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; + StringBuf buf; + SqlStmt* stmt; + int i; + int j; + const char* tablename; + const char* selectoption; + struct item item; // temp storage variable + bool* flag; // bit array for inventory matching + bool found; + int errors = 0; + + switch (tableswitch) { + case TABLE_INVENTORY: tablename = inventory_db; selectoption = "char_id"; break; + case TABLE_CART: tablename = cart_db; selectoption = "char_id"; break; + case TABLE_STORAGE: tablename = storage_db; selectoption = "account_id"; break; + case TABLE_GUILD_STORAGE: tablename = guild_storage_db; selectoption = "guild_id"; break; + default: + ShowError("Invalid table name!\n"); + return 1; + } + + + // The following code compares inventory with current database values + // and performs modification/deletion/insertion only on relevant rows. + // This approach is more complicated than a trivial delete&insert, but + // it significantly reduces cpu load on the database server. + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + return 1; + } + + SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + for( j = 0; j < MAX_SLOTS; ++j ) + SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + // bit array indicating which inventory items have already been matched + flag = (bool*) aCalloc(max, sizeof(bool)); + + while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) + { + found = false; + // search for the presence of the item in the char's inventory + for( i = 0; i < max; ++i ) + { + // skip empty and already matched entries + if( items[i].nameid == 0 || flag[i] ) + continue; + + if( items[i].nameid == item.nameid + && items[i].card[0] == item.card[0] + && items[i].card[2] == item.card[2] + && items[i].card[3] == item.card[3] + ) { //They are the same item. + ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); + if( j == MAX_SLOTS && + items[i].amount == item.amount && + items[i].equip == item.equip && + items[i].identify == item.identify && + items[i].refine == item.refine && + items[i].attribute == item.attribute && + items[i].expire_time == item.expire_time ) + ; //Do nothing. + else + { + // update all fields. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", + tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + found = flag[i] = true; //Item dealt with, + break; //skip to next item in the db. + } + } + if( !found ) + {// Item not present in inventory, remove it. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + } + SqlStmt_Free(stmt); + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_AppendStr(&buf, ") VALUES "); + + found = false; + // insert non-matched items into the db as new items + for( i = 0; i < max; ++i ) + { + // skip empty and already matched entries + if( items[i].nameid == 0 || flag[i] ) + continue; + + if( found ) + StringBuf_AppendStr(&buf, ","); + else + found = true; + + StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); + StringBuf_AppendStr(&buf, ")"); + } + + if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Destroy(&buf); + aFree(flag); + + return errors; } /* pretty much a copy of memitemdata_to_sql except it handles inventory_db exclusively, * - this is required because inventory db is the only one with the 'favorite' column. */ -int inventory_to_sql(const struct item items[], int max, int id) -{ - StringBuf buf; - SqlStmt *stmt; - int i; - int j; - struct item item; // temp storage variable - bool *flag; // bit array for inventory matching - bool found; - int errors = 0; - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); - - stmt = SqlStmt_Malloc(sql_handle); - if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_Execute(stmt)) { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); - for (j = 0; j < MAX_SLOTS; ++j) - SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - // bit array indicating which inventory items have already been matched - flag = (bool *) aCalloc(max, sizeof(bool)); - - while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { - found = false; - // search for the presence of the item in the char's inventory - for (i = 0; i < max; ++i) { - // skip empty and already matched entries - if (items[i].nameid == 0 || flag[i]) - continue; - - if (items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]); - if (j == MAX_SLOTS && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time && - items[i].favorite == item.favorite) - ; //Do nothing. - else { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'", - inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if (!found) { // Item not present in inventory, remove it. - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", inventory_db, item.id)) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`", inventory_db); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for (i = 0; i < max; ++i) { - // skip empty and already matched entries - if (items[i].nameid == 0 || flag[i]) - continue; - - if (found) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); - StringBuf_AppendStr(&buf, ")"); - } - - if (found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; +int inventory_to_sql(const struct item items[], int max, int id) { + StringBuf buf; + SqlStmt* stmt; + int i; + int j; + struct item item; // temp storage variable + bool* flag; // bit array for inventory matching + bool found; + int errors = 0; + + + // The following code compares inventory with current database values + // and performs modification/deletion/insertion only on relevant rows. + // This approach is more complicated than a trivial delete&insert, but + // it significantly reduces cpu load on the database server. + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + return 1; + } + + SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); + for( j = 0; j < MAX_SLOTS; ++j ) + SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + // bit array indicating which inventory items have already been matched + flag = (bool*) aCalloc(max, sizeof(bool)); + + while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) { + found = false; + // search for the presence of the item in the char's inventory + for( i = 0; i < max; ++i ) { + // skip empty and already matched entries + if( items[i].nameid == 0 || flag[i] ) + continue; + + if( items[i].nameid == item.nameid + && items[i].card[0] == item.card[0] + && items[i].card[2] == item.card[2] + && items[i].card[3] == item.card[3] + ) { //They are the same item. + ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); + if( j == MAX_SLOTS && + items[i].amount == item.amount && + items[i].equip == item.equip && + items[i].identify == item.identify && + items[i].refine == item.refine && + items[i].attribute == item.attribute && + items[i].expire_time == item.expire_time && + items[i].favorite == item.favorite ) + ; //Do nothing. + else { + // update all fields. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'", + inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + found = flag[i] = true; //Item dealt with, + break; //skip to next item in the db. + } + } + if( !found ) {// Item not present in inventory, remove it. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", inventory_db, item.id) ) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + } + SqlStmt_Free(stmt); + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`", inventory_db); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_AppendStr(&buf, ") VALUES "); + + found = false; + // insert non-matched items into the db as new items + for( i = 0; i < max; ++i ) { + // skip empty and already matched entries + if( items[i].nameid == 0 || flag[i] ) + continue; + + if( found ) + StringBuf_AppendStr(&buf, ","); + else + found = true; + + StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); + StringBuf_AppendStr(&buf, ")"); + } + + if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Destroy(&buf); + aFree(flag); + + return errors; } -int mmo_char_tobuf(uint8 *buf, struct mmo_charstatus *p); +int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p); //===================================================================================================== // Loads the basic character rooster for the given account. Returns total buffer used. -int mmo_chars_fromsql(struct char_session_data *sd, uint8 *buf) +int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) { - SqlStmt *stmt; - struct mmo_charstatus p; - int j = 0, i; - char last_map[MAP_NAME_LENGTH_EXT]; - - stmt = SqlStmt_Malloc(sql_handle); - if (stmt == NULL) { - SqlStmt_ShowDebug(stmt); - return 0; - } - memset(&p, 0, sizeof(p)); - - // read char data - if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," - "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," - "`robe`" - " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) - ) { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - for (i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++) { - p.last_point.map = mapindex_name2id(last_map); - sd->found_char[i] = p.char_id; - j += mmo_char_tobuf(WBUFP(buf, j), &p); - } - for (; i < MAX_CHARS; i++) - sd->found_char[i] = -1; - - memset(sd->new_name,0,sizeof(sd->new_name)); - - SqlStmt_Free(stmt); - return j; + SqlStmt* stmt; + struct mmo_charstatus p; + int j = 0, i; + char last_map[MAP_NAME_LENGTH_EXT]; + + stmt = SqlStmt_Malloc(sql_handle); + if( stmt == NULL ) + { + SqlStmt_ShowDebug(stmt); + return 0; + } + memset(&p, 0, sizeof(p)); + + // read char data + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," + "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," + "`robe`" + " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) + ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + return 0; + } + for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ ) + { + p.last_point.map = mapindex_name2id(last_map); + sd->found_char[i] = p.char_id; + j += mmo_char_tobuf(WBUFP(buf, j), &p); + } + for( ; i < MAX_CHARS; i++ ) + sd->found_char[i] = -1; + + memset(sd->new_name,0,sizeof(sd->new_name)); + + SqlStmt_Free(stmt); + return j; } //===================================================================================================== -int mmo_char_fromsql(int char_id, struct mmo_charstatus *p, bool load_everything) +int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything) { - int i,j; - char t_msg[128] = ""; - struct mmo_charstatus *cp; - StringBuf buf; - SqlStmt *stmt; - char last_map[MAP_NAME_LENGTH_EXT]; - char save_map[MAP_NAME_LENGTH_EXT]; - char point_map[MAP_NAME_LENGTH_EXT]; - struct point tmp_point; - struct item tmp_item; - struct s_skill tmp_skill; - struct s_friend tmp_friend; + int i,j; + char t_msg[128] = ""; + struct mmo_charstatus* cp; + StringBuf buf; + SqlStmt* stmt; + char last_map[MAP_NAME_LENGTH_EXT]; + char save_map[MAP_NAME_LENGTH_EXT]; + char point_map[MAP_NAME_LENGTH_EXT]; + struct point tmp_point; + struct item tmp_item; + struct s_skill tmp_skill; + struct s_friend tmp_friend; #ifdef HOTKEY_SAVING - struct hotkey tmp_hotkey; - int hotkey_num; + struct hotkey tmp_hotkey; + int hotkey_num; #endif - memset(p, 0, sizeof(struct mmo_charstatus)); - - if (save_log) ShowInfo("Char load request (%d)\n", char_id); - - stmt = SqlStmt_Malloc(sql_handle); - if (stmt == NULL) { - SqlStmt_ShowDebug(stmt); - return 0; - } - - // read char data - if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," - "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," - "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" - " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->partner_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->father, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) - ) { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - if (SQL_ERROR == SqlStmt_NextRow(stmt)) { - ShowError("Requested non-existant character id: %d!\n", char_id); - SqlStmt_Free(stmt); - return 0; - } - p->last_point.map = mapindex_name2id(last_map); - p->save_point.map = mapindex_name2id(save_map); - - strcat(t_msg, " status"); - - if (!load_everything) { // For quick selection of data when displaying the char menu - SqlStmt_Free(stmt); - return 1; - } - - //read memo data - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - - for (i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) { - tmp_point.map = mapindex_name2id(point_map); - memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); - } - strcat(t_msg, " memo"); - - //read inventory - //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); - for (i = 0; i < MAX_SLOTS; ++i) - StringBuf_Printf(&buf, ", `card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); - - if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - for (i = 0; i < MAX_SLOTS; ++i) - if (SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - - for (i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) - memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); - - strcat(t_msg, " inventory"); - - //read cart - //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Clear(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); - - if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - for (i = 0; i < MAX_SLOTS; ++i) - if (SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - - for (i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) - memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); - strcat(t_msg, " cart"); - - //read storage - storage_fromsql(p->account_id, &p->storage); - strcat(t_msg, " storage"); - - //read skill - //`skill` (`char_id`, `id`, `lv`) - if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - tmp_skill.flag = SKILL_FLAG_PERMANENT; - - for (i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) { - if (tmp_skill.id < ARRAYLENGTH(p->skill)) - memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " skills"); - - //read friends - //`friends` (`char_id`, `friend_account`, `friend_id`) - if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL)) - SqlStmt_ShowDebug(stmt); - - for (i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) - memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); - strcat(t_msg, " friends"); + memset(p, 0, sizeof(struct mmo_charstatus)); + + if (save_log) ShowInfo("Char load request (%d)\n", char_id); + + stmt = SqlStmt_Malloc(sql_handle); + if( stmt == NULL ) + { + SqlStmt_ShowDebug(stmt); + return 0; + } + + // read char data + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," + "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," + "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" + " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->partner_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->father, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) + ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + return 0; + } + if( SQL_ERROR == SqlStmt_NextRow(stmt) ) + { + ShowError("Requested non-existant character id: %d!\n", char_id); + SqlStmt_Free(stmt); + return 0; + } + p->last_point.map = mapindex_name2id(last_map); + p->save_point.map = mapindex_name2id(save_map); + + strcat(t_msg, " status"); + + if (!load_everything) // For quick selection of data when displaying the char menu + { + SqlStmt_Free(stmt); + return 1; + } + + //read memo data + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + { + tmp_point.map = mapindex_name2id(point_map); + memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); + } + strcat(t_msg, " memo"); + + //read inventory + //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); + for( i = 0; i < MAX_SLOTS; ++i ) + StringBuf_Printf(&buf, ", `card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); + + if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + for( i = 0; i < MAX_SLOTS; ++i ) + if( SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); + + strcat(t_msg, " inventory"); + + //read cart + //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Clear(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); + + if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + for( i = 0; i < MAX_SLOTS; ++i ) + if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); + strcat(t_msg, " cart"); + + //read storage + storage_fromsql(p->account_id, &p->storage); + strcat(t_msg, " storage"); + + //read skill + //`skill` (`char_id`, `id`, `lv`) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + tmp_skill.flag = SKILL_FLAG_PERMANENT; + + for( i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + { + if( tmp_skill.id < ARRAYLENGTH(p->skill) ) + memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " skills"); + + //read friends + //`friends` (`char_id`, `friend_account`, `friend_id`) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); + strcat(t_msg, " friends"); #ifdef HOTKEY_SAVING - //read hotkeys - //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` - if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - - while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { - if (hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS) - memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " hotkeys"); + //read hotkeys + //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) + { + if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS ) + memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " hotkeys"); #endif - /* Mercenary Owner DataBase */ - mercenary_owner_fromsql(char_id, p); - strcat(t_msg, " mercenary"); + /* Mercenary Owner DataBase */ + mercenary_owner_fromsql(char_id, p); + strcat(t_msg, " mercenary"); - if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); + if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); - cp = idb_ensure(char_db_, char_id, create_charstatus); - memcpy(cp, p, sizeof(struct mmo_charstatus)); - return 1; + cp = idb_ensure(char_db_, char_id, create_charstatus); + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 1; } //========================================================================================================== int mmo_char_sql_init(void) { - char_db_= idb_alloc(DB_OPT_RELEASE_DATA); + char_db_= idb_alloc(DB_OPT_RELEASE_DATA); - ShowStatus("Characters per Account: '%d'.\n", char_per_account); + ShowStatus("Characters per Account: '%d'.\n", char_per_account); - //the 'set offline' part is now in check_login_conn ... - //if the server connects to loginserver - //it will dc all off players - //and send the loginserver the new state.... + //the 'set offline' part is now in check_login_conn ... + //if the server connects to loginserver + //it will dc all off players + //and send the loginserver the new state.... - // Force all users offline in sql when starting char-server - // (useful when servers crashs and don't clean the database) - set_all_offline_sql(); + // Force all users offline in sql when starting char-server + // (useful when servers crashs and don't clean the database) + set_all_offline_sql(); - return 0; + return 0; } //----------------------------------- @@ -1320,193 +1357,199 @@ int mmo_char_sql_init(void) //----------------------------------- int rename_char_sql(struct char_session_data *sd, int char_id) { - struct mmo_charstatus char_dat; - char esc_name[NAME_LENGTH*2+1]; - - if (sd->new_name[0] == 0) // Not ready for rename - return 2; - - if (!mmo_char_fromsql(char_id, &char_dat, false)) // Only the short data is needed. - return 2; - - if (char_dat.rename == 0) - return 1; - - Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); - - // check if the char exist - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name)) { - Sql_ShowDebug(sql_handle); - return 4; - } - - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id)) { - Sql_ShowDebug(sql_handle); - return 3; - } - - // Change character's name into guild_db. - if (char_dat.guild_id) - inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); - - safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); - memset(sd->new_name,0,sizeof(sd->new_name)); - - // log change - if (log_char) { - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", - charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name)) - Sql_ShowDebug(sql_handle); - } - - return 0; + struct mmo_charstatus char_dat; + char esc_name[NAME_LENGTH*2+1]; + + if( sd->new_name[0] == 0 ) // Not ready for rename + return 2; + + if( !mmo_char_fromsql(char_id, &char_dat, false) ) // Only the short data is needed. + return 2; + + if( char_dat.rename == 0 ) + return 1; + + Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); + + // check if the char exist + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name) ) + { + Sql_ShowDebug(sql_handle); + return 4; + } + + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 3; + } + + // Change character's name into guild_db. + if( char_dat.guild_id ) + inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); + + safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); + memset(sd->new_name,0,sizeof(sd->new_name)); + + // log change + if( log_char ) + { + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", + charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) + Sql_ShowDebug(sql_handle); + } + + return 0; } -int check_char_name(char *name, char *esc_name) +int check_char_name(char * name, char * esc_name) { - int i; - - // check length of character name - if (name[0] == '\0') - return -2; // empty character name - /** - * The client does not allow you to create names with less than 4 characters, however, - * the use of WPE can bypass this, and this fixes the exploit. - **/ - if (strlen(name) < 4) - return -2; - // check content of character name - if (remove_control_chars(name)) - return -2; // control chars in name - - // check for reserved names - if (strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0) - return -1; // nick reserved for internal server messages - - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { - // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) - return -2; - } else if (char_name_option == 2) { - // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) - return -2; - } - if (name_ignoring_case) { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name)) { - Sql_ShowDebug(sql_handle); - return -2; - } - } else { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name)) { - Sql_ShowDebug(sql_handle); - return -2; - } - } - if (Sql_NumRows(sql_handle) > 0) - return -1; // name already exists - - return 0; + int i; + + // check length of character name + if( name[0] == '\0' ) + return -2; // empty character name + /** + * The client does not allow you to create names with less than 4 characters, however, + * the use of WPE can bypass this, and this fixes the exploit. + **/ + if( strlen( name ) < 4 ) + return -2; + // check content of character name + if( remove_control_chars(name) ) + return -2; // control chars in name + + // check for reserved names + if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 ) + return -1; // nick reserved for internal server messages + + // Check Authorised letters/symbols in the name of the character + if( char_name_option == 1 ) + { // only letters/symbols in char_name_letters are authorised + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) == NULL ) + return -2; + } + else if( char_name_option == 2 ) + { // letters/symbols in char_name_letters are forbidden + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) != NULL ) + return -2; + } + if( name_ignoring_case ) { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name) ) { + Sql_ShowDebug(sql_handle); + return -2; + } + } else { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name) ) { + Sql_ShowDebug(sql_handle); + return -2; + } + } + if( Sql_NumRows(sql_handle) > 0 ) + return -1; // name already exists + + return 0; } //----------------------------------- // Function to create a new character //----------------------------------- #if PACKETVER >= 20120307 -int make_new_char_sql(struct char_session_data *sd, char *name_, int slot, int hair_color, int hair_style) -{ - int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1; +int make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style) { + int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1; #else -int make_new_char_sql(struct char_session_data *sd, char *name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) -{ +int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) { #endif - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - int char_id, flag; + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + int char_id, flag; - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + safestrncpy(name, name_, NAME_LENGTH); + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - flag = check_char_name(name,esc_name); - if (flag < 0) - return flag; + flag = check_char_name(name,esc_name); + if( flag < 0 ) + return flag; - //check other inputs + //check other inputs #if PACKETVER >= 20120307 - if (slot >= MAX_CHARS) + if(slot >= MAX_CHARS) #else - if ((slot >= MAX_CHARS) // slots - || (str + agi + vit + int_ + dex + luk != 6*5) // stats - || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values - || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10)) // pairs + if((slot >= MAX_CHARS) // slots + || (str + agi + vit + int_ + dex + luk != 6*5 ) // stats + || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values + || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs #endif - return -2; // invalid input - - - // check the number of already existing chars in this account - if (char_per_account != 0) { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id)) - Sql_ShowDebug(sql_handle); - if (Sql_NumRows(sql_handle) >= char_per_account) - return -2; // character account limit exceeded - } - - // check char slot - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot)) - Sql_ShowDebug(sql_handle); - if (Sql_NumRows(sql_handle) > 0) - return -2; // slot already in use - - // validation success, log result - if (log_char) { - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color)) - Sql_ShowDebug(sql_handle); - } + return -2; // invalid input + + if (hair_style > 17 || hair_color > 8) + return -2; + + // check the number of already existing chars in this account + if( char_per_account != 0 ) { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) + Sql_ShowDebug(sql_handle); + if( Sql_NumRows(sql_handle) >= char_per_account ) + return -2; // character account limit exceeded + } + + // check char slot + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) ) + Sql_ShowDebug(sql_handle); + if( Sql_NumRows(sql_handle) > 0 ) + return -2; // slot already in use + + // validation success, log result + if (log_char) { + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) ) + Sql_ShowDebug(sql_handle); + } #if PACKETVER >= 20120307 - //Insert the new char entry to the database - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y)) { - Sql_ShowDebug(sql_handle); - return -2; //No, stop the procedure! - } + //Insert the new char entry to the database + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) + { + Sql_ShowDebug(sql_handle); + return -2; //No, stop the procedure! + } #else - //Insert the new char entry to the database - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y)) { - Sql_ShowDebug(sql_handle); - return -2; //No, stop the procedure! - } + //Insert the new char entry to the database + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) + { + Sql_ShowDebug(sql_handle); + return -2; //No, stop the procedure! + } #endif - //Retrieve the newly auto-generated char id - char_id = (int)Sql_LastInsertId(sql_handle); - //Give the char the default items - if (start_weapon > 0) { //add Start Weapon (Knife?) - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1)) - Sql_ShowDebug(sql_handle); - } - if (start_armor > 0) { //Add default armor (cotton shirt?) - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1)) - Sql_ShowDebug(sql_handle); - } - - ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); - return char_id; + //Retrieve the newly auto-generated char id + char_id = (int)Sql_LastInsertId(sql_handle); + //Give the char the default items + if (start_weapon > 0) { //add Start Weapon (Knife?) + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1) ) + Sql_ShowDebug(sql_handle); + } + if (start_armor > 0) { //Add default armor (cotton shirt?) + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1) ) + Sql_ShowDebug(sql_handle); + } + + ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); + return char_id; } /*----------------------------------------------------------------------------------------------------------*/ @@ -1514,19 +1557,19 @@ int make_new_char_sql(struct char_session_data *sd, char *name_, int str, int ag /*----------------------------------------------------------------------------------------------------------*/ int divorce_char_sql(int partner_id1, int partner_id2) { - unsigned char buf[64]; + unsigned char buf[64]; - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2)) - Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2) ) + Sql_ShowDebug(sql_handle); - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = partner_id1; - WBUFL(buf,6) = partner_id2; - mapif_sendall(buf,10); + WBUFW(buf,0) = 0x2b12; + WBUFL(buf,2) = partner_id1; + WBUFL(buf,6) = partner_id2; + mapif_sendall(buf,10); - return 0; + return 0; } /*----------------------------------------------------------------------------------------------------------*/ @@ -1537,169 +1580,151 @@ int divorce_char_sql(int partner_id1, int partner_id2) */ int delete_char_sql(int char_id) { - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. - int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id, elemental_id; - char *data; - size_t len; - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother`,`elemental_id` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) - Sql_ShowDebug(sql_handle); - - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { - ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); - Sql_FreeResult(sql_handle); - return -1; - } - - Sql_GetData(sql_handle, 0, &data, &len); - safestrncpy(name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 1, &data, NULL); - account_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - party_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - guild_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - base_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - hom_id = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - partner_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - father_id = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); - mother_id = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - elemental_id = atoi(data); - - Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); - Sql_FreeResult(sql_handle); - - //check for config char del condition [Lupus] - // TODO: Move this out to packet processing (0x68/0x1fb). - if ((char_del_level > 0 && base_level >= char_del_level) - || (char_del_level < 0 && base_level <= -char_del_level) - ) { - ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); - return -1; - } - - /* Divorce [Wizputer] */ - if (partner_id) - divorce_char_sql(char_id, partner_id); - - /* De-addopt [Zephyrus] */ - if (father_id || mother_id) { - // Char is Baby - unsigned char buf[64]; - - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id)) - Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id)) - Sql_ShowDebug(sql_handle); - - WBUFW(buf,0) = 0x2b25; - WBUFL(buf,2) = father_id; - WBUFL(buf,6) = mother_id; - WBUFL(buf,10) = char_id; // Baby - mapif_sendall(buf,14); - } - - //Make the character leave the party [Skotlex] - if (party_id) - inter_party_leave(party_id, account_id, char_id); - - /* delete char's pet */ - //Delete the hatched pet if you have one... - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id)) - Sql_ShowDebug(sql_handle); - - //Delete all pets that are stored in eggs (inventory + cart) - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id)) - Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* remove homunculus */ - if (hom_id) - mapif_homunculus_delete(hom_id); - - /* remove elemental */ - if (elemental_id) - mapif_elemental_delete(elemental_id); - - /* remove mercenary data */ - mercenary_owner_delete(char_id); - - /* delete char's friends list */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* delete char from other's friend list */ - //NOTE: Won't this cause problems for people who are already online? [Skotlex] - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id)) - Sql_ShowDebug(sql_handle); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. + int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id; + char* data; + size_t len; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); + Sql_FreeResult(sql_handle); + return -1; + } + + Sql_GetData(sql_handle, 0, &data, &len); safestrncpy(name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 1, &data, NULL); account_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); party_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); guild_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); hom_id = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); partner_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); father_id = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); mother_id = atoi(data); + + Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); + Sql_FreeResult(sql_handle); + + //check for config char del condition [Lupus] + // TODO: Move this out to packet processing (0x68/0x1fb). + if( ( char_del_level > 0 && base_level >= char_del_level ) + || ( char_del_level < 0 && base_level <= -char_del_level ) + ) { + ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); + return -1; + } + + /* Divorce [Wizputer] */ + if( partner_id ) + divorce_char_sql(char_id, partner_id); + + /* De-addopt [Zephyrus] */ + if( father_id || mother_id ) + { // Char is Baby + unsigned char buf[64]; + + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id) ) + Sql_ShowDebug(sql_handle); + + WBUFW(buf,0) = 0x2b25; + WBUFL(buf,2) = father_id; + WBUFL(buf,6) = mother_id; + WBUFL(buf,10) = char_id; // Baby + mapif_sendall(buf,14); + } + + //Make the character leave the party [Skotlex] + if (party_id) + inter_party_leave(party_id, account_id, char_id); + + /* delete char's pet */ + //Delete the hatched pet if you have one... + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id) ) + Sql_ShowDebug(sql_handle); + + //Delete all pets that are stored in eggs (inventory + cart) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* remove homunculus */ + if( hom_id ) + mapif_homunculus_delete(hom_id); + + /* remove mercenary data */ + mercenary_owner_delete(char_id); + + /* delete char's friends list */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete char from other's friend list */ + //NOTE: Won't this cause problems for people who are already online? [Skotlex] + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id) ) + Sql_ShowDebug(sql_handle); #ifdef HOTKEY_SAVING - /* delete hotkeys */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id)) - Sql_ShowDebug(sql_handle); + /* delete hotkeys */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id) ) + Sql_ShowDebug(sql_handle); #endif - /* delete inventory */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* delete cart inventory */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* delete memo areas */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* delete character registry */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* delete skills */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* delete mails (only received) */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `dest_id`='%d'", mail_db, char_id)) - Sql_ShowDebug(sql_handle); - + /* delete inventory */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete cart inventory */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete memo areas */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete character registry */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete skills */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id) ) + Sql_ShowDebug(sql_handle); + #ifdef ENABLE_SC_SAVING - /* status changes */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id)) - Sql_ShowDebug(sql_handle); + /* status changes */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id) ) + Sql_ShowDebug(sql_handle); #endif - if (log_char) { - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", - charlog_db, account_id, 0, char_id, esc_name)) - Sql_ShowDebug(sql_handle); - } - - /* delete character */ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) - Sql_ShowDebug(sql_handle); - - /* No need as we used inter_guild_leave [Skotlex] - // Also delete info from guildtables. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) - Sql_ShowDebug(sql_handle); - */ - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id)) - Sql_ShowDebug(sql_handle); - else if (Sql_NumRows(sql_handle) > 0) - mapif_parse_BreakGuild(0,guild_id); - else if (guild_id) - inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. - return 0; + if (log_char) { + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", + charlog_db, account_id, 0, char_id, esc_name) ) + Sql_ShowDebug(sql_handle); + } + + /* delete character */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* No need as we used inter_guild_leave [Skotlex] + // Also delete info from guildtables. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) + Sql_ShowDebug(sql_handle); + */ + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id) ) + Sql_ShowDebug(sql_handle); + else if( Sql_NumRows(sql_handle) > 0 ) + mapif_parse_BreakGuild(0,guild_id); + else if( guild_id ) + inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. + return 0; } //--------------------------------------------------------------------- @@ -1707,187 +1732,190 @@ int delete_char_sql(int char_id) //--------------------------------------------------------------------- int count_users(void) { - int i, users; - - users = 0; - for (i = 0; i < ARRAYLENGTH(server); i++) { - if (server[i].fd > 0) { - users += server[i].users; - } - } - return users; + int i, users; + + users = 0; + for(i = 0; i < ARRAYLENGTH(server); i++) { + if (server[i].fd > 0) { + users += server[i].users; + } + } + return users; } // Writes char data to the buffer in the format used by the client. // Used in packets 0x6b (chars info) and 0x6d (new char info) // Returns the size #define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls) -int mmo_char_tobuf(uint8 *buffer, struct mmo_charstatus *p) +int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) { - unsigned short offset = 0; - uint8 *buf; - - if (buffer == NULL || p == NULL) - return 0; - - buf = WBUFP(buffer,0); - WBUFL(buf,0) = p->char_id; - WBUFL(buf,4) = min(p->base_exp, INT32_MAX); - WBUFL(buf,8) = p->zeny; - WBUFL(buf,12) = min(p->job_exp, INT32_MAX); - WBUFL(buf,16) = p->job_level; - WBUFL(buf,20) = 0; // probably opt1 - WBUFL(buf,24) = 0; // probably opt2 - WBUFL(buf,28) = p->option; - WBUFL(buf,32) = p->karma; - WBUFL(buf,36) = p->manner; - WBUFW(buf,40) = min(p->status_point, INT16_MAX); - WBUFL(buf,42) = p->hp; - WBUFL(buf,46) = p->max_hp; - offset+=4; - buf = WBUFP(buffer,offset); - WBUFW(buf,46) = min(p->sp, INT16_MAX); - WBUFW(buf,48) = min(p->max_sp, INT16_MAX); - WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; - WBUFW(buf,52) = p->class_; - WBUFW(buf,54) = p->hair; - - //When the weapon is sent and your option is riding, the client crashes on login!? - WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; - - WBUFW(buf,58) = p->base_level; - WBUFW(buf,60) = min(p->skill_point, INT16_MAX); - WBUFW(buf,62) = p->head_bottom; - WBUFW(buf,64) = p->shield; - WBUFW(buf,66) = p->head_top; - WBUFW(buf,68) = p->head_mid; - WBUFW(buf,70) = p->hair_color; - WBUFW(buf,72) = p->clothes_color; - memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); - WBUFB(buf,98) = min(p->str, UINT8_MAX); - WBUFB(buf,99) = min(p->agi, UINT8_MAX); - WBUFB(buf,100) = min(p->vit, UINT8_MAX); - WBUFB(buf,101) = min(p->int_, UINT8_MAX); - WBUFB(buf,102) = min(p->dex, UINT8_MAX); - WBUFB(buf,103) = min(p->luk, UINT8_MAX); - WBUFW(buf,104) = p->slot; - WBUFW(buf,106) = (p->rename > 0) ? 0 : 1; - offset += 2; + unsigned short offset = 0; + uint8* buf; + + if( buffer == NULL || p == NULL ) + return 0; + + buf = WBUFP(buffer,0); + WBUFL(buf,0) = p->char_id; + WBUFL(buf,4) = min(p->base_exp, INT32_MAX); + WBUFL(buf,8) = p->zeny; + WBUFL(buf,12) = min(p->job_exp, INT32_MAX); + WBUFL(buf,16) = p->job_level; + WBUFL(buf,20) = 0; // probably opt1 + WBUFL(buf,24) = 0; // probably opt2 + WBUFL(buf,28) = p->option; + WBUFL(buf,32) = p->karma; + WBUFL(buf,36) = p->manner; + WBUFW(buf,40) = min(p->status_point, INT16_MAX); + WBUFL(buf,42) = p->hp; + WBUFL(buf,46) = p->max_hp; + offset+=4; + buf = WBUFP(buffer,offset); + WBUFW(buf,46) = min(p->sp, INT16_MAX); + WBUFW(buf,48) = min(p->max_sp, INT16_MAX); + WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; + WBUFW(buf,52) = p->class_; + WBUFW(buf,54) = p->hair; + + //When the weapon is sent and your option is riding, the client crashes on login!? + WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; + + WBUFW(buf,58) = p->base_level; + WBUFW(buf,60) = min(p->skill_point, INT16_MAX); + WBUFW(buf,62) = p->head_bottom; + WBUFW(buf,64) = p->shield; + WBUFW(buf,66) = p->head_top; + WBUFW(buf,68) = p->head_mid; + WBUFW(buf,70) = p->hair_color; + WBUFW(buf,72) = p->clothes_color; + memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); + WBUFB(buf,98) = min(p->str, UINT8_MAX); + WBUFB(buf,99) = min(p->agi, UINT8_MAX); + WBUFB(buf,100) = min(p->vit, UINT8_MAX); + WBUFB(buf,101) = min(p->int_, UINT8_MAX); + WBUFB(buf,102) = min(p->dex, UINT8_MAX); + WBUFB(buf,103) = min(p->luk, UINT8_MAX); + WBUFW(buf,104) = p->slot; + WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1; + offset += 2; #if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803 - mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char *)WBUFP(buf,108)); - offset += MAP_NAME_LENGTH_EXT; + mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108)); + offset += MAP_NAME_LENGTH_EXT; #endif #if PACKETVER >= 20100803 - WBUFL(buf,124) = TOL(p->delete_date); - offset += 4; + WBUFL(buf,124) = TOL(p->delete_date); + offset += 4; #endif #if PACKETVER >= 20110111 - WBUFL(buf,128) = p->robe; - offset += 4; + WBUFL(buf,128) = p->robe; + offset += 4; #endif #if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity. -#if PACKETVER >= 20110928 - WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) - offset += 4; -#endif -#if PACKETVER >= 20111025 - WBUFL(buf,136) = (p->rename > 0) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar) - offset += 4; -#endif + #if PACKETVER >= 20110928 + WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) + offset += 4; + #endif + #if PACKETVER >= 20111025 + WBUFL(buf,136) = ( p->rename > 0 ) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar) + offset += 4; + #endif #endif - return 106+offset; + return 106+offset; } //---------------------------------------- // Function to send characters to a player //---------------------------------------- -int mmo_char_send006b(int fd, struct char_session_data *sd) +int mmo_char_send006b(int fd, struct char_session_data* sd) { - int j, offset = 0; + int j, offset = 0; #if PACKETVER >= 20100413 - offset += 3; + offset += 3; #endif - if (save_log) - ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); + if (save_log) + ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); - j = 24 + offset; // offset - WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6b; + j = 24 + offset; // offset + WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); + WFIFOW(fd,0) = 0x6b; #if PACKETVER >= 20100413 - WFIFOB(fd,4) = MAX_CHARS; // Max slots. - WFIFOB(fd,5) = MAX_CHARS; // Available slots. - WFIFOB(fd,6) = MAX_CHARS; // Premium slots. + WFIFOB(fd,4) = MAX_CHARS; // Max slots. + WFIFOB(fd,5) = MAX_CHARS; // Available slots. + WFIFOB(fd,6) = MAX_CHARS; // Premium slots. #endif - memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes - j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); - WFIFOW(fd,2) = j; // packet len - WFIFOSET(fd,j); + memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes + j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); + WFIFOW(fd,2) = j; // packet len + WFIFOSET(fd,j); - return 0; + return 0; } int char_married(int pl1, int pl2) { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1)) - Sql_ShowDebug(sql_handle); - else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if (pl2 == atoi(data)) { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + if( pl2 == atoi(data) ) + { + Sql_FreeResult(sql_handle); + return 1; + } + } + Sql_FreeResult(sql_handle); + return 0; } int char_child(int parent_id, int child_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id)) - Sql_ShowDebug(sql_handle); - else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if (child_id == atoi(data)) { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + if( child_id == atoi(data) ) + { + Sql_FreeResult(sql_handle); + return 1; + } + } + Sql_FreeResult(sql_handle); + return 0; } int char_family(int cid1, int cid2, int cid3) { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3)) - Sql_ShowDebug(sql_handle); - else while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - int charid; - int partnerid; - int childid; - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - charid = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - partnerid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - childid = atoi(data); - - if ((cid1 == charid && ((cid2 == partnerid && cid3 == childid) || (cid2 == childid && cid3 == partnerid))) || - (cid1 == partnerid && ((cid2 == charid && cid3 == childid) || (cid2 == childid && cid3 == charid))) || - (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid)))) { - Sql_FreeResult(sql_handle); - return childid; - } - } - Sql_FreeResult(sql_handle); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) ) + Sql_ShowDebug(sql_handle); + else while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + int charid; + int partnerid; + int childid; + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); charid = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); partnerid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); childid = atoi(data); + + if( (cid1 == charid && ((cid2 == partnerid && cid3 == childid ) || (cid2 == childid && cid3 == partnerid))) || + (cid1 == partnerid && ((cid2 == charid && cid3 == childid ) || (cid2 == childid && cid3 == charid ))) || + (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid ))) ) + { + Sql_FreeResult(sql_handle); + return childid; + } + } + Sql_FreeResult(sql_handle); + return 0; } //---------------------------------------------------------------------- @@ -1895,58 +1923,58 @@ int char_family(int cid1, int cid2, int cid3) //---------------------------------------------------------------------- void disconnect_player(int account_id) { - int i; - struct char_session_data *sd; + int i; + struct char_session_data* sd; - // disconnect player if online on char-server - ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data *)session[i]->session_data) && sd->account_id == account_id); - if (i < fd_max) - set_eof(i); + // disconnect player if online on char-server + ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id ); + if( i < fd_max ) + set_eof(i); } static void char_auth_ok(int fd, struct char_session_data *sd) { - struct online_char_data *character; - - if ((character = (struct online_char_data *)idb_get(online_char_db, sd->account_id)) != NULL) { - // check if character is not online already. [Skotlex] - if (character->server > -1) { - //Character already online. KICK KICK KICK - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - if (character->fd >= 0 && character->fd != fd) { - //There's already a connection from this account that hasn't picked a char yet. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - character->fd = fd; - } - - if (login_fd > 0) { - // request account data - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2716; - WFIFOL(login_fd,2) = sd->account_id; - WFIFOSET(login_fd,6); - } - - // mark session as 'authed' - sd->auth = true; - - // set char online on charserver - set_char_charselect(sd->account_id); - - // continues when account data is received... + struct online_char_data* character; + + if( (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) + { // check if character is not online already. [Skotlex] + if (character->server > -1) + { //Character already online. KICK KICK KICK + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == INVALID_TIMER) + character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + if (character->fd >= 0 && character->fd != fd) + { //There's already a connection from this account that hasn't picked a char yet. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + character->fd = fd; + } + + if (login_fd > 0) { + // request account data + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2716; + WFIFOL(login_fd,2) = sd->account_id; + WFIFOSET(login_fd,6); + } + + // mark session as 'authed' + sd->auth = true; + + // set char online on charserver + set_char_charselect(sd->account_id); + + // continues when account data is received... } int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); @@ -1956,12 +1984,12 @@ void mapif_server_reset(int id); /// Resets all the data. void loginif_reset(void) { - int id; - // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] - for (id = 0; id < ARRAYLENGTH(server); ++id) - mapif_server_reset(id); - flush_fifos(); - exit(EXIT_FAILURE); + int id; + // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] + for( id = 0; id < ARRAYLENGTH(server); ++id ) + mapif_server_reset(id); + flush_fifos(); + exit(EXIT_FAILURE); } @@ -1970,361 +1998,366 @@ void loginif_reset(void) /// If all the conditions are met, it stops the core loop. void loginif_check_shutdown(void) { - if (runflag != CHARSERVER_ST_SHUTDOWN) - return; - runflag = CORE_ST_STOP; + if( runflag != CHARSERVER_ST_SHUTDOWN ) + return; + runflag = CORE_ST_STOP; } /// Called when the connection to Login Server is disconnected. void loginif_on_disconnect(void) { - ShowWarning("Connection to Login Server lost.\n\n"); + ShowWarning("Connection to Login Server lost.\n\n"); } /// Called when all the connection steps are completed. void loginif_on_ready(void) { - int i; + int i; - loginif_check_shutdown(); + loginif_check_shutdown(); + + //Send online accounts to login server. + send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); - //Send online accounts to login server. - send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); - - // if no map-server already connected, display a message... - ARR_FIND(0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0]); - if (i == ARRAYLENGTH(server)) - ShowStatus("Awaiting maps from map-server.\n"); + // if no map-server already connected, display a message... + ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0] ); + if( i == ARRAYLENGTH(server) ) + ShowStatus("Awaiting maps from map-server.\n"); } -int parse_fromlogin(int fd) -{ - struct char_session_data *sd = NULL; - int i; - - // only process data from the login-server - if (fd != login_fd) { - ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); - do_close(fd); - return 0; - } - - if (session[fd]->flag.eof) { - do_close(fd); - login_fd = -1; - loginif_on_disconnect(); - return 0; - } else if (session[fd]->flag.ping) { /* we've reached stall time */ - if (DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2)) { /* we can't wait any longer */ - set_eof(fd); - return 0; - } else if (session[fd]->flag.ping != 2) { /* we haven't sent ping out yet */ - WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) - WFIFOW(fd,0) = 0x2719; - WFIFOSET(fd,2); - - session[fd]->flag.ping = 2; - } - } - - sd = (struct char_session_data *)session[fd]->session_data; - - while (RFIFOREST(fd) >= 2) { - uint16 command = RFIFOW(fd,0); - - switch (command) { - - // acknowledgement of connect-to-loginserver request - case 0x2711: - if (RFIFOREST(fd) < 3) - return 0; - - if (RFIFOB(fd,2)) { - //printf("connect login server error : %d\n", RFIFOB(fd,2)); - ShowError("Can not connect to login-server.\n"); - ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); - ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); - ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); - set_eof(fd); - return 0; - } else { - ShowStatus("Connected to login-server (connection #%d).\n", fd); - loginif_on_ready(); - } - RFIFOSKIP(fd,3); - break; - - // acknowledgement of account authentication request - case 0x2713: - if (RFIFOREST(fd) < 25) - return 0; - { - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint8 sex = RFIFOB(fd,14); - uint8 result = RFIFOB(fd,15); - int request_id = RFIFOL(fd,16); - uint32 version = RFIFOL(fd,20); - uint8 clienttype = RFIFOB(fd,24); - RFIFOSKIP(fd,25); - - if (session_isActive(request_id) && (sd=(struct char_session_data *)session[request_id]->session_data) && - !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex) { - int client_fd = request_id; - sd->version = version; - sd->clienttype = clienttype; - switch (result) { - case 0:// ok - char_auth_ok(client_fd, sd); - break; - case 1:// auth failed - WFIFOHEAD(client_fd,3); - WFIFOW(client_fd,0) = 0x6c; - WFIFOB(client_fd,2) = 0;// rejected from server - WFIFOSET(client_fd,3); - break; - } - } - } - break; - - case 0x2717: // account data - if (RFIFOREST(fd) < 62) - return 0; - - // find the authenticated session with this account id - ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data *)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2)); - if (i < fd_max) { - int server_id; - memcpy(sd->email, RFIFOP(fd,6), 40); - sd->expiration_time = (time_t)RFIFOL(fd,46); - sd->group_id = RFIFOB(fd,50); - safestrncpy(sd->birthdate, (const char *)RFIFOP(fd,51), sizeof(sd->birthdate)); - ARR_FIND(0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0]); - // continued from char_auth_ok... - if (server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 - (max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group)) { - // refuse connection (over populated) - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x6c; - WFIFOW(i,2) = 0; - WFIFOSET(i,3); - } else { - // send characters to player - mmo_char_send006b(i, sd); +int parse_fromlogin(int fd) { + struct char_session_data* sd = NULL; + int i; + + // only process data from the login-server + if( fd != login_fd ) { + ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); + do_close(fd); + return 0; + } + + if( session[fd]->flag.eof ) { + do_close(fd); + login_fd = -1; + loginif_on_disconnect(); + return 0; + } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ + if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ + set_eof(fd); + return 0; + } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ + WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) + WFIFOW(fd,0) = 0x2719; + WFIFOSET(fd,2); + + session[fd]->flag.ping = 2; + } + } + + sd = (struct char_session_data*)session[fd]->session_data; + + while(RFIFOREST(fd) >= 2) { + uint16 command = RFIFOW(fd,0); + + switch( command ) + { + + // acknowledgement of connect-to-loginserver request + case 0x2711: + if (RFIFOREST(fd) < 3) + return 0; + + if (RFIFOB(fd,2)) { + //printf("connect login server error : %d\n", RFIFOB(fd,2)); + ShowError("Can not connect to login-server.\n"); + ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); + ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); + ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); + set_eof(fd); + return 0; + } else { + ShowStatus("Connected to login-server (connection #%d).\n", fd); + loginif_on_ready(); + } + RFIFOSKIP(fd,3); + break; + + // acknowledgement of account authentication request + case 0x2713: + if (RFIFOREST(fd) < 25) + return 0; + { + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint8 sex = RFIFOB(fd,14); + uint8 result = RFIFOB(fd,15); + int request_id = RFIFOL(fd,16); + uint32 version = RFIFOL(fd,20); + uint8 clienttype = RFIFOB(fd,24); + RFIFOSKIP(fd,25); + + if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) && + !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex ) + { + int client_fd = request_id; + sd->version = version; + sd->clienttype = clienttype; + switch( result ) + { + case 0:// ok + char_auth_ok(client_fd, sd); + break; + case 1:// auth failed + WFIFOHEAD(client_fd,3); + WFIFOW(client_fd,0) = 0x6c; + WFIFOB(client_fd,2) = 0;// rejected from server + WFIFOSET(client_fd,3); + break; + } + } + } + break; + + case 0x2717: // account data + if (RFIFOREST(fd) < 62) + return 0; + + // find the authenticated session with this account id + ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) ); + if( i < fd_max ) + { + int server_id; + memcpy(sd->email, RFIFOP(fd,6), 40); + sd->expiration_time = (time_t)RFIFOL(fd,46); + sd->group_id = RFIFOB(fd,50); + safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,51), sizeof(sd->birthdate)); + ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); + // continued from char_auth_ok... + if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 + ( max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) { + // refuse connection (over populated) + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x6c; + WFIFOW(i,2) = 0; + WFIFOSET(i,3); + } else { + // send characters to player + mmo_char_send006b(i, sd); #if PACKETVER >= 20110309 - // PIN code system, disabled - WFIFOHEAD(i, 12); - WFIFOW(i, 0) = 0x08B9; - WFIFOW(i, 2) = 0; - WFIFOW(i, 4) = 0; - WFIFOL(i, 6) = sd->account_id; - WFIFOW(i, 10) = 0; - WFIFOSET(i, 12); + // PIN code system, disabled + WFIFOHEAD(i, 12); + WFIFOW(i, 0) = 0x08B9; + WFIFOW(i, 2) = 0; + WFIFOW(i, 4) = 0; + WFIFOL(i, 6) = sd->account_id; + WFIFOW(i, 10) = 0; + WFIFOSET(i, 12); #endif - } - } - RFIFOSKIP(fd,62); - break; - - // login-server alive packet - case 0x2718: - if (RFIFOREST(fd) < 2) - return 0; - RFIFOSKIP(fd,2); - session[fd]->flag.ping = 0; - break; - - // changesex reply - case 0x2723: - if (RFIFOREST(fd) < 7) - return 0; - { - unsigned char buf[7]; - - int acc = RFIFOL(fd,2); - int sex = RFIFOB(fd,6); - RFIFOSKIP(fd,7); - - if (acc > 0) { - // TODO: Is this even possible? - int char_id[MAX_CHARS]; - int class_[MAX_CHARS]; - int guild_id[MAX_CHARS]; - int num; - char *data; - - struct auth_node *node = (struct auth_node *)idb_get(auth_db, acc); - if (node != NULL) - node->sex = sex; - - // get characters - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc)) - Sql_ShowDebug(sql_handle); - for (i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - Sql_GetData(sql_handle, 0, &data, NULL); - char_id[i] = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - class_[i] = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - guild_id[i] = atoi(data); - } - num = i; - for (i = 0; i < num; ++i) { - if (class_[i] == JOB_BARD || class_[i] == JOB_DANCER || - class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || - class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || - class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER || - class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T || - class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER || - class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO) { - // job modification - if (class_[i] == JOB_BARD || class_[i] == JOB_DANCER) - class_[i] = (sex ? JOB_BARD : JOB_DANCER); - else if (class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY) - class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); - else if (class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER) - class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); - else if (class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER) - class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); - else if (class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T) - class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); - else if (class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER) - class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); - else if (class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO) - class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO); - } - - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i])) - Sql_ShowDebug(sql_handle); - - if (guild_id[i]) // If there is a guild, update the guild_member data [Skotlex] - inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); - } - Sql_FreeResult(sql_handle); - - // disconnect player if online on char-server - disconnect_player(acc); - } - - // notify all mapservers about this change - WBUFW(buf,0) = 0x2b0d; - WBUFL(buf,2) = acc; - WBUFB(buf,6) = sex; - mapif_sendall(buf, 7); - } - break; - - // reply to an account_reg2 registry request - case 0x2729: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - { - //Receive account_reg2 registry, forward to map servers. - unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)]; - memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] - mapif_sendall(buf, WBUFW(buf,2)); - RFIFOSKIP(fd, RFIFOW(fd,2)); - } - break; - - // State change of account/ban notification (from login-server) - case 0x2731: - if (RFIFOREST(fd) < 11) - return 0; - - { - // send to all map-servers to disconnect the player - unsigned char buf[11]; - WBUFW(buf,0) = 0x2b14; - WBUFL(buf,2) = RFIFOL(fd,2); - WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban - WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment - mapif_sendall(buf, 11); - } - // disconnect player if online on char-server - disconnect_player(RFIFOL(fd,2)); - - RFIFOSKIP(fd,11); - break; - - // Login server request to kick a character out. [Skotlex] - case 0x2734: - if (RFIFOREST(fd) < 6) - return 0; - { - int aid = RFIFOL(fd,2); - struct online_char_data *character = (struct online_char_data *)idb_get(online_char_db, aid); - RFIFOSKIP(fd,6); - if (character != NULL) { - // account is already marked as online! - if (character->server > -1) { - //Kick it from the map server it is on. - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); - } else { - // Manual kick from char server. - struct char_session_data *tsd; - int i; - ARR_FIND(0, fd_max, i, session[i] && (tsd = (struct char_session_data *)session[i]->session_data) && tsd->account_id == aid); - if (i < fd_max) { - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x81; - WFIFOB(i,2) = 2; // "Someone has already logged in with this id" - WFIFOSET(i,3); - set_eof(i); - } else // still moving to the map-server - set_char_offline(-1, aid); - } - } - idb_remove(auth_db, aid);// reject auth attempts from map-server - } - break; - - // ip address update signal from login server - case 0x2735: { - unsigned char buf[2]; - uint32 new_ip = 0; - - WBUFW(buf,0) = 0x2b1e; - mapif_sendall(buf, 2); - - new_ip = host2ip(login_ip_str); - if (new_ip && new_ip != login_ip) - login_ip = new_ip; //Update login ip, too. - - new_ip = host2ip(char_ip_str); - if (new_ip && new_ip != char_ip) { - //Update ip. - char_ip = new_ip; - ShowInfo("Updating IP for [%s].\n", char_ip_str); - // notify login server about the change - WFIFOHEAD(fd,6); - WFIFOW(fd,0) = 0x2736; - WFIFOL(fd,2) = htonl(char_ip); - WFIFOSET(fd,6); - } - - RFIFOSKIP(fd,2); - } - break; - - default: - ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; + } + } + RFIFOSKIP(fd,62); + break; + + // login-server alive packet + case 0x2718: + if (RFIFOREST(fd) < 2) + return 0; + RFIFOSKIP(fd,2); + session[fd]->flag.ping = 0; + break; + + // changesex reply + case 0x2723: + if (RFIFOREST(fd) < 7) + return 0; + { + unsigned char buf[7]; + + int acc = RFIFOL(fd,2); + int sex = RFIFOB(fd,6); + RFIFOSKIP(fd,7); + + if( acc > 0 ) + {// TODO: Is this even possible? + int char_id[MAX_CHARS]; + int class_[MAX_CHARS]; + int guild_id[MAX_CHARS]; + int num; + char* data; + + struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); + if( node != NULL ) + node->sex = sex; + + // get characters + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data); + } + num = i; + for( i = 0; i < num; ++i ) + { + if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER || + class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || + class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || + class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER || + class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T || + class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER || + class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO ) + { + // job modification + if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ) + class_[i] = (sex ? JOB_BARD : JOB_DANCER); + else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ) + class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); + else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ) + class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); + else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ) + class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); + else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ) + class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); + else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ) + class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); + else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO ) + class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO); + } + + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) ) + Sql_ShowDebug(sql_handle); + + if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex] + inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); + } + Sql_FreeResult(sql_handle); + + // disconnect player if online on char-server + disconnect_player(acc); + } + + // notify all mapservers about this change + WBUFW(buf,0) = 0x2b0d; + WBUFL(buf,2) = acc; + WBUFB(buf,6) = sex; + mapif_sendall(buf, 7); + } + break; + + // reply to an account_reg2 registry request + case 0x2729: + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + + { //Receive account_reg2 registry, forward to map servers. + unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)]; + memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] + mapif_sendall(buf, WBUFW(buf,2)); + RFIFOSKIP(fd, RFIFOW(fd,2)); + } + break; + + // State change of account/ban notification (from login-server) + case 0x2731: + if (RFIFOREST(fd) < 11) + return 0; + + { // send to all map-servers to disconnect the player + unsigned char buf[11]; + WBUFW(buf,0) = 0x2b14; + WBUFL(buf,2) = RFIFOL(fd,2); + WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban + WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment + mapif_sendall(buf, 11); + } + // disconnect player if online on char-server + disconnect_player(RFIFOL(fd,2)); + + RFIFOSKIP(fd,11); + break; + + // Login server request to kick a character out. [Skotlex] + case 0x2734: + if (RFIFOREST(fd) < 6) + return 0; + { + int aid = RFIFOL(fd,2); + struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); + RFIFOSKIP(fd,6); + if( character != NULL ) + {// account is already marked as online! + if( character->server > -1 ) + { //Kick it from the map server it is on. + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == INVALID_TIMER) + character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); + } + else + {// Manual kick from char server. + struct char_session_data *tsd; + int i; + ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); + if( i < fd_max ) + { + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x81; + WFIFOB(i,2) = 2; // "Someone has already logged in with this id" + WFIFOSET(i,3); + set_eof(i); + } + else // still moving to the map-server + set_char_offline(-1, aid); + } + } + idb_remove(auth_db, aid);// reject auth attempts from map-server + } + break; + + // ip address update signal from login server + case 0x2735: + { + unsigned char buf[2]; + uint32 new_ip = 0; + + WBUFW(buf,0) = 0x2b1e; + mapif_sendall(buf, 2); + + new_ip = host2ip(login_ip_str); + if (new_ip && new_ip != login_ip) + login_ip = new_ip; //Update login ip, too. + + new_ip = host2ip(char_ip_str); + if (new_ip && new_ip != char_ip) + { //Update ip. + char_ip = new_ip; + ShowInfo("Updating IP for [%s].\n", char_ip_str); + // notify login server about the change + WFIFOHEAD(fd,6); + WFIFOW(fd,0) = 0x2736; + WFIFOL(fd,2) = htonl(char_ip); + WFIFOSET(fd,6); + } + + RFIFOSKIP(fd,2); + } + break; + + default: + ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; } int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data); @@ -2332,169 +2365,176 @@ int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); void do_init_loginif(void) { - // establish char-login connection if not present - add_timer_func_list(check_connect_login_server, "check_connect_login_server"); - add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); - - // send a list of all online account IDs to login server - add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); - add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour + // establish char-login connection if not present + add_timer_func_list(check_connect_login_server, "check_connect_login_server"); + add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); + + // send a list of all online account IDs to login server + add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); + add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour } void do_final_loginif(void) { - if (login_fd != -1) { - do_close(login_fd); - login_fd = -1; - } + if( login_fd != -1 ) + { + do_close(login_fd); + login_fd = -1; + } } int request_accreg2(int account_id, int char_id) { - if (login_fd > 0) { - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x272e; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = char_id; - WFIFOSET(login_fd,10); - return 1; - } - return 0; + if (login_fd > 0) { + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x272e; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = char_id; + WFIFOSET(login_fd,10); + return 1; + } + return 0; } //Send packet forward to login-server for account saving -int save_accreg2(unsigned char *buf, int len) +int save_accreg2(unsigned char* buf, int len) { - if (login_fd > 0) { - WFIFOHEAD(login_fd,len+4); - memcpy(WFIFOP(login_fd,4), buf, len); - WFIFOW(login_fd,0) = 0x2728; - WFIFOW(login_fd,2) = len+4; - WFIFOSET(login_fd,len+4); - return 1; - } - return 0; + if (login_fd > 0) { + WFIFOHEAD(login_fd,len+4); + memcpy(WFIFOP(login_fd,4), buf, len); + WFIFOW(login_fd,0) = 0x2728; + WFIFOW(login_fd,2) = len+4; + WFIFOSET(login_fd,len+4); + return 1; + } + return 0; } void char_read_fame_list(void) { - int i; - char *data; - size_t len; - - // Empty ranking lists - memset(smith_fame_list, 0, sizeof(smith_fame_list)); - memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); - memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); - // Build Blacksmith ranking list - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith)) - Sql_ShowDebug(sql_handle); - for (i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - smith_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - smith_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Alchemist ranking list - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist)) - Sql_ShowDebug(sql_handle); - for (i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - chemist_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - chemist_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Taekwon ranking list - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon)) - Sql_ShowDebug(sql_handle); - for (i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - taekwon_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - taekwon_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - Sql_FreeResult(sql_handle); + int i; + char* data; + size_t len; + + // Empty ranking lists + memset(smith_fame_list, 0, sizeof(smith_fame_list)); + memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); + memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); + // Build Blacksmith ranking list + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + smith_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + smith_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + // Build Alchemist ranking list + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + chemist_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + chemist_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + // Build Taekwon ranking list + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + taekwon_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + taekwon_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + Sql_FreeResult(sql_handle); } // Send map-servers the fame ranking lists int char_send_fame_list(int fd) { - int i, len = 8; - unsigned char buf[32000]; - - WBUFW(buf,0) = 0x2b1b; - - for (i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add blacksmith's block length - WBUFW(buf, 6) = len; - - for (i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add alchemist's block length - WBUFW(buf, 4) = len; - - for (i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add total packet length - WBUFW(buf, 2) = len; - - if (fd != -1) - mapif_send(fd, buf, len); - else - mapif_sendall(buf, len); - - return 0; + int i, len = 8; + unsigned char buf[32000]; + + WBUFW(buf,0) = 0x2b1b; + + for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add blacksmith's block length + WBUFW(buf, 6) = len; + + for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add alchemist's block length + WBUFW(buf, 4) = len; + + for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add total packet length + WBUFW(buf, 2) = len; + + if (fd != -1) + mapif_send(fd, buf, len); + else + mapif_sendall(buf, len); + + return 0; } void char_update_fame_list(int type, int index, int fame) { - unsigned char buf[8]; - WBUFW(buf,0) = 0x2b22; - WBUFB(buf,2) = type; - WBUFB(buf,3) = index; - WBUFL(buf,4) = fame; - mapif_sendall(buf, 8); + unsigned char buf[8]; + WBUFW(buf,0) = 0x2b22; + WBUFB(buf,2) = type; + WBUFB(buf,3) = index; + WBUFL(buf,4) = fame; + mapif_sendall(buf, 8); } //Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size) //Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) -int char_loadName(int char_id, char *name) +int char_loadName(int char_id, char* name) { - char *data; - size_t len; - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) - Sql_ShowDebug(sql_handle); - else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - Sql_GetData(sql_handle, 0, &data, &len); - safestrncpy(name, data, NAME_LENGTH); - return 1; - } else { - safestrncpy(name, unknown_char_name, NAME_LENGTH); - } - return 0; + char* data; + size_t len; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + Sql_GetData(sql_handle, 0, &data, &len); + safestrncpy(name, data, NAME_LENGTH); + return 1; + } + else + { + safestrncpy(name, unknown_char_name, NAME_LENGTH); + } + return 0; } int search_mapserver(unsigned short map, uint32 ip, uint16 port); @@ -2503,825 +2543,833 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port); /// Initializes a server structure. void mapif_server_init(int id) { - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; + memset(&server[id], 0, sizeof(server[id])); + server[id].fd = -1; } /// Destroys a server structure. void mapif_server_destroy(int id) { - if (server[id].fd == -1) { - do_close(server[id].fd); - server[id].fd = -1; - } + if( server[id].fd == -1 ) + { + do_close(server[id].fd); + server[id].fd = -1; + } } /// Resets all the data related to a server. void mapif_server_reset(int id) { - int i,j; - unsigned char buf[16384]; - int fd = server[id].fd; - //Notify other map servers that this one is gone. [Skotlex] - WBUFW(buf,0) = 0x2b20; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - j = 0; - for (i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[id].map[i]) - WBUFW(buf,10+(j++)*4) = server[id].map[i]; - if (j > 0) { - WBUFW(buf,2) = j * 4 + 10; - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `index`='%d'", ragsrvinfo_db, server[id].fd)) - Sql_ShowDebug(sql_handle); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. - mapif_server_destroy(id); - mapif_server_init(id); + int i,j; + unsigned char buf[16384]; + int fd = server[id].fd; + //Notify other map servers that this one is gone. [Skotlex] + WBUFW(buf,0) = 0x2b20; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + j = 0; + for(i = 0; i < MAX_MAP_PER_SERVER; i++) + if (server[id].map[i]) + WBUFW(buf,10+(j++)*4) = server[id].map[i]; + if (j > 0) { + WBUFW(buf,2) = j * 4 + 10; + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `index`='%d'", ragsrvinfo_db, server[id].fd) ) + Sql_ShowDebug(sql_handle); + online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. + mapif_server_destroy(id); + mapif_server_init(id); } /// Called when the connection to a Map Server is disconnected. void mapif_on_disconnect(int id) { - ShowStatus("Map-server #%d has disconnected.\n", id); - mapif_server_reset(id); + ShowStatus("Map-server #%d has disconnected.\n", id); + mapif_server_reset(id); } int parse_frommap(int fd) { - int i, j; - int id; - - ARR_FIND(0, ARRAYLENGTH(server), id, server[id].fd == fd); - if (id == ARRAYLENGTH(server)) { - // not a map server - ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd); - do_close(fd); - return 0; - } - if (session[fd]->flag.eof) { - do_close(fd); - server[id].fd = -1; - mapif_on_disconnect(id); - return 0; - } - - while (RFIFOREST(fd) >= 2) { - switch (RFIFOW(fd,0)) { - - case 0x2afa: // Receiving map names list from the map-server - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - memset(server[id].map, 0, sizeof(server[id].map)); - j = 0; - for (i = 4; i < RFIFOW(fd,2); i += 4) { - server[id].map[j] = RFIFOW(fd,i); - j++; - } - - ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", - id, j, CONVIP(server[id].ip), server[id].port); - ShowStatus("Map-server %d loading complete.\n", id); - - // send name for wisp to player - WFIFOHEAD(fd, 3 + NAME_LENGTH); - WFIFOW(fd,0) = 0x2afb; - WFIFOB(fd,2) = 0; - memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); - WFIFOSET(fd,3+NAME_LENGTH); - - char_send_fame_list(fd); //Send fame list. - - { - unsigned char buf[16384]; - int x; - if (j == 0) { - ShowWarning("Map-server %d has NO maps.\n", id); - } else { - // Transmitting maps information to the other map-servers - WBUFW(buf,0) = 0x2b04; - WBUFW(buf,2) = j * 4 + 10; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - // Transmitting the maps of the other map-servers to the new map-server - for (x = 0; x < ARRAYLENGTH(server); x++) { - if (server[x].fd > 0 && x != id) { - WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map)); - WFIFOW(fd,0) = 0x2b04; - WFIFOL(fd,4) = htonl(server[x].ip); - WFIFOW(fd,8) = htons(server[x].port); - j = 0; - for (i = 0; i < ARRAYLENGTH(server[x].map); i++) - if (server[x].map[i]) - WFIFOW(fd,10+(j++)*4) = server[x].map[i]; - if (j > 0) { - WFIFOW(fd,2) = j * 4 + 10; - WFIFOSET(fd,WFIFOW(fd,2)); - } - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] - if (RFIFOREST(fd) < 10) - return 0; - { + int i, j; + int id; + + ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd ); + if( id == ARRAYLENGTH(server) ) + {// not a map server + ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd); + do_close(fd); + return 0; + } + if( session[fd]->flag.eof ) + { + do_close(fd); + server[id].fd = -1; + mapif_on_disconnect(id); + return 0; + } + + while(RFIFOREST(fd) >= 2) + { + switch(RFIFOW(fd,0)) + { + + case 0x2afa: // Receiving map names list from the map-server + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + + memset(server[id].map, 0, sizeof(server[id].map)); + j = 0; + for(i = 4; i < RFIFOW(fd,2); i += 4) { + server[id].map[j] = RFIFOW(fd,i); + j++; + } + + ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", + id, j, CONVIP(server[id].ip), server[id].port); + ShowStatus("Map-server %d loading complete.\n", id); + + // send name for wisp to player + WFIFOHEAD(fd, 3 + NAME_LENGTH); + WFIFOW(fd,0) = 0x2afb; + WFIFOB(fd,2) = 0; + memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); + WFIFOSET(fd,3+NAME_LENGTH); + + char_send_fame_list(fd); //Send fame list. + + { + unsigned char buf[16384]; + int x; + if (j == 0) { + ShowWarning("Map-server %d has NO maps.\n", id); + } else { + // Transmitting maps information to the other map-servers + WBUFW(buf,0) = 0x2b04; + WBUFW(buf,2) = j * 4 + 10; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + // Transmitting the maps of the other map-servers to the new map-server + for(x = 0; x < ARRAYLENGTH(server); x++) { + if (server[x].fd > 0 && x != id) { + WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map)); + WFIFOW(fd,0) = 0x2b04; + WFIFOL(fd,4) = htonl(server[x].ip); + WFIFOW(fd,8) = htons(server[x].port); + j = 0; + for(i = 0; i < ARRAYLENGTH(server[x].map); i++) + if (server[x].map[i]) + WFIFOW(fd,10+(j++)*4) = server[x].map[i]; + if (j > 0) { + WFIFOW(fd,2) = j * 4 + 10; + WFIFOSET(fd,WFIFOW(fd,2)); + } + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] + if (RFIFOREST(fd) < 10) + return 0; + { #ifdef ENABLE_SC_SAVING - int aid, cid; - aid = RFIFOL(fd,2); - cid = RFIFOL(fd,6); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", - scdata_db, aid, cid)) { - Sql_ShowDebug(sql_handle); - break; - } - if (Sql_NumRows(sql_handle) > 0) { - struct status_change_data scdata; - int count; - char *data; - - WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); - WFIFOW(fd,0) = 0x2b1d; - WFIFOL(fd,4) = aid; - WFIFOL(fd,8) = cid; - for (count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count) { - Sql_GetData(sql_handle, 0, &data, NULL); - scdata.type = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - scdata.tick = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - scdata.val1 = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - scdata.val2 = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - scdata.val3 = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - scdata.val4 = atoi(data); - memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); - } - if (count >= 50) - ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); - if (count > 0) { - WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); - WFIFOW(fd,12) = count; - WFIFOSET(fd,WFIFOW(fd,2)); - - //Clear the data once loaded. - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid)) - Sql_ShowDebug(sql_handle); - } - } - Sql_FreeResult(sql_handle); + int aid, cid; + aid = RFIFOL(fd,2); + cid = RFIFOL(fd,6); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", + scdata_db, aid, cid) ) + { + Sql_ShowDebug(sql_handle); + break; + } + if( Sql_NumRows(sql_handle) > 0 ) + { + struct status_change_data scdata; + int count; + char* data; + + WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); + WFIFOW(fd,0) = 0x2b1d; + WFIFOL(fd,4) = aid; + WFIFOL(fd,8) = cid; + for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count ) + { + Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data); + memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); + } + if (count >= 50) + ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); + if (count > 0) + { + WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); + WFIFOW(fd,12) = count; + WFIFOSET(fd,WFIFOW(fd,2)); + + //Clear the data once loaded. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) ) + Sql_ShowDebug(sql_handle); + } + } + Sql_FreeResult(sql_handle); #endif - RFIFOSKIP(fd, 10); - } - break; - - case 0x2afe: //set MAP user count - if (RFIFOREST(fd) < 4) - return 0; - if (RFIFOW(fd,2) != server[id].users) { - server[id].users = RFIFOW(fd,2); - ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); - } - RFIFOSKIP(fd, 4); - break; - - case 0x2aff: //set MAP users - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - //TODO: When data mismatches memory, update guild/party online/offline states. - int aid, cid; - struct online_char_data *character; - - server[id].users = RFIFOW(fd,4); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' - for (i = 0; i < server[id].users; i++) { - aid = RFIFOL(fd,6+i*8); - cid = RFIFOL(fd,6+i*8+4); - character = idb_ensure(online_char_db, aid, create_online_char_data); - if (character->server > -1 && character->server != id) { - ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, id, aid, cid); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - character->server = id; - character->char_id = cid; - } - //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x2b01: // Receive character data from map-server for saving - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); - struct online_char_data *character; - - if (size - 13 != sizeof(struct mmo_charstatus)) { - ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus)); - RFIFOSKIP(fd,size); - break; - } - //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect - if (RFIFOB(fd,12) || ( - (character = (struct online_char_data *)idb_get(online_char_db, aid)) != NULL && - character->char_id == cid)) { - struct mmo_charstatus char_dat; - memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - mmo_char_tosql(cid, &char_dat); - } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. - ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); - set_char_online(id, cid, aid); - } - - if (RFIFOB(fd,12)) { - //Flag, set character offline after saving. [Skotlex] - set_char_offline(cid, aid); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. - WFIFOL(fd,2) = aid; - WFIFOL(fd,6) = cid; - WFIFOSET(fd,10); - } - RFIFOSKIP(fd,size); - } - break; - - case 0x2b02: // req char selection - if (RFIFOREST(fd) < 18) - return 0; - { - struct auth_node *node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint32 ip = RFIFOL(fd,14); - RFIFOSKIP(fd,18); - - if (runflag != CHARSERVER_ST_RUNNING) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 0;// not ok - WFIFOSET(fd,7); - } else { - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = account_id; - node->char_id = 0; - node->login_id1 = login_id1; - node->login_id2 = login_id2; - //node->sex = 0; - node->ip = ntohl(ip); - //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) - //node->gmlevel = 0; - idb_put(auth_db, account_id, node); - - //Set char to "@ char select" in online db [Kevin] - set_char_charselect(account_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 1;// ok - WFIFOSET(fd,7); - } - } - break; - - case 0x2b05: // request "change map server" - if (RFIFOREST(fd) < 39) - return 0; - { - int map_id, map_fd = -1; - struct online_char_data *data; - struct mmo_charstatus *char_data; - struct mmo_charstatus char_dat; - - map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. - if (map_id >= 0) - map_fd = server[map_id].fd; - //Char should just had been saved before this packet, so this should be safe. [Skotlex] - char_data = (struct mmo_charstatus *)uidb_get(char_db_,RFIFOL(fd,14)); - if (char_data == NULL) { //Really shouldn't happen. - mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); - char_data = (struct mmo_charstatus *)uidb_get(char_db_,RFIFOL(fd,14)); - } - - if (runflag == CHARSERVER_ST_RUNNING && - session_isActive(map_fd) && - char_data) { - //Send the map server the auth of this player. - struct auth_node *node; - - //Update the "last map" as this is where the player must be spawned on the new map server. - char_data->last_point.map = RFIFOW(fd,18); - char_data->last_point.x = RFIFOW(fd,20); - char_data->last_point.y = RFIFOW(fd,22); - char_data->sex = RFIFOB(fd,30); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = RFIFOL(fd,2); - node->char_id = RFIFOL(fd,14); - node->login_id1 = RFIFOL(fd,6); - node->login_id2 = RFIFOL(fd,10); - node->sex = RFIFOB(fd,30); - node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) - node->ip = ntohl(RFIFOL(fd,31)); - node->group_id = RFIFOL(fd,35); - node->changing_mapservers = 1; - idb_put(auth_db, RFIFOL(fd,2), node); - - data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); - data->char_id = char_data->char_id; - data->server = map_id; //Update server where char is. - - //Reply with an ack. - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOSET(fd,30); - } else { //Reply with nak - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOL(fd,6) = 0; //Set login1 to 0. - WFIFOSET(fd,30); - } - RFIFOSKIP(fd,39); - } - break; - - case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] - if (RFIFOREST(fd) < 10) - return 0; - { - int char_id, friend_id; - char_id = RFIFOL(fd,2); - friend_id = RFIFOL(fd,6); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", - friend_db, char_id, friend_id)) { - Sql_ShowDebug(sql_handle); - break; - } - RFIFOSKIP(fd,10); - } - break; - - case 0x2b08: // char name request - if (RFIFOREST(fd) < 6) - return 0; - - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b09; - WFIFOL(fd,2) = RFIFOL(fd,2); - char_loadName((int)RFIFOL(fd,2), (char *)WFIFOP(fd,6)); - WFIFOSET(fd,30); - - RFIFOSKIP(fd,6); - break; - - case 0x2b0c: // Map server send information to change an email of an account -> login-server - if (RFIFOREST(fd) < 86) - return 0; - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,86); - memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B - WFIFOW(login_fd,0) = 0x2722; - WFIFOSET(login_fd,86); - } - RFIFOSKIP(fd, 86); - break; - - case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) - if (RFIFOREST(fd) < 44) - return 0; - { - int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline - char esc_name[NAME_LENGTH*2+1]; - - int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) - const char *name = (char *)RFIFOP(fd,6); // name of the target character - int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban - short year = RFIFOW(fd,32); - short month = RFIFOW(fd,34); - short day = RFIFOW(fd,36); - short hour = RFIFOW(fd,38); - short minute = RFIFOW(fd,40); - short second = RFIFOW(fd,42); - RFIFOSKIP(fd,44); - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name)) - Sql_ShowDebug(sql_handle); - else if (Sql_NumRows(sql_handle) == 0) { - result = 1; // 1-player not found - } else if (SQL_SUCCESS != Sql_NextRow(sql_handle)) - Sql_ShowDebug(sql_handle); - //FIXME: set proper result value? - else { - char name[NAME_LENGTH]; - int account_id; - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - safestrncpy(name, data, sizeof(name)); - - if (login_fd <= 0) - result = 3; // 3-login-server offline - //FIXME: need to move this check to login server [ultramage] - // else - // if( acc != -1 && isGM(acc) < isGM(account_id) ) - // result = 2; // 2-gm level too low - else - switch (type) { - case 1: // block - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 5; // new account status - WFIFOSET(login_fd,10); - break; - case 2: // ban - WFIFOHEAD(login_fd,18); - WFIFOW(login_fd, 0) = 0x2725; - WFIFOL(login_fd, 2) = account_id; - WFIFOW(login_fd, 6) = year; - WFIFOW(login_fd, 8) = month; - WFIFOW(login_fd,10) = day; - WFIFOW(login_fd,12) = hour; - WFIFOW(login_fd,14) = minute; - WFIFOW(login_fd,16) = second; - WFIFOSET(login_fd,18); - break; - case 3: // unblock - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 0; // new account status - WFIFOSET(login_fd,10); - break; - case 4: // unban - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272a; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - case 5: // changesex - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2727; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - } - } - - Sql_FreeResult(sql_handle); - - // send answer if a player ask, not if the server ask - if (acc != -1 && type != 5) { // Don't send answer for changesex - WFIFOHEAD(fd,34); - WFIFOW(fd, 0) = 0x2b0f; - WFIFOL(fd, 2) = acc; - safestrncpy((char *)WFIFOP(fd,6), name, NAME_LENGTH); - WFIFOW(fd,30) = type; - WFIFOW(fd,32) = result; - WFIFOSET(fd,34); - } - } - break; - - case 0x2b10: // Update and send fame ranking list - if (RFIFOREST(fd) < 11) - return 0; - { - int cid = RFIFOL(fd, 2); - int fame = RFIFOL(fd, 6); - char type = RFIFOB(fd, 10); - int size; - struct fame_list *list; - int player_pos; - int fame_pos; - - switch (type) { - case 1: - size = fame_list_size_smith; - list = smith_fame_list; - break; - case 2: - size = fame_list_size_chemist; - list = chemist_fame_list; - break; - case 3: - size = fame_list_size_taekwon; - list = taekwon_fame_list; - break; - default: - size = 0; - list = NULL; - break; - } - - ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player - ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be - - if (player_pos == size && fame_pos == size) - ;// not on list and not enough fame to get on it - else if (fame_pos == player_pos) { - // same position - list[player_pos].fame = fame; - char_update_fame_list(type, player_pos, fame); - } else { - // move in the list - if (player_pos == size) { - // new ranker - not in the list - ARR_MOVE(size - 1, fame_pos, list, struct fame_list); - list[fame_pos].id = cid; - list[fame_pos].fame = fame; - char_loadName(cid, list[fame_pos].name); - } else { - // already in the list - if (fame_pos == size) - --fame_pos;// move to the end of the list - ARR_MOVE(player_pos, fame_pos, list, struct fame_list); - list[fame_pos].fame = fame; - } - char_send_fame_list(-1); - } - - RFIFOSKIP(fd,11); - } - break; - - // Divorce chars - case 0x2b11: - if (RFIFOREST(fd) < 10) - return 0; - - divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b16: // Receive rates [Wizputer] - if (RFIFOREST(fd) < 14) - return 0; - { - char esc_server_name[sizeof(server_name)*2+1]; - - Sql_EscapeString(sql_handle, esc_server_name, server_name); - - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", - ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10))) - Sql_ShowDebug(sql_handle); - RFIFOSKIP(fd,14); - } - break; - - case 0x2b17: // Character disconnected set online 0 [Wizputer] - if (RFIFOREST(fd) < 6) - return 0; - set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b18: // Reset all chars to offline [Wizputer] - set_all_offline(id); - RFIFOSKIP(fd,2); - break; - - case 0x2b19: // Character set online [Wizputer] - if (RFIFOREST(fd) < 10) - return 0; - set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b1a: // Build and send fame ranking lists [DracoRPG] - if (RFIFOREST(fd) < 2) - return 0; - char_read_fame_list(); - char_send_fame_list(-1); - RFIFOSKIP(fd,2); - break; - - case 0x2b1c: //Request to save status change data. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { + RFIFOSKIP(fd, 10); + } + break; + + case 0x2afe: //set MAP user count + if (RFIFOREST(fd) < 4) + return 0; + if (RFIFOW(fd,2) != server[id].users) { + server[id].users = RFIFOW(fd,2); + ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); + } + RFIFOSKIP(fd, 4); + break; + + case 0x2aff: //set MAP users + if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + //TODO: When data mismatches memory, update guild/party online/offline states. + int aid, cid; + struct online_char_data* character; + + server[id].users = RFIFOW(fd,4); + online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' + for(i = 0; i < server[id].users; i++) { + aid = RFIFOL(fd,6+i*8); + cid = RFIFOL(fd,6+i*8+4); + character = idb_ensure(online_char_db, aid, create_online_char_data); + if( character->server > -1 && character->server != id ) + { + ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, id, aid, cid); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + character->server = id; + character->char_id = cid; + } + //If any chars remain in -2, they will be cleaned in the cleanup timer. + RFIFOSKIP(fd,RFIFOW(fd,2)); + } + break; + + case 0x2b01: // Receive character data from map-server for saving + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); + struct online_char_data* character; + + if (size - 13 != sizeof(struct mmo_charstatus)) + { + ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus)); + RFIFOSKIP(fd,size); + break; + } + //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect + if (RFIFOB(fd,12) || ( + (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL && + character->char_id == cid)) + { + struct mmo_charstatus char_dat; + memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); + mmo_char_tosql(cid, &char_dat); + } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. + ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); + set_char_online(id, cid, aid); + } + + if (RFIFOB(fd,12)) + { //Flag, set character offline after saving. [Skotlex] + set_char_offline(cid, aid); + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. + WFIFOL(fd,2) = aid; + WFIFOL(fd,6) = cid; + WFIFOSET(fd,10); + } + RFIFOSKIP(fd,size); + } + break; + + case 0x2b02: // req char selection + if( RFIFOREST(fd) < 18 ) + return 0; + { + struct auth_node* node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint32 ip = RFIFOL(fd,14); + RFIFOSKIP(fd,18); + + if( runflag != CHARSERVER_ST_RUNNING ) + { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b03; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = 0;// not ok + WFIFOSET(fd,7); + } + else + { + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = account_id; + node->char_id = 0; + node->login_id1 = login_id1; + node->login_id2 = login_id2; + //node->sex = 0; + node->ip = ntohl(ip); + //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) + //node->gmlevel = 0; + idb_put(auth_db, account_id, node); + + //Set char to "@ char select" in online db [Kevin] + set_char_charselect(account_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b03; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = 1;// ok + WFIFOSET(fd,7); + } + } + break; + + case 0x2b05: // request "change map server" + if (RFIFOREST(fd) < 39) + return 0; + { + int map_id, map_fd = -1; + struct online_char_data* data; + struct mmo_charstatus* char_data; + struct mmo_charstatus char_dat; + + map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. + if (map_id >= 0) + map_fd = server[map_id].fd; + //Char should just had been saved before this packet, so this should be safe. [Skotlex] + char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); + if (char_data == NULL) { //Really shouldn't happen. + mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); + char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); + } + + if( runflag == CHARSERVER_ST_RUNNING && + session_isActive(map_fd) && + char_data ) + { //Send the map server the auth of this player. + struct auth_node* node; + + //Update the "last map" as this is where the player must be spawned on the new map server. + char_data->last_point.map = RFIFOW(fd,18); + char_data->last_point.x = RFIFOW(fd,20); + char_data->last_point.y = RFIFOW(fd,22); + char_data->sex = RFIFOB(fd,30); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = RFIFOL(fd,2); + node->char_id = RFIFOL(fd,14); + node->login_id1 = RFIFOL(fd,6); + node->login_id2 = RFIFOL(fd,10); + node->sex = RFIFOB(fd,30); + node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) + node->ip = ntohl(RFIFOL(fd,31)); + node->group_id = RFIFOL(fd,35); + node->changing_mapservers = 1; + idb_put(auth_db, RFIFOL(fd,2), node); + + data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); + data->char_id = char_data->char_id; + data->server = map_id; //Update server where char is. + + //Reply with an ack. + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOSET(fd,30); + } else { //Reply with nak + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOL(fd,6) = 0; //Set login1 to 0. + WFIFOSET(fd,30); + } + RFIFOSKIP(fd,39); + } + break; + + case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] + if (RFIFOREST(fd) < 10) + return 0; + { + int char_id, friend_id; + char_id = RFIFOL(fd,2); + friend_id = RFIFOL(fd,6); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", + friend_db, char_id, friend_id) ) { + Sql_ShowDebug(sql_handle); + break; + } + RFIFOSKIP(fd,10); + } + break; + + case 0x2b08: // char name request + if (RFIFOREST(fd) < 6) + return 0; + + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b09; + WFIFOL(fd,2) = RFIFOL(fd,2); + char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6)); + WFIFOSET(fd,30); + + RFIFOSKIP(fd,6); + break; + + case 0x2b0c: // Map server send information to change an email of an account -> login-server + if (RFIFOREST(fd) < 86) + return 0; + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,86); + memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B + WFIFOW(login_fd,0) = 0x2722; + WFIFOSET(login_fd,86); + } + RFIFOSKIP(fd, 86); + break; + + case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) + if (RFIFOREST(fd) < 44) + return 0; + { + int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline + char esc_name[NAME_LENGTH*2+1]; + + int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) + const char* name = (char*)RFIFOP(fd,6); // name of the target character + int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban + short year = RFIFOW(fd,32); + short month = RFIFOW(fd,34); + short day = RFIFOW(fd,36); + short hour = RFIFOW(fd,38); + short minute = RFIFOW(fd,40); + short second = RFIFOW(fd,42); + RFIFOSKIP(fd,44); + + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + Sql_ShowDebug(sql_handle); + else + if( Sql_NumRows(sql_handle) == 0 ) + { + result = 1; // 1-player not found + } + else + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + Sql_ShowDebug(sql_handle); + //FIXME: set proper result value? + else + { + char name[NAME_LENGTH]; + int account_id; + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); + + if( login_fd <= 0 ) + result = 3; // 3-login-server offline + //FIXME: need to move this check to login server [ultramage] +// else +// if( acc != -1 && isGM(acc) < isGM(account_id) ) +// result = 2; // 2-gm level too low + else + switch( type ) { + case 1: // block + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 5; // new account status + WFIFOSET(login_fd,10); + break; + case 2: // ban + WFIFOHEAD(login_fd,18); + WFIFOW(login_fd, 0) = 0x2725; + WFIFOL(login_fd, 2) = account_id; + WFIFOW(login_fd, 6) = year; + WFIFOW(login_fd, 8) = month; + WFIFOW(login_fd,10) = day; + WFIFOW(login_fd,12) = hour; + WFIFOW(login_fd,14) = minute; + WFIFOW(login_fd,16) = second; + WFIFOSET(login_fd,18); + break; + case 3: // unblock + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 0; // new account status + WFIFOSET(login_fd,10); + break; + case 4: // unban + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272a; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + case 5: // changesex + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2727; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + } + } + + Sql_FreeResult(sql_handle); + + // send answer if a player ask, not if the server ask + if( acc != -1 && type != 5) { // Don't send answer for changesex + WFIFOHEAD(fd,34); + WFIFOW(fd, 0) = 0x2b0f; + WFIFOL(fd, 2) = acc; + safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH); + WFIFOW(fd,30) = type; + WFIFOW(fd,32) = result; + WFIFOSET(fd,34); + } + } + break; + + case 0x2b10: // Update and send fame ranking list + if (RFIFOREST(fd) < 11) + return 0; + { + int cid = RFIFOL(fd, 2); + int fame = RFIFOL(fd, 6); + char type = RFIFOB(fd, 10); + int size; + struct fame_list* list; + int player_pos; + int fame_pos; + + switch(type) + { + case 1: size = fame_list_size_smith; list = smith_fame_list; break; + case 2: size = fame_list_size_chemist; list = chemist_fame_list; break; + case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break; + default: size = 0; list = NULL; break; + } + + ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player + ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be + + if( player_pos == size && fame_pos == size ) + ;// not on list and not enough fame to get on it + else if( fame_pos == player_pos ) + {// same position + list[player_pos].fame = fame; + char_update_fame_list(type, player_pos, fame); + } + else + {// move in the list + if( player_pos == size ) + {// new ranker - not in the list + ARR_MOVE(size - 1, fame_pos, list, struct fame_list); + list[fame_pos].id = cid; + list[fame_pos].fame = fame; + char_loadName(cid, list[fame_pos].name); + } + else + {// already in the list + if( fame_pos == size ) + --fame_pos;// move to the end of the list + ARR_MOVE(player_pos, fame_pos, list, struct fame_list); + list[fame_pos].fame = fame; + } + char_send_fame_list(-1); + } + + RFIFOSKIP(fd,11); + } + break; + + // Divorce chars + case 0x2b11: + if( RFIFOREST(fd) < 10 ) + return 0; + + divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b16: // Receive rates [Wizputer] + if( RFIFOREST(fd) < 14 ) + return 0; + { + char esc_server_name[sizeof(server_name)*2+1]; + + Sql_EscapeString(sql_handle, esc_server_name, server_name); + + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", + ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) ) + Sql_ShowDebug(sql_handle); + RFIFOSKIP(fd,14); + } + break; + + case 0x2b17: // Character disconnected set online 0 [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b18: // Reset all chars to offline [Wizputer] + set_all_offline(id); + RFIFOSKIP(fd,2); + break; + + case 0x2b19: // Character set online [Wizputer] + if (RFIFOREST(fd) < 10) + return 0; + set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b1a: // Build and send fame ranking lists [DracoRPG] + if (RFIFOREST(fd) < 2) + return 0; + char_read_fame_list(); + char_send_fame_list(-1); + RFIFOSKIP(fd,2); + break; + + case 0x2b1c: //Request to save status change data. [Skotlex] + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { #ifdef ENABLE_SC_SAVING - int count, aid, cid; - - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); - count = RFIFOW(fd, 12); - - if (count > 0) { - struct status_change_data data; - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); - for (i = 0; i < count; ++i) { - memcpy(&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); - if (i > 0) - StringBuf_AppendStr(&buf, ", "); - StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, - data.type, data.tick, data.val1, data.val2, data.val3, data.val4); - } - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } + int count, aid, cid; + + aid = RFIFOL(fd, 4); + cid = RFIFOL(fd, 8); + count = RFIFOW(fd, 12); + + if( count > 0 ) + { + struct status_change_data data; + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); + for( i = 0; i < count; ++i ) + { + memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); + if( i > 0 ) + StringBuf_AppendStr(&buf, ", "); + StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, + data.type, data.tick, data.val1, data.val2, data.val3, data.val4); + } + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + } #endif - RFIFOSKIP(fd, RFIFOW(fd, 2)); - } - break; - - case 0x2b23: // map-server alive packet - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2b24; - WFIFOSET(fd,2); - RFIFOSKIP(fd,2); - break; - - case 0x2b26: // auth request from map-server - if (RFIFOREST(fd) < 19) - return 0; - - { - int account_id; - int char_id; - int login_id1; - char sex; - uint32 ip; - struct auth_node *node; - struct mmo_charstatus *cd; - struct mmo_charstatus char_dat; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - login_id1 = RFIFOL(fd,10); - sex = RFIFOB(fd,14); - ip = ntohl(RFIFOL(fd,15)); - RFIFOSKIP(fd,19); - - node = (struct auth_node *)idb_get(auth_db, account_id); - cd = (struct mmo_charstatus *)uidb_get(char_db_,char_id); - if (cd == NULL) { - //Really shouldn't happen. - mmo_char_fromsql(char_id, &char_dat, true); - cd = (struct mmo_charstatus *)uidb_get(char_db_,char_id); - } - if (runflag == CHARSERVER_ST_RUNNING && - cd != NULL && - node != NULL && - node->account_id == account_id && - node->char_id == char_id && - node->login_id1 == login_id1 && - node->sex == sex /*&& - node->ip == ip*/) { - // auth ok - cd->sex = sex; - - WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); - WFIFOW(fd,0) = 0x2afd; - WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = node->login_id1; - WFIFOL(fd,12) = node->login_id2; - WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" - WFIFOL(fd,20) = node->group_id; - WFIFOB(fd,24) = node->changing_mapservers; - memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); - WFIFOSET(fd, WFIFOW(fd,2)); - - // only use the auth once and mark user online - idb_remove(auth_db, account_id); - set_char_online(id, char_id, account_id); - } else { - // auth failed - WFIFOHEAD(fd,19); - WFIFOW(fd,0) = 0x2b27; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = char_id; - WFIFOL(fd,10) = login_id1; - WFIFOB(fd,14) = sex; - WFIFOL(fd,15) = htonl(ip); - WFIFOSET(fd,19); - } - } - break; - - case 0x2736: // ip address update - if (RFIFOREST(fd) < 6) return 0; - server[id].ip = ntohl(RFIFOL(fd, 2)); - ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - case 0x3008: - if (RFIFOREST(fd) < RFIFOW(fd,4)) - return 0;/* packet wasn't fully received yet (still fragmented) */ - else { - int sfd;/* stat server fd */ - RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */ - - if ((sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true)) == -1) { - RFIFOSKIP(fd, RFIFOW(fd,2)); /* skip this packet */ - break;/* connection not possible, we drop the report */ - } - - session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */ - - WFIFOHEAD(sfd, RFIFOW(fd,2)); - - memcpy((char *)WFIFOP(sfd,0), (char *)RFIFOP(fd, 0), RFIFOW(fd,2)); - - WFIFOSET(sfd, RFIFOW(fd,2)); - - flush_fifo(sfd); - - do_close(sfd); - - RFIFOSKIP(fd, RFIFOW(fd,2)); /* skip this packet */ - } - break; - - - default: { - // inter server - packet - int r = inter_parse_frommap(fd); - if (r == 1) break; // processed - if (r == 2) return 0; // need more packet - - // no inter server packet. no char server packet -> disconnect - ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); - set_eof(fd); - return 0; - } - } // switch - } // while - - return 0; + RFIFOSKIP(fd, RFIFOW(fd, 2)); + } + break; + + case 0x2b23: // map-server alive packet + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2b24; + WFIFOSET(fd,2); + RFIFOSKIP(fd,2); + break; + + case 0x2b26: // auth request from map-server + if (RFIFOREST(fd) < 19) + return 0; + + { + int account_id; + int char_id; + int login_id1; + char sex; + uint32 ip; + struct auth_node* node; + struct mmo_charstatus* cd; + struct mmo_charstatus char_dat; + + account_id = RFIFOL(fd,2); + char_id = RFIFOL(fd,6); + login_id1 = RFIFOL(fd,10); + sex = RFIFOB(fd,14); + ip = ntohl(RFIFOL(fd,15)); + RFIFOSKIP(fd,19); + + node = (struct auth_node*)idb_get(auth_db, account_id); + cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); + if( cd == NULL ) + { //Really shouldn't happen. + mmo_char_fromsql(char_id, &char_dat, true); + cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); + } + if( runflag == CHARSERVER_ST_RUNNING && + cd != NULL && + node != NULL && + node->account_id == account_id && + node->char_id == char_id && + node->login_id1 == login_id1 && + node->sex == sex /*&& + node->ip == ip*/ ) + {// auth ok + cd->sex = sex; + + WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); + WFIFOW(fd,0) = 0x2afd; + WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = node->login_id1; + WFIFOL(fd,12) = node->login_id2; + WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" + WFIFOL(fd,20) = node->group_id; + WFIFOB(fd,24) = node->changing_mapservers; + memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); + WFIFOSET(fd, WFIFOW(fd,2)); + + // only use the auth once and mark user online + idb_remove(auth_db, account_id); + set_char_online(id, char_id, account_id); + } + else + {// auth failed + WFIFOHEAD(fd,19); + WFIFOW(fd,0) = 0x2b27; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = char_id; + WFIFOL(fd,10) = login_id1; + WFIFOB(fd,14) = sex; + WFIFOL(fd,15) = htonl(ip); + WFIFOSET(fd,19); + } + } + break; + + case 0x2736: // ip address update + if (RFIFOREST(fd) < 6) return 0; + server[id].ip = ntohl(RFIFOL(fd, 2)); + ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + case 0x3008: + if( RFIFOREST(fd) < RFIFOW(fd,4) ) + return 0;/* packet wasn't fully received yet (still fragmented) */ + else { + int sfd;/* stat server fd */ + RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */ + + if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true) ) == -1 ) { + RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */ + break;/* connection not possible, we drop the report */ + } + + session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */ + + WFIFOHEAD(sfd, RFIFOW(fd,2) ); + + memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2)); + + WFIFOSET(sfd, RFIFOW(fd,2) ); + + flush_fifo(sfd); + + do_close(sfd); + + RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */ + } + break; + + + default: + { + // inter server - packet + int r = inter_parse_frommap(fd); + if (r == 1) break; // processed + if (r == 2) return 0; // need more packet + + // no inter server packet. no char server packet -> disconnect + ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); + set_eof(fd); + return 0; + } + } // switch + } // while + + return 0; } void do_init_mapif(void) { - int i; - for (i = 0; i < ARRAYLENGTH(server); ++i) - mapif_server_init(i); + int i; + for( i = 0; i < ARRAYLENGTH(server); ++i ) + mapif_server_init(i); } void do_final_mapif(void) { - int i; - for (i = 0; i < ARRAYLENGTH(server); ++i) - mapif_server_destroy(i); + int i; + for( i = 0; i < ARRAYLENGTH(server); ++i ) + mapif_server_destroy(i); } // Searches for the mapserver that has a given map (and optionally ip/port, if not -1). // If found, returns the server's index in the 'server' array (otherwise returns -1). int search_mapserver(unsigned short map, uint32 ip, uint16 port) { - int i, j; - - for (i = 0; i < ARRAYLENGTH(server); i++) { - if (server[i].fd > 0 - && (ip == (uint32)-1 || server[i].ip == ip) - && (port == (uint16)-1 || server[i].port == port)) { - for (j = 0; server[i].map[j]; j++) - if (server[i].map[j] == map) - return i; - } - } - - return -1; + int i, j; + + for(i = 0; i < ARRAYLENGTH(server); i++) + { + if (server[i].fd > 0 + && (ip == (uint32)-1 || server[i].ip == ip) + && (port == (uint16)-1 || server[i].port == port)) + { + for (j = 0; server[i].map[j]; j++) + if (server[i].map[j] == map) + return i; + } + } + + return -1; } // Initialization process (currently only initialization inter_mapif) static int char_mapif_init(int fd) { - return inter_mapif_init(fd); + return inter_mapif_init(fd); } //-------------------------------------------- @@ -3329,15 +3377,15 @@ static int char_mapif_init(int fd) //-------------------------------------------- int lan_subnetcheck(uint32 ip) { - int i; - ARR_FIND(0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask)); - if (i < subnet_count) { - ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); - return subnet[i].map_ip; - } else { - ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); - return 0; - } + int i; + ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); + if( i < subnet_count ) { + ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); + return subnet[i].map_ip; + } else { + ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); + return 0; + } } @@ -3349,14 +3397,13 @@ int lan_subnetcheck(uint32 ip) /// 5 (0x71b): To delete a character you must withdraw from the party. /// Any (0x718): An unknown error has occurred. void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) -{ - // HC: <0828>.W .L .L .L - WFIFOHEAD(fd,14); - WFIFOW(fd,0) = 0x828; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOL(fd,10) = TOL(delete_date); - WFIFOSET(fd,14); +{// HC: <0828>.W .L .L .L + WFIFOHEAD(fd,14); + WFIFOW(fd,0) = 0x828; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOL(fd,10) = TOL(delete_date); + WFIFOSET(fd,14); } @@ -3369,13 +3416,12 @@ void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) /// 5 (0x71e): Date of birth do not match. /// Any (0x718): An unknown error has occurred. void char_delete2_accept_ack(int fd, int char_id, uint32 result) -{ - // HC: <082a>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82a; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); +{// HC: <082a>.W .L .L + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x82a; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOSET(fd,10); } @@ -3384,797 +3430,804 @@ void char_delete2_accept_ack(int fd, int char_id, uint32 result) /// 2 (0x719): A database error occurred. /// Any (0x718): An unknown error has occurred. void char_delete2_cancel_ack(int fd, int char_id, uint32 result) -{ - // HC: <082c>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); +{// HC: <082c>.W .L .L + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x82c; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOSET(fd,10); } -static void char_delete2_req(int fd, struct char_session_data *sd) -{ - // CH: <0827>.W .L - int char_id, i; - char *data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); - if (i == MAX_CHARS) { - // character not found - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle)) { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); - delete_date = strtoul(data, NULL, 10); - - if (delete_date) { // character already queued for deletion - char_delete2_ack(fd, char_id, 0, 0); - return; - } - - /* - // Aegis imposes these checks probably to avoid dead member - // entries in guilds/parties, otherwise they are not required. - // TODO: Figure out how these are enforced during waiting. - if( guild_id ) - {// character in guild - char_delete2_ack(fd, char_id, 4, 0); - return; - } - - if( party_id ) - {// character in party - char_delete2_ack(fd, char_id, 5, 0); - return; - } - */ - - // success - delete_date = time(NULL)+char_del_delay; - - if (SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id)) { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - char_delete2_ack(fd, char_id, 1, delete_date); +static void char_delete2_req(int fd, struct char_session_data* sd) +{// CH: <0827>.W .L + int char_id, i; + char* data; + time_t delete_date; + + char_id = RFIFOL(fd,2); + + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); + if( i == MAX_CHARS ) + {// character not found + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10); + + if( delete_date ) {// character already queued for deletion + char_delete2_ack(fd, char_id, 0, 0); + return; + } + +/* + // Aegis imposes these checks probably to avoid dead member + // entries in guilds/parties, otherwise they are not required. + // TODO: Figure out how these are enforced during waiting. + if( guild_id ) + {// character in guild + char_delete2_ack(fd, char_id, 4, 0); + return; + } + + if( party_id ) + {// character in party + char_delete2_ack(fd, char_id, 5, 0); + return; + } +*/ + + // success + delete_date = time(NULL)+char_del_delay; + + if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id) ) + { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + char_delete2_ack(fd, char_id, 1, delete_date); } -static void char_delete2_accept(int fd, struct char_session_data *sd) -{ - // CH: <0829>.W .L .6B - char birthdate[8+1]; - int char_id, i, k; - unsigned int base_level; - char *data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); - - // construct "YY-MM-DD" - birthdate[0] = RFIFOB(fd,6); - birthdate[1] = RFIFOB(fd,7); - birthdate[2] = '-'; - birthdate[3] = RFIFOB(fd,8); - birthdate[4] = RFIFOB(fd,9); - birthdate[5] = '-'; - birthdate[6] = RFIFOB(fd,10); - birthdate[7] = RFIFOB(fd,11); - birthdate[8] = 0; - - ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); - if (i == MAX_CHARS) { - // character not found - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle)) { - // data error - Sql_ShowDebug(sql_handle); - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); - base_level = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 1, &data, NULL); - delete_date = strtoul(data, NULL, 10); - - if (!delete_date || delete_date>time(NULL)) { - // not queued or delay not yet passed - char_delete2_accept_ack(fd, char_id, 4); - return; - } - - if (strcmp(sd->birthdate+2, birthdate)) { // +2 to cut off the century - // birth date is wrong - char_delete2_accept_ack(fd, char_id, 5); - return; - } - - if ((char_del_level > 0 && base_level >= (unsigned int)char_del_level) || (char_del_level < 0 && base_level <= (unsigned int)(-char_del_level))) { - // character level config restriction - char_delete2_accept_ack(fd, char_id, 2); - return; - } - - // success - if (delete_char_sql(char_id) < 0) { - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - // refresh character list cache - for (k = i; k < MAX_CHARS-1; k++) { - sd->found_char[k] = sd->found_char[k+1]; - } - sd->found_char[MAX_CHARS-1] = -1; - - char_delete2_accept_ack(fd, char_id, 1); +static void char_delete2_accept(int fd, struct char_session_data* sd) +{// CH: <0829>.W .L .6B + char birthdate[8+1]; + int char_id, i, k; + unsigned int base_level; + char* data; + time_t delete_date; + + char_id = RFIFOL(fd,2); + + ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); + + // construct "YY-MM-DD" + birthdate[0] = RFIFOB(fd,6); + birthdate[1] = RFIFOB(fd,7); + birthdate[2] = '-'; + birthdate[3] = RFIFOB(fd,8); + birthdate[4] = RFIFOB(fd,9); + birthdate[5] = '-'; + birthdate[6] = RFIFOB(fd,10); + birthdate[7] = RFIFOB(fd,11); + birthdate[8] = 0; + + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); + if( i == MAX_CHARS ) + {// character not found + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) + {// data error + Sql_ShowDebug(sql_handle); + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 1, &data, NULL); delete_date = strtoul(data, NULL, 10); + + if( !delete_date || delete_date>time(NULL) ) + {// not queued or delay not yet passed + char_delete2_accept_ack(fd, char_id, 4); + return; + } + + if( strcmp(sd->birthdate+2, birthdate) ) // +2 to cut off the century + {// birth date is wrong + char_delete2_accept_ack(fd, char_id, 5); + return; + } + + if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) ) + {// character level config restriction + char_delete2_accept_ack(fd, char_id, 2); + return; + } + + // success + if( delete_char_sql(char_id) < 0 ) + { + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + // refresh character list cache + for(k = i; k < MAX_CHARS-1; k++) + { + sd->found_char[k] = sd->found_char[k+1]; + } + sd->found_char[MAX_CHARS-1] = -1; + + char_delete2_accept_ack(fd, char_id, 1); } -static void char_delete2_cancel(int fd, struct char_session_data *sd) -{ - // CH: <082b>.W .L - int char_id, i; - - char_id = RFIFOL(fd,2); - - ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); - if (i == MAX_CHARS) { - // character not found - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - // there is no need to check, whether or not the character was - // queued for deletion, as the client prints an error message by - // itself, if it was not the case (@see char_delete2_cancel_ack) - if (SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id)) { - Sql_ShowDebug(sql_handle); - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - char_delete2_cancel_ack(fd, char_id, 1); +static void char_delete2_cancel(int fd, struct char_session_data* sd) +{// CH: <082b>.W .L + int char_id, i; + + char_id = RFIFOL(fd,2); + + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); + if( i == MAX_CHARS ) + {// character not found + char_delete2_cancel_ack(fd, char_id, 2); + return; + } + + // there is no need to check, whether or not the character was + // queued for deletion, as the client prints an error message by + // itself, if it was not the case (@see char_delete2_cancel_ack) + if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + char_delete2_cancel_ack(fd, char_id, 2); + return; + } + + char_delete2_cancel_ack(fd, char_id, 1); } int parse_char(int fd) { - int i, ch; - char email[40]; - unsigned short cmd; - int map_fd; - struct char_session_data *sd; - uint32 ipl = session[fd]->client_addr; - - sd = (struct char_session_data *)session[fd]->session_data; - - // disconnect any player if no login-server. - if (login_fd < 0) - set_eof(fd); - - if (session[fd]->flag.eof) { - if (sd != NULL && sd->auth) { - // already authed client - struct online_char_data *data = (struct online_char_data *)idb_get(online_char_db, sd->account_id); - if (data != NULL && data->fd == fd) - data->fd = -1; - if (data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] - set_char_offline(-1,sd->account_id); - } - do_close(fd); - return 0; - } - - while (RFIFOREST(fd) >= 2) { - //For use in packets that depend on an sd being present [Skotlex] -#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } - - cmd = RFIFOW(fd,0); - switch (cmd) { - - // request to connect - // 0065 .L .L .L .W .B - case 0x65: - if (RFIFOREST(fd) < 17) - return 0; - { - struct auth_node *node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - int sex = RFIFOB(fd,16); - RFIFOSKIP(fd,17); - - ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); - - if (sd) { - //Received again auth packet for already authentified account?? Discard it. - //TODO: Perhaps log this as a hack attempt? - //TODO: and perhaps send back a reply? - break; - } - - CREATE(session[fd]->session_data, struct char_session_data, 1); - sd = (struct char_session_data *)session[fd]->session_data; - sd->account_id = account_id; - sd->login_id1 = login_id1; - sd->login_id2 = login_id2; - sd->sex = sex; - sd->auth = false; // not authed yet - - // send back account_id - WFIFOHEAD(fd,4); - WFIFOL(fd,0) = account_id; - WFIFOSET(fd,4); - - if (runflag != CHARSERVER_ST_RUNNING) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0;// rejected from server - WFIFOSET(fd,3); - break; - } - - // search authentification - node = (struct auth_node *)idb_get(auth_db, account_id); - if (node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 /*&& - node->ip == ipl*/) { - // authentication found (coming from map server) - idb_remove(auth_db, account_id); - char_auth_ok(fd, sd); - } else { - // authentication not found (coming from login server) - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,23); - WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account - WFIFOL(login_fd,2) = sd->account_id; - WFIFOL(login_fd,6) = sd->login_id1; - WFIFOL(login_fd,10) = sd->login_id2; - WFIFOB(login_fd,14) = sd->sex; - WFIFOL(login_fd,15) = htonl(ipl); - WFIFOL(login_fd,19) = fd; - WFIFOSET(login_fd,23); - } else { // if no login-server, we must refuse connection - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } - } - } - break; - - // char select - case 0x66: - FIFOSD_CHECK(3); - { - struct mmo_charstatus char_dat; - struct mmo_charstatus *cd; - char *data; - int char_id; - uint32 subnet_map_ip; - struct auth_node *node; - - int slot = RFIFOB(fd,2); - RFIFOSKIP(fd,3); - - if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) - || SQL_SUCCESS != Sql_NextRow(sql_handle) - || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL)) { - //Not found?? May be forged packet. - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; // rejected from server - WFIFOSET(fd,3); - break; - } - - char_id = atoi(data); - Sql_FreeResult(sql_handle); - mmo_char_fromsql(char_id, &char_dat, true); - - //Have to switch over to the DB instance otherwise data won't propagate [Kevin] - cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); - cd->sex = sd->sex; - - if (log_char) { - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", - charlog_db, sd->account_id, slot, esc_name)) - Sql_ShowDebug(sql_handle); - } - ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); - - // searching map server - i = search_mapserver(cd->last_point.map, -1, -1); - - // if map is not found, we check major cities - if (i < 0 || !cd->last_point.map) { - unsigned short j; - //First check that there's actually a map server online. - ARR_FIND(0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0]); - if (j == ARRAYLENGTH(server)) { - ShowInfo("Connection Closed. No map servers available.\n"); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { - cd->last_point.x = 273; - cd->last_point.y = 354; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { - cd->last_point.x = 120; - cd->last_point.y = 100; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { - cd->last_point.x = 160; - cd->last_point.y = 94; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { - cd->last_point.x = 116; - cd->last_point.y = 57; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { - cd->last_point.x = 87; - cd->last_point.y = 117; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { - cd->last_point.x = 94; - cd->last_point.y = 103; - } else { - ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); - cd->last_point.map = j; - } - - //Send NEW auth packet [Kevin] - //FIXME: is this case even possible? [ultramage] - if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) { - ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); - server[i].fd = -1; - memset(&server[i], 0, sizeof(struct mmo_map_server)); - //Send server closed. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - - //Send player to map - WFIFOHEAD(fd,28); - WFIFOW(fd,0) = 0x71; - WFIFOL(fd,2) = cd->char_id; - mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char *)WFIFOP(fd,6)); - subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza] - WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); - WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - WFIFOSET(fd,28); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->char_id = cd->char_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->expiration_time = sd->expiration_time; - node->group_id = sd->group_id; - node->ip = ipl; - idb_put(auth_db, sd->account_id, node); - - set_char_online(-2,node->char_id,sd->account_id); - - } - break; - - // create new char + int i, ch; + char email[40]; + unsigned short cmd; + int map_fd; + struct char_session_data* sd; + uint32 ipl = session[fd]->client_addr; + + sd = (struct char_session_data*)session[fd]->session_data; + + // disconnect any player if no login-server. + if(login_fd < 0) + set_eof(fd); + + if(session[fd]->flag.eof) + { + if( sd != NULL && sd->auth ) + { // already authed client + struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id); + if( data != NULL && data->fd == fd) + data->fd = -1; + if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] + set_char_offline(-1,sd->account_id); + } + do_close(fd); + return 0; + } + + while( RFIFOREST(fd) >= 2 ) + { + //For use in packets that depend on an sd being present [Skotlex] + #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } + + cmd = RFIFOW(fd,0); + switch( cmd ) + { + + // request to connect + // 0065 .L .L .L .W .B + case 0x65: + if( RFIFOREST(fd) < 17 ) + return 0; + { + struct auth_node* node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + int sex = RFIFOB(fd,16); + RFIFOSKIP(fd,17); + + ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); + + if (sd) { + //Received again auth packet for already authentified account?? Discard it. + //TODO: Perhaps log this as a hack attempt? + //TODO: and perhaps send back a reply? + break; + } + + CREATE(session[fd]->session_data, struct char_session_data, 1); + sd = (struct char_session_data*)session[fd]->session_data; + sd->account_id = account_id; + sd->login_id1 = login_id1; + sd->login_id2 = login_id2; + sd->sex = sex; + sd->auth = false; // not authed yet + + // send back account_id + WFIFOHEAD(fd,4); + WFIFOL(fd,0) = account_id; + WFIFOSET(fd,4); + + if( runflag != CHARSERVER_ST_RUNNING ) + { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0;// rejected from server + WFIFOSET(fd,3); + break; + } + + // search authentification + node = (struct auth_node*)idb_get(auth_db, account_id); + if( node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 /*&& + node->ip == ipl*/ ) + {// authentication found (coming from map server) + idb_remove(auth_db, account_id); + char_auth_ok(fd, sd); + } + else + {// authentication not found (coming from login server) + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,23); + WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account + WFIFOL(login_fd,2) = sd->account_id; + WFIFOL(login_fd,6) = sd->login_id1; + WFIFOL(login_fd,10) = sd->login_id2; + WFIFOB(login_fd,14) = sd->sex; + WFIFOL(login_fd,15) = htonl(ipl); + WFIFOL(login_fd,19) = fd; + WFIFOSET(login_fd,23); + } else { // if no login-server, we must refuse connection + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + } + } + } + break; + + // char select + case 0x66: + FIFOSD_CHECK(3); + { + struct mmo_charstatus char_dat; + struct mmo_charstatus *cd; + char* data; + int char_id; + uint32 subnet_map_ip; + struct auth_node* node; + + int slot = RFIFOB(fd,2); + RFIFOSKIP(fd,3); + + if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) + || SQL_SUCCESS != Sql_NextRow(sql_handle) + || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) ) + { //Not found?? May be forged packet. + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; // rejected from server + WFIFOSET(fd,3); + break; + } + + char_id = atoi(data); + Sql_FreeResult(sql_handle); + mmo_char_fromsql(char_id, &char_dat, true); + + //Have to switch over to the DB instance otherwise data won't propagate [Kevin] + cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); + cd->sex = sd->sex; + + if (log_char) { + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", + charlog_db, sd->account_id, slot, esc_name) ) + Sql_ShowDebug(sql_handle); + } + ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); + + // searching map server + i = search_mapserver(cd->last_point.map, -1, -1); + + // if map is not found, we check major cities + if (i < 0 || !cd->last_point.map) { + unsigned short j; + //First check that there's actually a map server online. + ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] ); + if (j == ARRAYLENGTH(server)) { + ShowInfo("Connection Closed. No map servers available.\n"); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { + cd->last_point.x = 273; + cd->last_point.y = 354; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { + cd->last_point.x = 120; + cd->last_point.y = 100; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { + cd->last_point.x = 160; + cd->last_point.y = 94; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { + cd->last_point.x = 116; + cd->last_point.y = 57; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { + cd->last_point.x = 87; + cd->last_point.y = 117; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { + cd->last_point.x = 94; + cd->last_point.y = 103; + } else { + ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); + cd->last_point.map = j; + } + + //Send NEW auth packet [Kevin] + //FIXME: is this case even possible? [ultramage] + if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) + { + ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); + server[i].fd = -1; + memset(&server[i], 0, sizeof(struct mmo_map_server)); + //Send server closed. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + + //Send player to map + WFIFOHEAD(fd,28); + WFIFOW(fd,0) = 0x71; + WFIFOL(fd,2) = cd->char_id; + mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6)); + subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza] + WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); + WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + WFIFOSET(fd,28); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->char_id = cd->char_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->expiration_time = sd->expiration_time; + node->group_id = sd->group_id; + node->ip = ipl; + idb_put(auth_db, sd->account_id, node); + + set_char_online(-2,node->char_id,sd->account_id); + + } + break; + + // create new char #if PACKETVER >= 20120307 - // S 0970 .24B .B .W .W - case 0x970: - FIFOSD_CHECK(31); + // S 0970 .24B .B .W .W + case 0x970: + FIFOSD_CHECK(31); #else - // S 0067 .24B .B .B .B .B .B .B .B .W .W - case 0x67: - FIFOSD_CHECK(37); + // S 0067 .24B .B .B .B .B .B .B .B .W .W + case 0x67: + FIFOSD_CHECK(37); #endif - if (!char_new) //turn character creation on/off [Kevin] - i = -2; - else + if( !char_new ) //turn character creation on/off [Kevin] + i = -2; + else #if PACKETVER >= 20120307 - i = make_new_char_sql(sd, (char *)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29)); + i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29)); #else - i = make_new_char_sql(sd, (char *)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); + i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); #endif - //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) - if (i < 0) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6e; - switch (i) { - case -1: - WFIFOB(fd,2) = 0x00; - break; - case -2: - WFIFOB(fd,2) = 0xFF; - break; - case -3: - WFIFOB(fd,2) = 0x01; - break; - } - WFIFOSET(fd,3); - } else { - int len; - // retrieve data - struct mmo_charstatus char_dat; - mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. - - // send to player - WFIFOHEAD(fd,2+MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6d; - len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); - WFIFOSET(fd,len); - - // add new entry to the chars list - ARR_FIND(0, MAX_CHARS, ch, sd->found_char[ch] == -1); - if (ch < MAX_CHARS) - sd->found_char[ch] = i; // the char_id of the new char - } + //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) + if (i < 0) + { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6e; + switch (i) { + case -1: WFIFOB(fd,2) = 0x00; break; + case -2: WFIFOB(fd,2) = 0xFF; break; + case -3: WFIFOB(fd,2) = 0x01; break; + } + WFIFOSET(fd,3); + } + else + { + int len; + // retrieve data + struct mmo_charstatus char_dat; + mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. + + // send to player + WFIFOHEAD(fd,2+MAX_CHAR_BUF); + WFIFOW(fd,0) = 0x6d; + len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); + WFIFOSET(fd,len); + + // add new entry to the chars list + ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); + if( ch < MAX_CHARS ) + sd->found_char[ch] = i; // the char_id of the new char + } #if PACKETVER >= 20120307 - RFIFOSKIP(fd,31); + RFIFOSKIP(fd,31); #else - RFIFOSKIP(fd,37); + RFIFOSKIP(fd,37); #endif - break; - - // delete char - case 0x68: - // 2004-04-19aSakexe+ langtype 12 char deletion packet - case 0x1fb: - if (cmd == 0x68) FIFOSD_CHECK(46); - if (cmd == 0x1fb) FIFOSD_CHECK(56); - { - int cid = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); - memcpy(email, RFIFOP(fd,6), 40); - RFIFOSKIP(fd,(cmd == 0x68) ? 46 : 56); - - // Check if e-mail is correct - if (strcmpi(email, sd->email) && //email does not matches and - ( - strcmp("a@a.com", sd->email) || //it is not default email, or - (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default - )) { //Fail - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - - // check if this char exists - ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); - if (i == MAX_CHARS) { - // Such a character does not exist in the account - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - break; - } - - // remove char from list and compact it - for (ch = i; ch < MAX_CHARS-1; ch++) - sd->found_char[ch] = sd->found_char[ch+1]; - sd->found_char[MAX_CHARS-1] = -1; - - /* Delete character */ - if (delete_char_sql(cid)<0) { - //can't delete the char - //either SQL error or can't delete by some CONFIG conditions - //del fail - WFIFOHEAD(fd,3); - WFIFOW(fd, 0) = 0x70; - WFIFOB(fd, 2) = 0; - WFIFOSET(fd, 3); - break; - } - /* Char successfully deleted.*/ - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x6f; - WFIFOSET(fd,2); - } - break; - - // client keep-alive packet (every 12 seconds) - // R 0187 .l - case 0x187: - if (RFIFOREST(fd) < 6) - return 0; - RFIFOSKIP(fd,6); - break; - - // char rename request - // R 028d .l .l .24B - case 0x28d: - FIFOSD_CHECK(34); - { - int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); - RFIFOSKIP(fd,34); - - if (aid != sd->account_id) - break; - ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); - if (i == MAX_CHARS) - break; - - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if (!check_char_name(name,esc_name)) { - i = 1; - safestrncpy(sd->new_name, name, NAME_LENGTH); - } else - i = 0; - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x28e; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - //Confirm change name. - // 0x28f .L - case 0x28f: - // 0: Sucessfull - // 1: This character's name has already been changed. You cannot change a character's name more than once. - // 2: User information is not correct. - // 3: You have failed to change this character's name. - // 4: Another user is using this character name, so please select another one. - FIFOSD_CHECK(6); - { - int i; - int cid = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); - if (i == MAX_CHARS) - break; - i = rename_char_sql(sd, cid); - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x290; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - - // captcha code request (not implemented) - // R 07e5 .w .l - case 0x7e5: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,8); - break; - - // captcha code check (not implemented) - // R 07e7 .w .l .b10 .b14 - case 0x7e7: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,32); - break; - - // deletion timer request - case 0x827: - FIFOSD_CHECK(6); - char_delete2_req(fd, sd); - RFIFOSKIP(fd,6); - break; - - // deletion accept request - case 0x829: - FIFOSD_CHECK(12); - char_delete2_accept(fd, sd); - RFIFOSKIP(fd,12); - break; - - // deletion cancel request - case 0x82b: - FIFOSD_CHECK(6); - char_delete2_cancel(fd, sd); - RFIFOSKIP(fd,6); - break; - - // login as map-server - case 0x2af8: - if (RFIFOREST(fd) < 60) - return 0; - { - char *l_user = (char *)RFIFOP(fd,2); - char *l_pass = (char *)RFIFOP(fd,26); - l_user[23] = '\0'; - l_pass[23] = '\0'; - ARR_FIND(0, ARRAYLENGTH(server), i, server[i].fd <= 0); - if (runflag != CHARSERVER_ST_RUNNING || - i == ARRAYLENGTH(server) || - strcmp(l_user, userid) != 0 || - strcmp(l_pass, passwd) != 0) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - - server[i].fd = fd; - server[i].ip = ntohl(RFIFOL(fd,54)); - server[i].port = ntohs(RFIFOW(fd,58)); - server[i].users = 0; - memset(server[i].map, 0, sizeof(server[i].map)); - session[fd]->func_parse = parse_frommap; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - char_mapif_init(fd); - } - - RFIFOSKIP(fd,60); - } - return 0; // avoid processing of followup packets here - - // unknown packet received - default: - ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; + break; + + // delete char + case 0x68: + // 2004-04-19aSakexe+ langtype 12 char deletion packet + case 0x1fb: + if (cmd == 0x68) FIFOSD_CHECK(46); + if (cmd == 0x1fb) FIFOSD_CHECK(56); + { + int cid = RFIFOL(fd,2); + + ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); + memcpy(email, RFIFOP(fd,6), 40); + RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56); + + // Check if e-mail is correct + if(strcmpi(email, sd->email) && //email does not matches and + ( + strcmp("a@a.com", sd->email) || //it is not default email, or + (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default + )) { //Fail + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; // 00 = Incorrect Email address + WFIFOSET(fd,3); + break; + } + + // check if this char exists + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); + if( i == MAX_CHARS ) + { // Such a character does not exist in the account + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + break; + } + + // remove char from list and compact it + for(ch = i; ch < MAX_CHARS-1; ch++) + sd->found_char[ch] = sd->found_char[ch+1]; + sd->found_char[MAX_CHARS-1] = -1; + + /* Delete character */ + if(delete_char_sql(cid)<0){ + //can't delete the char + //either SQL error or can't delete by some CONFIG conditions + //del fail + WFIFOHEAD(fd,3); + WFIFOW(fd, 0) = 0x70; + WFIFOB(fd, 2) = 0; + WFIFOSET(fd, 3); + break; + } + /* Char successfully deleted.*/ + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x6f; + WFIFOSET(fd,2); + } + break; + + // client keep-alive packet (every 12 seconds) + // R 0187 .l + case 0x187: + if (RFIFOREST(fd) < 6) + return 0; + RFIFOSKIP(fd,6); + break; + + // char rename request + // R 028d .l .l .24B + case 0x28d: + FIFOSD_CHECK(34); + { + int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); + RFIFOSKIP(fd,34); + + if( aid != sd->account_id ) + break; + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); + if( i == MAX_CHARS ) + break; + + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( !check_char_name(name,esc_name) ) + { + i = 1; + safestrncpy(sd->new_name, name, NAME_LENGTH); + } + else + i = 0; + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x28e; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; + //Confirm change name. + // 0x28f .L + case 0x28f: + // 0: Sucessfull + // 1: This character's name has already been changed. You cannot change a character's name more than once. + // 2: User information is not correct. + // 3: You have failed to change this character's name. + // 4: Another user is using this character name, so please select another one. + FIFOSD_CHECK(6); + { + int i; + int cid = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); + if( i == MAX_CHARS ) + break; + i = rename_char_sql(sd, cid); + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x290; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; + + // captcha code request (not implemented) + // R 07e5 .w .l + case 0x7e5: + WFIFOHEAD(fd,5); + WFIFOW(fd,0) = 0x7e9; + WFIFOW(fd,2) = 5; + WFIFOB(fd,4) = 1; + WFIFOSET(fd,5); + RFIFOSKIP(fd,8); + break; + + // captcha code check (not implemented) + // R 07e7 .w .l .b10 .b14 + case 0x7e7: + WFIFOHEAD(fd,5); + WFIFOW(fd,0) = 0x7e9; + WFIFOW(fd,2) = 5; + WFIFOB(fd,4) = 1; + WFIFOSET(fd,5); + RFIFOSKIP(fd,32); + break; + + // deletion timer request + case 0x827: + FIFOSD_CHECK(6); + char_delete2_req(fd, sd); + RFIFOSKIP(fd,6); + break; + + // deletion accept request + case 0x829: + FIFOSD_CHECK(12); + char_delete2_accept(fd, sd); + RFIFOSKIP(fd,12); + break; + + // deletion cancel request + case 0x82b: + FIFOSD_CHECK(6); + char_delete2_cancel(fd, sd); + RFIFOSKIP(fd,6); + break; + + // login as map-server + case 0x2af8: + if (RFIFOREST(fd) < 60) + return 0; + { + char* l_user = (char*)RFIFOP(fd,2); + char* l_pass = (char*)RFIFOP(fd,26); + l_user[23] = '\0'; + l_pass[23] = '\0'; + ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 ); + if( runflag != CHARSERVER_ST_RUNNING || + i == ARRAYLENGTH(server) || + strcmp(l_user, userid) != 0 || + strcmp(l_pass, passwd) != 0 ) + { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } else { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + + server[i].fd = fd; + server[i].ip = ntohl(RFIFOL(fd,54)); + server[i].port = ntohs(RFIFOW(fd,58)); + server[i].users = 0; + memset(server[i].map, 0, sizeof(server[i].map)); + session[fd]->func_parse = parse_frommap; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + char_mapif_init(fd); + } + + RFIFOSKIP(fd,60); + } + return 0; // avoid processing of followup packets here + + // unknown packet received + default: + ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; } // Console Command Parser [Wizputer] -int parse_console(const char *command) +int parse_console(const char* command) { - ShowNotice("Console command: %s\n", command); - - if (strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0) - runflag = 0; - else if (strcmpi("alive", command) == 0 || strcmpi("status", command) == 0) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if (strcmpi("help", command) == 0) { - ShowInfo("To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo("To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - } - - return 0; + ShowNotice("Console command: %s\n", command); + + if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0 ) + runflag = 0; + else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 ) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if( strcmpi("help", command) == 0 ) + { + ShowInfo("To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|quit|end'\n"); + ShowInfo("To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + } + + return 0; } int mapif_sendall(unsigned char *buf, unsigned int len) { - int i, c; - - c = 0; - for (i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; + int i, c; + + c = 0; + for(i = 0; i < ARRAYLENGTH(server); i++) { + int fd; + if ((fd = server[i].fd) > 0) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; } int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) { - int i, c; - - c = 0; - for (i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0 && fd != sfd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; + int i, c; + + c = 0; + for(i = 0; i < ARRAYLENGTH(server); i++) { + int fd; + if ((fd = server[i].fd) > 0 && fd != sfd) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; } int mapif_send(int fd, unsigned char *buf, unsigned int len) { - if (fd >= 0) { - int i; - ARR_FIND(0, ARRAYLENGTH(server), i, fd == server[i].fd); - if (i < ARRAYLENGTH(server)) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - return 1; - } - } - return 0; + if (fd >= 0) { + int i; + ARR_FIND( 0, ARRAYLENGTH(server), i, fd == server[i].fd ); + if( i < ARRAYLENGTH(server) ) + { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + return 1; + } + } + return 0; } int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) { - uint8 buf[6]; - int users = count_users(); - - // only send an update when needed - static int prev_users = 0; - if (prev_users == users) - return 0; - prev_users = users; - - if (login_fd > 0 && session[login_fd]) { - // send number of user to login server - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2714; - WFIFOL(login_fd,2) = users; - WFIFOSET(login_fd,6); - } - - // send number of players to all map-servers - WBUFW(buf,0) = 0x2b00; - WBUFL(buf,2) = users; - mapif_sendall(buf,6); - - return 0; + uint8 buf[6]; + int users = count_users(); + + // only send an update when needed + static int prev_users = 0; + if( prev_users == users ) + return 0; + prev_users = users; + + if( login_fd > 0 && session[login_fd] ) + { + // send number of user to login server + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2714; + WFIFOL(login_fd,2) = users; + WFIFOSET(login_fd,6); + } + + // send number of players to all map-servers + WBUFW(buf,0) = 0x2b00; + WBUFL(buf,2) = users; + mapif_sendall(buf,6); + + return 0; } /** @@ -4183,64 +4236,66 @@ int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) */ static int send_accounts_tologin_sub(DBKey key, DBData *data, va_list ap) { - struct online_char_data *character = db_data2ptr(data); - int *i = va_arg(ap, int *); - - if (character->server > -1) { - WFIFOL(login_fd,8+(*i)*4) = character->account_id; - (*i)++; - return 1; - } - return 0; + struct online_char_data* character = db_data2ptr(data); + int* i = va_arg(ap, int*); + + if(character->server > -1) + { + WFIFOL(login_fd,8+(*i)*4) = character->account_id; + (*i)++; + return 1; + } + return 0; } int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data) { - if (login_fd > 0 && session[login_fd]) { - // send account list to login server - int users = online_char_db->size(online_char_db); - int i = 0; - - WFIFOHEAD(login_fd,8+users*4); - WFIFOW(login_fd,0) = 0x272d; - online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); - WFIFOW(login_fd,2) = 8+ i*4; - WFIFOL(login_fd,4) = i; - WFIFOSET(login_fd,WFIFOW(login_fd,2)); - } - return 0; + if (login_fd > 0 && session[login_fd]) + { + // send account list to login server + int users = online_char_db->size(online_char_db); + int i = 0; + + WFIFOHEAD(login_fd,8+users*4); + WFIFOW(login_fd,0) = 0x272d; + online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); + WFIFOW(login_fd,2) = 8+ i*4; + WFIFOL(login_fd,4) = i; + WFIFOSET(login_fd,WFIFOW(login_fd,2)); + } + return 0; } int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data) { - if (login_fd > 0 && session[login_fd] != NULL) - return 0; - - ShowInfo("Attempt to connect to login-server...\n"); - login_fd = make_connection(login_ip, login_port, false); - if (login_fd == -1) { - //Try again later. [Skotlex] - login_fd = 0; - return 0; - } - session[login_fd]->func_parse = parse_fromlogin; - session[login_fd]->flag.server = 1; - realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - WFIFOHEAD(login_fd,86); - WFIFOW(login_fd,0) = 0x2710; - memcpy(WFIFOP(login_fd,2), userid, 24); - memcpy(WFIFOP(login_fd,26), passwd, 24); - WFIFOL(login_fd,50) = 0; - WFIFOL(login_fd,54) = htonl(char_ip); - WFIFOW(login_fd,58) = htons(char_port); - memcpy(WFIFOP(login_fd,60), server_name, 20); - WFIFOW(login_fd,80) = 0; - WFIFOW(login_fd,82) = char_maintenance; - WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] - WFIFOSET(login_fd,86); - - return 1; + if (login_fd > 0 && session[login_fd] != NULL) + return 0; + + ShowInfo("Attempt to connect to login-server...\n"); + login_fd = make_connection(login_ip, login_port, false); + if (login_fd == -1) + { //Try again later. [Skotlex] + login_fd = 0; + return 0; + } + session[login_fd]->func_parse = parse_fromlogin; + session[login_fd]->flag.server = 1; + realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + WFIFOHEAD(login_fd,86); + WFIFOW(login_fd,0) = 0x2710; + memcpy(WFIFOP(login_fd,2), userid, 24); + memcpy(WFIFOP(login_fd,26), passwd, 24); + WFIFOL(login_fd,50) = 0; + WFIFOL(login_fd,54) = htonl(char_ip); + WFIFOW(login_fd,58) = htons(char_port); + memcpy(WFIFOP(login_fd,60), server_name, 20); + WFIFOW(login_fd,80) = 0; + WFIFOW(login_fd,82) = char_maintenance; + WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] + WFIFOSET(login_fd,86); + + return 1; } //------------------------------------------------ @@ -4249,13 +4304,13 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data //------------------------------------------------ static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data) { - struct online_char_data *character; - if ((character = (struct online_char_data *)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) { - //Mark it offline due to timeout. - character->waiting_disconnect = INVALID_TIMER; - set_char_offline(character->char_id, character->account_id); - } - return 0; + struct online_char_data* character; + if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) + { //Mark it offline due to timeout. + character->waiting_disconnect = INVALID_TIMER; + set_char_offline(character->char_id, character->account_id); + } + return 0; } /** @@ -4263,21 +4318,21 @@ static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_ */ static int online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) { - struct online_char_data *character= db_data2ptr(data); - if (character->fd != -1) - return 0; //Character still connected - if (character->server == -2) //Unknown server.. set them offline - set_char_offline(character->char_id, character->account_id); - if (character->server < 0) - //Free data from players that have not been online for a while. - db_remove(online_char_db, key); - return 0; + struct online_char_data *character= db_data2ptr(data); + if (character->fd != -1) + return 0; //Character still connected + if (character->server == -2) //Unknown server.. set them offline + set_char_offline(character->char_id, character->account_id); + if (character->server < 0) + //Free data from players that have not been online for a while. + db_remove(online_char_db, key); + return 0; } static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - online_char_db->foreach(online_char_db, online_data_cleanup_sub); - return 0; + online_char_db->foreach(online_char_db, online_data_cleanup_sub); + return 0; } //---------------------------------- @@ -4286,323 +4341,327 @@ static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data //---------------------------------- int char_lan_config_read(const char *lancfgName) { - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if ((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - while (fgets(line, sizeof(line), fp)) { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if (sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { - - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - remove_control_chars(w1); - remove_control_chars(w2); - remove_control_chars(w3); - remove_control_chars(w4); - - if (strcmpi(w1, "subnet") == 0) { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if ((subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask)) { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - if (subnet_count > 1) /* only useful if there is more than 1 */ - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + while(fgets(line, sizeof(line), fp)) { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { + + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + remove_control_chars(w1); + remove_control_chars(w2); + remove_control_chars(w3); + remove_control_chars(w4); + + if( strcmpi(w1, "subnet") == 0 ) + { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) + { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + if( subnet_count > 1 ) /* only useful if there is more than 1 */ + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; } -void sql_config_read(const char *cfgName) +void sql_config_read(const char* cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("File not found: %s\n", cfgName); - return; - } - - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (!strcmpi(w1,"char_db")) - safestrncpy(char_db, w2, sizeof(char_db)); - else if (!strcmpi(w1,"scdata_db")) - safestrncpy(scdata_db, w2, sizeof(scdata_db)); - else if (!strcmpi(w1,"cart_db")) - safestrncpy(cart_db, w2, sizeof(cart_db)); - else if (!strcmpi(w1,"inventory_db")) - safestrncpy(inventory_db, w2, sizeof(inventory_db)); - else if (!strcmpi(w1,"charlog_db")) - safestrncpy(charlog_db, w2, sizeof(charlog_db)); - else if (!strcmpi(w1,"storage_db")) - safestrncpy(storage_db, w2, sizeof(storage_db)); - else if (!strcmpi(w1,"reg_db")) - safestrncpy(reg_db, w2, sizeof(reg_db)); - else if (!strcmpi(w1,"skill_db")) - safestrncpy(skill_db, w2, sizeof(skill_db)); - else if (!strcmpi(w1,"interlog_db")) - safestrncpy(interlog_db, w2, sizeof(interlog_db)); - else if (!strcmpi(w1,"memo_db")) - safestrncpy(memo_db, w2, sizeof(memo_db)); - else if (!strcmpi(w1,"guild_db")) - safestrncpy(guild_db, w2, sizeof(guild_db)); - else if (!strcmpi(w1,"guild_alliance_db")) - safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); - else if (!strcmpi(w1,"guild_castle_db")) - safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); - else if (!strcmpi(w1,"guild_expulsion_db")) - safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); - else if (!strcmpi(w1,"guild_member_db")) - safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); - else if (!strcmpi(w1,"guild_skill_db")) - safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); - else if (!strcmpi(w1,"guild_position_db")) - safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); - else if (!strcmpi(w1,"guild_storage_db")) - safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); - else if (!strcmpi(w1,"party_db")) - safestrncpy(party_db, w2, sizeof(party_db)); - else if (!strcmpi(w1,"pet_db")) - safestrncpy(pet_db, w2, sizeof(pet_db)); - else if (!strcmpi(w1,"mail_db")) - safestrncpy(mail_db, w2, sizeof(mail_db)); - else if (!strcmpi(w1,"auction_db")) - safestrncpy(auction_db, w2, sizeof(auction_db)); - else if (!strcmpi(w1,"friend_db")) - safestrncpy(friend_db, w2, sizeof(friend_db)); - else if (!strcmpi(w1,"hotkey_db")) - safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); - else if (!strcmpi(w1,"quest_db")) - safestrncpy(quest_db,w2,sizeof(quest_db)); - else if (!strcmpi(w1,"homunculus_db")) - safestrncpy(homunculus_db,w2,sizeof(homunculus_db)); - else if (!strcmpi(w1,"skill_homunculus_db")) - safestrncpy(skill_homunculus_db,w2,sizeof(skill_homunculus_db)); - else if (!strcmpi(w1,"mercenary_db")) - safestrncpy(mercenary_db,w2,sizeof(mercenary_db)); - else if (!strcmpi(w1,"mercenary_owner_db")) - safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db)); - //support the import command, just like any other config - else if (!strcmpi(w1,"import")) - sql_config_read(w2); - } - fclose(fp); - ShowInfo("Done reading %s.\n", cfgName); + char line[1024], w1[1024], w2[1024]; + FILE* fp; + + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("File not found: %s\n", cfgName); + return; + } + + while(fgets(line, sizeof(line), fp)) + { + if(line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if(!strcmpi(w1,"char_db")) + safestrncpy(char_db, w2, sizeof(char_db)); + else if(!strcmpi(w1,"scdata_db")) + safestrncpy(scdata_db, w2, sizeof(scdata_db)); + else if(!strcmpi(w1,"cart_db")) + safestrncpy(cart_db, w2, sizeof(cart_db)); + else if(!strcmpi(w1,"inventory_db")) + safestrncpy(inventory_db, w2, sizeof(inventory_db)); + else if(!strcmpi(w1,"charlog_db")) + safestrncpy(charlog_db, w2, sizeof(charlog_db)); + else if(!strcmpi(w1,"storage_db")) + safestrncpy(storage_db, w2, sizeof(storage_db)); + else if(!strcmpi(w1,"reg_db")) + safestrncpy(reg_db, w2, sizeof(reg_db)); + else if(!strcmpi(w1,"skill_db")) + safestrncpy(skill_db, w2, sizeof(skill_db)); + else if(!strcmpi(w1,"interlog_db")) + safestrncpy(interlog_db, w2, sizeof(interlog_db)); + else if(!strcmpi(w1,"memo_db")) + safestrncpy(memo_db, w2, sizeof(memo_db)); + else if(!strcmpi(w1,"guild_db")) + safestrncpy(guild_db, w2, sizeof(guild_db)); + else if(!strcmpi(w1,"guild_alliance_db")) + safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); + else if(!strcmpi(w1,"guild_castle_db")) + safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); + else if(!strcmpi(w1,"guild_expulsion_db")) + safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); + else if(!strcmpi(w1,"guild_member_db")) + safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); + else if(!strcmpi(w1,"guild_skill_db")) + safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); + else if(!strcmpi(w1,"guild_position_db")) + safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); + else if(!strcmpi(w1,"guild_storage_db")) + safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); + else if(!strcmpi(w1,"party_db")) + safestrncpy(party_db, w2, sizeof(party_db)); + else if(!strcmpi(w1,"pet_db")) + safestrncpy(pet_db, w2, sizeof(pet_db)); + else if(!strcmpi(w1,"mail_db")) + safestrncpy(mail_db, w2, sizeof(mail_db)); + else if(!strcmpi(w1,"auction_db")) + safestrncpy(auction_db, w2, sizeof(auction_db)); + else if(!strcmpi(w1,"friend_db")) + safestrncpy(friend_db, w2, sizeof(friend_db)); + else if(!strcmpi(w1,"hotkey_db")) + safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); + else if(!strcmpi(w1,"quest_db")) + safestrncpy(quest_db,w2,sizeof(quest_db)); + else if(!strcmpi(w1,"homunculus_db")) + safestrncpy(homunculus_db,w2,sizeof(homunculus_db)); + else if(!strcmpi(w1,"skill_homunculus_db")) + safestrncpy(skill_homunculus_db,w2,sizeof(skill_homunculus_db)); + else if(!strcmpi(w1,"mercenary_db")) + safestrncpy(mercenary_db,w2,sizeof(mercenary_db)); + else if(!strcmpi(w1,"mercenary_owner_db")) + safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db)); + //support the import command, just like any other config + else if(!strcmpi(w1,"import")) + sql_config_read(w2); + } + fclose(fp); + ShowInfo("Done reading %s.\n", cfgName); } -int char_config_read(const char *cfgName) +int char_config_read(const char* cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp = fopen(cfgName, "r"); - - if (fp == NULL) { - ShowError("Configuration file not found: %s.\n", cfgName); - return 1; - } - - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars(w1); - remove_control_chars(w2); - if (strcmpi(w1,"timestamp_format") == 0) { - safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); - } else if (strcmpi(w1,"console_silent")==0) { - msg_silent = atoi(w2); - if (msg_silent) /* only bother if its actually enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } else if (strcmpi(w1,"stdout_with_ansisequence")==0) { - stdout_with_ansisequence = config_switch(w2); - } else if (strcmpi(w1, "userid") == 0) { - safestrncpy(userid, w2, sizeof(userid)); - } else if (strcmpi(w1, "passwd") == 0) { - safestrncpy(passwd, w2, sizeof(passwd)); - } else if (strcmpi(w1, "server_name") == 0) { - safestrncpy(server_name, w2, sizeof(server_name)); - } else if (strcmpi(w1, "wisp_server_name") == 0) { - if (strlen(w2) >= 4) { - safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); - } - } else if (strcmpi(w1, "login_ip") == 0) { - char ip_str[16]; - login_ip = host2ip(w2); - if (login_ip) { - safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); - ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); - } - } else if (strcmpi(w1, "login_port") == 0) { - login_port = atoi(w2); - } else if (strcmpi(w1, "char_ip") == 0) { - char ip_str[16]; - char_ip = host2ip(w2); - if (char_ip) { - safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); - ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); - } - } else if (strcmpi(w1, "bind_ip") == 0) { - char ip_str[16]; - bind_ip = host2ip(w2); - if (bind_ip) { - safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); - ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); - } - } else if (strcmpi(w1, "char_port") == 0) { - char_port = atoi(w2); - } else if (strcmpi(w1, "char_maintenance") == 0) { - char_maintenance = atoi(w2); - } else if (strcmpi(w1, "char_new") == 0) { - char_new = (bool)atoi(w2); - } else if (strcmpi(w1, "char_new_display") == 0) { - char_new_display = atoi(w2); - } else if (strcmpi(w1, "max_connect_user") == 0) { - max_connect_user = atoi(w2); - if (max_connect_user < 0) - max_connect_user = 0; // unlimited online players - } else if (strcmpi(w1, "gm_allow_group") == 0) { - gm_allow_group = atoi(w2); - } else if (strcmpi(w1, "autosave_time") == 0) { - autosave_interval = atoi(w2)*1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - } else if (strcmpi(w1, "save_log") == 0) { - save_log = config_switch(w2); - } else if (strcmpi(w1, "start_point") == 0) { - char map[MAP_NAME_LENGTH_EXT]; - int x, y; - if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) - continue; - start_point.map = mapindex_name2id(map); - if (!start_point.map) - ShowError("Specified start_point %s not found in map-index cache.\n", map); - start_point.x = x; - start_point.y = y; - } else if (strcmpi(w1, "start_zeny") == 0) { - start_zeny = atoi(w2); - if (start_zeny < 0) - start_zeny = 0; - } else if (strcmpi(w1, "start_weapon") == 0) { - start_weapon = atoi(w2); - if (start_weapon < 0) - start_weapon = 0; - } else if (strcmpi(w1, "start_armor") == 0) { - start_armor = atoi(w2); - if (start_armor < 0) - start_armor = 0; - } else if (strcmpi(w1,"log_char")==0) { //log char or not [devil] - log_char = atoi(w2); - } else if (strcmpi(w1, "unknown_char_name") == 0) { - safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); - unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "name_ignoring_case") == 0) { - name_ignoring_case = (bool)config_switch(w2); - } else if (strcmpi(w1, "char_name_option") == 0) { - char_name_option = atoi(w2); - } else if (strcmpi(w1, "char_name_letters") == 0) { - safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); - } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] - char_per_account = atoi(w2); - if (char_per_account == 0 || char_per_account > MAX_CHARS) { - if (char_per_account > MAX_CHARS) - ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS); - char_per_account = MAX_CHARS; - } - } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] - char_del_level = atoi(w2); - } else if (strcmpi(w1, "char_del_delay") == 0) { - char_del_delay = atoi(w2); - } else if (strcmpi(w1,"db_path")==0) { - safestrncpy(db_path, w2, sizeof(db_path)); - } else if (strcmpi(w1, "console") == 0) { - console = config_switch(w2); - } else if (strcmpi(w1, "fame_list_alchemist") == 0) { - fame_list_size_chemist = atoi(w2); - if (fame_list_size_chemist > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); - fame_list_size_chemist = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { - fame_list_size_smith = atoi(w2); - if (fame_list_size_smith > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); - fame_list_size_smith = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_taekwon") == 0) { - fame_list_size_taekwon = atoi(w2); - if (fame_list_size_taekwon > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); - fame_list_size_taekwon = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "guild_exp_rate") == 0) { - guild_exp_rate = atoi(w2); - } else if (strcmpi(w1, "import") == 0) { - char_config_read(w2); - } - } - fclose(fp); - - ShowInfo("Done reading %s.\n", cfgName); - return 0; + char line[1024], w1[1024], w2[1024]; + FILE* fp = fopen(cfgName, "r"); + + if (fp == NULL) { + ShowError("Configuration file not found: %s.\n", cfgName); + return 1; + } + + while(fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + remove_control_chars(w1); + remove_control_chars(w2); + if(strcmpi(w1,"timestamp_format") == 0) { + safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); + } else if(strcmpi(w1,"console_silent")==0){ + msg_silent = atoi(w2); + if( msg_silent ) /* only bother if its actually enabled */ + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ + stdout_with_ansisequence = config_switch(w2); + } else if (strcmpi(w1, "userid") == 0) { + safestrncpy(userid, w2, sizeof(userid)); + } else if (strcmpi(w1, "passwd") == 0) { + safestrncpy(passwd, w2, sizeof(passwd)); + } else if (strcmpi(w1, "server_name") == 0) { + safestrncpy(server_name, w2, sizeof(server_name)); + } else if (strcmpi(w1, "wisp_server_name") == 0) { + if (strlen(w2) >= 4) { + safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); + } + } else if (strcmpi(w1, "login_ip") == 0) { + char ip_str[16]; + login_ip = host2ip(w2); + if (login_ip) { + safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); + ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); + } + } else if (strcmpi(w1, "login_port") == 0) { + login_port = atoi(w2); + } else if (strcmpi(w1, "char_ip") == 0) { + char ip_str[16]; + char_ip = host2ip(w2); + if (char_ip){ + safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); + ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); + } + } else if (strcmpi(w1, "bind_ip") == 0) { + char ip_str[16]; + bind_ip = host2ip(w2); + if (bind_ip) { + safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); + ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); + } + } else if (strcmpi(w1, "char_port") == 0) { + char_port = atoi(w2); + } else if (strcmpi(w1, "char_maintenance") == 0) { + char_maintenance = atoi(w2); + } else if (strcmpi(w1, "char_new") == 0) { + char_new = (bool)atoi(w2); + } else if (strcmpi(w1, "char_new_display") == 0) { + char_new_display = atoi(w2); + } else if (strcmpi(w1, "max_connect_user") == 0) { + max_connect_user = atoi(w2); + if (max_connect_user < 0) + max_connect_user = 0; // unlimited online players + } else if(strcmpi(w1, "gm_allow_group") == 0) { + gm_allow_group = atoi(w2); + } else if (strcmpi(w1, "autosave_time") == 0) { + autosave_interval = atoi(w2)*1000; + if (autosave_interval <= 0) + autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + } else if (strcmpi(w1, "save_log") == 0) { + save_log = config_switch(w2); + } else if (strcmpi(w1, "start_point") == 0) { + char map[MAP_NAME_LENGTH_EXT]; + int x, y; + if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) + continue; + start_point.map = mapindex_name2id(map); + if (!start_point.map) + ShowError("Specified start_point %s not found in map-index cache.\n", map); + start_point.x = x; + start_point.y = y; + } else if (strcmpi(w1, "start_zeny") == 0) { + start_zeny = atoi(w2); + if (start_zeny < 0) + start_zeny = 0; + } else if (strcmpi(w1, "start_weapon") == 0) { + start_weapon = atoi(w2); + if (start_weapon < 0) + start_weapon = 0; + } else if (strcmpi(w1, "start_armor") == 0) { + start_armor = atoi(w2); + if (start_armor < 0) + start_armor = 0; + } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] + log_char = atoi(w2); + } else if (strcmpi(w1, "unknown_char_name") == 0) { + safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); + unknown_char_name[NAME_LENGTH-1] = '\0'; + } else if (strcmpi(w1, "name_ignoring_case") == 0) { + name_ignoring_case = (bool)config_switch(w2); + } else if (strcmpi(w1, "char_name_option") == 0) { + char_name_option = atoi(w2); + } else if (strcmpi(w1, "char_name_letters") == 0) { + safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); + } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] + char_per_account = atoi(w2); + if( char_per_account == 0 || char_per_account > MAX_CHARS ) { + if( char_per_account > MAX_CHARS ) + ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS); + char_per_account = MAX_CHARS; + } + } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] + char_del_level = atoi(w2); + } else if (strcmpi(w1, "char_del_delay") == 0) { + char_del_delay = atoi(w2); + } else if(strcmpi(w1,"db_path")==0) { + safestrncpy(db_path, w2, sizeof(db_path)); + } else if (strcmpi(w1, "console") == 0) { + console = config_switch(w2); + } else if (strcmpi(w1, "fame_list_alchemist") == 0) { + fame_list_size_chemist = atoi(w2); + if (fame_list_size_chemist > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); + fame_list_size_chemist = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { + fame_list_size_smith = atoi(w2); + if (fame_list_size_smith > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); + fame_list_size_smith = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_taekwon") == 0) { + fame_list_size_taekwon = atoi(w2); + if (fame_list_size_taekwon > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); + fame_list_size_taekwon = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "guild_exp_rate") == 0) { + guild_exp_rate = atoi(w2); + } else if (strcmpi(w1, "import") == 0) { + char_config_read(w2); + } + } + fclose(fp); + + ShowInfo("Done reading %s.\n", cfgName); + return 0; } void do_final(void) { - ShowStatus("Terminating...\n"); - - set_all_offline(-1); - set_all_offline_sql(); + ShowStatus("Terminating...\n"); - inter_final(); + set_all_offline(-1); + set_all_offline_sql(); - flush_fifos(); + inter_final(); - do_final_mapif(); - do_final_loginif(); + flush_fifos(); + + do_final_mapif(); + do_final_loginif(); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", ragsrvinfo_db)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", ragsrvinfo_db) ) + Sql_ShowDebug(sql_handle); - char_db_->destroy(char_db_, NULL); - online_char_db->destroy(online_char_db, NULL); - auth_db->destroy(auth_db, NULL); + char_db_->destroy(char_db_, NULL); + online_char_db->destroy(online_char_db, NULL); + auth_db->destroy(auth_db, NULL); - if (char_fd != -1) { - do_close(char_fd); - char_fd = -1; - } + if( char_fd != -1 ) + { + do_close(char_fd); + char_fd = -1; + } - Sql_Free(sql_handle); - mapindex_final(); + Sql_Free(sql_handle); + mapindex_final(); - ShowStatus("Finished.\n"); + ShowStatus("Finished.\n"); } //------------------------------ @@ -4615,107 +4674,111 @@ void do_abort(void) void set_server_type(void) { - SERVER_TYPE = ATHENA_SERVER_CHAR; + SERVER_TYPE = ATHENA_SERVER_CHAR; } /// Called when a terminate signal is received. void do_shutdown(void) { - if (runflag != CHARSERVER_ST_SHUTDOWN) { - int id; - runflag = CHARSERVER_ST_SHUTDOWN; - ShowStatus("Shutting down...\n"); - // TODO proper shutdown procedure; wait for acks?, kick all characters, ... [FlavoJS] - for (id = 0; id < ARRAYLENGTH(server); ++id) - mapif_server_reset(id); - loginif_check_shutdown(); - flush_fifos(); - runflag = CORE_ST_STOP; - } + if( runflag != CHARSERVER_ST_SHUTDOWN ) + { + int id; + runflag = CHARSERVER_ST_SHUTDOWN; + ShowStatus("Shutting down...\n"); + // TODO proper shutdown procedure; wait for acks?, kick all characters, ... [FlavoJS] + for( id = 0; id < ARRAYLENGTH(server); ++id ) + mapif_server_reset(id); + loginif_check_shutdown(); + flush_fifos(); + runflag = CORE_ST_STOP; + } } int do_init(int argc, char **argv) { - //Read map indexes - mapindex_init(); - start_point.map = mapindex_name2id("new_zone01"); - - char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); - char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); - sql_config_read(SQL_CONF_NAME); - - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { - ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); - ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); - } - - inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server configuration - - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); - mmo_char_sql_init(); - char_read_fame_list(); //Read fame lists. - - if ((naddr_ != 0) && (!login_ip || !char_ip)) { - char ip_str[16]; - ip2str(addr_[0], ip_str); - - if (naddr_ > 1) - ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); - else - ShowStatus("Defaulting to %s as our IP address\n", ip_str); - if (!login_ip) { - safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); - login_ip = str2ip(login_ip_str); - } - if (!char_ip) { - safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); - char_ip = str2ip(char_ip_str); - } - } - - do_init_loginif(); - do_init_mapif(); - - // periodically update the overall user count on all mapservers + login server - add_timer_func_list(broadcast_user_count, "broadcast_user_count"); - add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); - - // Timer to clear (online_char_db) - add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); - - // Online Data timers (checking if char still connected) - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); - - if (console) { - //##TODO invoke a CONSOLE_START plugin event - } - - //Cleaning the tables for NULL entrys @ startup [Sirius] - //Chardb clean - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db)) - Sql_ShowDebug(sql_handle); - - //guilddb clean - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db)) - Sql_ShowDebug(sql_handle); - - //guildmemberdb clean - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db)) - Sql_ShowDebug(sql_handle); - - set_defaultparse(parse_char); - char_fd = make_listen_bind(bind_ip, char_port); - ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); - - if (runflag != CORE_ST_STOP) { - shutdown_callback = do_shutdown; - runflag = CHARSERVER_ST_RUNNING; - } - - return 0; + //Read map indexes + mapindex_init(); + start_point.map = mapindex_name2id("new_zone01"); + + char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); + char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); + sql_config_read(SQL_CONF_NAME); + + if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { + ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); + ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); + ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); + } + + inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server configuration + + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); + mmo_char_sql_init(); + char_read_fame_list(); //Read fame lists. + + if ((naddr_ != 0) && (!login_ip || !char_ip)) + { + char ip_str[16]; + ip2str(addr_[0], ip_str); + + if (naddr_ > 1) + ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); + else + ShowStatus("Defaulting to %s as our IP address\n", ip_str); + if (!login_ip) { + safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); + login_ip = str2ip(login_ip_str); + } + if (!char_ip) { + safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); + char_ip = str2ip(char_ip_str); + } + } + + do_init_loginif(); + do_init_mapif(); + + // periodically update the overall user count on all mapservers + login server + add_timer_func_list(broadcast_user_count, "broadcast_user_count"); + add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); + + // Timer to clear (online_char_db) + add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); + + // Online Data timers (checking if char still connected) + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); + + if( console ) + { + //##TODO invoke a CONSOLE_START plugin event + } + + //Cleaning the tables for NULL entrys @ startup [Sirius] + //Chardb clean + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) ) + Sql_ShowDebug(sql_handle); + + //guilddb clean + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db) ) + Sql_ShowDebug(sql_handle); + + //guildmemberdb clean + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db) ) + Sql_ShowDebug(sql_handle); + + set_defaultparse(parse_char); + char_fd = make_listen_bind(bind_ip, char_port); + ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); + + if( runflag != CORE_ST_STOP ) + { + shutdown_callback = do_shutdown; + runflag = CHARSERVER_ST_RUNNING; + } + + return 0; } diff --git a/src/char/char.h b/src/char/char.h index cdef28718..dd1c80f9d 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -6,10 +6,11 @@ #include "../common/core.h" // CORE_ST_LAST -enum E_CHARSERVER_ST { - CHARSERVER_ST_RUNNING = CORE_ST_LAST, - CHARSERVER_ST_SHUTDOWN, - CHARSERVER_ST_LAST +enum E_CHARSERVER_ST +{ + CHARSERVER_ST_RUNNING = CORE_ST_LAST, + CHARSERVER_ST_SHUTDOWN, + CHARSERVER_ST_LAST }; struct mmo_charstatus; @@ -19,10 +20,10 @@ struct mmo_charstatus; #define DEFAULT_AUTOSAVE_INTERVAL 300*1000 enum { - TABLE_INVENTORY, - TABLE_CART, - TABLE_STORAGE, - TABLE_GUILD_STORAGE, + TABLE_INVENTORY, + TABLE_CART, + TABLE_STORAGE, + TABLE_GUILD_STORAGE, }; int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch); @@ -36,7 +37,7 @@ int char_child(int parent_id, int child_id); int char_family(int pl1,int pl2,int pl3); int request_accreg2(int account_id, int char_id); -int save_accreg2(unsigned char *buf, int len); +int save_accreg2(unsigned char* buf, int len); extern int char_name_option; extern char char_name_letters[]; diff --git a/src/char/int_auction.c b/src/char/int_auction.c index 4eadb4866..4fc9215a0 100644 --- a/src/char/int_auction.c +++ b/src/char/int_auction.c @@ -18,435 +18,442 @@ #include #include -static DBMap *auction_db_ = NULL; // int auction_id -> struct auction_data* +static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data* void auction_delete(struct auction_data *auction); static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data); static int auction_count(int char_id, bool buy) { - int i = 0; - struct auction_data *auction; - DBIterator *iter = db_iterator(auction_db_); - - for (auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter)) { - if ((buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id)) - i++; - } - dbi_destroy(iter); - - return i; + int i = 0; + struct auction_data *auction; + DBIterator *iter = db_iterator(auction_db_); + + for( auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter) ) + { + if( (buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id) ) + i++; + } + dbi_destroy(iter); + + return i; } void auction_save(struct auction_data *auction) { - int j; - StringBuf buf; - SqlStmt *stmt; - - if (!auction) - return; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", - auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); - StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); - - stmt = SqlStmt_Malloc(sql_handle); - if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt)) { - SqlStmt_ShowDebug(stmt); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); + int j; + StringBuf buf; + SqlStmt* stmt; + + if( !auction ) + return; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", + auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); + StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); } unsigned int auction_create(struct auction_data *auction) { - int j; - StringBuf buf; - SqlStmt *stmt; - - if (!auction) - return false; - - auction->timestamp = time(NULL) + (auction->hours * 3600); - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", - auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - stmt = SqlStmt_Malloc(sql_handle); - if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt)) { - SqlStmt_ShowDebug(stmt); - auction->auction_id = 0; - } else { - struct auction_data *auction_; - unsigned int tick = auction->hours * 3600000; - - auction->item.amount = 1; - auction->item.identify = 1; - auction->item.expire_time = 0; - - auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); - auction->auction_end_timer = add_timer(gettick() + tick , auction_end_timer, auction->auction_id, 0); - ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); - - CREATE(auction_, struct auction_data, 1); - memcpy(auction_, auction, sizeof(struct auction_data)); - idb_put(auction_db_, auction_->auction_id, auction_); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return auction->auction_id; + int j; + StringBuf buf; + SqlStmt* stmt; + + if( !auction ) + return false; + + auction->timestamp = time(NULL) + (auction->hours * 3600); + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", + auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + auction->auction_id = 0; + } + else + { + struct auction_data *auction_; + unsigned int tick = auction->hours * 3600000; + + auction->item.amount = 1; + auction->item.identify = 1; + auction->item.expire_time = 0; + + auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); + auction->auction_end_timer = add_timer( gettick() + tick , auction_end_timer, auction->auction_id, 0); + ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); + + CREATE(auction_, struct auction_data, 1); + memcpy(auction_, auction, sizeof(struct auction_data)); + idb_put(auction_db_, auction_->auction_id, auction_); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return auction->auction_id; } static void mapif_Auction_message(int char_id, unsigned char result) { - unsigned char buf[74]; - - WBUFW(buf,0) = 0x3854; - WBUFL(buf,2) = char_id; - WBUFL(buf,6) = result; - mapif_sendall(buf,7); + unsigned char buf[74]; + + WBUFW(buf,0) = 0x3854; + WBUFL(buf,2) = char_id; + WBUFL(buf,6) = result; + mapif_sendall(buf,7); } static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct auction_data *auction; - if ((auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL) { - if (auction->buyer_id) { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); - } else - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); - - ShowInfo("Auction End: id %u.\n", auction->auction_id); - - auction->auction_end_timer = INVALID_TIMER; - auction_delete(auction); - } - - return 0; + struct auction_data *auction; + if( (auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL ) + { + if( auction->buyer_id ) + { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); + } + else + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); + + ShowInfo("Auction End: id %u.\n", auction->auction_id); + + auction->auction_end_timer = INVALID_TIMER; + auction_delete(auction); + } + + return 0; } void auction_delete(struct auction_data *auction) { - unsigned int auction_id = auction->auction_id; + unsigned int auction_id = auction->auction_id; - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id) ) + Sql_ShowDebug(sql_handle); - if (auction->auction_end_timer != INVALID_TIMER) - delete_timer(auction->auction_end_timer, auction_end_timer); + if( auction->auction_end_timer != INVALID_TIMER ) + delete_timer(auction->auction_end_timer, auction_end_timer); - idb_remove(auction_db_, auction_id); + idb_remove(auction_db_, auction_id); } void inter_auctions_fromsql(void) { - int i; - struct auction_data *auction; - struct item *item; - char *data; - StringBuf buf; - unsigned int tick = gettick(), endtick; - time_t now = time(NULL); - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," - "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ",`card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - CREATE(auction, struct auction_data, 1); - Sql_GetData(sql_handle, 0, &data, NULL); - auction->auction_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - auction->seller_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - safestrncpy(auction->seller_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 3, &data, NULL); - auction->buyer_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - safestrncpy(auction->buyer_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 5, &data, NULL); - auction->price = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - auction->buynow = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - auction->hours = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); - auction->timestamp = atoi(data); - - item = &auction->item; - Sql_GetData(sql_handle, 9, &data, NULL); - item->nameid = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); - safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); - Sql_GetData(sql_handle,11, &data, NULL); - auction->type = atoi(data); - - Sql_GetData(sql_handle,12, &data, NULL); - item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); - item->attribute = atoi(data); - - item->identify = 1; - item->amount = 1; - item->expire_time = 0; - - for (i = 0; i < MAX_SLOTS; i++) { - Sql_GetData(sql_handle, 14 + i, &data, NULL); - item->card[i] = atoi(data); - } - - if (auction->timestamp > now) - endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; - else - endtick = tick + 10000; // 10 Second's to process ended auctions - - auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); - idb_put(auction_db_, auction->auction_id, auction); - } - - Sql_FreeResult(sql_handle); + int i; + struct auction_data *auction; + struct item *item; + char *data; + StringBuf buf; + unsigned int tick = gettick(), endtick; + time_t now = time(NULL); + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," + "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); + for( i = 0; i < MAX_SLOTS; i++ ) + StringBuf_Printf(&buf, ",`card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + CREATE(auction, struct auction_data, 1); + Sql_GetData(sql_handle, 0, &data, NULL); auction->auction_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); auction->seller_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(auction->seller_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 3, &data, NULL); auction->buyer_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(auction->buyer_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 5, &data, NULL); auction->price = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); auction->buynow = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); auction->hours = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); auction->timestamp = atoi(data); + + item = &auction->item; + Sql_GetData(sql_handle, 9, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); + Sql_GetData(sql_handle,11, &data, NULL); auction->type = atoi(data); + + Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); + + item->identify = 1; + item->amount = 1; + item->expire_time = 0; + + for( i = 0; i < MAX_SLOTS; i++ ) + { + Sql_GetData(sql_handle, 14 + i, &data, NULL); + item->card[i] = atoi(data); + } + + if( auction->timestamp > now ) + endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; + else + endtick = tick + 10000; // 10 Second's to process ended auctions + + auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); + idb_put(auction_db_, auction->auction_id, auction); + } + + Sql_FreeResult(sql_handle); } static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages, unsigned char *buf) { - int len = (sizeof(struct auction_data) * count) + 12; - - WFIFOHEAD(fd, len); - WFIFOW(fd,0) = 0x3850; - WFIFOW(fd,2) = len; - WFIFOL(fd,4) = char_id; - WFIFOW(fd,8) = count; - WFIFOW(fd,10) = pages; - memcpy(WFIFOP(fd,12), buf, len - 12); - WFIFOSET(fd,len); + int len = (sizeof(struct auction_data) * count) + 12; + + WFIFOHEAD(fd, len); + WFIFOW(fd,0) = 0x3850; + WFIFOW(fd,2) = len; + WFIFOL(fd,4) = char_id; + WFIFOW(fd,8) = count; + WFIFOW(fd,10) = pages; + memcpy(WFIFOP(fd,12), buf, len - 12); + WFIFOSET(fd,len); } static void mapif_parse_Auction_requestlist(int fd) { - char searchtext[NAME_LENGTH]; - int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); - int price = RFIFOL(fd,10); - short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); - unsigned char buf[5 * sizeof(struct auction_data)]; - DBIterator *iter = db_iterator(auction_db_); - struct auction_data *auction; - short i = 0, j = 0, pages = 1; - - memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); - - for (auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter)) { - if ((type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || - (type == 1 && auction->type != IT_WEAPON) || - (type == 2 && auction->type != IT_CARD) || - (type == 3 && auction->type != IT_ETC) || - (type == 4 && !strstr(auction->item_name, searchtext)) || - (type == 5 && auction->price > price) || - (type == 6 && auction->seller_id != char_id) || - (type == 7 && auction->buyer_id != char_id)) - continue; - - i++; - if (i > 5) { - // Counting Pages of Total Results (5 Results per Page) - pages++; - i = 1; // First Result of This Page - } - - if (page != pages) - continue; // This is not the requested Page - - memcpy(WBUFP(buf, j * len), auction, len); - j++; // Found Results - } - dbi_destroy(iter); - - mapif_Auction_sendlist(fd, char_id, j, pages, buf); + char searchtext[NAME_LENGTH]; + int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); + int price = RFIFOL(fd,10); + short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); + unsigned char buf[5 * sizeof(struct auction_data)]; + DBIterator *iter = db_iterator(auction_db_); + struct auction_data *auction; + short i = 0, j = 0, pages = 1; + + memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); + + for( auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter) ) + { + if( (type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || + (type == 1 && auction->type != IT_WEAPON) || + (type == 2 && auction->type != IT_CARD) || + (type == 3 && auction->type != IT_ETC) || + (type == 4 && !strstr(auction->item_name, searchtext)) || + (type == 5 && auction->price > price) || + (type == 6 && auction->seller_id != char_id) || + (type == 7 && auction->buyer_id != char_id) ) + continue; + + i++; + if( i > 5 ) + { // Counting Pages of Total Results (5 Results per Page) + pages++; + i = 1; // First Result of This Page + } + + if( page != pages ) + continue; // This is not the requested Page + + memcpy(WBUFP(buf, j * len), auction, len); + j++; // Found Results + } + dbi_destroy(iter); + + mapif_Auction_sendlist(fd, char_id, j, pages, buf); } static void mapif_Auction_register(int fd, struct auction_data *auction) { - int len = sizeof(struct auction_data) + 4; + int len = sizeof(struct auction_data) + 4; - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x3851; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); - WFIFOSET(fd,len); + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x3851; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); + WFIFOSET(fd,len); } static void mapif_parse_Auction_register(int fd) { - struct auction_data auction; - if (RFIFOW(fd,2) != sizeof(struct auction_data) + 4) - return; + struct auction_data auction; + if( RFIFOW(fd,2) != sizeof(struct auction_data) + 4 ) + return; - memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); - if (auction_count(auction.seller_id, false) < 5) - auction.auction_id = auction_create(&auction); + memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); + if( auction_count(auction.seller_id, false) < 5 ) + auction.auction_id = auction_create(&auction); - mapif_Auction_register(fd, &auction); + mapif_Auction_register(fd, &auction); } static void mapif_Auction_cancel(int fd, int char_id, unsigned char result) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3852; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3852; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); } static void mapif_parse_Auction_cancel(int fd) { - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL) { - mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect - return; - } - - if (auction->seller_id != char_id) { - mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction - return; - } - - if (auction->buyer_id > 0) { - mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled - return; - } - - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); - auction_delete(auction); - - mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) + { + mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect + return; + } + + if( auction->seller_id != char_id ) + { + mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction + return; + } + + if( auction->buyer_id > 0 ) + { + mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled + return; + } + + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); + auction_delete(auction); + + mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled } static void mapif_Auction_close(int fd, int char_id, unsigned char result) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3853; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3853; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); } static void mapif_parse_Auction_close(int fd) { - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL) { - mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect - return; - } - - if (auction->seller_id != char_id) { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - if (auction->buyer_id == 0) { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - // Send Money to Seller - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); - // Send Item to Buyer - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - auction_delete(auction); - - mapif_Auction_close(fd, char_id, 0); // You have ended the auction + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) + { + mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect + return; + } + + if( auction->seller_id != char_id ) + { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + if( auction->buyer_id == 0 ) + { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + // Send Money to Seller + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); + // Send Item to Buyer + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + auction_delete(auction); + + mapif_Auction_close(fd, char_id, 0); // You have ended the auction } static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result) { - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x3855; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = bid; // To Return Zeny - WFIFOB(fd,10) = result; - WFIFOSET(fd,11); + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x3855; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = bid; // To Return Zeny + WFIFOB(fd,10) = result; + WFIFOSET(fd,11); } static void mapif_parse_Auction_bid(int fd) { - int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); - unsigned int auction_id = RFIFOL(fd,8); - struct auction_data *auction; - - if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id) { - mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction - return; - } - - if (auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id) { - mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time - return; - } - - if (auction->buyer_id > 0) { - // Send Money back to the previous Buyer - if (auction->buyer_id != char_id) { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); - mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction - } else - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); - } - - auction->buyer_id = char_id; - safestrncpy(auction->buyer_name, (char *)RFIFOP(fd,16), NAME_LENGTH); - auction->price = bid; - - if (bid >= auction->buynow) { - // Automatic won the auction - mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction - - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); - mapif_Auction_message(char_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); - - auction_delete(auction); - return; - } - - auction_save(auction); - - mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction + int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); + unsigned int auction_id = RFIFOL(fd,8); + struct auction_data *auction; + + if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id ) + { + mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction + return; + } + + if( auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id ) + { + mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time + return; + } + + if( auction->buyer_id > 0 ) + { // Send Money back to the previous Buyer + if( auction->buyer_id != char_id ) + { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); + mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction + } + else + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); + } + + auction->buyer_id = char_id; + safestrncpy(auction->buyer_name, (char*)RFIFOP(fd,16), NAME_LENGTH); + auction->price = bid; + + if( bid >= auction->buynow ) + { // Automatic won the auction + mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction + + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); + mapif_Auction_message(char_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); + + auction_delete(auction); + return; + } + + auction_save(auction); + + mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction } /*========================================== @@ -454,39 +461,30 @@ static void mapif_parse_Auction_bid(int fd) *------------------------------------------*/ int inter_auction_parse_frommap(int fd) { - switch (RFIFOW(fd,0)) { - case 0x3050: - mapif_parse_Auction_requestlist(fd); - break; - case 0x3051: - mapif_parse_Auction_register(fd); - break; - case 0x3052: - mapif_parse_Auction_cancel(fd); - break; - case 0x3053: - mapif_parse_Auction_close(fd); - break; - case 0x3055: - mapif_parse_Auction_bid(fd); - break; - default: - return 0; - } - return 1; + switch(RFIFOW(fd,0)) + { + case 0x3050: mapif_parse_Auction_requestlist(fd); break; + case 0x3051: mapif_parse_Auction_register(fd); break; + case 0x3052: mapif_parse_Auction_cancel(fd); break; + case 0x3053: mapif_parse_Auction_close(fd); break; + case 0x3055: mapif_parse_Auction_bid(fd); break; + default: + return 0; + } + return 1; } int inter_auction_sql_init(void) { - auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - inter_auctions_fromsql(); + auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + inter_auctions_fromsql(); - return 0; + return 0; } void inter_auction_sql_final(void) { - auction_db_->destroy(auction_db_,NULL); + auction_db_->destroy(auction_db_,NULL); - return; + return; } diff --git a/src/char/int_elemental.c b/src/char/int_elemental.c index aa7ef5f65..7c76c4496 100644 --- a/src/char/int_elemental.c +++ b/src/char/int_elemental.c @@ -15,179 +15,147 @@ #include #include -bool mapif_elemental_save(struct s_elemental *ele) -{ - bool flag = true; - - if (ele->elemental_id == 0) { // Create new DB entry - if (SQL_ERROR == Sql_Query(sql_handle, - "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`life_time`)" - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%u')", - ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time)) { - Sql_ShowDebug(sql_handle); - flag = false; - } else - ele->elemental_id = (int)Sql_LastInsertId(sql_handle); - } else if (SQL_ERROR == Sql_Query(sql_handle, - "UPDATE `elemental` SET `char_id` = '%d', `class` = '%d', `mode` = '%d', `hp` = '%d', `sp` = '%d'," - "`max_hp` = '%d', `max_sp` = '%d', `str` = '%d', `agi` = '%d', `vit` = '%d', `int` = '%d', `dex` = '%d'," - "`luk` = '%d', `life_time` = '%u' WHERE `ele_id` = '%d'", - ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, - ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time, ele->elemental_id)) { - // Update DB entry - Sql_ShowDebug(sql_handle); - flag = false; - } - return flag; +bool mapif_elemental_save(struct s_elemental* ele) { + bool flag = true; + + if( ele->elemental_id == 0 ) { // Create new DB entry + if( SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`life_time`)" + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%u')", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + ele->elemental_id = (int)Sql_LastInsertId(sql_handle); + } else if( SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `elemental` SET `char_id` = '%d', `class` = '%d', `mode` = '%d', `hp` = '%d', `sp` = '%d'," + "`max_hp` = '%d', `max_sp` = '%d', `str` = '%d', `agi` = '%d', `vit` = '%d', `int` = '%d', `dex` = '%d'," + "`luk` = '%d', `life_time` = '%u' WHERE `ele_id` = '%d'", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, + ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time, ele->elemental_id) ) + { // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } + return flag; } -bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) -{ - char *data; - - memset(ele, 0, sizeof(struct s_elemental)); - ele->elemental_id = ele_id; - ele->char_id = char_id; - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `str`, `agi`, `vit`, `int`, `dex`," - "`luk`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", - ele_id, char_id)) { - Sql_ShowDebug(sql_handle); - return false; - } - - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); - ele->class_ = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - ele->mode = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - ele->hp = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - ele->sp = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - ele->max_hp = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - ele->max_sp = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - ele->str = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - ele->agi = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); - ele->vit = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - ele->int_ = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); - ele->dex = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); - ele->luk = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); - ele->life_time = atoi(data); - Sql_FreeResult(sql_handle); - if (save_log) - ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); - - return true; +bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) { + char* data; + + memset(ele, 0, sizeof(struct s_elemental)); + ele->elemental_id = ele_id; + ele->char_id = char_id; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `str`, `agi`, `vit`, `int`, `dex`," + "`luk`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", + ele_id, char_id) ) { + Sql_ShowDebug(sql_handle); + return false; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); ele->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); ele->mode = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); ele->hp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); ele->sp = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); ele->max_hp = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); ele->max_sp = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); ele->str = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); ele->agi = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); ele->vit = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); ele->int_ = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); ele->dex = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); ele->luk = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); ele->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if( save_log ) + ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); + + return true; } -bool mapif_elemental_delete(int ele_id) -{ - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `elemental` WHERE `ele_id` = '%d'", ele_id)) { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; +bool mapif_elemental_delete(int ele_id) { + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `elemental` WHERE `ele_id` = '%d'", ele_id) ) { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; } -static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) -{ - int size = sizeof(struct s_elemental) + 5; - - WFIFOHEAD(fd,size); - WFIFOW(fd,0) = 0x387c; - WFIFOW(fd,2) = size; - WFIFOB(fd,4) = flag; - memcpy(WFIFOP(fd,5),ele,sizeof(struct s_elemental)); - WFIFOSET(fd,size); +static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) { + int size = sizeof(struct s_elemental) + 5; + + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x387c; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),ele,sizeof(struct s_elemental)); + WFIFOSET(fd,size); } -static void mapif_parse_elemental_create(int fd, struct s_elemental *ele) -{ - bool result = mapif_elemental_save(ele); - mapif_elemental_send(fd, ele, result); +static void mapif_parse_elemental_create(int fd, struct s_elemental* ele) { + bool result = mapif_elemental_save(ele); + mapif_elemental_send(fd, ele, result); } -static void mapif_parse_elemental_load(int fd, int ele_id, int char_id) -{ - struct s_elemental ele; - bool result = mapif_elemental_load(ele_id, char_id, &ele); - mapif_elemental_send(fd, &ele, result); +static void mapif_parse_elemental_load(int fd, int ele_id, int char_id) { + struct s_elemental ele; + bool result = mapif_elemental_load(ele_id, char_id, &ele); + mapif_elemental_send(fd, &ele, result); } -static void mapif_elemental_deleted(int fd, unsigned char flag) -{ - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x387d; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); +static void mapif_elemental_deleted(int fd, unsigned char flag) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387d; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_elemental_delete(int fd, int ele_id) -{ - bool result = mapif_elemental_delete(ele_id); - mapif_elemental_deleted(fd, result); +static void mapif_parse_elemental_delete(int fd, int ele_id) { + bool result = mapif_elemental_delete(ele_id); + mapif_elemental_deleted(fd, result); } -static void mapif_elemental_saved(int fd, unsigned char flag) -{ - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x387e; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); +static void mapif_elemental_saved(int fd, unsigned char flag) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387e; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_elemental_save(int fd, struct s_elemental *ele) -{ - bool result = mapif_elemental_save(ele); - mapif_elemental_saved(fd, result); +static void mapif_parse_elemental_save(int fd, struct s_elemental* ele) { + bool result = mapif_elemental_save(ele); + mapif_elemental_saved(fd, result); } -void inter_elemental_sql_init(void) -{ - return; +void inter_elemental_sql_init(void) { + return; } -void inter_elemental_sql_final(void) -{ - return; +void inter_elemental_sql_final(void) { + return; } /*========================================== * Inter Packets *------------------------------------------*/ -int inter_elemental_parse_frommap(int fd) -{ - unsigned short cmd = RFIFOW(fd,0); - - switch (cmd) { - case 0x307c: - mapif_parse_elemental_create(fd, (struct s_elemental *)RFIFOP(fd,4)); - break; - case 0x307d: - mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); - break; - case 0x307e: - mapif_parse_elemental_delete(fd, (int)RFIFOL(fd,2)); - break; - case 0x307f: - mapif_parse_elemental_save(fd, (struct s_elemental *)RFIFOP(fd,4)); - break; - default: - return 0; - } - return 1; +int inter_elemental_parse_frommap(int fd) { + unsigned short cmd = RFIFOW(fd,0); + + switch( cmd ) { + case 0x307c: mapif_parse_elemental_create(fd, (struct s_elemental*)RFIFOP(fd,4)); break; + case 0x307d: mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; + case 0x307e: mapif_parse_elemental_delete(fd, (int)RFIFOL(fd,2)); break; + case 0x307f: mapif_parse_elemental_save(fd, (struct s_elemental*)RFIFOP(fd,4)); break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_guild.c b/src/char/int_guild.c index 2b4a9f3ac..b07a1933f 100644 --- a/src/char/int_guild.c +++ b/src/char/int_guild.c @@ -31,7 +31,7 @@ static const char dataToHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; //Guild cache -static DBMap *guild_db_; // int guild_id -> struct guild* +static DBMap* guild_db_; // int guild_id -> struct guild* static DBMap *castle_db; static unsigned int guild_exp[100]; @@ -47,703 +47,703 @@ int inter_guild_tosql(struct guild *g,int flag); static int guild_save_timer(int tid, unsigned int tick, int id, intptr_t data) { - static int last_id = 0; //To know in which guild we were. - int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. - DBIterator *iter = db_iterator(guild_db_); - DBKey key; - struct guild *g; - - if (last_id == 0) //Save the first guild in the list. - state = 1; - - for (g = db_data2ptr(iter->first(iter, &key)); dbi_exists(iter); g = db_data2ptr(iter->next(iter, &key))) { - if (state == 0 && g->guild_id == last_id) - state++; //Save next guild in the list. - else if (state == 1 && g->save_flag&GS_MASK) { - inter_guild_tosql(g, g->save_flag&GS_MASK); - g->save_flag &= ~GS_MASK; - - //Some guild saved. - last_id = g->guild_id; - state++; - } - - if (g->save_flag == GS_REMOVE) { - // Nothing to save, guild is ready for removal. - if (save_log) - ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); - db_remove(guild_db_, key); - } - } - dbi_destroy(iter); - - if (state != 2) //Reached the end of the guild db without saving. - last_id = 0; //Reset guild saved, return to beginning. - - state = guild_db_->size(guild_db_); - if (state < 1) state = 1; //Calculate the time slot for the next save. - add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); - return 0; + static int last_id = 0; //To know in which guild we were. + int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. + DBIterator *iter = db_iterator(guild_db_); + DBKey key; + struct guild* g; + + if( last_id == 0 ) //Save the first guild in the list. + state = 1; + + for( g = db_data2ptr(iter->first(iter, &key)); dbi_exists(iter); g = db_data2ptr(iter->next(iter, &key)) ) + { + if( state == 0 && g->guild_id == last_id ) + state++; //Save next guild in the list. + else + if( state == 1 && g->save_flag&GS_MASK ) + { + inter_guild_tosql(g, g->save_flag&GS_MASK); + g->save_flag &= ~GS_MASK; + + //Some guild saved. + last_id = g->guild_id; + state++; + } + + if( g->save_flag == GS_REMOVE ) + {// Nothing to save, guild is ready for removal. + if (save_log) + ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); + db_remove(guild_db_, key); + } + } + dbi_destroy(iter); + + if( state != 2 ) //Reached the end of the guild db without saving. + last_id = 0; //Reset guild saved, return to beginning. + + state = guild_db_->size(guild_db_); + if( state < 1 ) state = 1; //Calculate the time slot for the next save. + add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); + return 0; } int inter_guild_removemember_tosql(int account_id, int char_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id)) - Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id)) - Sql_ShowDebug(sql_handle); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + return 0; } // Save guild into sql int inter_guild_tosql(struct guild *g,int flag) { - // Table guild (GS_BASIC_MASK) - // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` - // GS_CONNECT `connect_member`,`average_lv` - // GS_MES `mes1`,`mes2` - // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` - // GS_BASIC `name`,`master`,`char_id` - - // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) - // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) - // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) - // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) - // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) - - // temporary storage for str convertion. They must be twice the size of the - // original string to ensure no overflows will occur. [Skotlex] - char t_info[256]; - char esc_name[NAME_LENGTH*2+1]; - char esc_master[NAME_LENGTH*2+1]; - char new_guild = 0; - int i=0; - - if (g->guild_id<=0 && g->guild_id != -1) return 0; - + // Table guild (GS_BASIC_MASK) + // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` + // GS_CONNECT `connect_member`,`average_lv` + // GS_MES `mes1`,`mes2` + // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` + // GS_BASIC `name`,`master`,`char_id` + + // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) + // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) + // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) + // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) + // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) + + // temporary storage for str convertion. They must be twice the size of the + // original string to ensure no overflows will occur. [Skotlex] + char t_info[256]; + char esc_name[NAME_LENGTH*2+1]; + char esc_master[NAME_LENGTH*2+1]; + char new_guild = 0; + int i=0; + + if (g->guild_id<=0 && g->guild_id != -1) return 0; + #ifdef NOISY - ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); + ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); #endif - Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); - *t_info = '\0'; - - // Insert a new guild the guild - if (flag&GS_BASIC && g->guild_id == -1) { - strcat(t_info, " guild_create"); - - // Create a new guild - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " - "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", - guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id)) { - Sql_ShowDebug(sql_handle); - if (g->guild_id == -1) - return 0; //Failed to create guild! - } else { - g->guild_id = (int)Sql_LastInsertId(sql_handle); - new_guild = 1; - } - } - - // If we need an update on an existing guild or more update on the new guild - if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) { - StringBuf buf; - bool add_comma = false; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); - - if (flag & GS_EMBLEM) { - char emblem_data[sizeof(g->emblem_data)*2+1]; - char *pData = emblem_data; - - strcat(t_info, " emblem"); - // Convert emblem_data to hex - //TODO: why not use binary directly? [ultramage] - for (i=0; iemblem_len; i++) { - *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; - *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; - } - *pData = 0; - StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); - add_comma = true; - } - if (flag & GS_BASIC) { - strcat(t_info, " basic"); - if (add_comma) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); - } - if (flag & GS_CONNECT) { - strcat(t_info, " connect"); - if (add_comma) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); - } - if (flag & GS_MES) { - char esc_mes1[sizeof(g->mes1)*2+1]; - char esc_mes2[sizeof(g->mes2)*2+1]; - - strcat(t_info, " mes"); - if (add_comma) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); - Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); - StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); - } - if (flag & GS_LEVEL) { - strcat(t_info, " level"); - if (add_comma) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); - } - StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); - if (SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } - - if (flag&GS_MEMBER) { - struct guild_member *m; - - strcat(t_info, " members"); - // Update only needed players - for (i=0; imax_member; i++) { - m = &g->member[i]; - if (!m->modified) - continue; - if (m->account_id) { - //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO - Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", - guild_member_db, g->guild_id, m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name)) - Sql_ShowDebug(sql_handle); - if (m->modified & GS_MEMBER_NEW) { - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", - char_db, g->guild_id, m->char_id)) - Sql_ShowDebug(sql_handle); - } - m->modified = GS_MEMBER_UNMODIFIED; - } - } - } - - if (flag&GS_POSITION) { - strcat(t_info, " positions"); - //printf("- Insert guild %d to guild_position\n",g->guild_id); - for (i=0; iposition[i]; - if (!p->modified) - continue; - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", - guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode)) - Sql_ShowDebug(sql_handle); - p->modified = GS_POSITION_UNMODIFIED; - } - } - - if (flag&GS_ALLIANCE) { - // Delete current alliances - // NOTE: no need to do it on both sides since both guilds in memory had - // their info changed, not to mention this would also mess up oppositions! - // [Skotlex] - //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id)) { - Sql_ShowDebug(sql_handle); - } else { - //printf("- Insert guild %d to guild_alliance\n",g->guild_id); - for (i=0; ialliance[i]; - if (a->guild_id>0) { - Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " - "VALUES ('%d','%d','%d','%s')", - guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name)) - Sql_ShowDebug(sql_handle); - } - } - } - } - - if (flag&GS_EXPULSION) { - strcat(t_info, " expulsions"); - //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); - for (i=0; iexpulsion[i]; - if (e->account_id>0) { - char esc_mes[sizeof(e->mes)*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); - if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " - "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes)) - Sql_ShowDebug(sql_handle); - } - } - } - - if (flag&GS_SKILL) { - strcat(t_info, " skills"); - //printf("- Insert guild %d to guild_skill\n",g->guild_id); - for (i=0; iskill[i].id>0 && g->skill[i].lv>0) { - if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", - guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv)) - Sql_ShowDebug(sql_handle); - } - } - } - - if (save_log) - ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); - return 1; + Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); + *t_info = '\0'; + + // Insert a new guild the guild + if (flag&GS_BASIC && g->guild_id == -1) + { + strcat(t_info, " guild_create"); + + // Create a new guild + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " + "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", + guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) + { + Sql_ShowDebug(sql_handle); + if (g->guild_id == -1) + return 0; //Failed to create guild! + } + else + { + g->guild_id = (int)Sql_LastInsertId(sql_handle); + new_guild = 1; + } + } + + // If we need an update on an existing guild or more update on the new guild + if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) + { + StringBuf buf; + bool add_comma = false; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); + + if (flag & GS_EMBLEM) + { + char emblem_data[sizeof(g->emblem_data)*2+1]; + char* pData = emblem_data; + + strcat(t_info, " emblem"); + // Convert emblem_data to hex + //TODO: why not use binary directly? [ultramage] + for(i=0; iemblem_len; i++){ + *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; + *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; + } + *pData = 0; + StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); + add_comma = true; + } + if (flag & GS_BASIC) + { + strcat(t_info, " basic"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); + } + if (flag & GS_CONNECT) + { + strcat(t_info, " connect"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); + } + if (flag & GS_MES) + { + char esc_mes1[sizeof(g->mes1)*2+1]; + char esc_mes2[sizeof(g->mes2)*2+1]; + + strcat(t_info, " mes"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); + Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); + StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); + } + if (flag & GS_LEVEL) + { + strcat(t_info, " level"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); + } + StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + } + + if (flag&GS_MEMBER) + { + struct guild_member *m; + + strcat(t_info, " members"); + // Update only needed players + for(i=0;imax_member;i++){ + m = &g->member[i]; + if (!m->modified) + continue; + if(m->account_id) { + //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO + Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", + guild_member_db, g->guild_id, m->account_id, m->char_id, + m->hair, m->hair_color, m->gender, + m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name) ) + Sql_ShowDebug(sql_handle); + if (m->modified & GS_MEMBER_NEW) + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", + char_db, g->guild_id, m->char_id) ) + Sql_ShowDebug(sql_handle); + } + m->modified = GS_MEMBER_UNMODIFIED; + } + } + } + + if (flag&GS_POSITION){ + strcat(t_info, " positions"); + //printf("- Insert guild %d to guild_position\n",g->guild_id); + for(i=0;iposition[i]; + if (!p->modified) + continue; + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", + guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode) ) + Sql_ShowDebug(sql_handle); + p->modified = GS_POSITION_UNMODIFIED; + } + } + + if (flag&GS_ALLIANCE) + { + // Delete current alliances + // NOTE: no need to do it on both sides since both guilds in memory had + // their info changed, not to mention this would also mess up oppositions! + // [Skotlex] + //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id) ) + { + Sql_ShowDebug(sql_handle); + } + else + { + //printf("- Insert guild %d to guild_alliance\n",g->guild_id); + for(i=0;ialliance[i]; + if(a->guild_id>0) + { + Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " + "VALUES ('%d','%d','%d','%s')", + guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name) ) + Sql_ShowDebug(sql_handle); + } + } + } + } + + if (flag&GS_EXPULSION){ + strcat(t_info, " expulsions"); + //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); + for(i=0;iexpulsion[i]; + if(e->account_id>0){ + char esc_mes[sizeof(e->mes)*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " + "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes) ) + Sql_ShowDebug(sql_handle); + } + } + } + + if (flag&GS_SKILL){ + strcat(t_info, " skills"); + //printf("- Insert guild %d to guild_skill\n",g->guild_id); + for(i=0;iskill[i].id>0 && g->skill[i].lv>0){ + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", + guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv) ) + Sql_ShowDebug(sql_handle); + } + } + } + + if (save_log) + ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); + return 1; } // Read guild from sql -struct guild *inter_guild_fromsql(int guild_id) { - struct guild *g; - char *data; - size_t len; - char *p; - int i; +struct guild * inter_guild_fromsql(int guild_id) +{ + struct guild *g; + char* data; + size_t len; + char* p; + int i; - if (guild_id <= 0) - return NULL; + if( guild_id <= 0 ) + return NULL; - g = (struct guild *)idb_get(guild_db_, guild_id); - if (g) - return g; + g = (struct guild*)idb_get(guild_db_, guild_id); + if( g ) + return g; #ifdef NOISY - ShowInfo("Guild load request (%d)...\n", guild_id); + ShowInfo("Guild load request (%d)...\n", guild_id); #endif - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " - "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id)) { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) - return NULL;// Guild does not exists. - - CREATE(g, struct guild, 1); - - g->guild_id = guild_id; - Sql_GetData(sql_handle, 0, &data, &len); - memcpy(g->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(g->master, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); - g->guild_lv = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - g->connect_member = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - g->max_member = atoi(data); - if (g->max_member > MAX_GUILD) { - // Fix reduction of MAX_GUILD [PoW] - ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - Sql_GetData(sql_handle, 5, &data, NULL); - g->average_lv = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - g->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); - g->next_exp = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); - g->skill_point = atoi(data); - Sql_GetData(sql_handle, 9, &data, &len); - memcpy(g->mes1, data, min(len, sizeof(g->mes1))); - Sql_GetData(sql_handle, 10, &data, &len); - memcpy(g->mes2, data, min(len, sizeof(g->mes2))); - Sql_GetData(sql_handle, 11, &data, &len); - g->emblem_len = atoi(data); - Sql_GetData(sql_handle, 12, &data, &len); - g->emblem_id = atoi(data); - Sql_GetData(sql_handle, 13, &data, &len); - // convert emblem data from hexadecimal to binary - //TODO: why not store it in the db as binary directly? [ultramage] - for (i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p) { - if (*data >= '0' && *data <= '9') - *p = *data - '0'; - else if (*data >= 'a' && *data <= 'f') - *p = *data - 'a' + 10; - else if (*data >= 'A' && *data <= 'F') - *p = *data - 'A' + 10; - *p <<= 4; - ++data; - - if (*data >= '0' && *data <= '9') - *p |= *data - '0'; - else if (*data >= 'a' && *data <= 'f') - *p |= *data - 'a' + 10; - else if (*data >= 'A' && *data <= 'F') - *p |= *data - 'A' + 10; - ++data; - } - - // load guild member info - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " - "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id)) { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for (i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - struct guild_member *m = &g->member[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); - m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - m->hair = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - m->hair_color = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - m->gender = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - m->class_ = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - m->lv = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - m->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); - m->exp_payper = (unsigned int)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - m->online = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); - m->position = atoi(data); - if (m->position >= MAX_GUILDPOSITION) // Fix reduction of MAX_GUILDPOSITION [PoW] - m->position = MAX_GUILDPOSITION - 1; - Sql_GetData(sql_handle, 11, &data, &len); - memcpy(m->name, data, min(len, NAME_LENGTH)); - m->modified = GS_MEMBER_UNMODIFIED; - } - - //printf("- Read guild_position %d from sql \n",guild_id); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id)) { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - int position; - struct guild_position *p; - - Sql_GetData(sql_handle, 0, &data, NULL); - position = atoi(data); - if (position < 0 || position >= MAX_GUILDPOSITION) - continue;// invalid position - p = &g->position[position]; - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); - p->mode = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - p->exp_mode = atoi(data); - p->modified = GS_POSITION_UNMODIFIED; - } - - //printf("- Read guild_alliance %d from sql \n",guild_id); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id)) { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for (i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - struct guild_alliance *a = &g->alliance[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); - a->opposition = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - a->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(a->name, data, min(len, NAME_LENGTH)); - } - - //printf("- Read guild_expulsion %d from sql \n",guild_id); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id)) { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for (i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - struct guild_expulsion *e = &g->expulsion[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); - e->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(e->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(e->mes, data, min(len, sizeof(e->mes))); - } - - //printf("- Read guild_skill %d from sql \n",guild_id); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id)) { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - - for (i = 0; i < MAX_GUILDSKILL; i++) { - //Skill IDs must always be initialized. [Skotlex] - g->skill[i].id = i + GD_SKILLBASE; - } - - while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - int id; - Sql_GetData(sql_handle, 0, &data, NULL); - id = atoi(data) - GD_SKILLBASE; - if (id < 0 && id >= MAX_GUILDSKILL) - continue;// invalid guild skill - Sql_GetData(sql_handle, 1, &data, NULL); - g->skill[id].lv = atoi(data); - } - Sql_FreeResult(sql_handle); - - idb_put(guild_db_, guild_id, g); //Add to cache - g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. - - if (save_log) - ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); - - return g; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " + "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + return NULL; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return NULL;// Guild does not exists. + + CREATE(g, struct guild, 1); + + g->guild_id = guild_id; + Sql_GetData(sql_handle, 0, &data, &len); memcpy(g->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 1, &data, &len); memcpy(g->master, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); g->guild_lv = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); g->connect_member = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); g->max_member = atoi(data); + if( g->max_member > MAX_GUILD ) + { // Fix reduction of MAX_GUILD [PoW] + ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + Sql_GetData(sql_handle, 5, &data, NULL); g->average_lv = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); g->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 7, &data, NULL); g->next_exp = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); g->skill_point = atoi(data); + Sql_GetData(sql_handle, 9, &data, &len); memcpy(g->mes1, data, min(len, sizeof(g->mes1))); + Sql_GetData(sql_handle, 10, &data, &len); memcpy(g->mes2, data, min(len, sizeof(g->mes2))); + Sql_GetData(sql_handle, 11, &data, &len); g->emblem_len = atoi(data); + Sql_GetData(sql_handle, 12, &data, &len); g->emblem_id = atoi(data); + Sql_GetData(sql_handle, 13, &data, &len); + // convert emblem data from hexadecimal to binary + //TODO: why not store it in the db as binary directly? [ultramage] + for( i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p ) + { + if( *data >= '0' && *data <= '9' ) + *p = *data - '0'; + else if( *data >= 'a' && *data <= 'f' ) + *p = *data - 'a' + 10; + else if( *data >= 'A' && *data <= 'F' ) + *p = *data - 'A' + 10; + *p <<= 4; + ++data; + + if( *data >= '0' && *data <= '9' ) + *p |= *data - '0'; + else if( *data >= 'a' && *data <= 'f' ) + *p |= *data - 'a' + 10; + else if( *data >= 'A' && *data <= 'F' ) + *p |= *data - 'A' + 10; + ++data; + } + + // load guild member info + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " + "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for( i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + struct guild_member* m = &g->member[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); m->hair = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); m->hair_color = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); m->gender = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); m->class_ = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); m->lv = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); m->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); m->exp_payper = (unsigned int)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); m->online = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); m->position = atoi(data); + if( m->position >= MAX_GUILDPOSITION ) // Fix reduction of MAX_GUILDPOSITION [PoW] + m->position = MAX_GUILDPOSITION - 1; + Sql_GetData(sql_handle, 11, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); + m->modified = GS_MEMBER_UNMODIFIED; + } + + //printf("- Read guild_position %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + int position; + struct guild_position* p; + + Sql_GetData(sql_handle, 0, &data, NULL); position = atoi(data); + if( position < 0 || position >= MAX_GUILDPOSITION ) + continue;// invalid position + p = &g->position[position]; + Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); p->mode = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); p->exp_mode = atoi(data); + p->modified = GS_POSITION_UNMODIFIED; + } + + //printf("- Read guild_alliance %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for( i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + struct guild_alliance* a = &g->alliance[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); a->opposition = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); a->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(a->name, data, min(len, NAME_LENGTH)); + } + + //printf("- Read guild_expulsion %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for( i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + struct guild_expulsion *e = &g->expulsion[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); e->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, &len); memcpy(e->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(e->mes, data, min(len, sizeof(e->mes))); + } + + //printf("- Read guild_skill %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + + for(i = 0; i < MAX_GUILDSKILL; i++) + { //Skill IDs must always be initialized. [Skotlex] + g->skill[i].id = i + GD_SKILLBASE; + } + + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + int id; + Sql_GetData(sql_handle, 0, &data, NULL); id = atoi(data) - GD_SKILLBASE; + if( id < 0 && id >= MAX_GUILDSKILL ) + continue;// invalid guild skill + Sql_GetData(sql_handle, 1, &data, NULL); g->skill[id].lv = atoi(data); + } + Sql_FreeResult(sql_handle); + + idb_put(guild_db_, guild_id, g); //Add to cache + g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. + + if (save_log) + ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); + + return g; } // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`) int inter_guildcastle_tosql(struct guild_castle *gc) { - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` SET `castle_id`='%d', `guild_id`='%d', `economy`='%d', `defense`='%d', " - "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", - guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, - gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); - for (i = 0; i < MAX_GUARDIANS; ++i) - StringBuf_Printf(&buf, ", `visibleG%d`='%d'", i, gc->guardian[i].visible); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - else if (save_log) - ShowInfo("Saved guild castle (%d)\n", gc->castle_id); - - StringBuf_Destroy(&buf); - return 0; + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "REPLACE INTO `%s` SET `castle_id`='%d', `guild_id`='%d', `economy`='%d', `defense`='%d', " + "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", + guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, + gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); + for (i = 0; i < MAX_GUARDIANS; ++i) + StringBuf_Printf(&buf, ", `visibleG%d`='%d'", i, gc->guardian[i].visible); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + else if(save_log) + ShowInfo("Saved guild castle (%d)\n", gc->castle_id); + + StringBuf_Destroy(&buf); + return 0; } // Read guild_castle from SQL -static struct guild_castle *inter_guildcastle_fromsql(int castle_id) { - char *data; - int i; - StringBuf buf; - struct guild_castle *gc = idb_get(castle_db, castle_id); - - if (gc != NULL) - return gc; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, " - "`triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`"); - for (i = 0; i < MAX_GUARDIANS; ++i) - StringBuf_Printf(&buf, ", `visibleG%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", guild_castle_db, castle_id); - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - return NULL; - } - StringBuf_Destroy(&buf); - - CREATE(gc, struct guild_castle, 1); - gc->castle_id = castle_id; - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - Sql_GetData(sql_handle, 1, &data, NULL); - gc->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - gc->economy = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - gc->defense = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - gc->triggerE = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - gc->triggerD = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - gc->nextTime = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - gc->payTime = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); - gc->createTime = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - gc->visibleC = atoi(data); - for (i = 10; i < 10+MAX_GUARDIANS; i++) { - Sql_GetData(sql_handle, i, &data, NULL); - gc->guardian[i-10].visible = atoi(data); - } - } - Sql_FreeResult(sql_handle); - - idb_put(castle_db, castle_id, gc); - - if (save_log) - ShowInfo("Loaded guild castle (%d - guild %d)\n", castle_id, gc->guild_id); - - return gc; +static struct guild_castle* inter_guildcastle_fromsql(int castle_id) +{ + char *data; + int i; + StringBuf buf; + struct guild_castle *gc = idb_get(castle_db, castle_id); + + if (gc != NULL) + return gc; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, " + "`triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`"); + for (i = 0; i < MAX_GUARDIANS; ++i) + StringBuf_Printf(&buf, ", `visibleG%d`", i); + StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", guild_castle_db, castle_id); + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + return NULL; + } + StringBuf_Destroy(&buf); + + CREATE(gc, struct guild_castle, 1); + gc->castle_id = castle_id; + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + Sql_GetData(sql_handle, 1, &data, NULL); gc->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); gc->economy = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); gc->defense = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); gc->triggerE = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); gc->triggerD = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); gc->nextTime = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); gc->payTime = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); gc->createTime = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); gc->visibleC = atoi(data); + for (i = 10; i < 10+MAX_GUARDIANS; i++) { + Sql_GetData(sql_handle, i, &data, NULL); gc->guardian[i-10].visible = atoi(data); + } + } + Sql_FreeResult(sql_handle); + + idb_put(castle_db, castle_id, gc); + + if (save_log) + ShowInfo("Loaded guild castle (%d - guild %d)\n", castle_id, gc->guild_id); + + return gc; } // Read exp_guild.txt int inter_guild_ReadEXP(void) { - int i; - FILE *fp; - char line[1024]; - for (i=0; i<100; i++) guild_exp[i]=0; - //this is going to be discussed, temp fix - sprintf(line, "%s/pre-re/exp_guild.txt", db_path); - fp=fopen(line,"r"); - if (fp==NULL) { - ShowError("can't read %s\n", line); - return 1; - } - i=0; - while (fgets(line, sizeof(line), fp) && i < 100) { - if (line[0]=='/' && line[1]=='/') - continue; - guild_exp[i]=(unsigned int)atof(line); - i++; - } - fclose(fp); - - return 0; + int i; + FILE *fp; + char line[1024]; + for (i=0;i<100;i++) guild_exp[i]=0; + //this is going to be discussed, temp fix + sprintf(line, "%s/pre-re/exp_guild.txt", db_path); + fp=fopen(line,"r"); + if(fp==NULL){ + ShowError("can't read %s\n", line); + return 1; + } + i=0; + while(fgets(line, sizeof(line), fp) && i < 100) + { + if(line[0]=='/' && line[1]=='/') + continue; + guild_exp[i]=(unsigned int)atof(line); + i++; + } + fclose(fp); + + return 0; } int inter_guild_CharOnline(int char_id, int guild_id) { - struct guild *g; - int i; - - if (guild_id == -1) { - //Get guild_id from the database - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { - Sql_ShowDebug(sql_handle); - return 0; - } - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } else { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - g = inter_guild_fromsql(guild_id); - if (!g) { - ShowError("Character %d's guild %d not found!\n", char_id, guild_id); - return 0; - } - - //Member has logged in before saving, tell saver not to delete - if (g->save_flag & GS_REMOVE) - g->save_flag &= ~GS_REMOVE; - - //Set member online - ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); - if (i < g->max_member) { - g->member[i].online = 1; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - return 1; + struct guild *g; + int i; + + if (guild_id == -1) { + //Get guild_id from the database + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } + else + { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + g = inter_guild_fromsql(guild_id); + if(!g) { + ShowError("Character %d's guild %d not found!\n", char_id, guild_id); + return 0; + } + + //Member has logged in before saving, tell saver not to delete + if(g->save_flag & GS_REMOVE) + g->save_flag &= ~GS_REMOVE; + + //Set member online + ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); + if( i < g->max_member ) + { + g->member[i].online = 1; + g->member[i].modified = GS_MEMBER_MODIFIED; + } + + return 1; } int inter_guild_CharOffline(int char_id, int guild_id) { - struct guild *g=NULL; - int online_count, i; - - if (guild_id == -1) { - //Get guild_id from the database - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { - Sql_ShowDebug(sql_handle); - return 0; - } - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } else { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - //Character has a guild, set character offline and check if they were the only member online - g = inter_guild_fromsql(guild_id); - if (g == NULL) //Guild not found? - return 0; - - //Set member offline - ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); - if (i < g->max_member) { - g->member[i].online = 0; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - online_count = 0; - for (i = 0; i < g->max_member; i++) - if (g->member[i].online) - online_count++; - - // Remove guild from memory if no players online - if (online_count == 0) - g->save_flag |= GS_REMOVE; - - return 1; + struct guild *g=NULL; + int online_count, i; + + if (guild_id == -1) + { + //Get guild_id from the database + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } + else + { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + //Character has a guild, set character offline and check if they were the only member online + g = inter_guild_fromsql(guild_id); + if (g == NULL) //Guild not found? + return 0; + + //Set member offline + ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); + if( i < g->max_member ) + { + g->member[i].online = 0; + g->member[i].modified = GS_MEMBER_MODIFIED; + } + + online_count = 0; + for( i = 0; i < g->max_member; i++ ) + if( g->member[i].online ) + online_count++; + + // Remove guild from memory if no players online + if( online_count == 0 ) + g->save_flag |= GS_REMOVE; + + return 1; } // Initialize guild sql int inter_guild_sql_init(void) { - //Initialize the guild cache - guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); - castle_db = idb_alloc(DB_OPT_RELEASE_DATA); - - //Read exp file - inter_guild_ReadEXP(); - - add_timer_func_list(guild_save_timer, "guild_save_timer"); - add_timer(gettick() + 10000, guild_save_timer, 0, 0); - return 0; + //Initialize the guild cache + guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); + castle_db = idb_alloc(DB_OPT_RELEASE_DATA); + + //Read exp file + inter_guild_ReadEXP(); + + add_timer_func_list(guild_save_timer, "guild_save_timer"); + add_timer(gettick() + 10000, guild_save_timer, 0, 0); + return 0; } /** @@ -751,134 +751,145 @@ int inter_guild_sql_init(void) */ static int guild_db_final(DBKey key, DBData *data, va_list ap) { - struct guild *g = db_data2ptr(data); - if (g->save_flag&GS_MASK) { - inter_guild_tosql(g, g->save_flag&GS_MASK); - return 1; - } - return 0; + struct guild *g = db_data2ptr(data); + if (g->save_flag&GS_MASK) { + inter_guild_tosql(g, g->save_flag&GS_MASK); + return 1; + } + return 0; } void inter_guild_sql_final(void) { - guild_db_->destroy(guild_db_, guild_db_final); - db_destroy(castle_db); - return; + guild_db_->destroy(guild_db_, guild_db_final); + db_destroy(castle_db); + return; } // Get guild_id by its name. Returns 0 if not found, -1 on error. int search_guildname(char *str) { - int guild_id; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - //Lookup guilds with the same name - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name)) { - Sql_ShowDebug(sql_handle); - return -1; - } - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } else { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - return guild_id; + int guild_id; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + //Lookup guilds with the same name + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name) ) + { + Sql_ShowDebug(sql_handle); + return -1; + } + + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } + else + { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + return guild_id; } // Check if guild is empty static bool guild_check_empty(struct guild *g) { - int i; - ARR_FIND(0, g->max_member, i, g->member[i].account_id > 0); - if (i < g->max_member) - return false; // not empty - - //Let the calling function handle the guild removal in case they need - //to do something else with it before freeing the data. [Skotlex] - return true; + int i; + ARR_FIND( 0, g->max_member, i, g->member[i].account_id > 0 ); + if( i < g->max_member) + return false; // not empty + + //Let the calling function handle the guild removal in case they need + //to do something else with it before freeing the data. [Skotlex] + return true; } unsigned int guild_nextexp(int level) { - if (level == 0) - return 1; - if (level < 100 && level > 0) // Change by hack - return guild_exp[level-1]; + if (level == 0) + return 1; + if (level < 100 && level > 0) // Change by hack + return guild_exp[level-1]; - return 0; + return 0; } int guild_checkskill(struct guild *g,int id) { - int idx = id - GD_SKILLBASE; + int idx = id - GD_SKILLBASE; - if (idx < 0 || idx >= MAX_GUILDSKILL) - return 0; + if(idx < 0 || idx >= MAX_GUILDSKILL) + return 0; - return g->skill[idx].lv; + return g->skill[idx].lv; } int guild_calcinfo(struct guild *g) { - int i,c; - unsigned int nextexp; - struct guild before = *g; // Save guild current values - - if (g->guild_lv<=0) - g->guild_lv = 1; - nextexp = guild_nextexp(g->guild_lv); - - // Consume guild exp and increase guild level - while (g->exp >= nextexp && nextexp > 0) { //fixed guild exp overflow [Kevin] - g->exp-=nextexp; - g->guild_lv++; - g->skill_point++; - nextexp = guild_nextexp(g->guild_lv); - } - - // Save next exp step - g->next_exp = nextexp; - - // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. - g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; - if (g->max_member > MAX_GUILD) { - ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - - // Compute the guild average level level - g->average_lv=0; - g->connect_member=0; - for (i=c=0; imax_member; i++) { - if (g->member[i].account_id>0) { - if (g->member[i].lv >= 0) { - g->average_lv+=g->member[i].lv; - c++; - } else { - ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); - } - - if (g->member[i].online) - g->connect_member++; - } - } - if (c) - g->average_lv /= c; - - // Check if guild stats has change - if (g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point) { - g->save_flag |= GS_LEVEL; - mapif_guild_info(-1,g); - return 1; - } - - return 0; + int i,c; + unsigned int nextexp; + struct guild before = *g; // Save guild current values + + if(g->guild_lv<=0) + g->guild_lv = 1; + nextexp = guild_nextexp(g->guild_lv); + + // Consume guild exp and increase guild level + while(g->exp >= nextexp && nextexp > 0){ //fixed guild exp overflow [Kevin] + g->exp-=nextexp; + g->guild_lv++; + g->skill_point++; + nextexp = guild_nextexp(g->guild_lv); + } + + // Save next exp step + g->next_exp = nextexp; + + // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. + g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; + if(g->max_member > MAX_GUILD) + { + ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + + // Compute the guild average level level + g->average_lv=0; + g->connect_member=0; + for(i=c=0;imax_member;i++) + { + if(g->member[i].account_id>0) + { + if (g->member[i].lv >= 0) + { + g->average_lv+=g->member[i].lv; + c++; + } + else + { + ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); + } + + if(g->member[i].online) + g->connect_member++; + } + } + if(c) + g->average_lv /= c; + + // Check if guild stats has change + if(g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point ) + { + g->save_flag |= GS_LEVEL; + mapif_guild_info(-1,g); + return 1; + } + + return 0; } //------------------------------------------------------------------- @@ -886,244 +897,245 @@ int guild_calcinfo(struct guild *g) int mapif_guild_created(int fd,int account_id,struct guild *g) { - WFIFOHEAD(fd, 10); - WFIFOW(fd,0)=0x3830; - WFIFOL(fd,2)=account_id; - if (g != NULL) { - WFIFOL(fd,6)=g->guild_id; - ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); - } else - WFIFOL(fd,6)=0; - - WFIFOSET(fd,10); - return 0; + WFIFOHEAD(fd, 10); + WFIFOW(fd,0)=0x3830; + WFIFOL(fd,2)=account_id; + if(g != NULL) + { + WFIFOL(fd,6)=g->guild_id; + ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); + } else + WFIFOL(fd,6)=0; + + WFIFOSET(fd,10); + return 0; } // Guild not found int mapif_guild_noinfo(int fd,int guild_id) { - unsigned char buf[12]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=8; - WBUFL(buf,4)=guild_id; - ShowWarning("int_guild: info not found %d\n",guild_id); - if (fd<0) - mapif_sendall(buf,8); - else - mapif_send(fd,buf,8); - return 0; + unsigned char buf[12]; + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=8; + WBUFL(buf,4)=guild_id; + ShowWarning("int_guild: info not found %d\n",guild_id); + if(fd<0) + mapif_sendall(buf,8); + else + mapif_send(fd,buf,8); + return 0; } // Send guild info int mapif_guild_info(int fd,struct guild *g) { - unsigned char buf[8+sizeof(struct guild)]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=4+sizeof(struct guild); - memcpy(buf+4,g,sizeof(struct guild)); - if (fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); - return 0; + unsigned char buf[8+sizeof(struct guild)]; + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=4+sizeof(struct guild); + memcpy(buf+4,g,sizeof(struct guild)); + if(fd<0) + mapif_sendall(buf,WBUFW(buf,2)); + else + mapif_send(fd,buf,WBUFW(buf,2)); + return 0; } // ACK member add int mapif_guild_memberadded(int fd,int guild_id,int account_id,int char_id,int flag) { - WFIFOHEAD(fd, 15); - WFIFOW(fd,0)=0x3832; - WFIFOL(fd,2)=guild_id; - WFIFOL(fd,6)=account_id; - WFIFOL(fd,10)=char_id; - WFIFOB(fd,14)=flag; - WFIFOSET(fd,15); - return 0; + WFIFOHEAD(fd, 15); + WFIFOW(fd,0)=0x3832; + WFIFOL(fd,2)=guild_id; + WFIFOL(fd,6)=account_id; + WFIFOL(fd,10)=char_id; + WFIFOB(fd,14)=flag; + WFIFOSET(fd,15); + return 0; } // ACK member leave int mapif_guild_withdraw(int guild_id,int account_id,int char_id,int flag, const char *name, const char *mes) { - unsigned char buf[55+NAME_LENGTH]; - WBUFW(buf, 0)=0x3834; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=account_id; - WBUFL(buf,10)=char_id; - WBUFB(buf,14)=flag; - memcpy(WBUFP(buf,15),mes,40); - memcpy(WBUFP(buf,55),name,NAME_LENGTH); - mapif_sendall(buf,55+NAME_LENGTH); - ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); - return 0; + unsigned char buf[55+NAME_LENGTH]; + WBUFW(buf, 0)=0x3834; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=account_id; + WBUFL(buf,10)=char_id; + WBUFB(buf,14)=flag; + memcpy(WBUFP(buf,15),mes,40); + memcpy(WBUFP(buf,55),name,NAME_LENGTH); + mapif_sendall(buf,55+NAME_LENGTH); + ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); + return 0; } // Send short member's info int mapif_guild_memberinfoshort(struct guild *g,int idx) { - unsigned char buf[19]; - WBUFW(buf, 0)=0x3835; - WBUFL(buf, 2)=g->guild_id; - WBUFL(buf, 6)=g->member[idx].account_id; - WBUFL(buf,10)=g->member[idx].char_id; - WBUFB(buf,14)=(unsigned char)g->member[idx].online; - WBUFW(buf,15)=g->member[idx].lv; - WBUFW(buf,17)=g->member[idx].class_; - mapif_sendall(buf,19); - return 0; + unsigned char buf[19]; + WBUFW(buf, 0)=0x3835; + WBUFL(buf, 2)=g->guild_id; + WBUFL(buf, 6)=g->member[idx].account_id; + WBUFL(buf,10)=g->member[idx].char_id; + WBUFB(buf,14)=(unsigned char)g->member[idx].online; + WBUFW(buf,15)=g->member[idx].lv; + WBUFW(buf,17)=g->member[idx].class_; + mapif_sendall(buf,19); + return 0; } // Send guild broken int mapif_guild_broken(int guild_id,int flag) { - unsigned char buf[7]; - WBUFW(buf,0)=0x3836; - WBUFL(buf,2)=guild_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - ShowInfo("int_guild: Guild broken (%d)\n",guild_id); - return 0; + unsigned char buf[7]; + WBUFW(buf,0)=0x3836; + WBUFL(buf,2)=guild_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + ShowInfo("int_guild: Guild broken (%d)\n",guild_id); + return 0; } // Send guild message int mapif_guild_message(int guild_id,int account_id,char *mes,int len, int sfd) { - unsigned char buf[512]; - if (len > 500) - len = 500; - WBUFW(buf,0)=0x3837; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=guild_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; + unsigned char buf[512]; + if (len > 500) + len = 500; + WBUFW(buf,0)=0x3837; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=guild_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); + return 0; } // Send basic info int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len) { - unsigned char buf[2048]; - if (len > 2038) - len = 2038; - WBUFW(buf, 0)=0x3839; - WBUFW(buf, 2)=len+10; - WBUFL(buf, 4)=guild_id; - WBUFW(buf, 8)=type; - memcpy(WBUFP(buf,10),data,len); - mapif_sendall(buf,len+10); - return 0; + unsigned char buf[2048]; + if (len > 2038) + len = 2038; + WBUFW(buf, 0)=0x3839; + WBUFW(buf, 2)=len+10; + WBUFL(buf, 4)=guild_id; + WBUFW(buf, 8)=type; + memcpy(WBUFP(buf,10),data,len); + mapif_sendall(buf,len+10); + return 0; } // Send member info int mapif_guild_memberinfochanged(int guild_id,int account_id,int char_id, int type,const void *data,int len) { - unsigned char buf[2048]; - if (len > 2030) - len = 2030; - WBUFW(buf, 0)=0x383a; - WBUFW(buf, 2)=len+18; - WBUFL(buf, 4)=guild_id; - WBUFL(buf, 8)=account_id; - WBUFL(buf,12)=char_id; - WBUFW(buf,16)=type; - memcpy(WBUFP(buf,18),data,len); - mapif_sendall(buf,len+18); - return 0; + unsigned char buf[2048]; + if (len > 2030) + len = 2030; + WBUFW(buf, 0)=0x383a; + WBUFW(buf, 2)=len+18; + WBUFL(buf, 4)=guild_id; + WBUFL(buf, 8)=account_id; + WBUFL(buf,12)=char_id; + WBUFW(buf,16)=type; + memcpy(WBUFP(buf,18),data,len); + mapif_sendall(buf,len+18); + return 0; } // ACK guild skill up int mapif_guild_skillupack(int guild_id,int skill_num,int account_id) { - unsigned char buf[14]; - WBUFW(buf, 0)=0x383c; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=skill_num; - WBUFL(buf,10)=account_id; - mapif_sendall(buf,14); - return 0; + unsigned char buf[14]; + WBUFW(buf, 0)=0x383c; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=skill_num; + WBUFL(buf,10)=account_id; + mapif_sendall(buf,14); + return 0; } // ACK guild alliance int mapif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag,const char *name1,const char *name2) { - unsigned char buf[19+2*NAME_LENGTH]; - WBUFW(buf, 0)=0x383d; - WBUFL(buf, 2)=guild_id1; - WBUFL(buf, 6)=guild_id2; - WBUFL(buf,10)=account_id1; - WBUFL(buf,14)=account_id2; - WBUFB(buf,18)=flag; - memcpy(WBUFP(buf,19),name1,NAME_LENGTH); - memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); - mapif_sendall(buf,19+2*NAME_LENGTH); - return 0; + unsigned char buf[19+2*NAME_LENGTH]; + WBUFW(buf, 0)=0x383d; + WBUFL(buf, 2)=guild_id1; + WBUFL(buf, 6)=guild_id2; + WBUFL(buf,10)=account_id1; + WBUFL(buf,14)=account_id2; + WBUFB(buf,18)=flag; + memcpy(WBUFP(buf,19),name1,NAME_LENGTH); + memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); + mapif_sendall(buf,19+2*NAME_LENGTH); + return 0; } // Send a guild position desc int mapif_guild_position(struct guild *g,int idx) { - unsigned char buf[12 + sizeof(struct guild_position)]; - WBUFW(buf,0)=0x383b; - WBUFW(buf,2)=sizeof(struct guild_position)+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=idx; - memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; + unsigned char buf[12 + sizeof(struct guild_position)]; + WBUFW(buf,0)=0x383b; + WBUFW(buf,2)=sizeof(struct guild_position)+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=idx; + memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); + mapif_sendall(buf,WBUFW(buf,2)); + return 0; } // Send the guild notice int mapif_guild_notice(struct guild *g) { - unsigned char buf[256]; - WBUFW(buf,0)=0x383e; - WBUFL(buf,2)=g->guild_id; - memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); - memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); - mapif_sendall(buf,186); - return 0; + unsigned char buf[256]; + WBUFW(buf,0)=0x383e; + WBUFL(buf,2)=g->guild_id; + memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); + memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); + mapif_sendall(buf,186); + return 0; } // Send emblem data int mapif_guild_emblem(struct guild *g) { - unsigned char buf[12 + sizeof(g->emblem_data)]; - WBUFW(buf,0)=0x383f; - WBUFW(buf,2)=g->emblem_len+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=g->emblem_id; - memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; + unsigned char buf[12 + sizeof(g->emblem_data)]; + WBUFW(buf,0)=0x383f; + WBUFW(buf,2)=g->emblem_len+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=g->emblem_id; + memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); + mapif_sendall(buf,WBUFW(buf,2)); + return 0; } int mapif_guild_master_changed(struct guild *g, int aid, int cid) { - unsigned char buf[14]; - WBUFW(buf,0)=0x3843; - WBUFL(buf,2)=g->guild_id; - WBUFL(buf,6)=aid; - WBUFL(buf,10)=cid; - mapif_sendall(buf,14); - return 0; + unsigned char buf[14]; + WBUFW(buf,0)=0x3843; + WBUFL(buf,2)=g->guild_id; + WBUFL(buf,6)=aid; + WBUFL(buf,10)=cid; + mapif_sendall(buf,14); + return 0; } int mapif_guild_castle_dataload(int fd, int sz, int *castle_ids) { - struct guild_castle *gc = NULL; - int num = (sz - 4) / sizeof(int); - int len = 4 + num * sizeof(*gc); - int i; - - WFIFOHEAD(fd, len); - WFIFOW(fd, 0) = 0x3840; - WFIFOW(fd, 2) = len; - for (i = 0; i < num; i++) { - gc = inter_guildcastle_fromsql(*(castle_ids++)); - memcpy(WFIFOP(fd, 4 + i * sizeof(*gc)), gc, sizeof(*gc)); - } - WFIFOSET(fd, len); - return 0; + struct guild_castle *gc = NULL; + int num = (sz - 4) / sizeof(int); + int len = 4 + num * sizeof(*gc); + int i; + + WFIFOHEAD(fd, len); + WFIFOW(fd, 0) = 0x3840; + WFIFOW(fd, 2) = len; + for (i = 0; i < num; i++) { + gc = inter_guildcastle_fromsql(*(castle_ids++)); + memcpy(WFIFOP(fd, 4 + i * sizeof(*gc)), gc, sizeof(*gc)); + } + WFIFOSET(fd, len); + return 0; } //------------------------------------------------------------------- @@ -1133,680 +1145,696 @@ int mapif_guild_castle_dataload(int fd, int sz, int *castle_ids) // Guild creation request int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member *master) { - struct guild *g; - int i=0; + struct guild *g; + int i=0; #ifdef NOISY - ShowInfo("Creating Guild (%s)\n", name); + ShowInfo("Creating Guild (%s)\n", name); #endif - if (search_guildname(name) != 0) { - ShowInfo("int_guild: guild with same name exists [%s]\n",name); - mapif_guild_created(fd,account_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } - - g = (struct guild *)aMalloc(sizeof(struct guild)); - memset(g,0,sizeof(struct guild)); - - memcpy(g->name,name,NAME_LENGTH); - memcpy(g->master,master->name,NAME_LENGTH); - memcpy(&g->member[0],master,sizeof(struct guild_member)); - g->member[0].modified = GS_MEMBER_MODIFIED; - - // Set default positions - g->position[0].mode=0x11; - strcpy(g->position[0].name,"GuildMaster"); - strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); - g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; - for (i=1; iposition[i].name,"Position %d",i+1); - g->position[i].modified = GS_POSITION_MODIFIED; - } - - // Initialize guild property - g->max_member=16; - g->average_lv=master->lv; - g->connect_member=1; - - for (i=0; iskill[i].id=i + GD_SKILLBASE; - g->guild_id= -1; //Request to create guild. - - // Create the guild - if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { - //Failed to Create guild.... - ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); - mapif_guild_created(fd,account_id,NULL); - aFree(g); - return 0; - } - ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); - - //Add to cache - idb_put(guild_db_, g->guild_id, g); - - // Report to client - mapif_guild_created(fd,account_id,g); - mapif_guild_info(fd,g); - - if (log_inter) - inter_log("guild %s (id=%d) created by master %s (id=%d)\n", - name, g->guild_id, master->name, master->account_id); - - return 0; + if(search_guildname(name) != 0){ + ShowInfo("int_guild: guild with same name exists [%s]\n",name); + mapif_guild_created(fd,account_id,NULL); + return 0; + } + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } + + g = (struct guild *)aMalloc(sizeof(struct guild)); + memset(g,0,sizeof(struct guild)); + + memcpy(g->name,name,NAME_LENGTH); + memcpy(g->master,master->name,NAME_LENGTH); + memcpy(&g->member[0],master,sizeof(struct guild_member)); + g->member[0].modified = GS_MEMBER_MODIFIED; + + // Set default positions + g->position[0].mode=0x11; + strcpy(g->position[0].name,"GuildMaster"); + strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); + g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; + for(i=1;iposition[i].name,"Position %d",i+1); + g->position[i].modified = GS_POSITION_MODIFIED; + } + + // Initialize guild property + g->max_member=16; + g->average_lv=master->lv; + g->connect_member=1; + + for(i=0;iskill[i].id=i + GD_SKILLBASE; + g->guild_id= -1; //Request to create guild. + + // Create the guild + if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { + //Failed to Create guild.... + ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); + mapif_guild_created(fd,account_id,NULL); + aFree(g); + return 0; + } + ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); + + //Add to cache + idb_put(guild_db_, g->guild_id, g); + + // Report to client + mapif_guild_created(fd,account_id,g); + mapif_guild_info(fd,g); + + if(log_inter) + inter_log("guild %s (id=%d) created by master %s (id=%d)\n", + name, g->guild_id, master->name, master->account_id ); + + return 0; } // Return guild info to client int mapif_parse_GuildInfo(int fd,int guild_id) { - struct guild *g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] - if (g) { - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - } else - mapif_guild_noinfo(fd,guild_id); // Failed to load info - return 0; + struct guild * g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] + if(g) + { + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + } + else + mapif_guild_noinfo(fd,guild_id); // Failed to load info + return 0; } // Add member to guild int mapif_parse_GuildAddMember(int fd,int guild_id,struct guild_member *m) { - struct guild *g; - int i; - - g = inter_guild_fromsql(guild_id); - if (g==NULL) { - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; - } - - // Find an empty slot - for (i=0; imax_member; i++) { - if (g->member[i].account_id==0) { - memcpy(&g->member[i],m,sizeof(struct guild_member)); - g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); - if (!guild_calcinfo(g)) //Send members if it was not invoked. - mapif_guild_info(-1,g); - - g->save_flag |= GS_MEMBER; - if (g->save_flag&GS_REMOVE) - g->save_flag&=~GS_REMOVE; - return 0; - } - } - - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; + struct guild * g; + int i; + + g = inter_guild_fromsql(guild_id); + if(g==NULL){ + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); + return 0; + } + + // Find an empty slot + for(i=0;imax_member;i++) + { + if(g->member[i].account_id==0) + { + memcpy(&g->member[i],m,sizeof(struct guild_member)); + g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); + if (!guild_calcinfo(g)) //Send members if it was not invoked. + mapif_guild_info(-1,g); + + g->save_flag |= GS_MEMBER; + if (g->save_flag&GS_REMOVE) + g->save_flag&=~GS_REMOVE; + return 0; + } + } + + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); + return 0; } // Delete member from guild int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, int flag, const char *mes) { - int i, j; - - struct guild *g = inter_guild_fromsql(guild_id); - if (g == NULL) { - // Unknown guild, just update the player - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id)) - Sql_ShowDebug(sql_handle); - // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - return 0; - } - - // Find the member - ARR_FIND(0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id); - if (i == g->max_member) { - //TODO - return 0; - } - - if (flag) { - // Write expulsion reason - // Find an empty slot - ARR_FIND(0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0); - if (j == MAX_GUILDEXPULSION) { - // Expulsion list is full, flush the oldest one - for (j = 0; j < MAX_GUILDEXPULSION - 1; j++) - g->expulsion[j] = g->expulsion[j+1]; - j = MAX_GUILDEXPULSION-1; - } - // Save the expulsion entry - g->expulsion[j].account_id = account_id; - safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); - safestrncpy(g->expulsion[j].mes, mes, 40); - } - - mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); - - memset(&g->member[i],0,sizeof(struct guild_member)); - - if (guild_check_empty(g)) - mapif_parse_BreakGuild(-1,guild_id); //Break the guild. - else { - //Update member info. - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - g->save_flag |= GS_EXPULSION; - } - - return 0; + int i, j; + + struct guild* g = inter_guild_fromsql(guild_id); + if( g == NULL ) + { + // Unknown guild, just update the player + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id) ) + Sql_ShowDebug(sql_handle); + // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); + return 0; + } + + // Find the member + ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); + if( i == g->max_member ) + { + //TODO + return 0; + } + + if( flag ) + { // Write expulsion reason + // Find an empty slot + ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); + if( j == MAX_GUILDEXPULSION ) + { + // Expulsion list is full, flush the oldest one + for( j = 0; j < MAX_GUILDEXPULSION - 1; j++ ) + g->expulsion[j] = g->expulsion[j+1]; + j = MAX_GUILDEXPULSION-1; + } + // Save the expulsion entry + g->expulsion[j].account_id = account_id; + safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); + safestrncpy(g->expulsion[j].mes, mes, 40); + } + + mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); + inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); + + memset(&g->member[i],0,sizeof(struct guild_member)); + + if( guild_check_empty(g) ) + mapif_parse_BreakGuild(-1,guild_id); //Break the guild. + else { + //Update member info. + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + g->save_flag |= GS_EXPULSION; + } + + return 0; } // Change member info int mapif_parse_GuildChangeMemberInfoShort(int fd,int guild_id,int account_id,int char_id,int online,int lv,int class_) { - // Could speed up by manipulating only guild_member - struct guild *g; - int i,sum,c; - int prev_count, prev_alv; - - g = inter_guild_fromsql(guild_id); - if (g==NULL) - return 0; - - ARR_FIND(0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id); - if (i < g->max_member) { - g->member[i].online = online; - g->member[i].lv = lv; - g->member[i].class_ = class_; - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfoshort(g,i); - } - - prev_count = g->connect_member; - prev_alv = g->average_lv; - - g->average_lv = 0; - g->connect_member = 0; - c = 0; - sum = 0; - - for (i = 0; i < g->max_member; i++) { - if (g->member[i].account_id > 0) { - sum += g->member[i].lv; - c++; - } - if (g->member[i].online) - g->connect_member++; - } - - if (c) { // this check should always succeed... - g->average_lv = sum / c; - if (g->connect_member != prev_count || g->average_lv != prev_alv) - g->save_flag |= GS_CONNECT; - if (g->save_flag & GS_REMOVE) - g->save_flag &= ~GS_REMOVE; - } - g->save_flag |= GS_MEMBER; //Update guild member data - return 0; + // Could speed up by manipulating only guild_member + struct guild * g; + int i,sum,c; + int prev_count, prev_alv; + + g = inter_guild_fromsql(guild_id); + if(g==NULL) + return 0; + + ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); + if( i < g->max_member ) + { + g->member[i].online = online; + g->member[i].lv = lv; + g->member[i].class_ = class_; + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfoshort(g,i); + } + + prev_count = g->connect_member; + prev_alv = g->average_lv; + + g->average_lv = 0; + g->connect_member = 0; + c = 0; + sum = 0; + + for( i = 0; i < g->max_member; i++ ) + { + if( g->member[i].account_id > 0 ) + { + sum += g->member[i].lv; + c++; + } + if( g->member[i].online ) + g->connect_member++; + } + + if( c ) // this check should always succeed... + { + g->average_lv = sum / c; + if( g->connect_member != prev_count || g->average_lv != prev_alv ) + g->save_flag |= GS_CONNECT; + if( g->save_flag & GS_REMOVE ) + g->save_flag &= ~GS_REMOVE; + } + g->save_flag |= GS_MEMBER; //Update guild member data + return 0; } // BreakGuild int mapif_parse_BreakGuild(int fd,int guild_id) { - struct guild *g; + struct guild * g; + + g = inter_guild_fromsql(guild_id); + if(g==NULL) + return 0; - g = inter_guild_fromsql(guild_id); - if (g==NULL) - return 0; + // Delete guild from sql + //printf("- Delete guild %d from guild\n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id) ) + Sql_ShowDebug(sql_handle); - // Delete guild from sql - //printf("- Delete guild %d from guild\n",guild_id); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id)) - Sql_ShowDebug(sql_handle); + //printf("- Update guild %d of char\n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id) ) + Sql_ShowDebug(sql_handle); - //printf("- Update guild %d of char\n",guild_id); - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id)) - Sql_ShowDebug(sql_handle); + mapif_guild_broken(guild_id,0); - mapif_guild_broken(guild_id,0); + if(log_inter) + inter_log("guild %s (id=%d) broken\n",g->name,guild_id); - if (log_inter) - inter_log("guild %s (id=%d) broken\n",g->name,guild_id); - - //Remove the guild from memory. [Skotlex] - idb_remove(guild_db_, guild_id); - return 0; + //Remove the guild from memory. [Skotlex] + idb_remove(guild_db_, guild_id); + return 0; } // Forward Guild message to others map servers int mapif_parse_GuildMessage(int fd,int guild_id,int account_id,char *mes,int len) { - return mapif_guild_message(guild_id,account_id,mes,len, fd); + return mapif_guild_message(guild_id,account_id,mes,len, fd); } -// Modification of the guild +// Modification of the guild int mapif_parse_GuildBasicInfoChange(int fd,int guild_id,int type,const char *data,int len) { - struct guild *g; - short dw=*((short *)data); - g = inter_guild_fromsql(guild_id); - if (g==NULL) - return 0; - - switch (type) { - case GBI_GUILDLV: - if (dw>0 && g->guild_lv+dw<=50) { - g->guild_lv+=dw; - g->skill_point+=dw; - } else if (dw<0 && g->guild_lv+dw>=1) - g->guild_lv+=dw; - mapif_guild_info(-1,g); - g->save_flag |= GS_LEVEL; - return 0; - default: - ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); - break; - } - mapif_guild_basicinfochanged(guild_id,type,data,len); - return 0; + struct guild * g; + short dw=*((short *)data); + g = inter_guild_fromsql(guild_id); + if(g==NULL) + return 0; + + switch(type) + { + case GBI_GUILDLV: + if(dw>0 && g->guild_lv+dw<=50) + { + g->guild_lv+=dw; + g->skill_point+=dw; + } + else if(dw<0 && g->guild_lv+dw>=1) + g->guild_lv+=dw; + mapif_guild_info(-1,g); + g->save_flag |= GS_LEVEL; + return 0; + default: + ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); + break; + } + mapif_guild_basicinfochanged(guild_id,type,data,len); + return 0; } -// Modification of the guild +// Modification of the guild int mapif_parse_GuildMemberInfoChange(int fd,int guild_id,int account_id,int char_id,int type,const char *data,int len) { - // Could make some improvement in speed, because only change guild_member - int i; - struct guild *g; - - g = inter_guild_fromsql(guild_id); - if (g==NULL) - return 0; - - // Search the member - for (i=0; imax_member; i++) - if (g->member[i].account_id==account_id && - g->member[i].char_id==char_id) - break; - - // Not Found - if (i==g->max_member) { - ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", - account_id,char_id,guild_id,g->name); - return 0; - } - - switch (type) { - case GMI_POSITION: { - g->member[i].position=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_EXP: { - // EXP - uint64 exp, old_exp=g->member[i].exp; - g->member[i].exp=*((uint64 *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - if (g->member[i].exp > old_exp) { - exp = g->member[i].exp - old_exp; - - // Compute gained exp - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; - - // Update guild exp - if (exp > UINT64_MAX - g->exp) - g->exp = UINT64_MAX; - else - g->exp+=exp; - - guild_calcinfo(g); - mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); - g->save_flag |= GS_LEVEL; - } - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_HAIR: { - g->member[i].hair=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_HAIR_COLOR: { - g->member[i].hair_color=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_GENDER: { - g->member[i].gender=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_CLASS: { - g->member[i].class_=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_LEVEL: { - g->member[i].lv=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - default: - ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); - break; - } - return 0; + // Could make some improvement in speed, because only change guild_member + int i; + struct guild * g; + + g = inter_guild_fromsql(guild_id); + if(g==NULL) + return 0; + + // Search the member + for(i=0;imax_member;i++) + if( g->member[i].account_id==account_id && + g->member[i].char_id==char_id ) + break; + + // Not Found + if(i==g->max_member){ + ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", + account_id,char_id,guild_id,g->name); + return 0; + } + + switch(type) + { + case GMI_POSITION: + { + g->member[i].position=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_EXP: + { // EXP + uint64 exp, old_exp=g->member[i].exp; + g->member[i].exp=*((uint64 *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + if (g->member[i].exp > old_exp) + { + exp = g->member[i].exp - old_exp; + + // Compute gained exp + if (guild_exp_rate != 100) + exp = exp*guild_exp_rate/100; + + // Update guild exp + if (exp > UINT64_MAX - g->exp) + g->exp = UINT64_MAX; + else + g->exp+=exp; + + guild_calcinfo(g); + mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); + g->save_flag |= GS_LEVEL; + } + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_HAIR: + { + g->member[i].hair=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_HAIR_COLOR: + { + g->member[i].hair_color=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_GENDER: + { + g->member[i].gender=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_CLASS: + { + g->member[i].class_=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_LEVEL: + { + g->member[i].lv=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + default: + ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); + break; + } + return 0; } int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender) { - return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char *)&gender, sizeof(gender)); + return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); } int inter_guild_charname_changed(int guild_id,int account_id, int char_id, char *name) { - struct guild *g; - int i, flag = 0; - - g = inter_guild_fromsql(guild_id); - if (g == NULL) { - ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); - return 0; - } - - ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); - if (i == g->max_member) { - ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); - return 0; - } - - if (!strcmp(g->member[i].name, g->master)) { - safestrncpy(g->master, name, NAME_LENGTH); - flag |= GS_BASIC; - } - safestrncpy(g->member[i].name, name, NAME_LENGTH); - g->member[i].modified = GS_MEMBER_MODIFIED; - flag |= GS_MEMBER; - - if (!inter_guild_tosql(g, flag)) - return 0; - - mapif_guild_info(-1,g); - - return 0; + struct guild *g; + int i, flag = 0; + + g = inter_guild_fromsql(guild_id); + if( g == NULL ) + { + ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); + return 0; + } + + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if( i == g->max_member ) + { + ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); + return 0; + } + + if( !strcmp(g->member[i].name, g->master) ) + { + safestrncpy(g->master, name, NAME_LENGTH); + flag |= GS_BASIC; + } + safestrncpy(g->member[i].name, name, NAME_LENGTH); + g->member[i].modified = GS_MEMBER_MODIFIED; + flag |= GS_MEMBER; + + if( !inter_guild_tosql(g, flag) ) + return 0; + + mapif_guild_info(-1,g); + + return 0; } // Change a position desc int mapif_parse_GuildPosition(int fd,int guild_id,int idx,struct guild_position *p) { - // Could make some improvement in speed, because only change guild_position - struct guild *g; - - g = inter_guild_fromsql(guild_id); - if (g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) - return 0; - - memcpy(&g->position[idx],p,sizeof(struct guild_position)); - mapif_guild_position(g,idx); - g->position[idx].modified = GS_POSITION_MODIFIED; - g->save_flag |= GS_POSITION; // Change guild_position - return 0; + // Could make some improvement in speed, because only change guild_position + struct guild * g; + + g = inter_guild_fromsql(guild_id); + if(g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) + return 0; + + memcpy(&g->position[idx],p,sizeof(struct guild_position)); + mapif_guild_position(g,idx); + g->position[idx].modified = GS_POSITION_MODIFIED; + g->save_flag |= GS_POSITION; // Change guild_position + return 0; } // Guild Skill UP int mapif_parse_GuildSkillUp(int fd,int guild_id,int skill_num,int account_id,int max) { - struct guild *g; - int idx = skill_num - GD_SKILLBASE; - - g = inter_guild_fromsql(guild_id); - if (g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) - return 0; - - if (g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; - g->skill_point--; - if (!guild_calcinfo(g)) - mapif_guild_info(-1,g); - mapif_guild_skillupack(guild_id,skill_num,account_id); - g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill - } - return 0; + struct guild * g; + int idx = skill_num - GD_SKILLBASE; + + g = inter_guild_fromsql(guild_id); + if(g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) + return 0; + + if(g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; + g->skill_point--; + if (!guild_calcinfo(g)) + mapif_guild_info(-1,g); + mapif_guild_skillupack(guild_id,skill_num,account_id); + g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill + } + return 0; } //Manual deletion of an alliance when partnering guild does not exists. [Skotlex] static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag) { - int i; - char name[NAME_LENGTH]; - - ARR_FIND(0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id); - if (i == MAX_GUILDALLIANCE) - return -1; - - strcpy(name, g->alliance[i].name); - g->alliance[i].guild_id=0; - - mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); - g->save_flag |= GS_ALLIANCE; - return 0; + int i; + char name[NAME_LENGTH]; + + ARR_FIND( 0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id ); + if( i == MAX_GUILDALLIANCE ) + return -1; + + strcpy(name, g->alliance[i].name); + g->alliance[i].guild_id=0; + + mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); + g->save_flag |= GS_ALLIANCE; + return 0; } // Alliance modification int mapif_parse_GuildAlliance(int fd,int guild_id1,int guild_id2,int account_id1,int account_id2,int flag) { - // Could speed up - struct guild *g[2]; - int j,i; - g[0] = inter_guild_fromsql(guild_id1); - g[1] = inter_guild_fromsql(guild_id2); - - if (g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. - return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. - - if (g[0]==NULL || g[1]==NULL) - return 0; - - if (flag&GUILD_ALLIANCE_REMOVE) { - // Remove alliance/opposition, in case of alliance, remove on both side - for (i=0; i<2-(flag&GUILD_ALLIANCE_TYPE_MASK); i++) { - ARR_FIND(0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK)); - if (j < MAX_GUILDALLIANCE) - g[i]->alliance[j].guild_id = 0; - } - } else { - // Add alliance, in case of alliance, add on both side - for (i=0; i<2-(flag&GUILD_ALLIANCE_TYPE_MASK); i++) { - // Search an empty slot - ARR_FIND(0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0); - if (j < MAX_GUILDALLIANCE) { - g[i]->alliance[j].guild_id=g[1-i]->guild_id; - memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); - // Set alliance type - g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; - } - } - } - - // Send on all map the new alliance/opposition - mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); - - // Mark the two guild to be saved - g[0]->save_flag |= GS_ALLIANCE; - g[1]->save_flag |= GS_ALLIANCE; - return 0; + // Could speed up + struct guild *g[2]; + int j,i; + g[0] = inter_guild_fromsql(guild_id1); + g[1] = inter_guild_fromsql(guild_id2); + + if(g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. + return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. + + if(g[0]==NULL || g[1]==NULL) + return 0; + + if(flag&GUILD_ALLIANCE_REMOVE) + { + // Remove alliance/opposition, in case of alliance, remove on both side + for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) + { + ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK) ); + if( j < MAX_GUILDALLIANCE ) + g[i]->alliance[j].guild_id = 0; + } + } + else + { + // Add alliance, in case of alliance, add on both side + for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) + { + // Search an empty slot + ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0 ); + if( j < MAX_GUILDALLIANCE ) + { + g[i]->alliance[j].guild_id=g[1-i]->guild_id; + memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); + // Set alliance type + g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; + } + } + } + + // Send on all map the new alliance/opposition + mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); + + // Mark the two guild to be saved + g[0]->save_flag |= GS_ALLIANCE; + g[1]->save_flag |= GS_ALLIANCE; + return 0; } // Change guild message int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes2) { - struct guild *g; + struct guild *g; - g = inter_guild_fromsql(guild_id); - if (g==NULL) - return 0; + g = inter_guild_fromsql(guild_id); + if(g==NULL) + return 0; - memcpy(g->mes1,mes1,MAX_GUILDMES1); - memcpy(g->mes2,mes2,MAX_GUILDMES2); - g->save_flag |= GS_MES; //Change mes of guild - return mapif_guild_notice(g); + memcpy(g->mes1,mes1,MAX_GUILDMES1); + memcpy(g->mes2,mes2,MAX_GUILDMES2); + g->save_flag |= GS_MES; //Change mes of guild + return mapif_guild_notice(g); } int mapif_parse_GuildEmblem(int fd,int len,int guild_id,int dummy,const char *data) { - struct guild *g; + struct guild * g; - g = inter_guild_fromsql(guild_id); - if (g==NULL) - return 0; + g = inter_guild_fromsql(guild_id); + if(g==NULL) + return 0; - if (len > sizeof(g->emblem_data)) - len = sizeof(g->emblem_data); + if (len > sizeof(g->emblem_data)) + len = sizeof(g->emblem_data); - memcpy(g->emblem_data,data,len); - g->emblem_len=len; - g->emblem_id++; - g->save_flag |= GS_EMBLEM; //Change guild - return mapif_guild_emblem(g); + memcpy(g->emblem_data,data,len); + g->emblem_len=len; + g->emblem_id++; + g->save_flag |= GS_EMBLEM; //Change guild + return mapif_guild_emblem(g); } int mapif_parse_GuildCastleDataLoad(int fd, int len, int *castle_ids) { - return mapif_guild_castle_dataload(fd, len, castle_ids); + return mapif_guild_castle_dataload(fd, len, castle_ids); } int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) { - struct guild_castle *gc = inter_guildcastle_fromsql(castle_id); - - if (gc == NULL) { - ShowError("mapif_parse_GuildCastleDataSave: castle id=%d not found\n", castle_id); - return 0; - } - - switch (index) { - case 1: - if (log_inter && gc->guild_id != value) { - int gid = (value) ? value : gc->guild_id; - struct guild *g = idb_get(guild_db_, gid); - inter_log("guild %s (id=%d) %s castle id=%d\n", - (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); - } - gc->guild_id = value; - break; - case 2: - gc->economy = value; - break; - case 3: - gc->defense = value; - break; - case 4: - gc->triggerE = value; - break; - case 5: - gc->triggerD = value; - break; - case 6: - gc->nextTime = value; - break; - case 7: - gc->payTime = value; - break; - case 8: - gc->createTime = value; - break; - case 9: - gc->visibleC = value; - break; - default: - if (index > 9 && index <= 9+MAX_GUARDIANS) { - gc->guardian[index-10].visible = value; - break; - } - ShowError("mapif_parse_GuildCastleDataSave: not found index=%d\n", index); - return 0; - } - inter_guildcastle_tosql(gc); - return 0; + struct guild_castle *gc = inter_guildcastle_fromsql(castle_id); + + if (gc == NULL) { + ShowError("mapif_parse_GuildCastleDataSave: castle id=%d not found\n", castle_id); + return 0; + } + + switch (index) { + case 1: + if (log_inter && gc->guild_id != value) { + int gid = (value) ? value : gc->guild_id; + struct guild *g = idb_get(guild_db_, gid); + inter_log("guild %s (id=%d) %s castle id=%d\n", + (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); + } + gc->guild_id = value; + break; + case 2: gc->economy = value; break; + case 3: gc->defense = value; break; + case 4: gc->triggerE = value; break; + case 5: gc->triggerD = value; break; + case 6: gc->nextTime = value; break; + case 7: gc->payTime = value; break; + case 8: gc->createTime = value; break; + case 9: gc->visibleC = value; break; + default: + if (index > 9 && index <= 9+MAX_GUARDIANS) { + gc->guardian[index-10].visible = value; + break; + } + ShowError("mapif_parse_GuildCastleDataSave: not found index=%d\n", index); + return 0; + } + inter_guildcastle_tosql(gc); + return 0; } -int mapif_parse_GuildMasterChange(int fd, int guild_id, const char *name, int len) +int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) { - struct guild *g; - struct guild_member gm; - int pos; - - g = inter_guild_fromsql(guild_id); - - if (g==NULL || len > NAME_LENGTH) - return 0; - - // Find member (name) - for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); - - if (pos == g->max_member) - return 0; //Character not found?? - - // Switch current and old GM - memcpy(&gm, &g->member[pos], sizeof(struct guild_member)); - memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); - memcpy(&g->member[0], &gm, sizeof(struct guild_member)); - - // Switch positions - g->member[pos].position = g->member[0].position; - g->member[pos].modified = GS_MEMBER_MODIFIED; - g->member[0].position = 0; //Position 0: guild Master. - g->member[0].modified = GS_MEMBER_MODIFIED; - - strncpy(g->master, name, len); - if (len < NAME_LENGTH) - g->master[len] = '\0'; - - ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); - g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. - return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); + struct guild * g; + struct guild_member gm; + int pos; + + g = inter_guild_fromsql(guild_id); + + if(g==NULL || len > NAME_LENGTH) + return 0; + + // Find member (name) + for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); + + if (pos == g->max_member) + return 0; //Character not found?? + + // Switch current and old GM + memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); + memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); + memcpy(&g->member[0], &gm, sizeof(struct guild_member)); + + // Switch positions + g->member[pos].position = g->member[0].position; + g->member[pos].modified = GS_MEMBER_MODIFIED; + g->member[0].position = 0; //Position 0: guild Master. + g->member[0].modified = GS_MEMBER_MODIFIED; + + strncpy(g->master, name, len); + if (len < NAME_LENGTH) + g->master[len] = '\0'; + + ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); + g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. + return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); } // Communication from the map server @@ -1814,78 +1842,44 @@ int mapif_parse_GuildMasterChange(int fd, int guild_id, const char *name, int le // Data packet length that you set to inter.c //- Shouldn't do checking and packet length, RFIFOSKIP is done by the caller // Must Return -// 1 : ok +// 1 : ok // 0 : error int inter_guild_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch (RFIFOW(fd,0)) { - case 0x3030: - mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char *)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); - break; - case 0x3031: - mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); - break; - case 0x3032: - mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); - break; - case 0x3033: - mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char *)RFIFOP(fd,8),RFIFOW(fd,2)-8); - break; - case 0x3034: - mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char *)RFIFOP(fd,15)); - break; - case 0x3035: - mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); - break; - case 0x3036: - mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); - break; - case 0x3037: - mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char *)RFIFOP(fd,12),RFIFOW(fd,2)-12); - break; - case 0x3039: - mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char *)RFIFOP(fd,10),RFIFOW(fd,2)-10); - break; - case 0x303A: - mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char *)RFIFOP(fd,18),RFIFOW(fd,2)-18); - break; - case 0x303B: - mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); - break; - case 0x303C: - mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); - break; - case 0x303D: - mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); - break; - case 0x303E: - mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char *)RFIFOP(fd,6),(const char *)RFIFOP(fd,66)); - break; - case 0x303F: - mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char *)RFIFOP(fd,12)); - break; - case 0x3040: - mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),(int *)RFIFOP(fd,4)); - break; - case 0x3041: - mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); - break; - - default: - return 0; - } - - return 1; + RFIFOHEAD(fd); + switch(RFIFOW(fd,0)) { + case 0x3030: mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char*)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); break; + case 0x3031: mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); break; + case 0x3032: mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); break; + case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break; + case 0x3034: mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char*)RFIFOP(fd,15)); break; + case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); break; + case 0x3036: mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); break; + case 0x3037: mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break; + case 0x3039: mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char*)RFIFOP(fd,10),RFIFOW(fd,2)-10); break; + case 0x303A: mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char*)RFIFOP(fd,18),RFIFOW(fd,2)-18); break; + case 0x303B: mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); break; + case 0x303C: mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); break; + case 0x303D: mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); break; + case 0x303E: mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char*)RFIFOP(fd,6),(const char*)RFIFOP(fd,66)); break; + case 0x303F: mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char*)RFIFOP(fd,12)); break; + case 0x3040: mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),(int *)RFIFOP(fd,4)); break; + case 0x3041: mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); break; + + default: + return 0; + } + + return 1; } //Leave request from the server (for deleting character from guild) int inter_guild_leave(int guild_id, int account_id, int char_id) { - return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); + return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); } int inter_guild_broken(int guild_id) { - return mapif_guild_broken(guild_id, 0); + return mapif_guild_broken(guild_id, 0); } diff --git a/src/char/int_guild.h b/src/char/int_guild.h index 5bc3c2fe3..47c42dcc5 100644 --- a/src/char/int_guild.h +++ b/src/char/int_guild.h @@ -5,19 +5,19 @@ #define _INT_GUILD_SQL_H_ enum { - GS_BASIC = 0x0001, - GS_MEMBER = 0x0002, - GS_POSITION = 0x0004, - GS_ALLIANCE = 0x0008, - GS_EXPULSION = 0x0010, - GS_SKILL = 0x0020, - GS_EMBLEM = 0x0040, - GS_CONNECT = 0x0080, - GS_LEVEL = 0x0100, - GS_MES = 0x0200, - GS_MASK = 0x03FF, - GS_BASIC_MASK = (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES), - GS_REMOVE = 0x8000, + GS_BASIC = 0x0001, + GS_MEMBER = 0x0002, + GS_POSITION = 0x0004, + GS_ALLIANCE = 0x0008, + GS_EXPULSION = 0x0010, + GS_SKILL = 0x0020, + GS_EMBLEM = 0x0040, + GS_CONNECT = 0x0080, + GS_LEVEL = 0x0100, + GS_MES = 0x0200, + GS_MASK = 0x03FF, + GS_BASIC_MASK = (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES), + GS_REMOVE = 0x8000, }; struct guild; diff --git a/src/char/int_homun.c b/src/char/int_homun.c index 5676556f4..933661954 100644 --- a/src/char/int_homun.c +++ b/src/char/int_homun.c @@ -18,281 +18,279 @@ int inter_homunculus_sql_init(void) { - return 0; + return 0; } void inter_homunculus_sql_final(void) { - return; + return; } static void mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, unsigned char flag) { - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3890; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - WFIFOB(fd,8)= flag; - memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); - WFIFOSET(fd, WFIFOW(fd,2)); + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd,0) = 0x3890; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + WFIFOB(fd,8)= flag; + memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); + WFIFOSET(fd, WFIFOW(fd,2)); } static void mapif_homunculus_deleted(int fd, int flag) { - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) = 0x3893; - WFIFOB(fd,2) = flag; //Flag 1 = success - WFIFOSET(fd, 3); + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) = 0x3893; + WFIFOB(fd,2) = flag; //Flag 1 = success + WFIFOSET(fd, 3); } static void mapif_homunculus_loaded(int fd, int account_id, struct s_homunculus *hd) { - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3891; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - if (hd != NULL) { - WFIFOB(fd,8) = 1; // success - memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); - } else { - WFIFOB(fd,8) = 0; // not found. - memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); - } - WFIFOSET(fd, sizeof(struct s_homunculus)+9); + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd,0) = 0x3891; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + if( hd != NULL ) + { + WFIFOB(fd,8) = 1; // success + memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); + } + else + { + WFIFOB(fd,8) = 0; // not found. + memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); + } + WFIFOSET(fd, sizeof(struct s_homunculus)+9); } static void mapif_homunculus_saved(int fd, int account_id, bool flag) { - WFIFOHEAD(fd, 7); - WFIFOW(fd,0) = 0x3892; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = flag; // 1:success, 0:failure - WFIFOSET(fd, 7); + WFIFOHEAD(fd, 7); + WFIFOW(fd,0) = 0x3892; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = flag; // 1:success, 0:failure + WFIFOSET(fd, 7); } -static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char *name) +static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char* name) { - WFIFOHEAD(fd, NAME_LENGTH+12); - WFIFOW(fd, 0) = 0x3894; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = flag; - safestrncpy((char *)WFIFOP(fd,11), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+12); + WFIFOHEAD(fd, NAME_LENGTH+12); + WFIFOW(fd, 0) = 0x3894; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = flag; + safestrncpy((char*)WFIFOP(fd,11), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+12); } -bool mapif_homunculus_save(struct s_homunculus *hd) +bool mapif_homunculus_save(struct s_homunculus* hd) { - bool flag = true; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); - - if (hd->hom_id == 0) { - // new homunculus - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " - "VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize)) { - Sql_ShowDebug(sql_handle); - flag = false; - } else { - hd->hom_id = (int)Sql_LastInsertId(sql_handle); - } - } else { - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id)) { - Sql_ShowDebug(sql_handle); - flag = false; - } else { - SqlStmt *stmt; - int i; - - stmt = SqlStmt_Malloc(sql_handle); - if (SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", skill_homunculus_db, hd->hom_id)) - SqlStmt_ShowDebug(stmt); - for (i = 0; i < MAX_HOMUNSKILL; ++i) { - if (hd->hskill[i].id > 0 && hd->hskill[i].lv != 0) { - SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); - SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); - if (SQL_ERROR == SqlStmt_Execute(stmt)) { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - flag = false; - break; - } - } - } - SqlStmt_Free(stmt); - } - } - - return flag; + bool flag = true; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); + + if( hd->hom_id == 0 ) + {// new homunculus + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " + "VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + { + hd->hom_id = (int)Sql_LastInsertId(sql_handle); + } + } + else + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", + homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + { + SqlStmt* stmt; + int i; + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", skill_homunculus_db, hd->hom_id) ) + SqlStmt_ShowDebug(stmt); + for( i = 0; i < MAX_HOMUNSKILL; ++i ) + { + if( hd->hskill[i].id > 0 && hd->hskill[i].lv != 0 ) + { + SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); + SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); + if( SQL_ERROR == SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + flag = false; + break; + } + } + } + SqlStmt_Free(stmt); + } + } + + return flag; } // Load an homunculus -bool mapif_homunculus_load(int homun_id, struct s_homunculus *hd) +bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd) { - int i; - char *data; - size_t len; - - memset(hd, 0, sizeof(*hd)); - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", homunculus_db, homun_id)) { - Sql_ShowDebug(sql_handle); - return false; - } - - if (!Sql_NumRows(sql_handle)) { - //No homunculus found. - Sql_FreeResult(sql_handle); - return false; - } - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - return false; - } - - hd->hom_id = homun_id; - Sql_GetData(sql_handle, 1, &data, NULL); - hd->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - hd->class_ = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - hd->prev_class = atoi(data); - Sql_GetData(sql_handle, 4, &data, &len); - safestrncpy(hd->name, data, sizeof(hd->name)); - Sql_GetData(sql_handle, 5, &data, NULL); - hd->level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - hd->exp = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - hd->intimacy = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); - hd->hunger = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - hd->str = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); - hd->agi = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); - hd->vit = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); - hd->int_ = atoi(data); - Sql_GetData(sql_handle, 13, &data, NULL); - hd->dex = atoi(data); - Sql_GetData(sql_handle, 14, &data, NULL); - hd->luk = atoi(data); - Sql_GetData(sql_handle, 15, &data, NULL); - hd->hp = atoi(data); - Sql_GetData(sql_handle, 16, &data, NULL); - hd->max_hp = atoi(data); - Sql_GetData(sql_handle, 17, &data, NULL); - hd->sp = atoi(data); - Sql_GetData(sql_handle, 18, &data, NULL); - hd->max_sp = atoi(data); - Sql_GetData(sql_handle, 19, &data, NULL); - hd->skillpts = atoi(data); - Sql_GetData(sql_handle, 20, &data, NULL); - hd->rename_flag = atoi(data); - Sql_GetData(sql_handle, 21, &data, NULL); - hd->vaporize = atoi(data); - Sql_FreeResult(sql_handle); - - hd->intimacy = cap_value(hd->intimacy, 0, 100000); - hd->hunger = cap_value(hd->hunger, 0, 100); - - // Load Homunculus Skill - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", skill_homunculus_db, homun_id)) { - Sql_ShowDebug(sql_handle); - return false; - } - while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - // id - Sql_GetData(sql_handle, 0, &data, NULL); - i = atoi(data); - if (i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL) - continue;// invalid skill id - i = i - HM_SKILLBASE; - hd->hskill[i].id = (unsigned short)atoi(data); - - // lv - Sql_GetData(sql_handle, 1, &data, NULL); - hd->hskill[i].lv = (unsigned char)atoi(data); - } - Sql_FreeResult(sql_handle); - - if (save_log) - ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); - - return true; + int i; + char* data; + size_t len; + + memset(hd, 0, sizeof(*hd)); + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", homunculus_db, homun_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + if( !Sql_NumRows(sql_handle) ) + { //No homunculus found. + Sql_FreeResult(sql_handle); + return false; + } + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + return false; + } + + hd->hom_id = homun_id; + Sql_GetData(sql_handle, 1, &data, NULL); hd->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); hd->class_ = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); hd->prev_class = atoi(data); + Sql_GetData(sql_handle, 4, &data, &len); safestrncpy(hd->name, data, sizeof(hd->name)); + Sql_GetData(sql_handle, 5, &data, NULL); hd->level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); hd->exp = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); hd->intimacy = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); hd->hunger = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); hd->str = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); hd->agi = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); hd->vit = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); hd->int_ = atoi(data); + Sql_GetData(sql_handle, 13, &data, NULL); hd->dex = atoi(data); + Sql_GetData(sql_handle, 14, &data, NULL); hd->luk = atoi(data); + Sql_GetData(sql_handle, 15, &data, NULL); hd->hp = atoi(data); + Sql_GetData(sql_handle, 16, &data, NULL); hd->max_hp = atoi(data); + Sql_GetData(sql_handle, 17, &data, NULL); hd->sp = atoi(data); + Sql_GetData(sql_handle, 18, &data, NULL); hd->max_sp = atoi(data); + Sql_GetData(sql_handle, 19, &data, NULL); hd->skillpts = atoi(data); + Sql_GetData(sql_handle, 20, &data, NULL); hd->rename_flag = atoi(data); + Sql_GetData(sql_handle, 21, &data, NULL); hd->vaporize = atoi(data); + Sql_FreeResult(sql_handle); + + hd->intimacy = cap_value(hd->intimacy, 0, 100000); + hd->hunger = cap_value(hd->hunger, 0, 100); + + // Load Homunculus Skill + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", skill_homunculus_db, homun_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + // id + Sql_GetData(sql_handle, 0, &data, NULL); + i = atoi(data); + if( i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL ) + continue;// invalid skill id + i = i - HM_SKILLBASE; + hd->hskill[i].id = (unsigned short)atoi(data); + + // lv + Sql_GetData(sql_handle, 1, &data, NULL); + hd->hskill[i].lv = (unsigned char)atoi(data); + } + Sql_FreeResult(sql_handle); + + if( save_log ) + ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); + + return true; } bool mapif_homunculus_delete(int homun_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", homunculus_db, homun_id) - || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", skill_homunculus_db, homun_id) - ) { - Sql_ShowDebug(sql_handle); - return false; - } - return true; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", homunculus_db, homun_id) + || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", skill_homunculus_db, homun_id) + ) { + Sql_ShowDebug(sql_handle); + return false; + } + return true; } bool mapif_homunculus_rename(char *name) { - int i; - - // Check Authorised letters/symbols in the name of the homun - if (char_name_option == 1) { - // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) - return false; - } else if (char_name_option == 2) { - // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) - return false; - } - - return true; + int i; + + // Check Authorised letters/symbols in the name of the homun + if( char_name_option == 1 ) + {// only letters/symbols in char_name_letters are authorised + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) == NULL ) + return false; + } else + if( char_name_option == 2 ) + {// letters/symbols in char_name_letters are forbidden + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) != NULL ) + return false; + } + + return true; } -static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus *phd) +static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus* phd) { - bool result = mapif_homunculus_save(phd); - mapif_homunculus_created(fd, account_id, phd, result); + bool result = mapif_homunculus_save(phd); + mapif_homunculus_created(fd, account_id, phd, result); } static void mapif_parse_homunculus_delete(int fd, int homun_id) { - bool result = mapif_homunculus_delete(homun_id); - mapif_homunculus_deleted(fd, result); + bool result = mapif_homunculus_delete(homun_id); + mapif_homunculus_deleted(fd, result); } static void mapif_parse_homunculus_load(int fd, int account_id, int homun_id) { - struct s_homunculus hd; - bool result = mapif_homunculus_load(homun_id, &hd); - mapif_homunculus_loaded(fd, account_id, (result ? &hd : NULL)); + struct s_homunculus hd; + bool result = mapif_homunculus_load(homun_id, &hd); + mapif_homunculus_loaded(fd, account_id, ( result ? &hd : NULL )); } -static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus *phd) +static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus* phd) { - bool result = mapif_homunculus_save(phd); - mapif_homunculus_saved(fd, account_id, result); + bool result = mapif_homunculus_save(phd); + mapif_homunculus_saved(fd, account_id, result); } -static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char *name) +static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char* name) { - bool result = mapif_homunculus_rename(name); - mapif_homunculus_renamed(fd, account_id, char_id, result, name); + bool result = mapif_homunculus_rename(name); + mapif_homunculus_renamed(fd, account_id, char_id, result, name); } /*========================================== @@ -300,26 +298,17 @@ static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, c *------------------------------------------*/ int inter_homunculus_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch (cmd) { - case 0x3090: - mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus *)RFIFOP(fd,8)); - break; - case 0x3091: - mapif_parse_homunculus_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); - break; - case 0x3092: - mapif_parse_homunculus_save(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus *)RFIFOP(fd,8)); - break; - case 0x3093: - mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); - break; - case 0x3094: - mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char *)RFIFOP(fd,10)); - break; - default: - return 0; - } - return 1; + unsigned short cmd = RFIFOW(fd,0); + + switch( cmd ) + { + case 0x3090: mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; + case 0x3091: mapif_parse_homunculus_load (fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; + case 0x3092: mapif_parse_homunculus_save (fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; + case 0x3093: mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); break; + case 0x3094: mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char*)RFIFOP(fd,10)); break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_homun.h b/src/char/int_homun.h index e7976d51a..1c0d76269 100644 --- a/src/char/int_homun.h +++ b/src/char/int_homun.h @@ -10,8 +10,8 @@ int inter_homunculus_sql_init(void); void inter_homunculus_sql_final(void); int inter_homunculus_parse_frommap(int fd); -bool mapif_homunculus_save(struct s_homunculus *hd); -bool mapif_homunculus_load(int homun_id, struct s_homunculus *hd); +bool mapif_homunculus_save(struct s_homunculus* hd); +bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd); bool mapif_homunculus_delete(int homun_id); bool mapif_homunculus_rename(char *name); diff --git a/src/char/int_mail.c b/src/char/int_mail.c index 2e34d9014..98da43aeb 100644 --- a/src/char/int_mail.c +++ b/src/char/int_mail.c @@ -15,200 +15,180 @@ #include #include -static int mail_fromsql(int char_id, struct mail_data *md) +static int mail_fromsql(int char_id, struct mail_data* md) { - int i, j; - struct mail_message *msg; - struct item *item; - char *data; - StringBuf buf; - - memset(md, 0, sizeof(struct mail_data)); - md->amount = 0; - md->full = false; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ",`card%d`", i); - - // I keep the `status` < 3 just in case someone forget to apply the sqlfix - StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", - mail_db, char_id, MAIL_MAX_INBOX + 1); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - msg = &md->msg[i]; - Sql_GetData(sql_handle, 0, &data, NULL); - msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); - msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); - msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); - safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); - msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); - msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - msg->zeny = atoi(data); - item = &msg->item; - Sql_GetData(sql_handle,10, &data, NULL); - item->amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); - item->nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); - item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); - item->attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); - item->identify = atoi(data); - item->expire_time = 0; - - for (j = 0; j < MAX_SLOTS; j++) { - Sql_GetData(sql_handle, 15 + j, &data, NULL); - item->card[j] = atoi(data); - } - } - - md->full = (Sql_NumRows(sql_handle) > MAIL_MAX_INBOX); - - md->amount = i; - Sql_FreeResult(sql_handle); - - md->unchecked = 0; - md->unread = 0; - for (i = 0; i < md->amount; i++) { - msg = &md->msg[i]; - if (msg->status == MAIL_NEW) { - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id)) - Sql_ShowDebug(sql_handle); - - msg->status = MAIL_UNREAD; - md->unchecked++; - } else if (msg->status == MAIL_UNREAD) - md->unread++; - } - - ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); - return 1; + int i, j; + struct mail_message *msg; + struct item *item; + char *data; + StringBuf buf; + + memset(md, 0, sizeof(struct mail_data)); + md->amount = 0; + md->full = false; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ",`card%d`", i); + + // I keep the `status` < 3 just in case someone forget to apply the sqlfix + StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", + mail_db, char_id, MAIL_MAX_INBOX + 1); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + msg = &md->msg[i]; + Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); + item = &msg->item; + Sql_GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data); + item->expire_time = 0; + + for (j = 0; j < MAX_SLOTS; j++) + { + Sql_GetData(sql_handle, 15 + j, &data, NULL); + item->card[j] = atoi(data); + } + } + + md->full = ( Sql_NumRows(sql_handle) > MAIL_MAX_INBOX ); + + md->amount = i; + Sql_FreeResult(sql_handle); + + md->unchecked = 0; + md->unread = 0; + for (i = 0; i < md->amount; i++) + { + msg = &md->msg[i]; + if( msg->status == MAIL_NEW ) + { + if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) ) + Sql_ShowDebug(sql_handle); + + msg->status = MAIL_UNREAD; + md->unchecked++; + } + else if ( msg->status == MAIL_UNREAD ) + md->unread++; + } + + ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); + return 1; } /// Stores a single message in the database. /// Returns the message's ID if successful (or 0 if it fails). -int mail_savemessage(struct mail_message *msg) +int mail_savemessage(struct mail_message* msg) { - StringBuf buf; - SqlStmt *stmt; - int j; - - // build message save query - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", - msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - // prepare and execute query - stmt = SqlStmt_Malloc(sql_handle); - if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt)) { - SqlStmt_ShowDebug(stmt); - msg->id = 0; - } else - msg->id = (int)SqlStmt_LastInsertId(stmt); - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return msg->id; + StringBuf buf; + SqlStmt* stmt; + int j; + + // build message save query + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", + msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + // prepare and execute query + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + msg->id = 0; + } else + msg->id = (int)SqlStmt_LastInsertId(stmt); + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return msg->id; } /// Retrieves a single message from the database. /// Returns true if the operation succeeds (or false if it fails). -static bool mail_loadmessage(int mail_id, struct mail_message *msg) +static bool mail_loadmessage(int mail_id, struct mail_message* msg) { - int j; - StringBuf buf; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) - || SQL_SUCCESS != Sql_NextRow(sql_handle)) { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - StringBuf_Destroy(&buf); - return false; - } else { - char *data; - - Sql_GetData(sql_handle, 0, &data, NULL); - msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); - msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); - msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); - safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); - msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); - msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - msg->zeny = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); - msg->item.amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); - msg->item.nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); - msg->item.refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); - msg->item.attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); - msg->item.identify = atoi(data); - msg->item.expire_time = 0; - - for (j = 0; j < MAX_SLOTS; j++) { - Sql_GetData(sql_handle,15 + j, &data, NULL); - msg->item.card[j] = atoi(data); - } - } - - StringBuf_Destroy(&buf); - Sql_FreeResult(sql_handle); - - return true; + int j; + StringBuf buf; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) + || SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + StringBuf_Destroy(&buf); + return false; + } + else + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); msg->item.amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); msg->item.nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); msg->item.refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); msg->item.attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data); + msg->item.expire_time = 0; + + for( j = 0; j < MAX_SLOTS; j++ ) + { + Sql_GetData(sql_handle,15 + j, &data, NULL); + msg->item.card[j] = atoi(data); + } + } + + StringBuf_Destroy(&buf); + Sql_FreeResult(sql_handle); + + return true; } /*========================================== @@ -216,22 +196,22 @@ static bool mail_loadmessage(int mail_id, struct mail_message *msg) *------------------------------------------*/ static void mapif_Mail_sendinbox(int fd, int char_id, unsigned char flag) { - struct mail_data md; - mail_fromsql(char_id, &md); - - //FIXME: dumping the whole structure like this is unsafe [ultramage] - WFIFOHEAD(fd, sizeof(md) + 9); - WFIFOW(fd,0) = 0x3848; - WFIFOW(fd,2) = sizeof(md) + 9; - WFIFOL(fd,4) = char_id; - WFIFOB(fd,8) = flag; - memcpy(WFIFOP(fd,9),&md,sizeof(md)); - WFIFOSET(fd,WFIFOW(fd,2)); + struct mail_data md; + mail_fromsql(char_id, &md); + + //FIXME: dumping the whole structure like this is unsafe [ultramage] + WFIFOHEAD(fd, sizeof(md) + 9); + WFIFOW(fd,0) = 0x3848; + WFIFOW(fd,2) = sizeof(md) + 9; + WFIFOL(fd,4) = char_id; + WFIFOB(fd,8) = flag; + memcpy(WFIFOP(fd,9),&md,sizeof(md)); + WFIFOSET(fd,WFIFOW(fd,2)); } static void mapif_parse_Mail_requestinbox(int fd) { - mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); + mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); } /*========================================== @@ -239,9 +219,9 @@ static void mapif_parse_Mail_requestinbox(int fd) *------------------------------------------*/ static void mapif_parse_Mail_read(int fd) { - int mail_id = RFIFOL(fd,2); - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id)) - Sql_ShowDebug(sql_handle); + int mail_id = RFIFOL(fd,2); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id) ) + Sql_ShowDebug(sql_handle); } /*========================================== @@ -249,57 +229,58 @@ static void mapif_parse_Mail_read(int fd) *------------------------------------------*/ static bool mail_DeleteAttach(int mail_id) { - StringBuf buf; - int i; + StringBuf buf; + int i; - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ", `card%d` = '0'", i); - StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ", `card%d` = '0'", i); + StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); - return false; - } + return false; + } - StringBuf_Destroy(&buf); - return true; + StringBuf_Destroy(&buf); + return true; } static void mapif_Mail_getattach(int fd, int char_id, int mail_id) { - struct mail_message msg; + struct mail_message msg; - if (!mail_loadmessage(mail_id, &msg)) - return; + if( !mail_loadmessage(mail_id, &msg) ) + return; - if (msg.dest_id != char_id) - return; + if( msg.dest_id != char_id ) + return; - if (msg.status != MAIL_READ) - return; + if( msg.status != MAIL_READ ) + return; - if ((msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1) - return; // No Attachment + if( (msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1 ) + return; // No Attachment - if (!mail_DeleteAttach(mail_id)) - return; + if( !mail_DeleteAttach(mail_id) ) + return; - WFIFOHEAD(fd, sizeof(struct item) + 12); - WFIFOW(fd,0) = 0x384a; - WFIFOW(fd,2) = sizeof(struct item) + 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; - memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOHEAD(fd, sizeof(struct item) + 12); + WFIFOW(fd,0) = 0x384a; + WFIFOW(fd,2) = sizeof(struct item) + 12; + WFIFOL(fd,4) = char_id; + WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; + memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); + WFIFOSET(fd,WFIFOW(fd,2)); } static void mapif_parse_Mail_getattach(int fd) { - mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== @@ -307,23 +288,24 @@ static void mapif_parse_Mail_getattach(int fd) *------------------------------------------*/ static void mapif_Mail_delete(int fd, int char_id, int mail_id) { - bool failed = false; - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id)) { - Sql_ShowDebug(sql_handle); - failed = true; - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384b; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = failed; - WFIFOSET(fd,11); + bool failed = false; + if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) + { + Sql_ShowDebug(sql_handle); + failed = true; + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384b; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = failed; + WFIFOSET(fd,11); } static void mapif_parse_Mail_delete(int fd) { - mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== @@ -331,17 +313,17 @@ static void mapif_parse_Mail_delete(int fd) *------------------------------------------*/ void mapif_Mail_new(struct mail_message *msg) { - unsigned char buf[74]; - - if (!msg || !msg->id) - return; - - WBUFW(buf,0) = 0x3849; - WBUFL(buf,2) = msg->dest_id; - WBUFL(buf,6) = msg->id; - memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); - memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); - mapif_sendall(buf, 74); + unsigned char buf[74]; + + if( !msg || !msg->id ) + return; + + WBUFW(buf,0) = 0x3849; + WBUFL(buf,2) = msg->dest_id; + WBUFL(buf,6) = msg->id; + memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); + memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); + mapif_sendall(buf, 74); } /*========================================== @@ -349,116 +331,120 @@ void mapif_Mail_new(struct mail_message *msg) *------------------------------------------*/ static void mapif_Mail_return(int fd, int char_id, int mail_id) { - struct mail_message msg; - int new_mail = 0; - - if (mail_loadmessage(mail_id, &msg)) { - if (msg.dest_id != char_id) - return; - else if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id)) - Sql_ShowDebug(sql_handle); - else { - char temp_[MAIL_TITLE_LENGTH]; - - // swap sender and receiver - swap(msg.send_id, msg.dest_id); - safestrncpy(temp_, msg.send_name, NAME_LENGTH); - safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); - safestrncpy(msg.dest_name, temp_, NAME_LENGTH); - - // set reply message title - snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); - safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); - - msg.status = MAIL_NEW; - msg.timestamp = time(NULL); - - new_mail = mail_savemessage(&msg); - mapif_Mail_new(&msg); - } - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = (new_mail == 0); - WFIFOSET(fd,11); + struct mail_message msg; + int new_mail = 0; + + if( mail_loadmessage(mail_id, &msg) ) + { + if( msg.dest_id != char_id) + return; + else if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) + Sql_ShowDebug(sql_handle); + else + { + char temp_[MAIL_TITLE_LENGTH]; + + // swap sender and receiver + swap(msg.send_id, msg.dest_id); + safestrncpy(temp_, msg.send_name, NAME_LENGTH); + safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); + safestrncpy(msg.dest_name, temp_, NAME_LENGTH); + + // set reply message title + snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); + safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); + + msg.status = MAIL_NEW; + msg.timestamp = time(NULL); + + new_mail = mail_savemessage(&msg); + mapif_Mail_new(&msg); + } + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384c; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = (new_mail == 0); + WFIFOSET(fd,11); } static void mapif_parse_Mail_return(int fd) { - mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== * Send Mail *------------------------------------------*/ -static void mapif_Mail_send(int fd, struct mail_message *msg) +static void mapif_Mail_send(int fd, struct mail_message* msg) { - int len = sizeof(struct mail_message) + 4; - - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x384d; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); - WFIFOSET(fd,len); + int len = sizeof(struct mail_message) + 4; + + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x384d; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); + WFIFOSET(fd,len); } static void mapif_parse_Mail_send(int fd) { - struct mail_message msg; - char esc_name[NAME_LENGTH*2+1]; - int account_id = 0; - - if (RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) - return; - - account_id = RFIFOL(fd,4); - memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); - - // Try to find the Dest Char by Name - Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name)) - Sql_ShowDebug(sql_handle); - else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - char *data; - Sql_GetData(sql_handle, 0, &data, NULL); - if (atoi(data) != account_id) { - // Cannot send mail to char in the same account - Sql_GetData(sql_handle, 1, &data, NULL); - msg.dest_id = atoi(data); - } - } - Sql_FreeResult(sql_handle); - msg.status = MAIL_NEW; - - if (msg.dest_id > 0) - msg.id = mail_savemessage(&msg); - - mapif_Mail_send(fd, &msg); // notify sender - mapif_Mail_new(&msg); // notify recipient + struct mail_message msg; + char esc_name[NAME_LENGTH*2+1]; + int account_id = 0; + + if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) + return; + + account_id = RFIFOL(fd,4); + memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); + + // Try to find the Dest Char by Name + Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); + if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + Sql_ShowDebug(sql_handle); + else + if ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + if (atoi(data) != account_id) + { // Cannot send mail to char in the same account + Sql_GetData(sql_handle, 1, &data, NULL); + msg.dest_id = atoi(data); + } + } + Sql_FreeResult(sql_handle); + msg.status = MAIL_NEW; + + if( msg.dest_id > 0 ) + msg.id = mail_savemessage(&msg); + + mapif_Mail_send(fd, &msg); // notify sender + mapif_Mail_new(&msg); // notify recipient } -void mail_sendmail(int send_id, const char *send_name, int dest_id, const char *dest_name, const char *title, const char *body, int zeny, struct item *item) +void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item) { - struct mail_message msg; - memset(&msg, 0, sizeof(struct mail_message)); - - msg.send_id = send_id; - safestrncpy(msg.send_name, send_name, NAME_LENGTH); - msg.dest_id = dest_id; - safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); - safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); - safestrncpy(msg.body, body, MAIL_BODY_LENGTH); - msg.zeny = zeny; - if (item != NULL) - memcpy(&msg.item, item, sizeof(struct item)); - - msg.timestamp = time(NULL); - - mail_savemessage(&msg); - mapif_Mail_new(&msg); + struct mail_message msg; + memset(&msg, 0, sizeof(struct mail_message)); + + msg.send_id = send_id; + safestrncpy(msg.send_name, send_name, NAME_LENGTH); + msg.dest_id = dest_id; + safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); + safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); + safestrncpy(msg.body, body, MAIL_BODY_LENGTH); + msg.zeny = zeny; + if( item != NULL ) + memcpy(&msg.item, item, sizeof(struct item)); + + msg.timestamp = time(NULL); + + mail_savemessage(&msg); + mapif_Mail_new(&msg); } /*========================================== @@ -466,37 +452,26 @@ void mail_sendmail(int send_id, const char *send_name, int dest_id, const char * *------------------------------------------*/ int inter_mail_parse_frommap(int fd) { - switch (RFIFOW(fd,0)) { - case 0x3048: - mapif_parse_Mail_requestinbox(fd); - break; - case 0x3049: - mapif_parse_Mail_read(fd); - break; - case 0x304a: - mapif_parse_Mail_getattach(fd); - break; - case 0x304b: - mapif_parse_Mail_delete(fd); - break; - case 0x304c: - mapif_parse_Mail_return(fd); - break; - case 0x304d: - mapif_parse_Mail_send(fd); - break; - default: - return 0; - } - return 1; + switch(RFIFOW(fd,0)) + { + case 0x3048: mapif_parse_Mail_requestinbox(fd); break; + case 0x3049: mapif_parse_Mail_read(fd); break; + case 0x304a: mapif_parse_Mail_getattach(fd); break; + case 0x304b: mapif_parse_Mail_delete(fd); break; + case 0x304c: mapif_parse_Mail_return(fd); break; + case 0x304d: mapif_parse_Mail_send(fd); break; + default: + return 0; + } + return 1; } int inter_mail_sql_init(void) { - return 1; + return 1; } void inter_mail_sql_final(void) { - return; + return; } diff --git a/src/char/int_mail.h b/src/char/int_mail.h index 0fef3d4ab..77db51e5b 100644 --- a/src/char/int_mail.h +++ b/src/char/int_mail.h @@ -5,12 +5,12 @@ #define _INT_MAIL_SQL_H_ int inter_mail_parse_frommap(int fd); -void mail_sendmail(int send_id, const char *send_name, int dest_id, const char *dest_name, const char *title, const char *body, int zeny, struct item *item); +void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item); int inter_mail_sql_init(void); void inter_mail_sql_final(void); -int mail_savemessage(struct mail_message *msg); +int mail_savemessage(struct mail_message* msg); void mapif_Mail_new(struct mail_message *msg); #endif /* _INT_MAIL_SQL_H_ */ diff --git a/src/char/int_mercenary.c b/src/char/int_mercenary.c index 528f05524..3b3714416 100644 --- a/src/char/int_mercenary.c +++ b/src/char/int_mercenary.c @@ -17,188 +17,185 @@ bool mercenary_owner_fromsql(int char_id, struct mmo_charstatus *status) { - char *data; - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id)) { - Sql_ShowDebug(sql_handle); - return false; - } - - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); - status->mer_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - status->arch_calls = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - status->arch_faith = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - status->spear_calls = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - status->spear_faith = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - status->sword_calls = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - status->sword_faith = atoi(data); - Sql_FreeResult(sql_handle); - - return true; + char* data; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); status->mer_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); status->arch_calls = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); status->arch_faith = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); status->spear_calls = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); status->spear_faith = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); status->sword_calls = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); status->sword_faith = atoi(data); + Sql_FreeResult(sql_handle); + + return true; } bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status) { - if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith)) { - Sql_ShowDebug(sql_handle); - return false; - } + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith) ) + { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } bool mercenary_owner_delete(int char_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) + Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_db, char_id)) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_db, char_id) ) + Sql_ShowDebug(sql_handle); - return true; + return true; } -bool mapif_mercenary_save(struct s_mercenary *merc) +bool mapif_mercenary_save(struct s_mercenary* merc) { - bool flag = true; + bool flag = true; - if (merc->mercenary_id == 0) { - // Create new DB entry - if (SQL_ERROR == Sql_Query(sql_handle, - "INSERT INTO `%s` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time)) { - Sql_ShowDebug(sql_handle); - flag = false; - } else - merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); - } else if (SQL_ERROR == Sql_Query(sql_handle, - "UPDATE `%s` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id)) { - // Update DB entry - Sql_ShowDebug(sql_handle); - flag = false; - } + if( merc->mercenary_id == 0 ) + { // Create new DB entry + if( SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `%s` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", + mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); + } + else if( SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `%s` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", + mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id) ) + { // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } - return flag; + return flag; } bool mapif_mercenary_load(int merc_id, int char_id, struct s_mercenary *merc) { - char *data; - - memset(merc, 0, sizeof(struct s_mercenary)); - merc->mercenary_id = merc_id; - merc->char_id = char_id; + char* data; - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", mercenary_db, merc_id, char_id)) { - Sql_ShowDebug(sql_handle); - return false; - } + memset(merc, 0, sizeof(struct s_mercenary)); + merc->mercenary_id = merc_id; + merc->char_id = char_id; - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { - Sql_FreeResult(sql_handle); - return false; - } + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", mercenary_db, merc_id, char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } - Sql_GetData(sql_handle, 0, &data, NULL); - merc->class_ = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - merc->hp = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - merc->sp = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - merc->kill_count = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - merc->life_time = atoi(data); - Sql_FreeResult(sql_handle); - if (save_log) - ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_FreeResult(sql_handle); + return false; + } - return true; + Sql_GetData(sql_handle, 0, &data, NULL); merc->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); merc->hp = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); merc->sp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); merc->kill_count = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); merc->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if( save_log ) + ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); + + return true; } bool mapif_mercenary_delete(int merc_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", mercenary_db, merc_id)) { - Sql_ShowDebug(sql_handle); - return false; - } + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", mercenary_db, merc_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } static void mapif_mercenary_send(int fd, struct s_mercenary *merc, unsigned char flag) { - int size = sizeof(struct s_mercenary) + 5; + int size = sizeof(struct s_mercenary) + 5; - WFIFOHEAD(fd,size); - WFIFOW(fd,0) = 0x3870; - WFIFOW(fd,2) = size; - WFIFOB(fd,4) = flag; - memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); - WFIFOSET(fd,size); + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x3870; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); + WFIFOSET(fd,size); } -static void mapif_parse_mercenary_create(int fd, struct s_mercenary *merc) +static void mapif_parse_mercenary_create(int fd, struct s_mercenary* merc) { - bool result = mapif_mercenary_save(merc); - mapif_mercenary_send(fd, merc, result); + bool result = mapif_mercenary_save(merc); + mapif_mercenary_send(fd, merc, result); } static void mapif_parse_mercenary_load(int fd, int merc_id, int char_id) { - struct s_mercenary merc; - bool result = mapif_mercenary_load(merc_id, char_id, &merc); - mapif_mercenary_send(fd, &merc, result); + struct s_mercenary merc; + bool result = mapif_mercenary_load(merc_id, char_id, &merc); + mapif_mercenary_send(fd, &merc, result); } static void mapif_mercenary_deleted(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3871; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3871; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } static void mapif_parse_mercenary_delete(int fd, int merc_id) { - bool result = mapif_mercenary_delete(merc_id); - mapif_mercenary_deleted(fd, result); + bool result = mapif_mercenary_delete(merc_id); + mapif_mercenary_deleted(fd, result); } static void mapif_mercenary_saved(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3872; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3872; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_mercenary_save(int fd, struct s_mercenary *merc) +static void mapif_parse_mercenary_save(int fd, struct s_mercenary* merc) { - bool result = mapif_mercenary_save(merc); - mapif_mercenary_saved(fd, result); + bool result = mapif_mercenary_save(merc); + mapif_mercenary_saved(fd, result); } int inter_mercenary_sql_init(void) { - return 0; + return 0; } void inter_mercenary_sql_final(void) { - return; + return; } /*========================================== @@ -206,23 +203,16 @@ void inter_mercenary_sql_final(void) *------------------------------------------*/ int inter_mercenary_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch (cmd) { - case 0x3070: - mapif_parse_mercenary_create(fd, (struct s_mercenary *)RFIFOP(fd,4)); - break; - case 0x3071: - mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); - break; - case 0x3072: - mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); - break; - case 0x3073: - mapif_parse_mercenary_save(fd, (struct s_mercenary *)RFIFOP(fd,4)); - break; - default: - return 0; - } - return 1; + unsigned short cmd = RFIFOW(fd,0); + + switch( cmd ) + { + case 0x3070: mapif_parse_mercenary_create(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; + case 0x3071: mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; + case 0x3072: mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); break; + case 0x3073: mapif_parse_mercenary_save(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_party.c b/src/char/int_party.c index 862a943f1..a88e5c586 100644 --- a/src/char/int_party.c +++ b/src/char/int_party.c @@ -19,14 +19,14 @@ #include struct party_data { - struct party party; - unsigned int min_lv, max_lv; - int family; //Is this party a family? if so, this holds the child id. - unsigned char size; //Total size of party. + struct party party; + unsigned int min_lv, max_lv; + int family; //Is this party a family? if so, this holds the child id. + unsigned char size; //Total size of party. }; static struct party_data *party_pt; -static DBMap *party_db_; // int party_id -> struct party_data* +static DBMap* party_db_; // int party_id -> struct party_data* int mapif_party_broken(int party_id,int flag); int party_check_empty(struct party_data *p); @@ -35,297 +35,292 @@ int party_check_exp_share(struct party_data *p); int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag); //Updates party's level range and unsets even share if broken. -static int int_party_check_lv(struct party_data *p) -{ - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - for (i=0; iparty.member[i].online || p->party.member[i].char_id == p->family) - continue; - - lv=p->party.member[i].lv; - if (lv < p->min_lv) p->min_lv = lv; - if (lv > p->max_lv) p->max_lv = lv; - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; - mapif_party_optionchanged(0, &p->party, 0, 0); - return 0; - } - return 1; +static int int_party_check_lv(struct party_data *p) { + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + for(i=0;iparty.member[i].online || p->party.member[i].char_id == p->family ) + continue; + + lv=p->party.member[i].lv; + if (lv < p->min_lv) p->min_lv = lv; + if (lv > p->max_lv) p->max_lv = lv; + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; + mapif_party_optionchanged(0, &p->party, 0, 0); + return 0; + } + return 1; } //Calculates the state of a party. static void int_party_calc_state(struct party_data *p) { - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - p->party.count = - p->size = - p->family = 0; - - //Check party size - for (i=0; iparty.member[i].lv) continue; - p->size++; - if (p->party.member[i].online) - p->party.count++; - } - if (p->size == 2 && (char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id))) { - //Child should be able to share with either of their parents [RoM] - if (p->party.member[0].class_&0x2000) //first slot is the child? - p->family = p->party.member[0].char_id; - else - p->family = p->party.member[1].char_id; - } else if (p->size == 3) { - //Check Family State. - p->family = char_family( - p->party.member[0].char_id, - p->party.member[1].char_id, - p->party.member[2].char_id - ); - } - //max/min levels. - for (i=0; iparty.member[i].lv; - if (!lv) continue; - if (p->party.member[i].online && - //On families, the kid is not counted towards exp share rules. - p->party.member[i].char_id != p->family) { - if (lv < p->min_lv) p->min_lv=lv; - if (p->max_lv < lv) p->max_lv=lv; - } - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; //Set off even share. - mapif_party_optionchanged(0, &p->party, 0, 0); - } - return; + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + p->party.count = + p->size = + p->family = 0; + + //Check party size + for(i=0;iparty.member[i].lv) continue; + p->size++; + if(p->party.member[i].online) + p->party.count++; + } + if( p->size == 2 && ( char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id) ) ) { + //Child should be able to share with either of their parents [RoM] + if(p->party.member[0].class_&0x2000) //first slot is the child? + p->family = p->party.member[0].char_id; + else + p->family = p->party.member[1].char_id; + } else if( p->size == 3 ) { + //Check Family State. + p->family = char_family( + p->party.member[0].char_id, + p->party.member[1].char_id, + p->party.member[2].char_id + ); + } + //max/min levels. + for(i=0;iparty.member[i].lv; + if (!lv) continue; + if(p->party.member[i].online && + //On families, the kid is not counted towards exp share rules. + p->party.member[i].char_id != p->family) + { + if( lv < p->min_lv ) p->min_lv=lv; + if( p->max_lv < lv ) p->max_lv=lv; + } + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; //Set off even share. + mapif_party_optionchanged(0, &p->party, 0, 0); + } + return; } // Save party to mysql int inter_party_tosql(struct party *p, int flag, int index) { - // 'party' ('party_id','name','exp','item','leader_id','leader_char') - char esc_name[NAME_LENGTH*2+1];// escaped party name - int party_id; + // 'party' ('party_id','name','exp','item','leader_id','leader_char') + char esc_name[NAME_LENGTH*2+1];// escaped party name + int party_id; - if (p == NULL || p->party_id == 0) - return 0; - party_id = p->party_id; + if( p == NULL || p->party_id == 0 ) + return 0; + party_id = p->party_id; #ifdef NOISY - ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); + ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); #endif - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - - if (flag & PS_BREAK) { - // Break the party - // we'll skip name-checking and just reset everyone with the same party id [celest] - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id)) - Sql_ShowDebug(sql_handle); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id)) - Sql_ShowDebug(sql_handle); - //Remove from memory - idb_remove(party_db_, party_id); - return 1; - } - - if (flag & PS_CREATE) { - // Create party - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " - "VALUES ('%s', '%d', '%d', '%d', '%d')", - party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id)) { - Sql_ShowDebug(sql_handle); - return 0; - } - party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); - } - - if (flag & PS_BASIC) { - // Update party info. - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", - party_db, esc_name, p->exp, p->item, party_id)) - Sql_ShowDebug(sql_handle); - } - - if (flag & PS_LEADER) { - // Update leader - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", - party_db, p->member[index].account_id, p->member[index].char_id, party_id)) - Sql_ShowDebug(sql_handle); - } - - if (flag & PS_ADDMEMBER) { - // Add one party member. - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id)) - Sql_ShowDebug(sql_handle); - } - - if (flag & PS_DELMEMBER) { - // Remove one party member. - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id)) - Sql_ShowDebug(sql_handle); - } - - if (save_log) - ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); - return 1; + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + + if( flag & PS_BREAK ) + {// Break the party + // we'll skip name-checking and just reset everyone with the same party id [celest] + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) + Sql_ShowDebug(sql_handle); + //Remove from memory + idb_remove(party_db_, party_id); + return 1; + } + + if( flag & PS_CREATE ) + {// Create party + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " + "VALUES ('%s', '%d', '%d', '%d', '%d')", + party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); + } + + if( flag & PS_BASIC ) + {// Update party info. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", + party_db, esc_name, p->exp, p->item, party_id) ) + Sql_ShowDebug(sql_handle); + } + + if( flag & PS_LEADER ) + {// Update leader + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", + party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) + Sql_ShowDebug(sql_handle); + } + + if( flag & PS_ADDMEMBER ) + {// Add one party member. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) + Sql_ShowDebug(sql_handle); + } + + if( flag & PS_DELMEMBER ) + {// Remove one party member. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) + Sql_ShowDebug(sql_handle); + } + + if( save_log ) + ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); + return 1; } // Read party from mysql -struct party_data *inter_party_fromsql(int party_id) { - int leader_id = 0; - int leader_char = 0; - struct party_data *p; - struct party_member *m; - char *data; - size_t len; - int i; +struct party_data *inter_party_fromsql(int party_id) +{ + int leader_id = 0; + int leader_char = 0; + struct party_data* p; + struct party_member* m; + char* data; + size_t len; + int i; #ifdef NOISY - ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); + ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); #endif - if (party_id <= 0) - return NULL; - - //Load from memory - p = (struct party_data *)idb_get(party_db_, party_id); - if (p != NULL) - return p; - - p = party_pt; - memset(p, 0, sizeof(struct party_data)); - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id)) { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) - return NULL; - - p->party.party_id = party_id; - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(p->party.name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); - p->party.exp = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 3, &data, NULL); - p->party.item = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - leader_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - leader_char = atoi(data); - Sql_FreeResult(sql_handle); - - // Load members - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id)) { - Sql_ShowDebug(sql_handle); - return NULL; - } - for (i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - m = &p->party.member[i]; - Sql_GetData(sql_handle, 0, &data, NULL); - m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(m->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); - m->lv = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - m->map = mapindex_name2id(data); - Sql_GetData(sql_handle, 5, &data, NULL); - m->online = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 6, &data, NULL); - m->class_ = atoi(data); - m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); - } - Sql_FreeResult(sql_handle); - - if (save_log) - ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); - //Add party to memory. - CREATE(p, struct party_data, 1); - memcpy(p, party_pt, sizeof(struct party_data)); - //init state - int_party_calc_state(p); - idb_put(party_db_, party_id, p); - return p; + if( party_id <= 0 ) + return NULL; + + //Load from memory + p = (struct party_data*)idb_get(party_db_, party_id); + if( p != NULL ) + return p; + + p = party_pt; + memset(p, 0, sizeof(struct party_data)); + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) + { + Sql_ShowDebug(sql_handle); + return NULL; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return NULL; + + p->party.party_id = party_id; + Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->party.name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); p->party.exp = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 3, &data, NULL); p->party.item = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); leader_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); leader_char = atoi(data); + Sql_FreeResult(sql_handle); + + // Load members + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id) ) + { + Sql_ShowDebug(sql_handle); + return NULL; + } + for( i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + m = &p->party.member[i]; + Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); m->lv = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); m->map = mapindex_name2id(data); + Sql_GetData(sql_handle, 5, &data, NULL); m->online = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 6, &data, NULL); m->class_ = atoi(data); + m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); + } + Sql_FreeResult(sql_handle); + + if( save_log ) + ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); + //Add party to memory. + CREATE(p, struct party_data, 1); + memcpy(p, party_pt, sizeof(struct party_data)); + //init state + int_party_calc_state(p); + idb_put(party_db_, party_id, p); + return p; } int inter_party_sql_init(void) { - //memory alloc - party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - party_pt = (struct party_data *)aCalloc(sizeof(struct party_data), 1); - if (!party_pt) { - ShowFatalError("inter_party_sql_init: Out of Memory!\n"); - exit(EXIT_FAILURE); - } - - /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] - ShowStatus("cleaning party table...\n"); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", - party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) - Sql_ShowDebug(sql_handle); - */ - return 0; + //memory alloc + party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1); + if (!party_pt) { + ShowFatalError("inter_party_sql_init: Out of Memory!\n"); + exit(EXIT_FAILURE); + } + + /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] + ShowStatus("cleaning party table...\n"); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", + party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) + Sql_ShowDebug(sql_handle); + */ + return 0; } void inter_party_sql_final(void) { - party_db_->destroy(party_db_, NULL); - aFree(party_pt); - return; + party_db_->destroy(party_db_, NULL); + aFree(party_pt); + return; } // Search for the party according to its name -struct party_data *search_partyname(char *str) { - char esc_name[NAME_LENGTH*2+1]; - char *data; - struct party_data *p = NULL; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name)) - Sql_ShowDebug(sql_handle); - else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - Sql_GetData(sql_handle, 0, &data, NULL); - p = inter_party_fromsql(atoi(data)); - } - Sql_FreeResult(sql_handle); - - return p; +struct party_data* search_partyname(char* str) +{ + char esc_name[NAME_LENGTH*2+1]; + char* data; + struct party_data* p = NULL; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + Sql_GetData(sql_handle, 0, &data, NULL); + p = inter_party_fromsql(atoi(data)); + } + Sql_FreeResult(sql_handle); + + return p; } // Returns whether this party can keep having exp share or not. int party_check_exp_share(struct party_data *p) { - return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); + return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); } // Is there any member in the party? int party_check_empty(struct party_data *p) { - int i; - if (p==NULL||p->party.party_id==0) return 1; - for (i=0; iparty.member[i].account_id; i++); - if (i < MAX_PARTY) return 0; - // If there is no member, then break the party - mapif_party_broken(p->party.party_id,0); - inter_party_tosql(&p->party, PS_BREAK, 0); - return 1; + int i; + if (p==NULL||p->party.party_id==0) return 1; + for(i=0;iparty.member[i].account_id;i++); + if (i < MAX_PARTY) return 0; + // If there is no member, then break the party + mapif_party_broken(p->party.party_id,0); + inter_party_tosql(&p->party, PS_BREAK, 0); + return 1; } //------------------------------------------------------------------- @@ -335,135 +330,133 @@ int party_check_empty(struct party_data *p) // Create a party whether or not int mapif_party_created(int fd,int account_id,int char_id,struct party *p) { - WFIFOHEAD(fd, 39); - WFIFOW(fd,0)=0x3820; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=char_id; - if (p!=NULL) { - WFIFOB(fd,10)=0; - WFIFOL(fd,11)=p->party_id; - memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); - ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); - } else { - WFIFOB(fd,10)=1; - WFIFOL(fd,11)=0; - memset(WFIFOP(fd,15),0,NAME_LENGTH); - } - WFIFOSET(fd,39); - - return 0; + WFIFOHEAD(fd, 39); + WFIFOW(fd,0)=0x3820; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=char_id; + if(p!=NULL){ + WFIFOB(fd,10)=0; + WFIFOL(fd,11)=p->party_id; + memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); + ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); + }else{ + WFIFOB(fd,10)=1; + WFIFOL(fd,11)=0; + memset(WFIFOP(fd,15),0,NAME_LENGTH); + } + WFIFOSET(fd,39); + + return 0; } //Party information not found static void mapif_party_noinfo(int fd, int party_id, int char_id) { - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3821; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = party_id; - WFIFOSET(fd,12); - ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); + WFIFOHEAD(fd, 12); + WFIFOW(fd,0) = 0x3821; + WFIFOW(fd,2) = 12; + WFIFOL(fd,4) = char_id; + WFIFOL(fd,8) = party_id; + WFIFOSET(fd,12); + ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); } //Digest party information -static void mapif_party_info(int fd, struct party *p, int char_id) +static void mapif_party_info(int fd, struct party* p, int char_id) { - unsigned char buf[8 + sizeof(struct party)]; - WBUFW(buf,0) = 0x3821; - WBUFW(buf,2) = 8 + sizeof(struct party); - WBUFL(buf,4) = char_id; - memcpy(WBUFP(buf,8), p, sizeof(struct party)); - - if (fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); + unsigned char buf[8 + sizeof(struct party)]; + WBUFW(buf,0) = 0x3821; + WBUFW(buf,2) = 8 + sizeof(struct party); + WBUFL(buf,4) = char_id; + memcpy(WBUFP(buf,8), p, sizeof(struct party)); + + if(fd<0) + mapif_sendall(buf,WBUFW(buf,2)); + else + mapif_send(fd,buf,WBUFW(buf,2)); } //Whether or not additional party members -int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) -{ - WFIFOHEAD(fd, 15); - WFIFOW(fd,0) = 0x3822; - WFIFOL(fd,2) = party_id; - WFIFOL(fd,6) = account_id; - WFIFOL(fd,10) = char_id; - WFIFOB(fd,14) = flag; - WFIFOSET(fd,15); - - return 0; +int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) { + WFIFOHEAD(fd, 15); + WFIFOW(fd,0) = 0x3822; + WFIFOL(fd,2) = party_id; + WFIFOL(fd,6) = account_id; + WFIFOL(fd,10) = char_id; + WFIFOB(fd,14) = flag; + WFIFOSET(fd,15); + + return 0; } // Party setting change notification int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag) { - unsigned char buf[16]; - WBUFW(buf,0)=0x3823; - WBUFL(buf,2)=p->party_id; - WBUFL(buf,6)=account_id; - WBUFW(buf,10)=p->exp; - WBUFW(buf,12)=p->item; - WBUFB(buf,14)=flag; - if (flag==0) - mapif_sendall(buf,15); - else - mapif_send(fd,buf,15); - return 0; + unsigned char buf[16]; + WBUFW(buf,0)=0x3823; + WBUFL(buf,2)=p->party_id; + WBUFL(buf,6)=account_id; + WBUFW(buf,10)=p->exp; + WBUFW(buf,12)=p->item; + WBUFB(buf,14)=flag; + if(flag==0) + mapif_sendall(buf,15); + else + mapif_send(fd,buf,15); + return 0; } //Withdrawal notification party -int mapif_party_withdraw(int party_id,int account_id, int char_id) -{ - unsigned char buf[16]; - - WBUFW(buf,0) = 0x3824; - WBUFL(buf,2) = party_id; - WBUFL(buf,6) = account_id; - WBUFL(buf,10) = char_id; - mapif_sendall(buf, 14); - return 0; +int mapif_party_withdraw(int party_id,int account_id, int char_id) { + unsigned char buf[16]; + + WBUFW(buf,0) = 0x3824; + WBUFL(buf,2) = party_id; + WBUFL(buf,6) = account_id; + WBUFL(buf,10) = char_id; + mapif_sendall(buf, 14); + return 0; } //Party map update notification int mapif_party_membermoved(struct party *p,int idx) { - unsigned char buf[20]; - - WBUFW(buf,0) = 0x3825; - WBUFL(buf,2) = p->party_id; - WBUFL(buf,6) = p->member[idx].account_id; - WBUFL(buf,10) = p->member[idx].char_id; - WBUFW(buf,14) = p->member[idx].map; - WBUFB(buf,16) = p->member[idx].online; - WBUFW(buf,17) = p->member[idx].lv; - mapif_sendall(buf, 19); - return 0; + unsigned char buf[20]; + + WBUFW(buf,0) = 0x3825; + WBUFL(buf,2) = p->party_id; + WBUFL(buf,6) = p->member[idx].account_id; + WBUFL(buf,10) = p->member[idx].char_id; + WBUFW(buf,14) = p->member[idx].map; + WBUFB(buf,16) = p->member[idx].online; + WBUFW(buf,17) = p->member[idx].lv; + mapif_sendall(buf, 19); + return 0; } //Dissolution party notification int mapif_party_broken(int party_id,int flag) { - unsigned char buf[16]; - WBUFW(buf,0)=0x3826; - WBUFL(buf,2)=party_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - //printf("int_party: broken %d\n",party_id); - return 0; + unsigned char buf[16]; + WBUFW(buf,0)=0x3826; + WBUFL(buf,2)=party_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + //printf("int_party: broken %d\n",party_id); + return 0; } //Remarks in the party int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) { - unsigned char buf[512]; - WBUFW(buf,0)=0x3827; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=party_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; + unsigned char buf[512]; + WBUFW(buf,0)=0x3827; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=party_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); + return 0; } //------------------------------------------------------------------- @@ -473,267 +466,273 @@ int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) // Create Party int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) { - struct party_data *p; - int i; - if ((p=search_partyname(name))!=NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } - - p = (struct party_data *)aCalloc(1, sizeof(struct party_data)); - - memcpy(p->party.name,name,NAME_LENGTH); - p->party.exp=0; - p->party.item=(item?1:0)|(item2?2:0); - - memcpy(&p->party.member[0], leader, sizeof(struct party_member)); - p->party.member[0].leader=1; - p->party.member[0].online=1; - - p->party.party_id=-1;//New party. - if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { - //Add party to db - int_party_calc_state(p); - idb_put(party_db_, p->party.party_id, p); - mapif_party_info(fd, &p->party, 0); - mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); - } else { //Failed to create party. - aFree(p); - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - } - - return 0; + struct party_data *p; + int i; + if( (p=search_partyname(name))!=NULL){ + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + } + + p = (struct party_data*)aCalloc(1, sizeof(struct party_data)); + + memcpy(p->party.name,name,NAME_LENGTH); + p->party.exp=0; + p->party.item=(item?1:0)|(item2?2:0); + + memcpy(&p->party.member[0], leader, sizeof(struct party_member)); + p->party.member[0].leader=1; + p->party.member[0].online=1; + + p->party.party_id=-1;//New party. + if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { + //Add party to db + int_party_calc_state(p); + idb_put(party_db_, p->party.party_id, p); + mapif_party_info(fd, &p->party, 0); + mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); + } else { //Failed to create party. + aFree(p); + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + } + + return 0; } // Party information request static void mapif_parse_PartyInfo(int fd, int party_id, int char_id) { - struct party_data *p; - p = inter_party_fromsql(party_id); + struct party_data *p; + p = inter_party_fromsql(party_id); - if (p) - mapif_party_info(fd, &p->party, char_id); - else - mapif_party_noinfo(fd, party_id, char_id); + if (p) + mapif_party_info(fd, &p->party, char_id); + else + mapif_party_noinfo(fd, party_id, char_id); } // Add a player to party request int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if (p == NULL || p->size == MAX_PARTY) { - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - ARR_FIND(0, MAX_PARTY, i, p->party.member[i].account_id == 0); - if (i == MAX_PARTY) { - // Party full - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - memcpy(&p->party.member[i], member, sizeof(struct party_member)); - p->party.member[i].leader = 0; - if (p->party.member[i].online) p->party.count++; - p->size++; - if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] - int_party_calc_state(p); - else //Check even share range. - if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { - if (p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - - mapif_party_info(-1, &p->party, 0); - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); - inter_party_tosql(&p->party, PS_ADDMEMBER, i); - - return 0; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + if( p == NULL || p->size == MAX_PARTY ) { + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 ); + if( i == MAX_PARTY ) + {// Party full + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + memcpy(&p->party.member[i], member, sizeof(struct party_member)); + p->party.member[i].leader = 0; + if (p->party.member[i].online) p->party.count++; + p->size++; + if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] + int_party_calc_state(p); + else //Check even share range. + if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { + if (p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + + mapif_party_info(-1, &p->party, 0); + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); + inter_party_tosql(&p->party, PS_ADDMEMBER, i); + + return 0; } //Party setting change request int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item) { - struct party_data *p; - int flag = 0; - p = inter_party_fromsql(party_id); - - if (!p) - return 0; - - p->party.exp=exp; - if (exp && !party_check_exp_share(p)) { - flag|=0x01; - p->party.exp=0; - } - p->party.item = item&0x3; //Filter out invalid values. - mapif_party_optionchanged(fd,&p->party,account_id,flag); - inter_party_tosql(&p->party, PS_BASIC, 0); - return 0; + struct party_data *p; + int flag = 0; + p = inter_party_fromsql(party_id); + + if(!p) + return 0; + + p->party.exp=exp; + if( exp && !party_check_exp_share(p) ){ + flag|=0x01; + p->party.exp=0; + } + p->party.item = item&0x3; //Filter out invalid values. + mapif_party_optionchanged(fd,&p->party,account_id,flag); + inter_party_tosql(&p->party, PS_BASIC, 0); + return 0; } //Request leave party int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) { - struct party_data *p; - int i,j=-1; - - p = inter_party_fromsql(party_id); - if (p == NULL) { - // Party does not exists? - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id)) - Sql_ShowDebug(sql_handle); - return 0; - } - - for (i = 0; i < MAX_PARTY; i++) { - if (p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) { - break; - } - } - if (i >= MAX_PARTY) - return 0; //Member not found? - - mapif_party_withdraw(party_id, account_id, char_id); - - if (p->party.member[i].leader) { - p->party.member[i].account_id = 0; - for (j = 0; j < MAX_PARTY; j++) { - if (!p->party.member[j].account_id) - continue; - mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); - p->party.member[j].account_id = 0; - } - //Party gets deleted on the check_empty call below. - } else { - inter_party_tosql(&p->party,PS_DELMEMBER,i); - j = p->party.member[i].lv; - if (p->party.member[i].online) p->party.count--; - memset(&p->party.member[i], 0, sizeof(struct party_member)); - p->size--; - if (j == p->min_lv || j == p->max_lv || p->family) { - if (p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - } - - if (party_check_empty(p) == 0) - mapif_party_info(-1, &p->party, 0); - return 0; + struct party_data *p; + int i,j=-1; + + p = inter_party_fromsql(party_id); + if( p == NULL ) + {// Party does not exists? + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) + Sql_ShowDebug(sql_handle); + return 0; + } + + for (i = 0; i < MAX_PARTY; i++) { + if(p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) { + break; + } + } + if (i >= MAX_PARTY) + return 0; //Member not found? + + mapif_party_withdraw(party_id, account_id, char_id); + + if (p->party.member[i].leader){ + p->party.member[i].account_id = 0; + for (j = 0; j < MAX_PARTY; j++) { + if (!p->party.member[j].account_id) + continue; + mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); + p->party.member[j].account_id = 0; + } + //Party gets deleted on the check_empty call below. + } else { + inter_party_tosql(&p->party,PS_DELMEMBER,i); + j = p->party.member[i].lv; + if(p->party.member[i].online) p->party.count--; + memset(&p->party.member[i], 0, sizeof(struct party_member)); + p->size--; + if (j == p->min_lv || j == p->max_lv || p->family) + { + if(p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + } + + if (party_check_empty(p) == 0) + mapif_party_info(-1, &p->party, 0); + return 0; } // When member goes to other map or levels up. int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if (p == NULL) - return 0; - - for (i = 0; i < MAX_PARTY && - (p->party.member[i].account_id != account_id || - p->party.member[i].char_id != char_id); i++); - - if (i == MAX_PARTY) return 0; - - if (p->party.member[i].online != online) { - p->party.member[i].online = online; - if (online) - p->party.count++; - else - p->party.count--; - // Even share check situations: Family state (always breaks) - // character logging on/off is max/min level (update level range) - // or character logging on/off has a different level (update level range using new level) - if (p->family || - (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || - (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) - ) { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } - //Send online/offline update. - mapif_party_membermoved(&p->party, i); - } - - if (p->party.member[i].lv != lv) { - if (p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } else - p->party.member[i].lv = lv; - //There is no need to send level update to map servers - //since they do nothing with it. - } - - if (p->party.member[i].map != map) { - p->party.member[i].map = map; - mapif_party_membermoved(&p->party, i); - } - return 0; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + if (p == NULL) + return 0; + + for(i = 0; i < MAX_PARTY && + (p->party.member[i].account_id != account_id || + p->party.member[i].char_id != char_id); i++); + + if (i == MAX_PARTY) return 0; + + if (p->party.member[i].online != online) + { + p->party.member[i].online = online; + if (online) + p->party.count++; + else + p->party.count--; + // Even share check situations: Family state (always breaks) + // character logging on/off is max/min level (update level range) + // or character logging on/off has a different level (update level range using new level) + if (p->family || + (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || + (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) + ) + { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } + //Send online/offline update. + mapif_party_membermoved(&p->party, i); + } + + if (p->party.member[i].lv != lv) { + if(p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) + { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } else + p->party.member[i].lv = lv; + //There is no need to send level update to map servers + //since they do nothing with it. + } + + if (p->party.member[i].map != map) { + p->party.member[i].map = map; + mapif_party_membermoved(&p->party, i); + } + return 0; } //Request party dissolution int mapif_parse_BreakParty(int fd,int party_id) { - struct party_data *p; + struct party_data *p; - p = inter_party_fromsql(party_id); + p = inter_party_fromsql(party_id); - if (!p) - return 0; - inter_party_tosql(&p->party,PS_BREAK,0); - mapif_party_broken(fd,party_id); - return 0; + if(!p) + return 0; + inter_party_tosql(&p->party,PS_BREAK,0); + mapif_party_broken(fd,party_id); + return 0; } //Party sending the message int mapif_parse_PartyMessage(int fd,int party_id,int account_id,char *mes,int len) { - return mapif_party_message(party_id,account_id,mes,len, fd); + return mapif_party_message(party_id,account_id,mes,len, fd); } int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - - if (!p) - return 0; - - for (i = 0; i < MAX_PARTY; i++) { - if (p->party.member[i].leader) - p->party.member[i].leader = 0; - if (p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) { - p->party.member[i].leader = 1; - inter_party_tosql(&p->party,PS_LEADER, i); - } - } - return 1; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + + if(!p) + return 0; + + for (i = 0; i < MAX_PARTY; i++) + { + if(p->party.member[i].leader) + p->party.member[i].leader = 0; + if(p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) + { + p->party.member[i].leader = 1; + inter_party_tosql(&p->party,PS_LEADER, i); + } + } + return 1; } @@ -742,139 +741,123 @@ int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id // Data packet length is set to inter.c that you // Do NOT go and check the packet length, RFIFOSKIP is done by the caller // Return : -// 0 : error -// 1 : ok +// 0 : error +// 1 : ok int inter_party_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch (RFIFOW(fd,0)) { - case 0x3020: - mapif_parse_CreateParty(fd, (char *)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member *)RFIFOP(fd,30)); - break; - case 0x3021: - mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); - break; - case 0x3022: - mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member *)RFIFOP(fd,8)); - break; - case 0x3023: - mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); - break; - case 0x3024: - mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); - break; - case 0x3025: - mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); - break; - case 0x3026: - mapif_parse_BreakParty(fd, RFIFOL(fd,2)); - break; - case 0x3027: - mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char *)RFIFOP(fd,12), RFIFOW(fd,2)-12); - break; - case 0x3029: - mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); - break; - default: - return 0; - } - return 1; + RFIFOHEAD(fd); + switch(RFIFOW(fd,0)) { + case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break; + case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); break; + case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break; + case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break; + case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; + case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break; + case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break; + case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; + case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; + default: + return 0; + } + return 1; } //Leave request from the server (for delete character) int inter_party_leave(int party_id,int account_id, int char_id) { - return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); + return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); } int inter_party_CharOnline(int char_id, int party_id) { - struct party_data *p; - int i; - - if (party_id == -1) { - // Get party_id from the database - char *data; - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { - Sql_ShowDebug(sql_handle); - return 0; - } - - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - p = inter_party_fromsql(party_id); - if (!p) { - ShowError("Character %d's party %d not found!\n", char_id, party_id); - return 0; - } - - //Set member online - for (i=0; iparty.member[i].char_id == char_id) { - if (!p->party.member[i].online) { - p->party.member[i].online = 1; - p->party.count++; - if (p->party.member[i].lv < p->min_lv || - p->party.member[i].lv > p->max_lv) - int_party_check_lv(p); - } - break; - } - } - return 1; + struct party_data* p; + int i; + + if( party_id == -1 ) + {// Get party_id from the database + char* data; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + p = inter_party_fromsql(party_id); + if(!p) { + ShowError("Character %d's party %d not found!\n", char_id, party_id); + return 0; + } + + //Set member online + for(i=0; iparty.member[i].char_id == char_id) { + if (!p->party.member[i].online) { + p->party.member[i].online = 1; + p->party.count++; + if (p->party.member[i].lv < p->min_lv || + p->party.member[i].lv > p->max_lv) + int_party_check_lv(p); + } + break; + } + } + return 1; } -int inter_party_CharOffline(int char_id, int party_id) -{ - struct party_data *p=NULL; - int i; - - if (party_id == -1) { - // Get guild_id from the database - char *data; - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { - Sql_ShowDebug(sql_handle); - return 0; - } - - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - //Character has a party, set character offline and check if they were the only member online - if ((p = inter_party_fromsql(party_id)) == NULL) - return 0; - - //Set member offline - for (i=0; i< MAX_PARTY; i++) { - if (p->party.member[i].char_id == char_id) { - p->party.member[i].online = 0; - p->party.count--; - if (p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - int_party_check_lv(p); - break; - } - } - - if (!p->party.count) - //Parties don't have any data that needs be saved at this point... so just remove it from memory. - idb_remove(party_db_, party_id); - return 1; +int inter_party_CharOffline(int char_id, int party_id) { + struct party_data *p=NULL; + int i; + + if( party_id == -1 ) + {// Get guild_id from the database + char* data; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + //Character has a party, set character offline and check if they were the only member online + if ((p = inter_party_fromsql(party_id)) == NULL) + return 0; + + //Set member offline + for(i=0; i< MAX_PARTY; i++) { + if(p->party.member[i].char_id == char_id) + { + p->party.member[i].online = 0; + p->party.count--; + if(p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) + int_party_check_lv(p); + break; + } + } + + if(!p->party.count) + //Parties don't have any data that needs be saved at this point... so just remove it from memory. + idb_remove(party_db_, party_id); + return 1; } diff --git a/src/char/int_party.h b/src/char/int_party.h index 27df25f15..d8cdcdc6a 100644 --- a/src/char/int_party.h +++ b/src/char/int_party.h @@ -6,12 +6,12 @@ //Party Flags on what to save/delete. enum { - PS_CREATE = 0x01, //Create a new party entry (index holds leader's info) - PS_BASIC = 0x02, //Update basic party info. - PS_LEADER = 0x04, //Update party's leader - PS_ADDMEMBER = 0x08, //Specify new party member (index specifies which party member) - PS_DELMEMBER = 0x10, //Specify member that left (index specifies which party member) - PS_BREAK = 0x20, //Specify that this party must be deleted. + PS_CREATE = 0x01, //Create a new party entry (index holds leader's info) + PS_BASIC = 0x02, //Update basic party info. + PS_LEADER = 0x04, //Update party's leader + PS_ADDMEMBER = 0x08, //Specify new party member (index specifies which party member) + PS_DELMEMBER = 0x10, //Specify member that left (index specifies which party member) + PS_BREAK = 0x20, //Specify that this party must be deleted. }; struct party; diff --git a/src/char/int_pet.c b/src/char/int_pet.c index e04138c0a..114398290 100644 --- a/src/char/int_pet.c +++ b/src/char/int_pet.c @@ -18,319 +18,292 @@ struct s_pet *pet_pt; //--------------------------------------------------------- -int inter_pet_tosql(int pet_id, struct s_pet *p) +int inter_pet_tosql(int pet_id, struct s_pet* p) { - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - char esc_name[NAME_LENGTH*2+1];// escaped pet name - - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if (pet_id == -1) { - // New pet. - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " - "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate)) { - Sql_ShowDebug(sql_handle); - return 0; - } - p->pet_id = (int)Sql_LastInsertId(sql_handle); - } else { - // Update pet. - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id)) { - Sql_ShowDebug(sql_handle); - return 0; - } - } - - if (save_log) - ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); - return 1; + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + char esc_name[NAME_LENGTH*2+1];// escaped pet name + + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if( pet_id == -1 ) + {// New pet. + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " + "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + p->pet_id = (int)Sql_LastInsertId(sql_handle); + } + else + {// Update pet. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + } + + if (save_log) + ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); + return 1; } -int inter_pet_fromsql(int pet_id, struct s_pet *p) +int inter_pet_fromsql(int pet_id, struct s_pet* p) { - char *data; - size_t len; + char* data; + size_t len; #ifdef NOISY - ShowInfo("Loading pet (%d)...\n",pet_id); + ShowInfo("Loading pet (%d)...\n",pet_id); #endif - memset(p, 0, sizeof(struct s_pet)); - - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id)) { - Sql_ShowDebug(sql_handle); - return 0; - } - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - p->pet_id = pet_id; - Sql_GetData(sql_handle, 1, &data, NULL); - p->class_ = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); - p->account_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - p->char_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - p->level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - p->egg_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - p->equip = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); - p->intimate = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); - p->hungry = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); - p->rename_flag = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); - p->incuvate = atoi(data); - - Sql_FreeResult(sql_handle); - - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if (save_log) - ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); - } - return 0; + memset(p, 0, sizeof(struct s_pet)); + + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + p->pet_id = pet_id; + Sql_GetData(sql_handle, 1, &data, NULL); p->class_ = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); p->account_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); p->char_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); p->level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); p->egg_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); p->equip = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); p->intimate = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); p->hungry = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); p->rename_flag = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); p->incuvate = atoi(data); + + Sql_FreeResult(sql_handle); + + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if( save_log ) + ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); + } + return 0; } //---------------------------------------------- -int inter_pet_sql_init(void) -{ - //memory alloc - pet_pt = (struct s_pet *)aCalloc(sizeof(struct s_pet), 1); - return 0; +int inter_pet_sql_init(void){ + //memory alloc + pet_pt = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); + return 0; } -void inter_pet_sql_final(void) -{ - if (pet_pt) aFree(pet_pt); - return; +void inter_pet_sql_final(void){ + if (pet_pt) aFree(pet_pt); + return; } //---------------------------------- -int inter_pet_delete(int pet_id) -{ - ShowInfo("delete pet request: %d...\n",pet_id); +int inter_pet_delete(int pet_id){ + ShowInfo("delete pet request: %d...\n",pet_id); - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id)) - Sql_ShowDebug(sql_handle); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) + Sql_ShowDebug(sql_handle); + return 0; } //------------------------------------------------------ int mapif_pet_created(int fd, int account_id, struct s_pet *p) { - WFIFOHEAD(fd, 11); - WFIFOW(fd, 0) =0x3880; - WFIFOL(fd, 2) =account_id; - if (p!=NULL) { - WFIFOB(fd, 6)=0; - WFIFOL(fd, 7) =p->pet_id; - ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); - } else { - WFIFOB(fd, 6)=1; - WFIFOL(fd, 7)=0; - } - WFIFOSET(fd, 11); - - return 0; + WFIFOHEAD(fd, 11); + WFIFOW(fd, 0) =0x3880; + WFIFOL(fd, 2) =account_id; + if(p!=NULL){ + WFIFOB(fd, 6)=0; + WFIFOL(fd, 7) =p->pet_id; + ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); + }else{ + WFIFOB(fd, 6)=1; + WFIFOL(fd, 7)=0; + } + WFIFOSET(fd, 11); + + return 0; } -int mapif_pet_info(int fd, int account_id, struct s_pet *p) -{ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=0; - memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; +int mapif_pet_info(int fd, int account_id, struct s_pet *p){ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=0; + memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); + + return 0; } -int mapif_pet_noinfo(int fd, int account_id) -{ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=1; - memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; +int mapif_pet_noinfo(int fd, int account_id){ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=1; + memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); + + return 0; } -int mapif_save_pet_ack(int fd, int account_id, int flag) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd, 0) =0x3882; - WFIFOL(fd, 2) =account_id; - WFIFOB(fd, 6) =flag; - WFIFOSET(fd, 7); +int mapif_save_pet_ack(int fd, int account_id, int flag){ + WFIFOHEAD(fd, 7); + WFIFOW(fd, 0) =0x3882; + WFIFOL(fd, 2) =account_id; + WFIFOB(fd, 6) =flag; + WFIFOSET(fd, 7); - return 0; + return 0; } -int mapif_delete_pet_ack(int fd, int flag) -{ - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) =0x3883; - WFIFOB(fd, 2) =flag; - WFIFOSET(fd, 3); +int mapif_delete_pet_ack(int fd, int flag){ + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) =0x3883; + WFIFOB(fd, 2) =flag; + WFIFOSET(fd, 3); - return 0; + return 0; } int mapif_create_pet(int fd, int account_id, int char_id, short pet_class, short pet_lv, short pet_egg_id, - short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name) + short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name) { - memset(pet_pt, 0, sizeof(struct s_pet)); - strncpy(pet_pt->name, pet_name, NAME_LENGTH); - if (incuvate == 1) - pet_pt->account_id = pet_pt->char_id = 0; - else { - pet_pt->account_id = account_id; - pet_pt->char_id = char_id; - } - pet_pt->class_ = pet_class; - pet_pt->level = pet_lv; - pet_pt->egg_id = pet_egg_id; - pet_pt->equip = pet_equip; - pet_pt->intimate = intimate; - pet_pt->hungry = hungry; - pet_pt->rename_flag = rename_flag; - pet_pt->incuvate = incuvate; - - if (pet_pt->hungry < 0) - pet_pt->hungry = 0; - else if (pet_pt->hungry > 100) - pet_pt->hungry = 100; - if (pet_pt->intimate < 0) - pet_pt->intimate = 0; - else if (pet_pt->intimate > 1000) - pet_pt->intimate = 1000; - - pet_pt->pet_id = -1; //Signal NEW pet. - if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) - mapif_pet_created(fd, account_id, pet_pt); - else //Failed... - mapif_pet_created(fd, account_id, NULL); - - return 0; + memset(pet_pt, 0, sizeof(struct s_pet)); + strncpy(pet_pt->name, pet_name, NAME_LENGTH); + if(incuvate == 1) + pet_pt->account_id = pet_pt->char_id = 0; + else { + pet_pt->account_id = account_id; + pet_pt->char_id = char_id; + } + pet_pt->class_ = pet_class; + pet_pt->level = pet_lv; + pet_pt->egg_id = pet_egg_id; + pet_pt->equip = pet_equip; + pet_pt->intimate = intimate; + pet_pt->hungry = hungry; + pet_pt->rename_flag = rename_flag; + pet_pt->incuvate = incuvate; + + if(pet_pt->hungry < 0) + pet_pt->hungry = 0; + else if(pet_pt->hungry > 100) + pet_pt->hungry = 100; + if(pet_pt->intimate < 0) + pet_pt->intimate = 0; + else if(pet_pt->intimate > 1000) + pet_pt->intimate = 1000; + + pet_pt->pet_id = -1; //Signal NEW pet. + if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) + mapif_pet_created(fd, account_id, pet_pt); + else //Failed... + mapif_pet_created(fd, account_id, NULL); + + return 0; } -int mapif_load_pet(int fd, int account_id, int char_id, int pet_id) -{ - memset(pet_pt, 0, sizeof(struct s_pet)); - - inter_pet_fromsql(pet_id, pet_pt); - - if (pet_pt!=NULL) { - if (pet_pt->incuvate == 1) { - pet_pt->account_id = pet_pt->char_id = 0; - mapif_pet_info(fd, account_id, pet_pt); - } else if (account_id == pet_pt->account_id && char_id == pet_pt->char_id) - mapif_pet_info(fd, account_id, pet_pt); - else - mapif_pet_noinfo(fd, account_id); - } else - mapif_pet_noinfo(fd, account_id); - - return 0; +int mapif_load_pet(int fd, int account_id, int char_id, int pet_id){ + memset(pet_pt, 0, sizeof(struct s_pet)); + + inter_pet_fromsql(pet_id, pet_pt); + + if(pet_pt!=NULL) { + if(pet_pt->incuvate == 1) { + pet_pt->account_id = pet_pt->char_id = 0; + mapif_pet_info(fd, account_id, pet_pt); + } + else if(account_id == pet_pt->account_id && char_id == pet_pt->char_id) + mapif_pet_info(fd, account_id, pet_pt); + else + mapif_pet_noinfo(fd, account_id); + } + else + mapif_pet_noinfo(fd, account_id); + + return 0; } -int mapif_save_pet(int fd, int account_id, struct s_pet *data) -{ - //here process pet save request. - int len; - RFIFOHEAD(fd); - len=RFIFOW(fd, 2); - if (sizeof(struct s_pet)!=len-8) { - ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); - } - - else { - if (data->hungry < 0) - data->hungry = 0; - else if (data->hungry > 100) - data->hungry = 100; - if (data->intimate < 0) - data->intimate = 0; - else if (data->intimate > 1000) - data->intimate = 1000; - inter_pet_tosql(data->pet_id,data); - mapif_save_pet_ack(fd, account_id, 0); - } - - return 0; +int mapif_save_pet(int fd, int account_id, struct s_pet *data) { + //here process pet save request. + int len; + RFIFOHEAD(fd); + len=RFIFOW(fd, 2); + if(sizeof(struct s_pet)!=len-8) { + ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); + } + + else{ + if(data->hungry < 0) + data->hungry = 0; + else if(data->hungry > 100) + data->hungry = 100; + if(data->intimate < 0) + data->intimate = 0; + else if(data->intimate > 1000) + data->intimate = 1000; + inter_pet_tosql(data->pet_id,data); + mapif_save_pet_ack(fd, account_id, 0); + } + + return 0; } -int mapif_delete_pet(int fd, int pet_id) -{ - mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); +int mapif_delete_pet(int fd, int pet_id){ + mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); - return 0; + return 0; } -int mapif_parse_CreatePet(int fd) -{ - RFIFOHEAD(fd); - mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), - RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char *)RFIFOP(fd, 24)); - return 0; +int mapif_parse_CreatePet(int fd){ + RFIFOHEAD(fd); + mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), + RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24)); + return 0; } -int mapif_parse_LoadPet(int fd) -{ - RFIFOHEAD(fd); - mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); - return 0; +int mapif_parse_LoadPet(int fd){ + RFIFOHEAD(fd); + mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); + return 0; } -int mapif_parse_SavePet(int fd) -{ - RFIFOHEAD(fd); - mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); - return 0; +int mapif_parse_SavePet(int fd){ + RFIFOHEAD(fd); + mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); + return 0; } -int mapif_parse_DeletePet(int fd) -{ - RFIFOHEAD(fd); - mapif_delete_pet(fd, RFIFOL(fd, 2)); - return 0; +int mapif_parse_DeletePet(int fd){ + RFIFOHEAD(fd); + mapif_delete_pet(fd, RFIFOL(fd, 2)); + return 0; } -int inter_pet_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch (RFIFOW(fd, 0)) { - case 0x3080: - mapif_parse_CreatePet(fd); - break; - case 0x3081: - mapif_parse_LoadPet(fd); - break; - case 0x3082: - mapif_parse_SavePet(fd); - break; - case 0x3083: - mapif_parse_DeletePet(fd); - break; - default: - return 0; - } - return 1; +int inter_pet_parse_frommap(int fd){ + RFIFOHEAD(fd); + switch(RFIFOW(fd, 0)){ + case 0x3080: mapif_parse_CreatePet(fd); break; + case 0x3081: mapif_parse_LoadPet(fd); break; + case 0x3082: mapif_parse_SavePet(fd); break; + case 0x3083: mapif_parse_DeletePet(fd); break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_quest.c b/src/char/int_quest.c index 8ba6ef95a..224205412 100644 --- a/src/char/int_quest.c +++ b/src/char/int_quest.c @@ -21,158 +21,164 @@ //Load entire questlog for a character int mapif_quests_fromsql(int char_id, struct quest questlog[]) { - int i; - struct quest tmp_quest; - SqlStmt *stmt; - - stmt = SqlStmt_Malloc(sql_handle); - if (stmt == NULL) { - SqlStmt_ShowDebug(stmt); - return 0; - } - - memset(&tmp_quest, 0, sizeof(struct quest)); - - if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL)) - SqlStmt_ShowDebug(stmt); - - for (i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) - memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); - - SqlStmt_Free(stmt); - return i; + int i; + struct quest tmp_quest; + SqlStmt * stmt; + + stmt = SqlStmt_Malloc(sql_handle); + if( stmt == NULL ) + { + SqlStmt_ShowDebug(stmt); + return 0; + } + + memset(&tmp_quest, 0, sizeof(struct quest)); + + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); + + SqlStmt_Free(stmt); + return i; } //Delete a quest bool mapif_quest_delete(int char_id, int quest_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id)) { - Sql_ShowDebug(sql_handle); - return false; - } + if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Add a quest to a questlog bool mapif_quest_add(int char_id, struct quest qd) { - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2])) { - Sql_ShowDebug(sql_handle); - return false; - } + if ( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) ) + { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Update a questlog bool mapif_quest_update(int char_id, struct quest qd) { - if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id)) { - Sql_ShowDebug(sql_handle); - return false; - } + if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Save quests int mapif_parse_quest_save(int fd) { - int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); - int char_id = RFIFOL(fd,4); - struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; - bool success = true; - - memset(qd1, 0, sizeof(qd1)); - memset(qd2, 0, sizeof(qd2)); - if (num1) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); - num2 = mapif_quests_fromsql(char_id, qd2); - - for (i = 0; i < num1; i++) { - ARR_FIND(0, num2, j, qd1[i].quest_id == qd2[j].quest_id); - if (j < num2) { // Update existed quests - // Only states and counts are changable. - ARR_FIND(0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k]); - if (k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state) - success &= mapif_quest_update(char_id, qd1[i]); - - if (j < (--num2)) { - memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); - memset(&qd2[num2], 0, sizeof(struct quest)); - } - - } else // Add new quests - success &= mapif_quest_add(char_id, qd1[i]); - } - - for (i = 0; i < num2; i++) // Quests not in qd1 but in qd2 are to be erased. - success &= mapif_quest_delete(char_id, qd2[i].quest_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3861; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = success?1:0; - WFIFOSET(fd,7); - - return 0; + int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); + int char_id = RFIFOL(fd,4); + struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; + bool success = true; + + memset(qd1, 0, sizeof(qd1)); + memset(qd2, 0, sizeof(qd2)); + if( num1 ) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); + num2 = mapif_quests_fromsql(char_id, qd2); + + for( i = 0; i < num1; i++ ) + { + ARR_FIND( 0, num2, j, qd1[i].quest_id == qd2[j].quest_id ); + if( j < num2 ) // Update existed quests + { // Only states and counts are changable. + ARR_FIND( 0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k] ); + if( k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state ) + success &= mapif_quest_update(char_id, qd1[i]); + + if( j < (--num2) ) + { + memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); + memset(&qd2[num2], 0, sizeof(struct quest)); + } + + } + else // Add new quests + success &= mapif_quest_add(char_id, qd1[i]); + } + + for( i = 0; i < num2; i++ ) // Quests not in qd1 but in qd2 are to be erased. + success &= mapif_quest_delete(char_id, qd2[i].quest_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3861; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = success?1:0; + WFIFOSET(fd,7); + + return 0; } //Send questlog to map server int mapif_parse_quest_load(int fd) { - int char_id = RFIFOL(fd,2); - struct quest tmp_questlog[MAX_QUEST_DB]; - int num_quests, i, num_complete = 0; - int complete[MAX_QUEST_DB]; - - memset(tmp_questlog, 0, sizeof(tmp_questlog)); - memset(complete, 0, sizeof(complete)); - - num_quests = mapif_quests_fromsql(char_id, tmp_questlog); - - WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); - WFIFOW(fd,0) = 0x3860; - WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; - WFIFOL(fd,4) = char_id; - - //Active and inactive quests - for (i = 0; i < num_quests; i++) { - if (tmp_questlog[i].state == Q_COMPLETE) { - complete[num_complete++] = i; - continue; - } - memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); - } - - // Completed quests - for (i = num_quests - num_complete; i < num_quests; i++) - memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); - - WFIFOSET(fd,num_quests*sizeof(struct quest)+8); - - return 0; + int char_id = RFIFOL(fd,2); + struct quest tmp_questlog[MAX_QUEST_DB]; + int num_quests, i, num_complete = 0; + int complete[MAX_QUEST_DB]; + + memset(tmp_questlog, 0, sizeof(tmp_questlog)); + memset(complete, 0, sizeof(complete)); + + num_quests = mapif_quests_fromsql(char_id, tmp_questlog); + + WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); + WFIFOW(fd,0) = 0x3860; + WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; + WFIFOL(fd,4) = char_id; + + //Active and inactive quests + for( i = 0; i < num_quests; i++ ) + { + if( tmp_questlog[i].state == Q_COMPLETE ) + { + complete[num_complete++] = i; + continue; + } + memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); + } + + // Completed quests + for( i = num_quests - num_complete; i < num_quests; i++ ) + memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); + + WFIFOSET(fd,num_quests*sizeof(struct quest)+8); + + return 0; } int inter_quest_parse_frommap(int fd) { - switch (RFIFOW(fd,0)) { - case 0x3060: - mapif_parse_quest_load(fd); - break; - case 0x3061: - mapif_parse_quest_save(fd); - break; - default: - return 0; - } - return 1; + switch(RFIFOW(fd,0)) + { + case 0x3060: mapif_parse_quest_load(fd); break; + case 0x3061: mapif_parse_quest_save(fd); break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 6f94ecc32..248a4521f 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -15,155 +15,142 @@ #include -#define STORAGE_MEMINC 16 +#define STORAGE_MEMINC 16 /// Save storage data to sql -int storage_tosql(int account_id, struct storage_data *p) +int storage_tosql(int account_id, struct storage_data* p) { - memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); - return 0; + memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); + return 0; } /// Load storage data to mem -int storage_fromsql(int account_id, struct storage_data *p) +int storage_fromsql(int account_id, struct storage_data* p) { - StringBuf buf; - struct item *item; - char *data; - int i; - int j; - - memset(p, 0, sizeof(struct storage_data)); //clean up memory - p->storage_amount = 0; - - // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for (i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); - item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - item->attribute = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - item->expire_time = (unsigned int)atoi(data); - for (j = 0; j < MAX_SLOTS; ++j) { - Sql_GetData(sql_handle, 8+j, &data, NULL); - item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); - return 1; + StringBuf buf; + struct item* item; + char* data; + int i; + int j; + + memset(p, 0, sizeof(struct storage_data)); //clean up memory + p->storage_amount = 0; + + // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for( i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data); + for( j = 0; j < MAX_SLOTS; ++j ) + { + Sql_GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data); + } + } + p->storage_amount = i; + Sql_FreeResult(sql_handle); + + ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); + return 1; } /// Save guild_storage data to sql -int guild_storage_tosql(int guild_id, struct guild_storage *p) +int guild_storage_tosql(int guild_id, struct guild_storage* p) { - memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); - ShowInfo("guild storage save to DB - guild: %d\n", guild_id); - return 0; + memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); + ShowInfo ("guild storage save to DB - guild: %d\n", guild_id); + return 0; } /// Load guild_storage data to mem -int guild_storage_fromsql(int guild_id, struct guild_storage *p) +int guild_storage_fromsql(int guild_id, struct guild_storage* p) { - StringBuf buf; - struct item *item; - char *data; - int i; - int j; - - memset(p, 0, sizeof(struct guild_storage)); //clean up memory - p->storage_amount = 0; - p->guild_id = guild_id; - - // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); - for (j = 0; j < MAX_SLOTS; ++j) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for (i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); - item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); - item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - item->attribute = atoi(data); - item->expire_time = 0; - for (j = 0; j < MAX_SLOTS; ++j) { - Sql_GetData(sql_handle, 7+j, &data, NULL); - item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); - return 0; + StringBuf buf; + struct item* item; + char* data; + int i; + int j; + + memset(p, 0, sizeof(struct guild_storage)); //clean up memory + p->storage_amount = 0; + p->guild_id = guild_id; + + // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); + item->expire_time = 0; + for( j = 0; j < MAX_SLOTS; ++j ) + { + Sql_GetData(sql_handle, 7+j, &data, NULL); item->card[j] = atoi(data); + } + } + p->storage_amount = i; + Sql_FreeResult(sql_handle); + + ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); + return 0; } //--------------------------------------------------------- // storage data initialize int inter_storage_sql_init(void) { - return 1; + return 1; } // storage data finalize void inter_storage_sql_final(void) { - return; + return; } // q?f[^? int inter_storage_delete(int account_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id)) - Sql_ShowDebug(sql_handle); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id) ) + Sql_ShowDebug(sql_handle); + return 0; } int inter_guild_storage_delete(int guild_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id)) - Sql_ShowDebug(sql_handle); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id) ) + Sql_ShowDebug(sql_handle); + return 0; } //--------------------------------------------------------- @@ -171,38 +158,38 @@ int inter_guild_storage_delete(int guild_id) int mapif_load_guild_storage(int fd,int account_id,int guild_id) { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id)) - Sql_ShowDebug(sql_handle); - else if (Sql_NumRows(sql_handle) > 0) { - // guild exists - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = sizeof(struct guild_storage)+12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = guild_id; - guild_storage_fromsql(guild_id, (struct guild_storage *)WFIFOP(fd,12)); - WFIFOSET(fd, WFIFOW(fd,2)); - return 0; - } - // guild does not exist - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = 0; - WFIFOSET(fd, 12); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) + Sql_ShowDebug(sql_handle); + else if( Sql_NumRows(sql_handle) > 0 ) + {// guild exists + WFIFOHEAD(fd, sizeof(struct guild_storage)+12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = sizeof(struct guild_storage)+12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = guild_id; + guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12)); + WFIFOSET(fd, WFIFOW(fd,2)); + return 0; + } + // guild does not exist + Sql_FreeResult(sql_handle); + WFIFOHEAD(fd, 12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = 12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = 0; + WFIFOSET(fd, 12); + return 0; } int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) { - WFIFOHEAD(fd,11); - WFIFOW(fd,0)=0x3819; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=guild_id; - WFIFOB(fd,10)=fail; - WFIFOSET(fd,11); - return 0; + WFIFOHEAD(fd,11); + WFIFOW(fd,0)=0x3819; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=guild_id; + WFIFOB(fd,10)=fail; + WFIFOSET(fd,11); + return 0; } //--------------------------------------------------------- @@ -210,51 +197,50 @@ int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) int mapif_parse_LoadGuildStorage(int fd) { - RFIFOHEAD(fd); - mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - return 0; + RFIFOHEAD(fd); + mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + return 0; } int mapif_parse_SaveGuildStorage(int fd) { - int guild_id; - int len; - - RFIFOHEAD(fd); - guild_id = RFIFOL(fd,8); - len = RFIFOW(fd,2); - - if (sizeof(struct guild_storage) != len - 12) { - ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); - } else { - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id)) - Sql_ShowDebug(sql_handle); - else if (Sql_NumRows(sql_handle) > 0) { - // guild exists - Sql_FreeResult(sql_handle); - guild_storage_tosql(guild_id, (struct guild_storage *)RFIFOP(fd,12)); - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); - return 0; - } - Sql_FreeResult(sql_handle); - } - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); - return 0; + int guild_id; + int len; + + RFIFOHEAD(fd); + guild_id = RFIFOL(fd,8); + len = RFIFOW(fd,2); + + if( sizeof(struct guild_storage) != len - 12 ) + { + ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); + } + else + { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) + Sql_ShowDebug(sql_handle); + else if( Sql_NumRows(sql_handle) > 0 ) + {// guild exists + Sql_FreeResult(sql_handle); + guild_storage_tosql(guild_id, (struct guild_storage*)RFIFOP(fd,12)); + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); + return 0; + } + Sql_FreeResult(sql_handle); + } + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); + return 0; } int inter_storage_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch (RFIFOW(fd,0)) { - case 0x3018: - mapif_parse_LoadGuildStorage(fd); - break; - case 0x3019: - mapif_parse_SaveGuildStorage(fd); - break; - default: - return 0; - } - return 1; + RFIFOHEAD(fd); + switch(RFIFOW(fd,0)){ + case 0x3018: mapif_parse_LoadGuildStorage(fd); break; + case 0x3019: mapif_parse_SaveGuildStorage(fd); break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_storage.h b/src/char/int_storage.h index 6285a8d21..811608f82 100644 --- a/src/char/int_storage.h +++ b/src/char/int_storage.h @@ -15,7 +15,7 @@ int inter_guild_storage_delete(int guild_id); int inter_storage_parse_frommap(int fd); //Exported for use in the TXT-SQL converter. -int storage_fromsql(int account_id, struct storage_data *p); +int storage_fromsql(int account_id, struct storage_data* p); int storage_tosql(int account_id,struct storage_data *p); int guild_storage_tosql(int guild_id, struct guild_storage *p); diff --git a/src/char/inter.c b/src/char/inter.c index 9b33d271e..8863b41d8 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -28,11 +28,11 @@ #include // for stat/lstat/fstat - [Dekamaster/Ultimate GM Tool] -#define WISDATA_TTL (60*1000) //Wis data Time To Live (60 seconds) -#define WISDELLIST_MAX 256 // Number of elements in the list Delete data Wis +#define WISDATA_TTL (60*1000) //Wis data Time To Live (60 seconds) +#define WISDELLIST_MAX 256 // Number of elements in the list Delete data Wis -Sql *sql_handle = NULL; +Sql* sql_handle = NULL; int char_server_port = 3306; char char_server_ip[32] = "127.0.0.1"; @@ -47,800 +47,778 @@ char main_chat_nick[16] = "Main"; // recv. packet list int inter_recv_packet_length[] = { - -1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- - -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- - -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- - -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] - 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] - -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] + -1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- + 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- + -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party + -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- + -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- + -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] + 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] + -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] + 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- + -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] }; struct WisData { - int id, fd, count, len; - unsigned long tick; - unsigned char src[24], dst[24], msg[512]; + int id, fd, count, len; + unsigned long tick; + unsigned char src[24], dst[24], msg[512]; }; -static DBMap *wis_db = NULL; // int wis_id -> struct WisData* +static DBMap* wis_db = NULL; // int wis_id -> struct WisData* static int wis_dellist[WISDELLIST_MAX], wis_delnum; #define MAX_JOB_NAMES 106 -static char *msg_table[MAX_JOB_NAMES]; // messages 550 ~ 655 are job names +static char* msg_table[MAX_JOB_NAMES]; // messages 550 ~ 655 are job names -const char *msg_txt(int msg_number) -{ - msg_number -= 550; - if (msg_number >= 0 && msg_number < MAX_JOB_NAMES && - msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; +const char* msg_txt(int msg_number) { + msg_number -= 550; + if (msg_number >= 0 && msg_number < MAX_JOB_NAMES && + msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') + return msg_table[msg_number]; - return "Unknown"; + return "Unknown"; } /*========================================== * Read Message Data -- at char server we only keep job names. *------------------------------------------*/ -int msg_config_read(const char *cfgName) -{ - int msg_number; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - static int called = 1; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("Messages file not found: %s\n", cfgName); - return 1; - } - - if ((--called) == 0) - memset(msg_table, 0, sizeof(msg_table[0]) * MAX_JOB_NAMES); - - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (strcmpi(w1, "import") == 0) - msg_config_read(w2); - else { - msg_number = atoi(w1); - if (msg_number < 550 || msg_number > (550+MAX_JOB_NAMES)) - continue; - msg_number -= 550; - if (msg_number >= 0 && msg_number < MAX_JOB_NAMES) { - if (msg_table[msg_number] != NULL) - aFree(msg_table[msg_number]); - msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof(char)); - strcpy(msg_table[msg_number],w2); - } - } - } - - fclose(fp); - - return 0; +int msg_config_read(const char* cfgName) { + int msg_number; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + static int called = 1; + + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("Messages file not found: %s\n", cfgName); + return 1; + } + + if ((--called) == 0) + memset(msg_table, 0, sizeof(msg_table[0]) * MAX_JOB_NAMES); + + while(fgets(line, sizeof(line), fp) ) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (strcmpi(w1, "import") == 0) + msg_config_read(w2); + else { + msg_number = atoi(w1); + if( msg_number < 550 || msg_number > (550+MAX_JOB_NAMES) ) + continue; + msg_number -= 550; + if (msg_number >= 0 && msg_number < MAX_JOB_NAMES) { + if (msg_table[msg_number] != NULL) + aFree(msg_table[msg_number]); + msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); + strcpy(msg_table[msg_number],w2); + } + } + } + + fclose(fp); + + return 0; } /*========================================== * Cleanup Message Data *------------------------------------------*/ -void do_final_msg(void) -{ - int i; - for (i = 0; i < MAX_JOB_NAMES; i++) - aFree(msg_table[i]); +void do_final_msg(void) { + int i; + for (i = 0; i < MAX_JOB_NAMES; i++) + aFree(msg_table[i]); } /* from pc.c due to @accinfo. any ideas to replace this crap are more than welcome. */ -const char *job_name(int class_) -{ - switch (class_) { - case JOB_NOVICE: - case JOB_SWORDMAN: - case JOB_MAGE: - case JOB_ARCHER: - case JOB_ACOLYTE: - case JOB_MERCHANT: - case JOB_THIEF: - return msg_txt(550 - JOB_NOVICE+class_); - - case JOB_KNIGHT: - case JOB_PRIEST: - case JOB_WIZARD: - case JOB_BLACKSMITH: - case JOB_HUNTER: - case JOB_ASSASSIN: - return msg_txt(557 - JOB_KNIGHT+class_); - - case JOB_KNIGHT2: - return msg_txt(557); - - case JOB_CRUSADER: - case JOB_MONK: - case JOB_SAGE: - case JOB_ROGUE: - case JOB_ALCHEMIST: - case JOB_BARD: - case JOB_DANCER: - return msg_txt(563 - JOB_CRUSADER+class_); - - case JOB_CRUSADER2: - return msg_txt(563); - - case JOB_WEDDING: - case JOB_SUPER_NOVICE: - case JOB_GUNSLINGER: - case JOB_NINJA: - case JOB_XMAS: - return msg_txt(570 - JOB_WEDDING+class_); - - case JOB_SUMMER: - return msg_txt(621); - - case JOB_NOVICE_HIGH: - case JOB_SWORDMAN_HIGH: - case JOB_MAGE_HIGH: - case JOB_ARCHER_HIGH: - case JOB_ACOLYTE_HIGH: - case JOB_MERCHANT_HIGH: - case JOB_THIEF_HIGH: - return msg_txt(575 - JOB_NOVICE_HIGH+class_); - - case JOB_LORD_KNIGHT: - case JOB_HIGH_PRIEST: - case JOB_HIGH_WIZARD: - case JOB_WHITESMITH: - case JOB_SNIPER: - case JOB_ASSASSIN_CROSS: - return msg_txt(582 - JOB_LORD_KNIGHT+class_); - - case JOB_LORD_KNIGHT2: - return msg_txt(582); - - case JOB_PALADIN: - case JOB_CHAMPION: - case JOB_PROFESSOR: - case JOB_STALKER: - case JOB_CREATOR: - case JOB_CLOWN: - case JOB_GYPSY: - return msg_txt(588 - JOB_PALADIN + class_); - - case JOB_PALADIN2: - return msg_txt(588); - - case JOB_BABY: - case JOB_BABY_SWORDMAN: - case JOB_BABY_MAGE: - case JOB_BABY_ARCHER: - case JOB_BABY_ACOLYTE: - case JOB_BABY_MERCHANT: - case JOB_BABY_THIEF: - return msg_txt(595 - JOB_BABY + class_); - - case JOB_BABY_KNIGHT: - case JOB_BABY_PRIEST: - case JOB_BABY_WIZARD: - case JOB_BABY_BLACKSMITH: - case JOB_BABY_HUNTER: - case JOB_BABY_ASSASSIN: - return msg_txt(602 - JOB_BABY_KNIGHT + class_); - - case JOB_BABY_KNIGHT2: - return msg_txt(602); - - case JOB_BABY_CRUSADER: - case JOB_BABY_MONK: - case JOB_BABY_SAGE: - case JOB_BABY_ROGUE: - case JOB_BABY_ALCHEMIST: - case JOB_BABY_BARD: - case JOB_BABY_DANCER: - return msg_txt(608 - JOB_BABY_CRUSADER + class_); - - case JOB_BABY_CRUSADER2: - return msg_txt(608); - - case JOB_SUPER_BABY: - return msg_txt(615); - - case JOB_TAEKWON: - return msg_txt(616); - case JOB_STAR_GLADIATOR: - case JOB_STAR_GLADIATOR2: - return msg_txt(617); - case JOB_SOUL_LINKER: - return msg_txt(618); - - case JOB_GANGSI: - case JOB_DEATH_KNIGHT: - case JOB_DARK_COLLECTOR: - return msg_txt(622 - JOB_GANGSI+class_); - - case JOB_RUNE_KNIGHT: - case JOB_WARLOCK: - case JOB_RANGER: - case JOB_ARCH_BISHOP: - case JOB_MECHANIC: - case JOB_GUILLOTINE_CROSS: - return msg_txt(625 - JOB_RUNE_KNIGHT+class_); - - case JOB_RUNE_KNIGHT_T: - case JOB_WARLOCK_T: - case JOB_RANGER_T: - case JOB_ARCH_BISHOP_T: - case JOB_MECHANIC_T: - case JOB_GUILLOTINE_CROSS_T: - return msg_txt(625 - JOB_RUNE_KNIGHT_T+class_); - - case JOB_ROYAL_GUARD: - case JOB_SORCERER: - case JOB_MINSTREL: - case JOB_WANDERER: - case JOB_SURA: - case JOB_GENETIC: - case JOB_SHADOW_CHASER: - return msg_txt(631 - JOB_ROYAL_GUARD+class_); - - case JOB_ROYAL_GUARD_T: - case JOB_SORCERER_T: - case JOB_MINSTREL_T: - case JOB_WANDERER_T: - case JOB_SURA_T: - case JOB_GENETIC_T: - case JOB_SHADOW_CHASER_T: - return msg_txt(631 - JOB_ROYAL_GUARD_T+class_); - - case JOB_RUNE_KNIGHT2: - case JOB_RUNE_KNIGHT_T2: - return msg_txt(625); - - case JOB_ROYAL_GUARD2: - case JOB_ROYAL_GUARD_T2: - return msg_txt(631); - - case JOB_RANGER2: - case JOB_RANGER_T2: - return msg_txt(627); - - case JOB_MECHANIC2: - case JOB_MECHANIC_T2: - return msg_txt(629); - - case JOB_BABY_RUNE: - case JOB_BABY_WARLOCK: - case JOB_BABY_RANGER: - case JOB_BABY_BISHOP: - case JOB_BABY_MECHANIC: - case JOB_BABY_CROSS: - case JOB_BABY_GUARD: - case JOB_BABY_SORCERER: - case JOB_BABY_MINSTREL: - case JOB_BABY_WANDERER: - case JOB_BABY_SURA: - case JOB_BABY_GENETIC: - case JOB_BABY_CHASER: - return msg_txt(638 - JOB_BABY_RUNE+class_); - - case JOB_BABY_RUNE2: - return msg_txt(638); - - case JOB_BABY_GUARD2: - return msg_txt(644); - - case JOB_BABY_RANGER2: - return msg_txt(640); - - case JOB_BABY_MECHANIC2: - return msg_txt(642); - - case JOB_SUPER_NOVICE_E: - case JOB_SUPER_BABY_E: - return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); - - case JOB_KAGEROU: - case JOB_OBORO: - return msg_txt(653 - JOB_KAGEROU+class_); - - default: - return msg_txt(655); - } +const char* job_name(int class_) { + switch (class_) { + case JOB_NOVICE: + case JOB_SWORDMAN: + case JOB_MAGE: + case JOB_ARCHER: + case JOB_ACOLYTE: + case JOB_MERCHANT: + case JOB_THIEF: + return msg_txt(550 - JOB_NOVICE+class_); + + case JOB_KNIGHT: + case JOB_PRIEST: + case JOB_WIZARD: + case JOB_BLACKSMITH: + case JOB_HUNTER: + case JOB_ASSASSIN: + return msg_txt(557 - JOB_KNIGHT+class_); + + case JOB_KNIGHT2: + return msg_txt(557); + + case JOB_CRUSADER: + case JOB_MONK: + case JOB_SAGE: + case JOB_ROGUE: + case JOB_ALCHEMIST: + case JOB_BARD: + case JOB_DANCER: + return msg_txt(563 - JOB_CRUSADER+class_); + + case JOB_CRUSADER2: + return msg_txt(563); + + case JOB_WEDDING: + case JOB_SUPER_NOVICE: + case JOB_GUNSLINGER: + case JOB_NINJA: + case JOB_XMAS: + return msg_txt(570 - JOB_WEDDING+class_); + + case JOB_SUMMER: + return msg_txt(621); + + case JOB_NOVICE_HIGH: + case JOB_SWORDMAN_HIGH: + case JOB_MAGE_HIGH: + case JOB_ARCHER_HIGH: + case JOB_ACOLYTE_HIGH: + case JOB_MERCHANT_HIGH: + case JOB_THIEF_HIGH: + return msg_txt(575 - JOB_NOVICE_HIGH+class_); + + case JOB_LORD_KNIGHT: + case JOB_HIGH_PRIEST: + case JOB_HIGH_WIZARD: + case JOB_WHITESMITH: + case JOB_SNIPER: + case JOB_ASSASSIN_CROSS: + return msg_txt(582 - JOB_LORD_KNIGHT+class_); + + case JOB_LORD_KNIGHT2: + return msg_txt(582); + + case JOB_PALADIN: + case JOB_CHAMPION: + case JOB_PROFESSOR: + case JOB_STALKER: + case JOB_CREATOR: + case JOB_CLOWN: + case JOB_GYPSY: + return msg_txt(588 - JOB_PALADIN + class_); + + case JOB_PALADIN2: + return msg_txt(588); + + case JOB_BABY: + case JOB_BABY_SWORDMAN: + case JOB_BABY_MAGE: + case JOB_BABY_ARCHER: + case JOB_BABY_ACOLYTE: + case JOB_BABY_MERCHANT: + case JOB_BABY_THIEF: + return msg_txt(595 - JOB_BABY + class_); + + case JOB_BABY_KNIGHT: + case JOB_BABY_PRIEST: + case JOB_BABY_WIZARD: + case JOB_BABY_BLACKSMITH: + case JOB_BABY_HUNTER: + case JOB_BABY_ASSASSIN: + return msg_txt(602 - JOB_BABY_KNIGHT + class_); + + case JOB_BABY_KNIGHT2: + return msg_txt(602); + + case JOB_BABY_CRUSADER: + case JOB_BABY_MONK: + case JOB_BABY_SAGE: + case JOB_BABY_ROGUE: + case JOB_BABY_ALCHEMIST: + case JOB_BABY_BARD: + case JOB_BABY_DANCER: + return msg_txt(608 - JOB_BABY_CRUSADER + class_); + + case JOB_BABY_CRUSADER2: + return msg_txt(608); + + case JOB_SUPER_BABY: + return msg_txt(615); + + case JOB_TAEKWON: + return msg_txt(616); + case JOB_STAR_GLADIATOR: + case JOB_STAR_GLADIATOR2: + return msg_txt(617); + case JOB_SOUL_LINKER: + return msg_txt(618); + + case JOB_GANGSI: + case JOB_DEATH_KNIGHT: + case JOB_DARK_COLLECTOR: + return msg_txt(622 - JOB_GANGSI+class_); + + case JOB_RUNE_KNIGHT: + case JOB_WARLOCK: + case JOB_RANGER: + case JOB_ARCH_BISHOP: + case JOB_MECHANIC: + case JOB_GUILLOTINE_CROSS: + return msg_txt(625 - JOB_RUNE_KNIGHT+class_); + + case JOB_RUNE_KNIGHT_T: + case JOB_WARLOCK_T: + case JOB_RANGER_T: + case JOB_ARCH_BISHOP_T: + case JOB_MECHANIC_T: + case JOB_GUILLOTINE_CROSS_T: + return msg_txt(625 - JOB_RUNE_KNIGHT_T+class_); + + case JOB_ROYAL_GUARD: + case JOB_SORCERER: + case JOB_MINSTREL: + case JOB_WANDERER: + case JOB_SURA: + case JOB_GENETIC: + case JOB_SHADOW_CHASER: + return msg_txt(631 - JOB_ROYAL_GUARD+class_); + + case JOB_ROYAL_GUARD_T: + case JOB_SORCERER_T: + case JOB_MINSTREL_T: + case JOB_WANDERER_T: + case JOB_SURA_T: + case JOB_GENETIC_T: + case JOB_SHADOW_CHASER_T: + return msg_txt(631 - JOB_ROYAL_GUARD_T+class_); + + case JOB_RUNE_KNIGHT2: + case JOB_RUNE_KNIGHT_T2: + return msg_txt(625); + + case JOB_ROYAL_GUARD2: + case JOB_ROYAL_GUARD_T2: + return msg_txt(631); + + case JOB_RANGER2: + case JOB_RANGER_T2: + return msg_txt(627); + + case JOB_MECHANIC2: + case JOB_MECHANIC_T2: + return msg_txt(629); + + case JOB_BABY_RUNE: + case JOB_BABY_WARLOCK: + case JOB_BABY_RANGER: + case JOB_BABY_BISHOP: + case JOB_BABY_MECHANIC: + case JOB_BABY_CROSS: + case JOB_BABY_GUARD: + case JOB_BABY_SORCERER: + case JOB_BABY_MINSTREL: + case JOB_BABY_WANDERER: + case JOB_BABY_SURA: + case JOB_BABY_GENETIC: + case JOB_BABY_CHASER: + return msg_txt(638 - JOB_BABY_RUNE+class_); + + case JOB_BABY_RUNE2: + return msg_txt(638); + + case JOB_BABY_GUARD2: + return msg_txt(644); + + case JOB_BABY_RANGER2: + return msg_txt(640); + + case JOB_BABY_MECHANIC2: + return msg_txt(642); + + case JOB_SUPER_NOVICE_E: + case JOB_SUPER_BABY_E: + return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); + + case JOB_KAGEROU: + case JOB_OBORO: + return msg_txt(653 - JOB_KAGEROU+class_); + + default: + return msg_txt(655); + } } /** * [Dekamaster/Nightroad] **/ -const char *geoip_countryname[253] = {"Unknown","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", - "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", - "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", - "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", - "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", - "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", - "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", - "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", - "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", - "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", - "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", - "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", - "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", - "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", - "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", - "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", - "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", - "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", - "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", - "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", - "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", - "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", - "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", - "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", - "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", - "Saint Barthelemy","Saint Martin" - }; +const char * geoip_countryname[253] = {"Unknown","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", + "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", + "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", + "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", + "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", + "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", + "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", + "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", + "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", + "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", + "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", + "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", + "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", + "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", + "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", + "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", + "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", + "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", + "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", + "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", + "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", + "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", + "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", + "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", + "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", + "Saint Barthelemy","Saint Martin"}; unsigned char *geoip_cache; -void geoip_readdb(void) -{ - struct stat bufa; - FILE *db=fopen("./db/GeoIP.dat","rb"); - fstat(fileno(db), &bufa); - geoip_cache = (unsigned char *) malloc(sizeof(unsigned char) * bufa.st_size); - if (fread(geoip_cache, sizeof(unsigned char), bufa.st_size, db) != bufa.st_size) { - ShowError("geoip_cache reading didn't read all elements \n"); - } - fclose(db); - ShowStatus("Finished Reading "CL_GREEN"GeoIP"CL_RESET" Database.\n"); +void geoip_readdb(void){ + struct stat bufa; + FILE *db=fopen("./db/GeoIP.dat","rb"); + fstat(fileno(db), &bufa); + geoip_cache = (unsigned char *) malloc(sizeof(unsigned char) * bufa.st_size); + if(fread(geoip_cache, sizeof(unsigned char), bufa.st_size, db) != bufa.st_size) { ShowError("geoip_cache reading didn't read all elements \n"); } + fclose(db); + ShowStatus("Finished Reading "CL_GREEN"GeoIP"CL_RESET" Database.\n"); } /* [Dekamaster/Nightroad] */ /* WHY NOT A DBMAP: There are millions of entries in GeoIP and it has its own algorithm to go quickly through them, a DBMap wouldn't be efficient */ -const char *geoip_getcountry(uint32 ipnum) -{ - int depth; - unsigned int x; - const unsigned char *buf; - unsigned int offset = 0; - - for (depth = 31; depth >= 0; depth--) { - buf = geoip_cache + (long)6 *offset; - if (ipnum & (1 << depth)) { - /* Take the right-hand branch */ - x = (buf[3*1 + 0] << (0*8)) - + (buf[3*1 + 1] << (1*8)) - + (buf[3*1 + 2] << (2*8)); - } else { - /* Take the left-hand branch */ - x = (buf[3*0 + 0] << (0*8)) - + (buf[3*0 + 1] << (1*8)) - + (buf[3*0 + 2] << (2*8)); - } - if (x >= 16776960) { - x=x-16776960; - return geoip_countryname[x]; - } - offset = x; - } - return geoip_countryname[0]; +const char* geoip_getcountry(uint32 ipnum){ + int depth; + unsigned int x; + const unsigned char *buf; + unsigned int offset = 0; + + for (depth = 31; depth >= 0; depth--) { + buf = geoip_cache + (long)6 *offset; + if (ipnum & (1 << depth)) { + /* Take the right-hand branch */ + x = (buf[3*1 + 0] << (0*8)) + + (buf[3*1 + 1] << (1*8)) + + (buf[3*1 + 2] << (2*8)); + } else { + /* Take the left-hand branch */ + x = (buf[3*0 + 0] << (0*8)) + + (buf[3*0 + 1] << (1*8)) + + (buf[3*0 + 2] << (2*8)); + } + if (x >= 16776960) { + x=x-16776960; + return geoip_countryname[x]; + } + offset = x; + } + return geoip_countryname[0]; } /* sends a mesasge to map server (fd) to a user (u_fd) although we use fd we keep aid for safe-check */ /* extremely handy I believe it will serve other uses in the near future */ -void inter_to_fd(int fd, int u_fd, int aid, char *msg, ...) -{ - char msg_out[512]; - va_list ap; - int len = 1;/* yes we start at 1 */ +void inter_to_fd(int fd, int u_fd, int aid, char* msg, ...) { + char msg_out[512]; + va_list ap; + int len = 1;/* yes we start at 1 */ - va_start(ap,msg); - len += vsnprintf(msg_out, 512, msg, ap); - va_end(ap); + va_start(ap,msg); + len += vsnprintf(msg_out, 512, msg, ap); + va_end(ap); - WFIFOHEAD(fd,12 + len); + WFIFOHEAD(fd,12 + len); - WFIFOW(fd,0) = 0x3807; - WFIFOW(fd,2) = 12 + (unsigned short)len; - WFIFOL(fd,4) = u_fd; - WFIFOL(fd,8) = aid; - safestrncpy((char *)WFIFOP(fd,12), msg_out, len); + WFIFOW(fd,0) = 0x3807; + WFIFOW(fd,2) = 12 + (unsigned short)len; + WFIFOL(fd,4) = u_fd; + WFIFOL(fd,8) = aid; + safestrncpy((char*)WFIFOP(fd,12), msg_out, len); - WFIFOSET(fd,12 + len); + WFIFOSET(fd,12 + len); - return; + return; } /* [Dekamaster/Nightroad] */ -void mapif_parse_accinfo(int fd) -{ - int u_fd = RFIFOL(fd,2), aid = RFIFOL(fd,6), castergroup = RFIFOL(fd,10); - char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1]; - int account_id; - char *data; - - safestrncpy(query, (char *) RFIFOP(fd,14), NAME_LENGTH); - - Sql_EscapeString(sql_handle, query_esq, query); - - account_id = atoi(query); - - if (account_id < START_ACCOUNT_NUM) { // is string - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `char` WHERE `name` LIKE '%s' LIMIT 10", query_esq) - || Sql_NumRows(sql_handle) == 0) { - if (Sql_NumRows(sql_handle) == 0) { - inter_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); - } else { - Sql_ShowDebug(sql_handle); - inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); - } - Sql_FreeResult(sql_handle); - return; - } else { - if (Sql_NumRows(sql_handle) == 1) { //we found a perfect match - Sql_NextRow(sql_handle); - Sql_GetData(sql_handle, 0, &data, NULL); - account_id = atoi(data); - Sql_FreeResult(sql_handle); - } else {// more than one, listing... [Dekamaster/Nightroad] - inter_to_fd(fd, u_fd, aid, "Your query returned the following %d results, please be more specific...",(int)Sql_NumRows(sql_handle)); - while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - int class_; - short base_level, job_level, online; - char name[NAME_LENGTH]; - - Sql_GetData(sql_handle, 0, &data, NULL); - account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - safestrncpy(name, data, sizeof(name)); - Sql_GetData(sql_handle, 2, &data, NULL); - class_ = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - base_level = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - job_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - online = atoi(data); - - inter_to_fd(fd, u_fd, aid, "[AID: %d] %s | %s | Level: %d/%d | %s", account_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); - } - Sql_FreeResult(sql_handle); - return; - } - } - } - - /* it will only get here if we have a single match */ - if (account_id) { - char userid[NAME_LENGTH], user_pass[NAME_LENGTH], email[40], last_ip[20], lastlogin[30]; - short level = -1; - int logincount = 0,state = 0; - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `userid`, `user_pass`, `email`, `last_ip`, `group_id`, `lastlogin`, `logincount`, `state` FROM `login` WHERE `account_id` = '%d' LIMIT 1", account_id) - || Sql_NumRows(sql_handle) == 0) { - if (Sql_NumRows(sql_handle) == 0) { - inter_to_fd(fd, u_fd, aid, "No account with ID '%d' was found.", account_id); - } else { - inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); - Sql_ShowDebug(sql_handle); - } - } else { - Sql_NextRow(sql_handle); - Sql_GetData(sql_handle, 0, &data, NULL); - safestrncpy(userid, data, sizeof(userid)); - Sql_GetData(sql_handle, 1, &data, NULL); - safestrncpy(user_pass, data, sizeof(user_pass)); - Sql_GetData(sql_handle, 2, &data, NULL); - safestrncpy(email, data, sizeof(email)); - Sql_GetData(sql_handle, 3, &data, NULL); - safestrncpy(last_ip, data, sizeof(last_ip)); - Sql_GetData(sql_handle, 4, &data, NULL); - level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - safestrncpy(lastlogin, data, sizeof(lastlogin)); - Sql_GetData(sql_handle, 6, &data, NULL); - logincount = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); - state = atoi(data); - } - - Sql_FreeResult(sql_handle); - - if (level == -1) - return; - - inter_to_fd(fd, u_fd, aid, "-- Account %d --", account_id); - inter_to_fd(fd, u_fd, aid, "User: %s | GM Group: %d | State: %d", userid, level, state); - - if (level < castergroup) /* only show pass if your gm level is greater than the one you're searching for */ - inter_to_fd(fd, u_fd, aid, "Password: %s", user_pass); - - inter_to_fd(fd, u_fd, aid, "Account e-mail: %s", email); - inter_to_fd(fd, u_fd, aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip))); - inter_to_fd(fd, u_fd, aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin); - inter_to_fd(fd, u_fd, aid, "-- Character Details --"); - - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `char` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", account_id, MAX_CHARS) - || Sql_NumRows(sql_handle) == 0) { - - if (Sql_NumRows(sql_handle) == 0) - inter_to_fd(fd, u_fd, aid,"This account doesn't have characters."); - else { - inter_to_fd(fd, u_fd, aid,"An error occured, bother your admin about it."); - Sql_ShowDebug(sql_handle); - } - - } else { - while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - int char_id, class_; - short char_num, base_level, job_level, online; - char name[NAME_LENGTH]; - - Sql_GetData(sql_handle, 0, &data, NULL); - char_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); - safestrncpy(name, data, sizeof(name)); - Sql_GetData(sql_handle, 2, &data, NULL); - char_num = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); - class_ = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); - base_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); - job_level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); - online = atoi(data); - - inter_to_fd(fd, u_fd, aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); - } - } - Sql_FreeResult(sql_handle); - } - - return; +void mapif_parse_accinfo(int fd) { + int u_fd = RFIFOL(fd,2), aid = RFIFOL(fd,6), castergroup = RFIFOL(fd,10); + char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1]; + int account_id; + char *data; + + safestrncpy(query, (char*) RFIFOP(fd,14), NAME_LENGTH); + + Sql_EscapeString(sql_handle, query_esq, query); + + account_id = atoi(query); + + if (account_id < START_ACCOUNT_NUM) { // is string + if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `char` WHERE `name` LIKE '%s' LIMIT 10", query_esq) + || Sql_NumRows(sql_handle) == 0 ) { + if( Sql_NumRows(sql_handle) == 0 ) { + inter_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); + } else { + Sql_ShowDebug(sql_handle); + inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); + } + Sql_FreeResult(sql_handle); + return; + } else { + if( Sql_NumRows(sql_handle) == 1 ) {//we found a perfect match + Sql_NextRow(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); + Sql_FreeResult(sql_handle); + } else {// more than one, listing... [Dekamaster/Nightroad] + inter_to_fd(fd, u_fd, aid, "Your query returned the following %d results, please be more specific...",(int)Sql_NumRows(sql_handle)); + while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { + int class_; + short base_level, job_level, online; + char name[NAME_LENGTH]; + + Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); + Sql_GetData(sql_handle, 2, &data, NULL); class_ = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); base_level = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); job_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); online = atoi(data); + + inter_to_fd(fd, u_fd, aid, "[AID: %d] %s | %s | Level: %d/%d | %s", account_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); + } + Sql_FreeResult(sql_handle); + return; + } + } + } + + /* it will only get here if we have a single match */ + if( account_id ) { + char userid[NAME_LENGTH], user_pass[NAME_LENGTH], email[40], last_ip[20], lastlogin[30]; + short level = -1; + int logincount = 0,state = 0; + if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `userid`, `user_pass`, `email`, `last_ip`, `group_id`, `lastlogin`, `logincount`, `state` FROM `login` WHERE `account_id` = '%d' LIMIT 1", account_id) + || Sql_NumRows(sql_handle) == 0 ) { + if( Sql_NumRows(sql_handle) == 0 ) { + inter_to_fd(fd, u_fd, aid, "No account with ID '%d' was found.", account_id ); + } else { + inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); + Sql_ShowDebug(sql_handle); + } + } else { + Sql_NextRow(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(userid, data, sizeof(userid)); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(user_pass, data, sizeof(user_pass)); + Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(email, data, sizeof(email)); + Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(last_ip, data, sizeof(last_ip)); + Sql_GetData(sql_handle, 4, &data, NULL); level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(lastlogin, data, sizeof(lastlogin)); + Sql_GetData(sql_handle, 6, &data, NULL); logincount = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); state = atoi(data); + } + + Sql_FreeResult(sql_handle); + + if (level == -1) + return; + + inter_to_fd(fd, u_fd, aid, "-- Account %d --", account_id ); + inter_to_fd(fd, u_fd, aid, "User: %s | GM Group: %d | State: %d", userid, level, state ); + + if (level < castergroup) /* only show pass if your gm level is greater than the one you're searching for */ + inter_to_fd(fd, u_fd, aid, "Password: %s", user_pass ); + + inter_to_fd(fd, u_fd, aid, "Account e-mail: %s", email); + inter_to_fd(fd, u_fd, aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip)) ); + inter_to_fd(fd, u_fd, aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin ); + inter_to_fd(fd, u_fd, aid, "-- Character Details --" ); + + + if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `char` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", account_id, MAX_CHARS) + || Sql_NumRows(sql_handle) == 0 ) { + + if( Sql_NumRows(sql_handle) == 0 ) + inter_to_fd(fd, u_fd, aid,"This account doesn't have characters."); + else { + inter_to_fd(fd, u_fd, aid,"An error occured, bother your admin about it."); + Sql_ShowDebug(sql_handle); + } + + } else { + while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { + int char_id, class_; + short char_num, base_level, job_level, online; + char name[NAME_LENGTH]; + + Sql_GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); + Sql_GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); online = atoi(data); + + inter_to_fd(fd, u_fd, aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); + } + } + Sql_FreeResult(sql_handle); + } + + return; } //-------------------------------------------------------- // Save registry to sql -int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type) +int inter_accreg_tosql(int account_id, int char_id, struct accreg* reg, int type) { - struct global_reg *r; - StringBuf buf; - int i; - - if (account_id <= 0) - return 0; - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch (type) { - case 3: //Char Reg - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) - Sql_ShowDebug(sql_handle); - account_id = 0; - break; - case 2: //Account Reg - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id)) - Sql_ShowDebug(sql_handle); - char_id = 0; - break; - case 1: //Account2 Reg - ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_tosql: Invalid type %d\n", type); - return 0; - } - - if (reg->reg_num <= 0) - return 0; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db); - - for (i = 0; i < reg->reg_num; ++i) { - r = ®->reg[i]; - if (r->str[0] != '\0' && r->value[0] != '\0') { - char str[32]; - char val[256]; - - if (i > 0) - StringBuf_AppendStr(&buf, ","); - - Sql_EscapeString(sql_handle, str, r->str); - Sql_EscapeString(sql_handle, val, r->value); - - StringBuf_Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val); - } - } - - if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - } - - StringBuf_Destroy(&buf); - - return 1; + struct global_reg* r; + StringBuf buf; + int i; + + if( account_id <= 0 ) + return 0; + reg->account_id = account_id; + reg->char_id = char_id; + + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch( type ) + { + case 3: //Char Reg + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + Sql_ShowDebug(sql_handle); + account_id = 0; + break; + case 2: //Account Reg + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) + Sql_ShowDebug(sql_handle); + char_id = 0; + break; + case 1: //Account2 Reg + ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_tosql: Invalid type %d\n", type); + return 0; + } + + if( reg->reg_num <= 0 ) + return 0; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db); + + for( i = 0; i < reg->reg_num; ++i ) { + r = ®->reg[i]; + if( r->str[0] != '\0' && r->value[0] != '\0' ) { + char str[32]; + char val[256]; + + if( i > 0 ) + StringBuf_AppendStr(&buf, ","); + + Sql_EscapeString(sql_handle, str, r->str); + Sql_EscapeString(sql_handle, val, r->value); + + StringBuf_Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val); + } + } + + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { + Sql_ShowDebug(sql_handle); + } + + StringBuf_Destroy(&buf); + + return 1; } // Load account_reg from sql (type=2) int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type) { - struct global_reg *r; - char *data; - size_t len; - int i; - - if (reg == NULL) - return 0; - - memset(reg, 0, sizeof(struct accreg)); - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch (type) { - case 3: //char reg - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) - Sql_ShowDebug(sql_handle); - break; - case 2: //account reg - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id)) - Sql_ShowDebug(sql_handle); - break; - case 1: //account2 reg - ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_fromsql: Invalid type %d\n", type); - return 0; - } - for (i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { - r = ®->reg[i]; - // str - Sql_GetData(sql_handle, 0, &data, &len); - memcpy(r->str, data, min(len, sizeof(r->str))); - // value - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(r->value, data, min(len, sizeof(r->value))); - } - reg->reg_num = i; - Sql_FreeResult(sql_handle); - return 1; + struct global_reg* r; + char* data; + size_t len; + int i; + + if( reg == NULL) + return 0; + + memset(reg, 0, sizeof(struct accreg)); + reg->account_id = account_id; + reg->char_id = char_id; + + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch( type ) + { + case 3: //char reg + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + Sql_ShowDebug(sql_handle); + break; + case 2: //account reg + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) + Sql_ShowDebug(sql_handle); + break; + case 1: //account2 reg + ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_fromsql: Invalid type %d\n", type); + return 0; + } + for( i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + r = ®->reg[i]; + // str + Sql_GetData(sql_handle, 0, &data, &len); + memcpy(r->str, data, min(len, sizeof(r->str))); + // value + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(r->value, data, min(len, sizeof(r->value))); + } + reg->reg_num = i; + Sql_FreeResult(sql_handle); + return 1; } // Initialize int inter_accreg_sql_init(void) { - CREATE(accreg_pt, struct accreg, 1); - return 0; + CREATE(accreg_pt, struct accreg, 1); + return 0; } /*========================================== * read config file *------------------------------------------*/ -static int inter_config_read(const char *cfgName) +static int inter_config_read(const char* cfgName) { - int i; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("File not found: %s\n", cfgName); - return 1; - } - - while (fgets(line, sizeof(line), fp)) { - i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); - if (i != 2) - continue; - - if (!strcmpi(w1,"char_server_ip")) { - strcpy(char_server_ip,w2); - } else if (!strcmpi(w1,"char_server_port")) { - char_server_port = atoi(w2); - } else if (!strcmpi(w1,"char_server_id")) { - strcpy(char_server_id,w2); - } else if (!strcmpi(w1,"char_server_pw")) { - strcpy(char_server_pw,w2); - } else if (!strcmpi(w1,"char_server_db")) { - strcpy(char_server_db,w2); - } else if (!strcmpi(w1,"default_codepage")) { - strcpy(default_codepage,w2); - } else if (!strcmpi(w1,"party_share_level")) - party_share_level = atoi(w2); - else if (!strcmpi(w1,"log_inter")) - log_inter = atoi(w2); - else if (!strcmpi(w1,"main_chat_nick")) - safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); - else if (!strcmpi(w1,"import")) - inter_config_read(w2); - } - fclose(fp); - - ShowInfo("Done reading %s.\n", cfgName); - - return 0; + int i; + char line[1024], w1[1024], w2[1024]; + FILE* fp; + + fp = fopen(cfgName, "r"); + if(fp == NULL) { + ShowError("File not found: %s\n", cfgName); + return 1; + } + + while(fgets(line, sizeof(line), fp)) + { + i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); + if(i != 2) + continue; + + if(!strcmpi(w1,"char_server_ip")) { + strcpy(char_server_ip,w2); + } else + if(!strcmpi(w1,"char_server_port")) { + char_server_port = atoi(w2); + } else + if(!strcmpi(w1,"char_server_id")) { + strcpy(char_server_id,w2); + } else + if(!strcmpi(w1,"char_server_pw")) { + strcpy(char_server_pw,w2); + } else + if(!strcmpi(w1,"char_server_db")) { + strcpy(char_server_db,w2); + } else + if(!strcmpi(w1,"default_codepage")) { + strcpy(default_codepage,w2); + } + else if(!strcmpi(w1,"party_share_level")) + party_share_level = atoi(w2); + else if(!strcmpi(w1,"log_inter")) + log_inter = atoi(w2); + else if(!strcmpi(w1,"main_chat_nick")) + safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); + else if(!strcmpi(w1,"import")) + inter_config_read(w2); + } + fclose(fp); + + ShowInfo ("Done reading %s.\n", cfgName); + + return 0; } // Save interlog into sql -int inter_log(char *fmt, ...) +int inter_log(char* fmt, ...) { - char str[255]; - char esc_str[sizeof(str)*2+1];// escaped str - va_list ap; + char str[255]; + char esc_str[sizeof(str)*2+1];// escaped str + va_list ap; - va_start(ap,fmt); - vsnprintf(str, sizeof(str), fmt, ap); - va_end(ap); + va_start(ap,fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); - Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str)) - Sql_ShowDebug(sql_handle); + Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str) ) + Sql_ShowDebug(sql_handle); - return 0; + return 0; } // initialize int inter_init_sql(const char *file) { - //int i; - - inter_config_read(file); - - //DB connection initialized - sql_handle = Sql_Malloc(); - ShowInfo("Connect Character DB server.... (Character Server)\n"); - if (SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db)) { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if (*default_codepage) { - if (SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage)) - Sql_ShowDebug(sql_handle); - } - - wis_db = idb_alloc(DB_OPT_RELEASE_DATA); - inter_guild_sql_init(); - inter_storage_sql_init(); - inter_party_sql_init(); - inter_pet_sql_init(); - inter_homunculus_sql_init(); - inter_mercenary_sql_init(); - inter_elemental_sql_init(); - inter_accreg_sql_init(); - inter_mail_sql_init(); - inter_auction_sql_init(); - - geoip_readdb(); - msg_config_read("conf/msg_athena.conf"); - return 0; + //int i; + + inter_config_read(file); + + //DB connection initialized + sql_handle = Sql_Malloc(); + ShowInfo("Connect Character DB server.... (Character Server)\n"); + if( SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db) ) + { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + + if( *default_codepage ) { + if( SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage) ) + Sql_ShowDebug(sql_handle); + } + + wis_db = idb_alloc(DB_OPT_RELEASE_DATA); + inter_guild_sql_init(); + inter_storage_sql_init(); + inter_party_sql_init(); + inter_pet_sql_init(); + inter_homunculus_sql_init(); + inter_mercenary_sql_init(); + inter_elemental_sql_init(); + inter_accreg_sql_init(); + inter_mail_sql_init(); + inter_auction_sql_init(); + + geoip_readdb(); + msg_config_read("conf/msg_athena.conf"); + return 0; } // finalize void inter_final(void) { - wis_db->destroy(wis_db, NULL); - - inter_guild_sql_final(); - inter_storage_sql_final(); - inter_party_sql_final(); - inter_pet_sql_final(); - inter_homunculus_sql_final(); - inter_mercenary_sql_final(); - inter_elemental_sql_final(); - inter_mail_sql_final(); - inter_auction_sql_final(); - - if (accreg_pt) aFree(accreg_pt); - - do_final_msg(); - return; + wis_db->destroy(wis_db, NULL); + + inter_guild_sql_final(); + inter_storage_sql_final(); + inter_party_sql_final(); + inter_pet_sql_final(); + inter_homunculus_sql_final(); + inter_mercenary_sql_final(); + inter_elemental_sql_final(); + inter_mail_sql_final(); + inter_auction_sql_final(); + + if (accreg_pt) aFree(accreg_pt); + + do_final_msg(); + return; } int inter_mapif_init(int fd) { - return 0; + return 0; } @@ -849,98 +827,99 @@ int inter_mapif_init(int fd) // broadcast sending int mapif_broadcast(unsigned char *mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, int sfd) { - unsigned char *buf = (unsigned char *)aMalloc((len)*sizeof(unsigned char)); - - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = len; - WBUFL(buf,4) = fontColor; - WBUFW(buf,8) = fontType; - WBUFW(buf,10) = fontSize; - WBUFW(buf,12) = fontAlign; - WBUFW(buf,14) = fontY; - memcpy(WBUFP(buf,16), mes, len - 16); - mapif_sendallwos(sfd, buf, len); - - if (buf) - aFree(buf); - return 0; + unsigned char *buf = (unsigned char*)aMalloc((len)*sizeof(unsigned char)); + + WBUFW(buf,0) = 0x3800; + WBUFW(buf,2) = len; + WBUFL(buf,4) = fontColor; + WBUFW(buf,8) = fontType; + WBUFW(buf,10) = fontSize; + WBUFW(buf,12) = fontAlign; + WBUFW(buf,14) = fontY; + memcpy(WBUFP(buf,16), mes, len - 16); + mapif_sendallwos(sfd, buf, len); + + if (buf) + aFree(buf); + return 0; } // Wis sending int mapif_wis_message(struct WisData *wd) { - unsigned char buf[2048]; - if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] - - WBUFW(buf, 0) = 0x3801; - WBUFW(buf, 2) = 56 +wd->len; - WBUFL(buf, 4) = wd->id; - memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); - memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); - memcpy(WBUFP(buf,56), wd->msg, wd->len); - wd->count = mapif_sendall(buf,WBUFW(buf,2)); - - return 0; + unsigned char buf[2048]; + if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] + + WBUFW(buf, 0) = 0x3801; + WBUFW(buf, 2) = 56 +wd->len; + WBUFL(buf, 4) = wd->id; + memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); + memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); + memcpy(WBUFP(buf,56), wd->msg, wd->len); + wd->count = mapif_sendall(buf,WBUFW(buf,2)); + + return 0; } // Wis sending result int mapif_wis_end(struct WisData *wd, int flag) { - unsigned char buf[27]; + unsigned char buf[27]; - WBUFW(buf, 0)=0x3802; - memcpy(WBUFP(buf, 2),wd->src,24); - WBUFB(buf,26)=flag; - mapif_send(wd->fd,buf,27); - return 0; + WBUFW(buf, 0)=0x3802; + memcpy(WBUFP(buf, 2),wd->src,24); + WBUFB(buf,26)=flag; + mapif_send(wd->fd,buf,27); + return 0; } // Account registry transfer to map-server static void mapif_account_reg(int fd, unsigned char *src) { - WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO - mapif_sendallwos(fd, src, WBUFW(src,2)); + WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO + mapif_sendallwos(fd, src, WBUFW(src,2)); } // Send the requested account_reg int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) { - struct accreg *reg=accreg_pt; - WFIFOHEAD(fd, 13 + 5000); - inter_accreg_fromsql(account_id,char_id,reg,type); - - WFIFOW(fd,0)=0x3804; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=char_id; - WFIFOB(fd,12)=type; - if (reg->reg_num==0) { - WFIFOW(fd,2)=13; - } else { - int i,p; - for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { - p+= sprintf((char *)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char *)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; - } - WFIFOW(fd,2)=p; - if (p>= 5000) - ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; + struct accreg *reg=accreg_pt; + WFIFOHEAD(fd, 13 + 5000); + inter_accreg_fromsql(account_id,char_id,reg,type); + + WFIFOW(fd,0)=0x3804; + WFIFOL(fd,4)=account_id; + WFIFOL(fd,8)=char_id; + WFIFOB(fd,12)=type; + if(reg->reg_num==0){ + WFIFOW(fd,2)=13; + }else{ + int i,p; + for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { + p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. + p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; + } + WFIFOW(fd,2)=p; + if (p>= 5000) + ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); + } + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; } //Request to kick char from a certain map server. [Skotlex] int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) { - if (fd >= 0) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b1f; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = reason; - WFIFOSET(fd,7); - return 0; - } - return -1; + if (fd >= 0) + { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b1f; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = reason; + WFIFOSET(fd,7); + return 0; + } + return -1; } //-------------------------------------------------------- @@ -951,34 +930,34 @@ int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) */ int check_ttl_wisdata_sub(DBKey key, DBData *data, va_list ap) { - unsigned long tick; - struct WisData *wd = db_data2ptr(data); - tick = va_arg(ap, unsigned long); + unsigned long tick; + struct WisData *wd = db_data2ptr(data); + tick = va_arg(ap, unsigned long); - if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) - wis_dellist[wis_delnum++] = wd->id; + if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) + wis_dellist[wis_delnum++] = wd->id; - return 0; + return 0; } int check_ttl_wisdata(void) { - unsigned long tick = gettick(); - int i; - - do { - wis_delnum = 0; - wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); - for (i = 0; i < wis_delnum; i++) { - struct WisData *wd = (struct WisData *)idb_get(wis_db, wis_dellist[i]); - ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); - // removed. not send information after a timeout. Just no answer for the player - //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, wd->id); - } - } while (wis_delnum >= WISDELLIST_MAX); - - return 0; + unsigned long tick = gettick(); + int i; + + do { + wis_delnum = 0; + wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); + for(i = 0; i < wis_delnum; i++) { + struct WisData *wd = (struct WisData*)idb_get(wis_db, wis_dellist[i]); + ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); + // removed. not send information after a timeout. Just no answer for the player + //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, wd->id); + } + } while(wis_delnum >= WISDELLIST_MAX); + + return 0; } //-------------------------------------------------------- @@ -986,206 +965,209 @@ int check_ttl_wisdata(void) // broadcast sending int mapif_parse_broadcast(int fd) { - mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); - return 0; + mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); + return 0; } // Wisp/page request to send int mapif_parse_WisRequest(int fd) { - struct WisData *wd; - static int wisid = 0; - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1];// escaped name - char *data; - size_t len; - - - if (fd <= 0) { - return 0; // check if we have a valid fd - } - - if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { - ShowWarning("inter: Wis message size too long.\n"); - return 0; - } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... - ShowError("inter: Wis message doesn't exist.\n"); - return 0; - } - - safestrncpy(name, (char *)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name)) - Sql_ShowDebug(sql_handle); - - // search if character exists before to ask all map-servers - if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { - unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } else { - // Character exists. So, ask all map-servers - // to be sure of the correct name, rewrite it - Sql_GetData(sql_handle, 0, &data, &len); - memset(name, 0, NAME_LENGTH); - memcpy(name, data, min(len, NAME_LENGTH)); - // if source is destination, don't ask other servers. - if (strncmp((const char *)RFIFOP(fd,4), name, NAME_LENGTH) == 0) { - uint8 buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } else { - - CREATE(wd, struct WisData, 1); - - // Whether the failure of previous wisp/page transmission (timeout) - check_ttl_wisdata(); - - wd->id = ++wisid; - wd->fd = fd; - wd->len= RFIFOW(fd,2)-52; - memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); - memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); - memcpy(wd->msg, RFIFOP(fd,52), wd->len); - wd->tick = gettick(); - idb_put(wis_db, wd->id, wd); - mapif_wis_message(wd); - } - } - - Sql_FreeResult(sql_handle); - return 0; + struct WisData* wd; + static int wisid = 0; + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1];// escaped name + char* data; + size_t len; + + + if ( fd <= 0 ) {return 0;} // check if we have a valid fd + + if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { + ShowWarning("inter: Wis message size too long.\n"); + return 0; + } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... + ShowError("inter: Wis message doesn't exist.\n"); + return 0; + } + + safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] + + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) + Sql_ShowDebug(sql_handle); + + // search if character exists before to ask all map-servers + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + unsigned char buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } + else + {// Character exists. So, ask all map-servers + // to be sure of the correct name, rewrite it + Sql_GetData(sql_handle, 0, &data, &len); + memset(name, 0, NAME_LENGTH); + memcpy(name, data, min(len, NAME_LENGTH)); + // if source is destination, don't ask other servers. + if( strncmp((const char*)RFIFOP(fd,4), name, NAME_LENGTH) == 0 ) + { + uint8 buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } + else + { + + CREATE(wd, struct WisData, 1); + + // Whether the failure of previous wisp/page transmission (timeout) + check_ttl_wisdata(); + + wd->id = ++wisid; + wd->fd = fd; + wd->len= RFIFOW(fd,2)-52; + memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); + memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); + memcpy(wd->msg, RFIFOP(fd,52), wd->len); + wd->tick = gettick(); + idb_put(wis_db, wd->id, wd); + mapif_wis_message(wd); + } + } + + Sql_FreeResult(sql_handle); + return 0; } // Wisp/page transmission result int mapif_parse_WisReply(int fd) { - int id, flag; - struct WisData *wd; + int id, flag; + struct WisData *wd; - id = RFIFOL(fd,2); - flag = RFIFOB(fd,6); - wd = (struct WisData *)idb_get(wis_db, id); - if (wd == NULL) - return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server + id = RFIFOL(fd,2); + flag = RFIFOB(fd,6); + wd = (struct WisData*)idb_get(wis_db, id); + if (wd == NULL) + return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server - if ((--wd->count) <= 0 || flag != 1) { - mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, id); - } + if ((--wd->count) <= 0 || flag != 1) { + mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, id); + } - return 0; + return 0; } // Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) int mapif_parse_WisToGM(int fd) { - unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B + unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B - memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf, 0) = 0x3803; - mapif_sendall(buf, RFIFOW(fd,2)); + memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf, 0) = 0x3803; + mapif_sendall(buf, RFIFOW(fd,2)); - return 0; + return 0; } // Save account_reg into sql (type=2) int mapif_parse_Registry(int fd) { - int j,p,len, max; - struct accreg *reg=accreg_pt; - - memset(accreg_pt,0,sizeof(struct accreg)); - switch (RFIFOB(fd, 12)) { - case 3: //Character registry - max = GLOBAL_REG_NUM; - break; - case 2: //Account Registry - max = ACCOUNT_REG_NUM; - break; - case 1: //Account2 registry, must be sent over to login server. - return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); - default: - return 1; - } - for (j=0,p=13; jreg[j].str,&len); - reg->reg[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char *)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); - reg->reg[j].value[len]='\0'; - p +=len+1; - } - reg->reg_num=j; - - inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); - mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. - return 0; + int j,p,len, max; + struct accreg *reg=accreg_pt; + + memset(accreg_pt,0,sizeof(struct accreg)); + switch (RFIFOB(fd, 12)) { + case 3: //Character registry + max = GLOBAL_REG_NUM; + break; + case 2: //Account Registry + max = ACCOUNT_REG_NUM; + break; + case 1: //Account2 registry, must be sent over to login server. + return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); + default: + return 1; + } + for(j=0,p=13;jreg[j].str,&len); + reg->reg[j].str[len]='\0'; + p +=len+1; //+1 to skip the '\0' between strings. + sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); + reg->reg[j].value[len]='\0'; + p +=len+1; + } + reg->reg_num=j; + + inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); + mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. + return 0; } // Request the value of all registries. int mapif_parse_RegistryRequest(int fd) { - //Load Char Registry - if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); - //Load Account Registry - if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); - //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); - return 1; + //Load Char Registry + if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); + //Load Account Registry + if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); + //Ask Login Server for Account2 values. + if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); + return 1; } static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name) { - WFIFOHEAD(fd, NAME_LENGTH+13); - WFIFOW(fd, 0) = 0x3806; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = type; - WFIFOB(fd,11) = flag; - memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+13); + WFIFOHEAD(fd, NAME_LENGTH+13); + WFIFOW(fd, 0) = 0x3806; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = type; + WFIFOB(fd,11) = flag; + memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+13); } int mapif_parse_NameChangeRequest(int fd) { - int account_id, char_id, type; - char *name; - int i; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - type = RFIFOB(fd,10); - name = (char *)RFIFOP(fd,11); - - // Check Authorised letters/symbols in the name - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } - //TODO: type holds the type of object to rename. - //If it were a player, it needs to have the guild information and db information - //updated here, because changing it on the map won't make it be saved [Skotlex] - - //name allowed. - mapif_namechange_ack(fd, account_id, char_id, type, 1, name); - return 0; + int account_id, char_id, type; + char* name; + int i; + + account_id = RFIFOL(fd,2); + char_id = RFIFOL(fd,6); + type = RFIFOB(fd,10); + name = (char*)RFIFOP(fd,11); + + // Check Authorised letters/symbols in the name + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } + //TODO: type holds the type of object to rename. + //If it were a player, it needs to have the guild information and db information + //updated here, because changing it on the map won't make it be saved [Skotlex] + + //name allowed. + mapif_namechange_ack(fd, account_id, char_id, type, 1, name); + return 0; } //-------------------------------------------------------- @@ -1196,75 +1178,59 @@ int mapif_parse_NameChangeRequest(int fd) /// @param length The minimum allowed length, or -1 for dynamic lookup int inter_check_length(int fd, int length) { - if (length == -1) { - // variable-length packet - if (RFIFOREST(fd) < 4) - return 0; - length = RFIFOW(fd,2); - } + if( length == -1 ) + {// variable-length packet + if( RFIFOREST(fd) < 4 ) + return 0; + length = RFIFOW(fd,2); + } - if ((int)RFIFOREST(fd) < length) - return 0; + if( (int)RFIFOREST(fd) < length ) + return 0; - return length; + return length; } int inter_parse_frommap(int fd) { - int cmd; - int len = 0; - cmd = RFIFOW(fd,0); - // Check is valid packet entry - if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) - return 0; - - // Check packet length - if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; - - switch (cmd) { - case 0x3000: - mapif_parse_broadcast(fd); - break; - case 0x3001: - mapif_parse_WisRequest(fd); - break; - case 0x3002: - mapif_parse_WisReply(fd); - break; - case 0x3003: - mapif_parse_WisToGM(fd); - break; - case 0x3004: - mapif_parse_Registry(fd); - break; - case 0x3005: - mapif_parse_RegistryRequest(fd); - break; - case 0x3006: - mapif_parse_NameChangeRequest(fd); - break; - case 0x3007: - mapif_parse_accinfo(fd); - break; - /* 0x3008 is used by the report stuff */ - default: - if (inter_party_parse_frommap(fd) - || inter_guild_parse_frommap(fd) - || inter_storage_parse_frommap(fd) - || inter_pet_parse_frommap(fd) - || inter_homunculus_parse_frommap(fd) - || inter_mercenary_parse_frommap(fd) - || inter_elemental_parse_frommap(fd) - || inter_mail_parse_frommap(fd) - || inter_auction_parse_frommap(fd) - || inter_quest_parse_frommap(fd) - ) - break; - else - return 0; - } - - RFIFOSKIP(fd, len); - return 1; + int cmd; + int len = 0; + cmd = RFIFOW(fd,0); + // Check is valid packet entry + if(cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) + return 0; + + // Check packet length + if((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) + return 2; + + switch(cmd) { + case 0x3000: mapif_parse_broadcast(fd); break; + case 0x3001: mapif_parse_WisRequest(fd); break; + case 0x3002: mapif_parse_WisReply(fd); break; + case 0x3003: mapif_parse_WisToGM(fd); break; + case 0x3004: mapif_parse_Registry(fd); break; + case 0x3005: mapif_parse_RegistryRequest(fd); break; + case 0x3006: mapif_parse_NameChangeRequest(fd); break; + case 0x3007: mapif_parse_accinfo(fd); break; + /* 0x3008 is used by the report stuff */ + default: + if( inter_party_parse_frommap(fd) + || inter_guild_parse_frommap(fd) + || inter_storage_parse_frommap(fd) + || inter_pet_parse_frommap(fd) + || inter_homunculus_parse_frommap(fd) + || inter_mercenary_parse_frommap(fd) + || inter_elemental_parse_frommap(fd) + || inter_mail_parse_frommap(fd) + || inter_auction_parse_frommap(fd) + || inter_quest_parse_frommap(fd) + ) + break; + else + return 0; + } + + RFIFOSKIP(fd, len); + return 1; } diff --git a/src/char/inter.h b/src/char/inter.h index 199d70bb4..ac2e1785f 100644 --- a/src/char/inter.h +++ b/src/char/inter.h @@ -20,8 +20,8 @@ int inter_log(char *fmt,...); extern unsigned int party_share_level; -extern Sql *sql_handle; -extern Sql *lsql_handle; +extern Sql* sql_handle; +extern Sql* lsql_handle; extern char main_chat_nick[16]; diff --git a/src/common/atomic.h b/src/common/atomic.h index a7e953db2..b1a4bda92 100644 --- a/src/common/atomic.h +++ b/src/common/atomic.h @@ -4,16 +4,16 @@ #ifndef _rA_ATOMIC_H_ #define _rA_ATOMIC_H_ -// Atomic Operations +// Atomic Operations // (Interlocked CompareExchange, Add .. and so on ..) -// +// // Implementation varies / depends on: -// - Architecture -// - Compiler -// - Operating System +// - Architecture +// - Compiler +// - Operating System // // our Abstraction is fully API-Compatible to Microsofts implementation @ NT5.0+ -// +// #include "../common/cbasetypes.h" #if defined(_MSC_VER) @@ -22,65 +22,60 @@ #if !defined(_M_X64) // When compiling for windows 32bit, the 8byte interlocked operations are not provided by microsoft // (because they need at least i586 so its not generic enough.. ... ) -forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp) -{ - _asm { - lea esi,_cmp; - lea edi,exch; - - mov eax,[esi]; - mov edx,4[esi]; - mov ebx,[edi]; - mov ecx,4[edi]; - mov esi,dest; - - lock CMPXCHG8B [esi]; - } +forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp){ + _asm{ + lea esi,_cmp; + lea edi,exch; + + mov eax,[esi]; + mov edx,4[esi]; + mov ebx,[edi]; + mov ecx,4[edi]; + mov esi,dest; + + lock CMPXCHG8B [esi]; + } } -forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend) -{ - __int64 old; - do { - old = *addend; - } while (InterlockedCompareExchange64(addend, (old+1), old) != old); +forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend){ + __int64 old; + do{ + old = *addend; + }while(InterlockedCompareExchange64(addend, (old+1), old) != old); - return (old + 1); + return (old + 1); } -forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend) -{ - __int64 old; +forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend){ + __int64 old; - do { - old = *addend; - } while (InterlockedCompareExchange64(addend, (old-1), old) != old); + do{ + old = *addend; + }while(InterlockedCompareExchange64(addend, (old-1), old) != old); - return (old - 1); + return (old - 1); } -forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment) -{ - __int64 old; +forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){ + __int64 old; - do { - old = *addend; - } while (InterlockedCompareExchange64(addend, (old + increment), old) != old); + do{ + old = *addend; + }while(InterlockedCompareExchange64(addend, (old + increment), old) != old); - return old; + return old; } -forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val) -{ - __int64 old; - do { - old = *target; - } while (InterlockedCompareExchange64(target, val, old) != old); +forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val){ + __int64 old; + do{ + old = *target; + }while(InterlockedCompareExchange64(target, val, old) != old); - return old; + return old; } #endif //endif 32bit windows @@ -91,62 +86,52 @@ forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 v #error Your Target Platfrom is not supported #endif -static forceinline int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment) -{ - return __sync_fetch_and_add(addend, increment); +static forceinline int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){ + return __sync_fetch_and_add(addend, increment); }//end: InterlockedExchangeAdd64() -static forceinline int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment) -{ - return __sync_fetch_and_add(addend, increment); +static forceinline int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment){ + return __sync_fetch_and_add(addend, increment); }//end: InterlockedExchangeAdd() -static forceinline int64 InterlockedIncrement64(volatile int64 *addend) -{ - return __sync_add_and_fetch(addend, 1); +static forceinline int64 InterlockedIncrement64(volatile int64 *addend){ + return __sync_add_and_fetch(addend, 1); }//end: InterlockedIncrement64() -static forceinline int32 InterlockedIncrement(volatile int32 *addend) -{ - return __sync_add_and_fetch(addend, 1); +static forceinline int32 InterlockedIncrement(volatile int32 *addend){ + return __sync_add_and_fetch(addend, 1); }//end: InterlockedIncrement() -static forceinline int64 InterlockedDecrement64(volatile int64 *addend) -{ - return __sync_sub_and_fetch(addend, 1); +static forceinline int64 InterlockedDecrement64(volatile int64 *addend){ + return __sync_sub_and_fetch(addend, 1); }//end: InterlockedDecrement64() -static forceinline int32 InterlockedDecrement(volatile int32 *addend) -{ - return __sync_sub_and_fetch(addend, 1); +static forceinline int32 InterlockedDecrement(volatile int32 *addend){ + return __sync_sub_and_fetch(addend, 1); }//end: InterlockedDecrement() -static forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp) -{ - return __sync_val_compare_and_swap(dest, cmp, exch); +static forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp){ + return __sync_val_compare_and_swap(dest, cmp, exch); }//end: InterlockedCompareExchange64() -static forceinline int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp) -{ - return __sync_val_compare_and_swap(dest, cmp, exch); +static forceinline int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp){ + return __sync_val_compare_and_swap(dest, cmp, exch); }//end: InterlockedCompareExchnage() -static forceinline int64 InterlockedExchange64(volatile int64 *target, int64 val) -{ - return __sync_lock_test_and_set(target, val); +static forceinline int64 InterlockedExchange64(volatile int64 *target, int64 val){ + return __sync_lock_test_and_set(target, val); }//end: InterlockedExchange64() -static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val) -{ +static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val){ return __sync_lock_test_and_set(target, val); }//end: InterlockedExchange() diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index a47a7434f..731a8b578 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -59,11 +59,11 @@ // debug function name #ifndef __NETBSD__ #if __STDC_VERSION__ < 199901L -# if __GNUC__ >= 2 -# define __func__ __FUNCTION__ -# else -# define __func__ "" -# endif +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif #endif #endif @@ -106,56 +106,56 @@ // Integers with guaranteed _exact_ size. ////////////////////////////////////////////////////////////////////////// -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; -typedef int64_t int64; +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; -typedef int8_t sint8; -typedef int16_t sint16; -typedef int32_t sint32; -typedef int64_t sint64; +typedef int8_t sint8; +typedef int16_t sint16; +typedef int32_t sint32; +typedef int64_t sint64; -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; #undef UINT8_MIN #undef UINT16_MIN #undef UINT32_MIN #undef UINT64_MIN -#define UINT8_MIN ((uint8) UINT8_C(0x00)) -#define UINT16_MIN ((uint16)UINT16_C(0x0000)) -#define UINT32_MIN ((uint32)UINT32_C(0x00000000)) -#define UINT64_MIN ((uint64)UINT64_C(0x0000000000000000)) +#define UINT8_MIN ((uint8) UINT8_C(0x00)) +#define UINT16_MIN ((uint16)UINT16_C(0x0000)) +#define UINT32_MIN ((uint32)UINT32_C(0x00000000)) +#define UINT64_MIN ((uint64)UINT64_C(0x0000000000000000)) #undef UINT8_MAX #undef UINT16_MAX #undef UINT32_MAX #undef UINT64_MAX -#define UINT8_MAX ((uint8) UINT8_C(0xFF)) -#define UINT16_MAX ((uint16)UINT16_C(0xFFFF)) -#define UINT32_MAX ((uint32)UINT32_C(0xFFFFFFFF)) -#define UINT64_MAX ((uint64)UINT64_C(0xFFFFFFFFFFFFFFFF)) +#define UINT8_MAX ((uint8) UINT8_C(0xFF)) +#define UINT16_MAX ((uint16)UINT16_C(0xFFFF)) +#define UINT32_MAX ((uint32)UINT32_C(0xFFFFFFFF)) +#define UINT64_MAX ((uint64)UINT64_C(0xFFFFFFFFFFFFFFFF)) #undef SINT8_MIN #undef SINT16_MIN #undef SINT32_MIN #undef SINT64_MIN -#define SINT8_MIN ((sint8) INT8_C(0x80)) -#define SINT16_MIN ((sint16)INT16_C(0x8000)) -#define SINT32_MIN ((sint32)INT32_C(0x80000000)) -#define SINT64_MIN ((sint32)INT64_C(0x8000000000000000)) +#define SINT8_MIN ((sint8) INT8_C(0x80)) +#define SINT16_MIN ((sint16)INT16_C(0x8000)) +#define SINT32_MIN ((sint32)INT32_C(0x80000000)) +#define SINT64_MIN ((sint32)INT64_C(0x8000000000000000)) #undef SINT8_MAX #undef SINT16_MAX #undef SINT32_MAX #undef SINT64_MAX -#define SINT8_MAX ((sint8) INT8_C(0x7F)) -#define SINT16_MAX ((sint16)INT16_C(0x7FFF)) -#define SINT32_MAX ((sint32)INT32_C(0x7FFFFFFF)) -#define SINT64_MAX ((sint64)INT64_C(0x7FFFFFFFFFFFFFFF)) +#define SINT8_MAX ((sint8) INT8_C(0x7F)) +#define SINT16_MAX ((sint16)INT16_C(0x7FFF)) +#define SINT32_MAX ((sint32)INT32_C(0x7FFFFFFF)) +#define SINT64_MAX ((sint64)INT64_C(0x7FFFFFFFFFFFFFFF)) ////////////////////////////////////////////////////////////////////////// // Integers with guaranteed _minimum_ size. @@ -180,10 +180,10 @@ typedef unsigned long int ppuint32; #if defined(WIN32) && !defined(MINGW) // does not have a signed size_t ////////////////////////////// -#if defined(_WIN64) // naive 64bit windows platform -typedef __int64 ssize_t; +#if defined(_WIN64) // naive 64bit windows platform +typedef __int64 ssize_t; #else -typedef int ssize_t; +typedef int ssize_t; #endif ////////////////////////////// #endif @@ -201,23 +201,23 @@ typedef uintptr_t uintptr; // Add a 'sysint' Type which has the width of the platform we're compiled for. ////////////////////////////////////////////////////////////////////////// #if defined(__GNUC__) -#if defined(__x86_64__) -typedef int64 sysint; -typedef uint64 usysint; -#else -typedef int32 sysint; -typedef uint32 usysint; -#endif + #if defined(__x86_64__) + typedef int64 sysint; + typedef uint64 usysint; + #else + typedef int32 sysint; + typedef uint32 usysint; + #endif #elif defined(_MSC_VER) -#if defined(_M_X64) -typedef int64 sysint; -typedef uint64 usysint; -#else -typedef int32 sysint; -typedef uint32 usysint; -#endif + #if defined(_M_X64) + typedef int64 sysint; + typedef uint64 usysint; + #else + typedef int32 sysint; + typedef uint32 usysint; + #endif #else -#error Compiler / Platform is unsupported. + #error Compiler / Platform is unsupported. #endif @@ -225,21 +225,21 @@ typedef uint32 usysint; // some redefine of function redefines for some Compilers ////////////////////////////////////////////////////////////////////////// #if defined(_MSC_VER) || defined(__BORLANDC__) -#define strcasecmp stricmp -#define strncasecmp strnicmp -#define strncmpi strnicmp -#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +#define strncmpi strnicmp +#define snprintf _snprintf #if defined(_MSC_VER) && _MSC_VER < 1400 -#define vsnprintf _vsnprintf +#define vsnprintf _vsnprintf #endif #else -#define strcmpi strcasecmp -#define stricmp strcasecmp -#define strncmpi strncasecmp -#define strnicmp strncasecmp +#define strcmpi strcasecmp +#define stricmp strcasecmp +#define strncmpi strncasecmp +#define strnicmp strncasecmp #endif #if defined(_MSC_VER) && _MSC_VER > 1200 -#define strtoull _strtoui64 +#define strtoull _strtoui64 #endif // keyword replacement @@ -262,8 +262,8 @@ typedef uint32 usysint; // boolean types for C typedef char bool; -#define false (1==0) -#define true (1==1) +#define false (1==0) +#define true (1==1) ////////////////////////////// #endif // not __cplusplus @@ -276,7 +276,7 @@ typedef char bool; #undef swap #endif // hmm only ints? -//#define swap(a,b) { int temp=a; a=b; b=temp;} +//#define swap(a,b) { int temp=a; a=b; b=temp;} // if using macros then something that is type independent //#define swap(a,b) ((a == b) || ((a ^= b), (b ^= a), (a ^= b))) // Avoid "value computed is not used" warning and generates the same assembly code @@ -299,7 +299,7 @@ typedef char bool; ////////////////////////////////////////////////////////////////////////// // number of bits in a byte #ifndef NBBY -#define NBBY 8 +#define NBBY 8 #endif ////////////////////////////////////////////////////////////////////////// @@ -383,20 +383,17 @@ typedef char bool; // Set a pointer variable to a pointer value. #ifdef __cplusplus template -void SET_POINTER(T1 *&var, T2 *p) +void SET_POINTER(T1*&var, T2* p) { - var = static_cast(p); + var = static_cast(p); } template -void SET_FUNCPOINTER(T1 &var, T2 p) +void SET_FUNCPOINTER(T1& var, T2 p) { - char ASSERT_POINTERSIZE[sizeof(T1) == sizeof(void *) && sizeof(T2) == sizeof(void *)?1:-1]; // 1 if true, -1 if false - union { - T1 out; - T2 in; - } tmp;// /!\ WARNING casting a pointer to a function pointer is against the C++ standard - tmp.in = p; - var = tmp.out; + char ASSERT_POINTERSIZE[sizeof(T1) == sizeof(void*) && sizeof(T2) == sizeof(void*)?1:-1];// 1 if true, -1 if false + union{ T1 out; T2 in; } tmp;// /!\ WARNING casting a pointer to a function pointer is against the C++ standard + tmp.in = p; + var = tmp.out; } #else #define SET_POINTER(var,p) (var) = (p) diff --git a/src/common/conf.c b/src/common/conf.c index 2027b4b09..3057bd4dc 100644 --- a/src/common/conf.c +++ b/src/common/conf.c @@ -8,14 +8,14 @@ int conf_read_file(config_t *config, const char *config_filename) { - config_init(config); - if (!config_read_file(config, config_filename)) { - ShowError("%s:%d - %s\n", config_error_file(config), - config_error_line(config), config_error_text(config)); - config_destroy(config); - return 1; - } - return 0; + config_init(config); + if (!config_read_file(config, config_filename)) { + ShowError("%s:%d - %s\n", config_error_file(config), + config_error_line(config), config_error_text(config)); + config_destroy(config); + return 1; + } + return 0; } // @@ -28,81 +28,82 @@ int config_setting_copy(config_setting_t *parent, const config_setting_t *src); void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src) { - if (config_setting_is_aggregate(src)) { - config_setting_copy_aggregate(parent, src); - } else { - config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); - - if (set == NULL) - return; - - if (CONFIG_TYPE_INT == config_setting_type(src)) { - config_setting_set_int(set, config_setting_get_int(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { - config_setting_set_int64(set, config_setting_get_int64(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { - config_setting_set_float(set, config_setting_get_float(src)); - } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { - config_setting_set_string(set, config_setting_get_string(src)); - } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { - config_setting_set_bool(set, config_setting_get_bool(src)); - } - } + if (config_setting_is_aggregate(src)) { + config_setting_copy_aggregate(parent, src); + } + else { + config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); + + if (set == NULL) + return; + + if (CONFIG_TYPE_INT == config_setting_type(src)) { + config_setting_set_int(set, config_setting_get_int(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { + config_setting_set_int64(set, config_setting_get_int64(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { + config_setting_set_float(set, config_setting_get_float(src)); + } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { + config_setting_set_string(set, config_setting_get_string(src)); + } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { + config_setting_set_bool(set, config_setting_get_bool(src)); + } + } } void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src) { - config_setting_t *set = NULL; - - if (config_setting_is_aggregate(src)) - config_setting_copy_aggregate(parent, src); - else if (CONFIG_TYPE_INT == config_setting_type(src)) { - set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { - set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { - config_setting_set_float_elem(parent, -1, config_setting_get_float(src)); - } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { - config_setting_set_string_elem(parent, -1, config_setting_get_string(src)); - } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { - config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src)); - } + config_setting_t *set = NULL; + + if (config_setting_is_aggregate(src)) + config_setting_copy_aggregate(parent, src); + else if (CONFIG_TYPE_INT == config_setting_type(src)) { + set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { + set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { + config_setting_set_float_elem(parent, -1, config_setting_get_float(src)); + } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { + config_setting_set_string_elem(parent, -1, config_setting_get_string(src)); + } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { + config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src)); + } } void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src) { - config_setting_t *newAgg; - int i, n; - - newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); - - if (newAgg == NULL) - return; - - n = config_setting_length(src); - - for (i = 0; i < n; i++) { - if (config_setting_is_group(src)) { - config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); - } else { - config_setting_copy_elem(newAgg, config_setting_get_elem(src, i)); - } - } + config_setting_t *newAgg; + int i, n; + + newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); + + if (newAgg == NULL) + return; + + n = config_setting_length(src); + + for (i = 0; i < n; i++) { + if (config_setting_is_group(src)) { + config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); + } else { + config_setting_copy_elem(newAgg, config_setting_get_elem(src, i)); + } + } } int config_setting_copy(config_setting_t *parent, const config_setting_t *src) { - if (!config_setting_is_group(parent) && !config_setting_is_list(parent)) - return CONFIG_FALSE; - - if (config_setting_is_aggregate(src)) { - config_setting_copy_aggregate(parent, src); - } else { - config_setting_copy_simple(parent, src); - } - return CONFIG_TRUE; + if (!config_setting_is_group(parent) && !config_setting_is_list(parent)) + return CONFIG_FALSE; + + if (config_setting_is_aggregate(src)) { + config_setting_copy_aggregate(parent, src); + } else { + config_setting_copy_simple(parent, src); + } + return CONFIG_TRUE; } diff --git a/src/common/core.c b/src/common/core.c index efab15dcb..e1f99885b 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -28,7 +28,7 @@ void (*shutdown_callback)(void) = NULL; #if defined(BUILDBOT) -int buildbotflag = 0; + int buildbotflag = 0; #endif int runflag = CORE_ST_RUN; @@ -38,14 +38,14 @@ char **arg_v = NULL; char *SERVER_NAME = NULL; char SERVER_TYPE = ATHENA_SERVER_NONE; -#ifndef MINICORE // minimalist Core +#ifndef MINICORE // minimalist Core // Added by Gabuzomeu // // This is an implementation of signal() using sigaction() for portability. // (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced // Programming in the UNIX Environment_. // -#ifdef WIN32 // windows don't have SIGPIPE +#ifdef WIN32 // windows don't have SIGPIPE #define SIGPIPE SIGINT #endif @@ -54,225 +54,229 @@ char SERVER_TYPE = ATHENA_SERVER_NONE; #else sigfunc *compat_signal(int signo, sigfunc *func) { - struct sigaction sact, oact; + struct sigaction sact, oact; - sact.sa_handler = func; - sigemptyset(&sact.sa_mask); - sact.sa_flags = 0; + sact.sa_handler = func; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; #ifdef SA_INTERRUPT - sact.sa_flags |= SA_INTERRUPT; /* SunOS */ + sact.sa_flags |= SA_INTERRUPT; /* SunOS */ #endif - if (sigaction(signo, &sact, &oact) < 0) - return (SIG_ERR); + if (sigaction(signo, &sact, &oact) < 0) + return (SIG_ERR); - return (oact.sa_handler); + return (oact.sa_handler); } #endif /*====================================== - * CORE : Console events for Windows + * CORE : Console events for Windows *--------------------------------------*/ #ifdef _WIN32 static BOOL WINAPI console_handler(DWORD c_event) { - switch (c_event) { - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - if (shutdown_callback != NULL) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - default: - return FALSE; + switch(c_event) + { + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + if( shutdown_callback != NULL ) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + default: + return FALSE; } return TRUE; } static void cevents_init() { - if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE) - ShowWarning("Unable to install the console handler!\n"); + if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE) + ShowWarning ("Unable to install the console handler!\n"); } #endif /*====================================== - * CORE : Signal Sub Function + * CORE : Signal Sub Function *--------------------------------------*/ static void sig_proc(int sn) { - static int is_called = 0; - - switch (sn) { - case SIGINT: - case SIGTERM: - if (++is_called > 3) - exit(EXIT_SUCCESS); - if (shutdown_callback != NULL) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - case SIGSEGV: - case SIGFPE: - do_abort(); - // Pass the signal to the system's default handler - compat_signal(sn, SIG_DFL); - raise(sn); - break; + static int is_called = 0; + + switch (sn) { + case SIGINT: + case SIGTERM: + if (++is_called > 3) + exit(EXIT_SUCCESS); + if( shutdown_callback != NULL ) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + case SIGSEGV: + case SIGFPE: + do_abort(); + // Pass the signal to the system's default handler + compat_signal(sn, SIG_DFL); + raise(sn); + break; #ifndef _WIN32 - case SIGXFSZ: - // ignore and allow it to set errno to EFBIG - ShowWarning("Max file size reached!\n"); - //run_flag = 0; // should we quit? - break; - case SIGPIPE: - //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c - break; // does nothing here + case SIGXFSZ: + // ignore and allow it to set errno to EFBIG + ShowWarning ("Max file size reached!\n"); + //run_flag = 0; // should we quit? + break; + case SIGPIPE: + //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c + break; // does nothing here #endif - } + } } -void signals_init(void) +void signals_init (void) { - compat_signal(SIGTERM, sig_proc); - compat_signal(SIGINT, sig_proc); + compat_signal(SIGTERM, sig_proc); + compat_signal(SIGINT, sig_proc); #ifndef _DEBUG // need unhandled exceptions to debug on Windows - compat_signal(SIGSEGV, sig_proc); - compat_signal(SIGFPE, sig_proc); + compat_signal(SIGSEGV, sig_proc); + compat_signal(SIGFPE, sig_proc); #endif #ifndef _WIN32 - compat_signal(SIGILL, SIG_DFL); - compat_signal(SIGXFSZ, sig_proc); - compat_signal(SIGPIPE, sig_proc); - compat_signal(SIGBUS, SIG_DFL); - compat_signal(SIGTRAP, SIG_DFL); + compat_signal(SIGILL, SIG_DFL); + compat_signal(SIGXFSZ, sig_proc); + compat_signal(SIGPIPE, sig_proc); + compat_signal(SIGBUS, SIG_DFL); + compat_signal(SIGTRAP, SIG_DFL); #endif } #endif #ifdef SVNVERSION -const char *get_svn_revision(void) -{ - return EXPAND_AND_QUOTE(SVNVERSION); -} + const char *get_svn_revision(void) + { + return EXPAND_AND_QUOTE(SVNVERSION); + } #else// not SVNVERSION -const char *get_svn_revision(void) +const char* get_svn_revision(void) { - static char svn_version_buffer[16] = ""; - FILE *fp; - - if (svn_version_buffer[0] != '\0') - return svn_version_buffer; - - // subversion 1.7 uses a sqlite3 database - // FIXME this is hackish at best... - // - ignores database file structure - // - assumes the data in NODES.dav_cache column ends with "!svn/ver//)" - // - since it's a cache column, the data might not even exist - if ((fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL) { -#ifndef SVNNODEPATH - //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up -#define SVNNODEPATH trunk -#endif - const char *prefix = "!svn/ver/"; - const char *postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this - size_t prefix_len = strlen(prefix); - size_t postfix_len = strlen(postfix); - size_t i,j,len; - char *buffer; - - // read file to buffer - fseek(fp, 0, SEEK_END); - len = ftell(fp); - buffer = (char *)aMalloc(len + 1); - fseek(fp, 0, SEEK_SET); - len = fread(buffer, 1, len, fp); - buffer[len] = '\0'; - fclose(fp); - - // parse buffer - for (i = prefix_len + 1; i + postfix_len <= len; ++i) { - if (buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0) - continue; // postfix missmatch - for (j = i; j > 0; --j) { - // skip digits - if (!ISDIGIT(buffer[j - 1])) - break; - } - if (memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0) - continue; // prefix missmatch - // done - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j)); - break; - } - aFree(buffer); - - if (svn_version_buffer[0] != '\0') - return svn_version_buffer; - } - - // subversion 1.6 and older? - if ((fp = fopen(".svn/entries", "r")) != NULL) { - char line[1024]; - int rev; - // Check the version - if (fgets(line, sizeof(line), fp)) { - if (!ISDIGIT(line[0])) { - // XML File format - while (fgets(line,sizeof(line),fp)) - if (strstr(line,"revision=")) break; - if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) { - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev); - } - } else { - // Bin File format - if (fgets(line, sizeof(line), fp) == NULL) { - printf("Can't get bin name\n"); // Get the name - } - if (fgets(line, sizeof(line), fp) == NULL) { - printf("Can't get entries kind\n"); // Get the entries kind - } - if (fgets(line, sizeof(line), fp)) { // Get the rev numver - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); - } - } - } - fclose(fp); - - if (svn_version_buffer[0] != '\0') - return svn_version_buffer; - } - - // fallback - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown"); - return svn_version_buffer; + static char svn_version_buffer[16] = ""; + FILE *fp; + + if( svn_version_buffer[0] != '\0' ) + return svn_version_buffer; + + // subversion 1.7 uses a sqlite3 database + // FIXME this is hackish at best... + // - ignores database file structure + // - assumes the data in NODES.dav_cache column ends with "!svn/ver//)" + // - since it's a cache column, the data might not even exist + if( (fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL ) + { + #ifndef SVNNODEPATH + //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up + #define SVNNODEPATH trunk + #endif + const char* prefix = "!svn/ver/"; + const char* postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this + size_t prefix_len = strlen(prefix); + size_t postfix_len = strlen(postfix); + size_t i,j,len; + char* buffer; + + // read file to buffer + fseek(fp, 0, SEEK_END); + len = ftell(fp); + buffer = (char*)aMalloc(len + 1); + fseek(fp, 0, SEEK_SET); + len = fread(buffer, 1, len, fp); + buffer[len] = '\0'; + fclose(fp); + + // parse buffer + for( i = prefix_len + 1; i + postfix_len <= len; ++i ) + { + if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 ) + continue; // postfix missmatch + for( j = i; j > 0; --j ) + {// skip digits + if( !ISDIGIT(buffer[j - 1]) ) + break; + } + if( memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0 ) + continue; // prefix missmatch + // done + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j)); + break; + } + aFree(buffer); + + if( svn_version_buffer[0] != '\0' ) + return svn_version_buffer; + } + + // subversion 1.6 and older? + if ((fp = fopen(".svn/entries", "r")) != NULL) + { + char line[1024]; + int rev; + // Check the version + if (fgets(line, sizeof(line), fp)) + { + if(!ISDIGIT(line[0])) + { + // XML File format + while (fgets(line,sizeof(line),fp)) + if (strstr(line,"revision=")) break; + if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) { + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev); + } + } + else + { + // Bin File format + if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get bin name\n"); } // Get the name + if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get entries kind\n"); } // Get the entries kind + if(fgets(line, sizeof(line), fp)) // Get the rev numver + { + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); + } + } + } + fclose(fp); + + if( svn_version_buffer[0] != '\0' ) + return svn_version_buffer; + } + + // fallback + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown"); + return svn_version_buffer; } #endif /*====================================== - * CORE : Display title + * CORE : Display title * ASCII By CalciumKid 1/12/2011 *--------------------------------------*/ -static void display_title(void) -{ - //ClearScreen(); // clear screen and go up/left (0, 0 position in text) - - ShowMessage("\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - - ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); +static void display_title(void) { + //ClearScreen(); // clear screen and go up/left (0, 0 position in text) + + ShowMessage("\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + + ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); } // Warning if executed as superuser (root) @@ -280,73 +284,72 @@ void usercheck(void) { #ifndef _WIN32 if (geteuid() == 0) { - ShowWarning("You are running rAthena with root privileges, it is not necessary.\n"); + ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n"); } #endif } /*====================================== - * CORE : MAINROUTINE + * CORE : MAINROUTINE *--------------------------------------*/ -int main(int argc, char **argv) +int main (int argc, char **argv) { - { - // initialize program arguments - char *p1 = SERVER_NAME = argv[0]; - char *p2 = p1; - while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) { - SERVER_NAME = ++p1; - p2 = p1; - } - arg_c = argc; - arg_v = argv; - } - - malloc_init();// needed for Show* in display_title() [FlavioJS] + {// initialize program arguments + char *p1 = SERVER_NAME = argv[0]; + char *p2 = p1; + while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) + { + SERVER_NAME = ++p1; + p2 = p1; + } + arg_c = argc; + arg_v = argv; + } + + malloc_init();// needed for Show* in display_title() [FlavioJS] #ifdef MINICORE // minimalist Core - display_title(); - usercheck(); - do_init(argc,argv); - do_final(); + display_title(); + usercheck(); + do_init(argc,argv); + do_final(); #else// not MINICORE - set_server_type(); - display_title(); - usercheck(); + set_server_type(); + display_title(); + usercheck(); - rathread_init(); - mempool_init(); - db_init(); - signals_init(); + rathread_init(); + mempool_init(); + db_init(); + signals_init(); #ifdef _WIN32 - cevents_init(); + cevents_init(); #endif - timer_init(); - socket_init(); + timer_init(); + socket_init(); - do_init(argc,argv); + do_init(argc,argv); - { - // Main runtime cycle - int next; - while (runflag != CORE_ST_STOP) { - next = do_timer(gettick_nocache()); - do_sockets(next); - } - } + {// Main runtime cycle + int next; + while (runflag != CORE_ST_STOP) { + next = do_timer(gettick_nocache()); + do_sockets(next); + } + } - do_final(); + do_final(); - timer_final(); - socket_final(); - db_final(); - mempool_final(); - rathread_final(); + timer_final(); + socket_final(); + db_final(); + mempool_final(); + rathread_final(); #endif - malloc_final(); + malloc_final(); - return 0; + return 0; } diff --git a/src/common/core.h b/src/common/core.h index d12723445..d48962c94 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -1,14 +1,14 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _CORE_H_ -#define _CORE_H_ +#ifndef _CORE_H_ +#define _CORE_H_ extern int arg_c; extern char **arg_v; #if defined(BUILDBOT) -extern int buildbotflag; + extern int buildbotflag; #endif /// @see E_CORE_ST @@ -16,27 +16,28 @@ extern int runflag; extern char *SERVER_NAME; enum { - ATHENA_SERVER_NONE = 0, // not defined - ATHENA_SERVER_LOGIN = 1, // login server - ATHENA_SERVER_CHAR = 2, // char server - ATHENA_SERVER_INTER = 4, // inter server - ATHENA_SERVER_MAP = 8, // map server + ATHENA_SERVER_NONE = 0, // not defined + ATHENA_SERVER_LOGIN = 1, // login server + ATHENA_SERVER_CHAR = 2, // char server + ATHENA_SERVER_INTER = 4, // inter server + ATHENA_SERVER_MAP = 8, // map server }; extern char SERVER_TYPE; -extern int parse_console(const char *buf); +extern int parse_console(const char* buf); extern const char *get_svn_revision(void); -extern int do_init(int,char **); +extern int do_init(int,char**); extern void set_server_type(void); extern void do_abort(void); extern void do_final(void); /// The main loop continues until runflag is CORE_ST_STOP -enum E_CORE_ST { - CORE_ST_STOP = 0, - CORE_ST_RUN, - CORE_ST_LAST +enum E_CORE_ST +{ + CORE_ST_STOP = 0, + CORE_ST_RUN, + CORE_ST_LAST }; /// Called when a terminate signal is received. (Ctrl+C pressed) diff --git a/src/common/db.c b/src/common/db.c index c5db21a02..204c6d2ea 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -88,7 +88,7 @@ \*****************************************************************************/ /** - * If defined statistics about database nodes, database creating/destruction + * If defined statistics about database nodes, database creating/destruction * and function usage are keept and displayed when finalizing the database * system. * WARNING: This adds overhead to every database operation (not shure how much). @@ -112,8 +112,8 @@ * @see struct dbn */ typedef enum node_color { - RED, - BLACK + RED, + BLACK } node_color; /** @@ -129,16 +129,16 @@ typedef enum node_color { * @see DBMap_impl#ht */ typedef struct dbn { - // Tree structure - struct dbn *parent; - struct dbn *left; - struct dbn *right; - // Node data - DBKey key; - DBData data; - // Other - node_color color; - unsigned deleted : 1; + // Tree structure + struct dbn *parent; + struct dbn *left; + struct dbn *right; + // Node data + DBKey key; + DBData data; + // Other + node_color color; + unsigned deleted : 1; } *DBNode; /** @@ -149,8 +149,8 @@ typedef struct dbn { * @see DBMap_impl#free_list */ struct db_free { - DBNode node; - DBNode *root; + DBNode node; + DBNode *root; }; /** @@ -176,28 +176,28 @@ struct db_free { * @see #db_alloc(const char*,int,DBType,DBOptions,unsigned short) */ typedef struct DBMap_impl { - // Database interface - struct DBMap vtable; - // File and line of allocation - const char *alloc_file; - int alloc_line; - // Lock system - struct db_free *free_list; - unsigned int free_count; - unsigned int free_max; - unsigned int free_lock; - // Other - ERS nodes; - DBComparator cmp; - DBHasher hash; - DBReleaser release; - DBNode ht[HASH_SIZE]; - DBNode cache; - DBType type; - DBOptions options; - uint32 item_count; - unsigned short maxlen; - unsigned global_lock : 1; + // Database interface + struct DBMap vtable; + // File and line of allocation + const char *alloc_file; + int alloc_line; + // Lock system + struct db_free *free_list; + unsigned int free_count; + unsigned int free_max; + unsigned int free_lock; + // Other + ERS nodes; + DBComparator cmp; + DBHasher hash; + DBReleaser release; + DBNode ht[HASH_SIZE]; + DBNode cache; + DBType type; + DBOptions options; + uint32 item_count; + unsigned short maxlen; + unsigned global_lock : 1; } DBMap_impl; /** @@ -212,11 +212,11 @@ typedef struct DBMap_impl { * @see #DBNode */ typedef struct DBIterator_impl { - // Iterator interface - struct DBIterator vtable; - DBMap_impl *db; - int ht_index; - DBNode node; + // Iterator interface + struct DBIterator vtable; + DBMap_impl* db; + int ht_index; + DBNode node; } DBIterator_impl; #if defined(DB_ENABLE_STATS) @@ -227,92 +227,92 @@ typedef struct DBIterator_impl { * @see #stats */ static struct db_stats { - // Node alloc/free - uint32 db_node_alloc; - uint32 db_node_free; - // Database creating/destruction counters - uint32 db_int_alloc; - uint32 db_uint_alloc; - uint32 db_string_alloc; - uint32 db_istring_alloc; - uint32 db_int_destroy; - uint32 db_uint_destroy; - uint32 db_string_destroy; - uint32 db_istring_destroy; - // Function usage counters - uint32 db_rotate_left; - uint32 db_rotate_right; - uint32 db_rebalance; - uint32 db_rebalance_erase; - uint32 db_is_key_null; - uint32 db_dup_key; - uint32 db_dup_key_free; - uint32 db_free_add; - uint32 db_free_remove; - uint32 db_free_lock; - uint32 db_free_unlock; - uint32 db_int_cmp; - uint32 db_uint_cmp; - uint32 db_string_cmp; - uint32 db_istring_cmp; - uint32 db_int_hash; - uint32 db_uint_hash; - uint32 db_string_hash; - uint32 db_istring_hash; - uint32 db_release_nothing; - uint32 db_release_key; - uint32 db_release_data; - uint32 db_release_both; - uint32 dbit_first; - uint32 dbit_last; - uint32 dbit_next; - uint32 dbit_prev; - uint32 dbit_exists; - uint32 dbit_remove; - uint32 dbit_destroy; - uint32 db_iterator; - uint32 db_exists; - uint32 db_get; - uint32 db_getall; - uint32 db_vgetall; - uint32 db_ensure; - uint32 db_vensure; - uint32 db_put; - uint32 db_remove; - uint32 db_foreach; - uint32 db_vforeach; - uint32 db_clear; - uint32 db_vclear; - uint32 db_destroy; - uint32 db_vdestroy; - uint32 db_size; - uint32 db_type; - uint32 db_options; - uint32 db_fix_options; - uint32 db_default_cmp; - uint32 db_default_hash; - uint32 db_default_release; - uint32 db_custom_release; - uint32 db_alloc; - uint32 db_i2key; - uint32 db_ui2key; - uint32 db_str2key; - uint32 db_i2data; - uint32 db_ui2data; - uint32 db_ptr2data; - uint32 db_data2i; - uint32 db_data2ui; - uint32 db_data2ptr; - uint32 db_init; - uint32 db_final; + // Node alloc/free + uint32 db_node_alloc; + uint32 db_node_free; + // Database creating/destruction counters + uint32 db_int_alloc; + uint32 db_uint_alloc; + uint32 db_string_alloc; + uint32 db_istring_alloc; + uint32 db_int_destroy; + uint32 db_uint_destroy; + uint32 db_string_destroy; + uint32 db_istring_destroy; + // Function usage counters + uint32 db_rotate_left; + uint32 db_rotate_right; + uint32 db_rebalance; + uint32 db_rebalance_erase; + uint32 db_is_key_null; + uint32 db_dup_key; + uint32 db_dup_key_free; + uint32 db_free_add; + uint32 db_free_remove; + uint32 db_free_lock; + uint32 db_free_unlock; + uint32 db_int_cmp; + uint32 db_uint_cmp; + uint32 db_string_cmp; + uint32 db_istring_cmp; + uint32 db_int_hash; + uint32 db_uint_hash; + uint32 db_string_hash; + uint32 db_istring_hash; + uint32 db_release_nothing; + uint32 db_release_key; + uint32 db_release_data; + uint32 db_release_both; + uint32 dbit_first; + uint32 dbit_last; + uint32 dbit_next; + uint32 dbit_prev; + uint32 dbit_exists; + uint32 dbit_remove; + uint32 dbit_destroy; + uint32 db_iterator; + uint32 db_exists; + uint32 db_get; + uint32 db_getall; + uint32 db_vgetall; + uint32 db_ensure; + uint32 db_vensure; + uint32 db_put; + uint32 db_remove; + uint32 db_foreach; + uint32 db_vforeach; + uint32 db_clear; + uint32 db_vclear; + uint32 db_destroy; + uint32 db_vdestroy; + uint32 db_size; + uint32 db_type; + uint32 db_options; + uint32 db_fix_options; + uint32 db_default_cmp; + uint32 db_default_hash; + uint32 db_default_release; + uint32 db_custom_release; + uint32 db_alloc; + uint32 db_i2key; + uint32 db_ui2key; + uint32 db_str2key; + uint32 db_i2data; + uint32 db_ui2data; + uint32 db_ptr2data; + uint32 db_data2i; + uint32 db_data2ui; + uint32 db_data2ptr; + uint32 db_init; + uint32 db_final; } stats = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 }; #define DB_COUNTSTAT(token) if (stats. ## token != UINT32_MAX) ++stats. ## token #else /* !defined(DB_ENABLE_STATS) */ @@ -346,25 +346,25 @@ static struct db_stats { */ static void db_rotate_left(DBNode node, DBNode *root) { - DBNode y = node->right; + DBNode y = node->right; - DB_COUNTSTAT(db_rotate_left); - // put the left of y at the right of node - node->right = y->left; - if (y->left) - y->left->parent = node; - y->parent = node->parent; - // link y and node's parent - if (node == *root) { - *root = y; // node was root - } else if (node == node->parent->left) { - node->parent->left = y; // node was at the left - } else { - node->parent->right = y; // node was at the right - } - // put node at the left of y - y->left = node; - node->parent = y; + DB_COUNTSTAT(db_rotate_left); + // put the left of y at the right of node + node->right = y->left; + if (y->left) + y->left->parent = node; + y->parent = node->parent; + // link y and node's parent + if (node == *root) { + *root = y; // node was root + } else if (node == node->parent->left) { + node->parent->left = y; // node was at the left + } else { + node->parent->right = y; // node was at the right + } + // put node at the left of y + y->left = node; + node->parent = y; } /** @@ -377,25 +377,25 @@ static void db_rotate_left(DBNode node, DBNode *root) */ static void db_rotate_right(DBNode node, DBNode *root) { - DBNode y = node->left; + DBNode y = node->left; - DB_COUNTSTAT(db_rotate_right); - // put the right of y at the left of node - node->left = y->right; - if (y->right != 0) - y->right->parent = node; - y->parent = node->parent; - // link y and node's parent - if (node == *root) { - *root = y; // node was root - } else if (node == node->parent->right) { - node->parent->right = y; // node was at the right - } else { - node->parent->left = y; // node was at the left - } - // put node at the right of y - y->right = node; - node->parent = y; + DB_COUNTSTAT(db_rotate_right); + // put the right of y at the left of node + node->left = y->right; + if (y->right != 0) + y->right->parent = node; + y->parent = node->parent; + // link y and node's parent + if (node == *root) { + *root = y; // node was root + } else if (node == node->parent->right) { + node->parent->right = y; // node was at the right + } else { + node->parent->left = y; // node was at the left + } + // put node at the right of y + y->right = node; + node->parent = y; } /** @@ -410,55 +410,55 @@ static void db_rotate_right(DBNode node, DBNode *root) */ static void db_rebalance(DBNode node, DBNode *root) { - DBNode y; - - DB_COUNTSTAT(db_rebalance); - // Restore the RED-BLACK properties - node->color = RED; - while (node != *root && node->parent->color == RED) { - if (node->parent == node->parent->parent->left) { - // If node's parent is a left, y is node's right 'uncle' - y = node->parent->parent->right; - if (y && y->color == RED) { // case 1 - // change the colors and move up the tree - node->parent->color = BLACK; - y->color = BLACK; - node->parent->parent->color = RED; - node = node->parent->parent; - } else { - if (node == node->parent->right) { // case 2 - // move up and rotate - node = node->parent; - db_rotate_left(node, root); - } - // case 3 - node->parent->color = BLACK; - node->parent->parent->color = RED; - db_rotate_right(node->parent->parent, root); - } - } else { - // If node's parent is a right, y is node's left 'uncle' - y = node->parent->parent->left; - if (y && y->color == RED) { // case 1 - // change the colors and move up the tree - node->parent->color = BLACK; - y->color = BLACK; - node->parent->parent->color = RED; - node = node->parent->parent; - } else { - if (node == node->parent->left) { // case 2 - // move up and rotate - node = node->parent; - db_rotate_right(node, root); - } - // case 3 - node->parent->color = BLACK; - node->parent->parent->color = RED; - db_rotate_left(node->parent->parent, root); - } - } - } - (*root)->color = BLACK; // the root can and should always be black + DBNode y; + + DB_COUNTSTAT(db_rebalance); + // Restore the RED-BLACK properties + node->color = RED; + while (node != *root && node->parent->color == RED) { + if (node->parent == node->parent->parent->left) { + // If node's parent is a left, y is node's right 'uncle' + y = node->parent->parent->right; + if (y && y->color == RED) { // case 1 + // change the colors and move up the tree + node->parent->color = BLACK; + y->color = BLACK; + node->parent->parent->color = RED; + node = node->parent->parent; + } else { + if (node == node->parent->right) { // case 2 + // move up and rotate + node = node->parent; + db_rotate_left(node, root); + } + // case 3 + node->parent->color = BLACK; + node->parent->parent->color = RED; + db_rotate_right(node->parent->parent, root); + } + } else { + // If node's parent is a right, y is node's left 'uncle' + y = node->parent->parent->left; + if (y && y->color == RED) { // case 1 + // change the colors and move up the tree + node->parent->color = BLACK; + y->color = BLACK; + node->parent->parent->color = RED; + node = node->parent->parent; + } else { + if (node == node->parent->left) { // case 2 + // move up and rotate + node = node->parent; + db_rotate_right(node, root); + } + // case 3 + node->parent->color = BLACK; + node->parent->parent->color = RED; + db_rotate_left(node->parent->parent, root); + } + } + } + (*root)->color = BLACK; // the root can and should always be black } /** @@ -472,133 +472,133 @@ static void db_rebalance(DBNode node, DBNode *root) */ static void db_rebalance_erase(DBNode node, DBNode *root) { - DBNode y = node; - DBNode x = NULL; - DBNode x_parent = NULL; - DBNode w; - - DB_COUNTSTAT(db_rebalance_erase); - // Select where to change the tree - if (y->left == NULL) { // no left - x = y->right; - } else if (y->right == NULL) { // no right - x = y->left; - } else { // both exist, go to the leftmost node of the right sub-tree - y = y->right; - while (y->left != NULL) - y = y->left; - x = y->right; - } - - // Remove the node from the tree - if (y != node) { // both childs existed - // put the left of 'node' in the left of 'y' - node->left->parent = y; - y->left = node->left; - - // 'y' is not the direct child of 'node' - if (y != node->right) { - // put 'x' in the old position of 'y' - x_parent = y->parent; - if (x) x->parent = y->parent; - y->parent->left = x; - // put the right of 'node' in 'y' - y->right = node->right; - node->right->parent = y; - // 'y' is a direct child of 'node' - } else { - x_parent = y; - } - - // link 'y' and the parent of 'node' - if (*root == node) { - *root = y; // 'node' was the root - } else if (node->parent->left == node) { - node->parent->left = y; // 'node' was at the left - } else { - node->parent->right = y; // 'node' was at the right - } - y->parent = node->parent; - // switch colors - { - node_color tmp = y->color; - y->color = node->color; - node->color = tmp; - } - y = node; - } else { // one child did not exist - // put x in node's position - x_parent = y->parent; - if (x) x->parent = y->parent; - // link x and node's parent - if (*root == node) { - *root = x; // node was the root - } else if (node->parent->left == node) { - node->parent->left = x; // node was at the left - } else { - node->parent->right = x; // node was at the right - } - } - - // Restore the RED-BLACK properties - if (y->color != RED) { - while (x != *root && (x == NULL || x->color == BLACK)) { - if (x == x_parent->left) { - w = x_parent->right; - if (w->color == RED) { - w->color = BLACK; - x_parent->color = RED; - db_rotate_left(x_parent, root); - w = x_parent->right; - } - if ((w->left == NULL || w->left->color == BLACK) && - (w->right == NULL || w->right->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } else { - if (w->right == NULL || w->right->color == BLACK) { - if (w->left) w->left->color = BLACK; - w->color = RED; - db_rotate_right(w, root); - w = x_parent->right; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->right) w->right->color = BLACK; - db_rotate_left(x_parent, root); - break; - } - } else { - w = x_parent->left; - if (w->color == RED) { - w->color = BLACK; - x_parent->color = RED; - db_rotate_right(x_parent, root); - w = x_parent->left; - } - if ((w->right == NULL || w->right->color == BLACK) && - (w->left == NULL || w->left->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } else { - if (w->left == NULL || w->left->color == BLACK) { - if (w->right) w->right->color = BLACK; - w->color = RED; - db_rotate_left(w, root); - w = x_parent->left; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->left) w->left->color = BLACK; - db_rotate_right(x_parent, root); - break; - } - } - } - if (x) x->color = BLACK; - } + DBNode y = node; + DBNode x = NULL; + DBNode x_parent = NULL; + DBNode w; + + DB_COUNTSTAT(db_rebalance_erase); + // Select where to change the tree + if (y->left == NULL) { // no left + x = y->right; + } else if (y->right == NULL) { // no right + x = y->left; + } else { // both exist, go to the leftmost node of the right sub-tree + y = y->right; + while (y->left != NULL) + y = y->left; + x = y->right; + } + + // Remove the node from the tree + if (y != node) { // both childs existed + // put the left of 'node' in the left of 'y' + node->left->parent = y; + y->left = node->left; + + // 'y' is not the direct child of 'node' + if (y != node->right) { + // put 'x' in the old position of 'y' + x_parent = y->parent; + if (x) x->parent = y->parent; + y->parent->left = x; + // put the right of 'node' in 'y' + y->right = node->right; + node->right->parent = y; + // 'y' is a direct child of 'node' + } else { + x_parent = y; + } + + // link 'y' and the parent of 'node' + if (*root == node) { + *root = y; // 'node' was the root + } else if (node->parent->left == node) { + node->parent->left = y; // 'node' was at the left + } else { + node->parent->right = y; // 'node' was at the right + } + y->parent = node->parent; + // switch colors + { + node_color tmp = y->color; + y->color = node->color; + node->color = tmp; + } + y = node; + } else { // one child did not exist + // put x in node's position + x_parent = y->parent; + if (x) x->parent = y->parent; + // link x and node's parent + if (*root == node) { + *root = x; // node was the root + } else if (node->parent->left == node) { + node->parent->left = x; // node was at the left + } else { + node->parent->right = x; // node was at the right + } + } + + // Restore the RED-BLACK properties + if (y->color != RED) { + while (x != *root && (x == NULL || x->color == BLACK)) { + if (x == x_parent->left) { + w = x_parent->right; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_left(x_parent, root); + w = x_parent->right; + } + if ((w->left == NULL || w->left->color == BLACK) && + (w->right == NULL || w->right->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->right == NULL || w->right->color == BLACK) { + if (w->left) w->left->color = BLACK; + w->color = RED; + db_rotate_right(w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->right) w->right->color = BLACK; + db_rotate_left(x_parent, root); + break; + } + } else { + w = x_parent->left; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_right(x_parent, root); + w = x_parent->left; + } + if ((w->right == NULL || w->right->color == BLACK) && + (w->left == NULL || w->left->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->left == NULL || w->left->color == BLACK) { + if (w->right) w->right->color = BLACK; + w->color = RED; + db_rotate_left(w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->left) w->left->color = BLACK; + db_rotate_right(x_parent, root); + break; + } + } + } + if (x) x->color = BLACK; + } } /** @@ -613,15 +613,15 @@ static void db_rebalance_erase(DBNode node, DBNode *root) */ static int db_is_key_null(DBType type, DBKey key) { - DB_COUNTSTAT(db_is_key_null); - switch (type) { - case DB_STRING: - case DB_ISTRING: - return (key.str == NULL); + DB_COUNTSTAT(db_is_key_null); + switch (type) { + case DB_STRING: + case DB_ISTRING: + return (key.str == NULL); - default: // Not a pointer - return 0; - } + default: // Not a pointer + return 0; + } } /** @@ -635,25 +635,25 @@ static int db_is_key_null(DBType type, DBKey key) * @see #db_obj_put(DBMap*,DBKey,void *) * @see #db_dup_key_free(DBMap_impl*,DBKey) */ -static DBKey db_dup_key(DBMap_impl *db, DBKey key) +static DBKey db_dup_key(DBMap_impl* db, DBKey key) { - char *str; - size_t len; + char *str; + size_t len; - DB_COUNTSTAT(db_dup_key); - switch (db->type) { - case DB_STRING: - case DB_ISTRING: - len = strnlen(key.str, db->maxlen); - str = (char *)aMalloc(len + 1); - memcpy(str, key.str, len); - str[len] = '\0'; - key.str = str; - return key; + DB_COUNTSTAT(db_dup_key); + switch (db->type) { + case DB_STRING: + case DB_ISTRING: + len = strnlen(key.str, db->maxlen); + str = (char*)aMalloc(len + 1); + memcpy(str, key.str, len); + str[len] = '\0'; + key.str = str; + return key; - default: - return key; - } + default: + return key; + } } /** @@ -663,18 +663,18 @@ static DBKey db_dup_key(DBMap_impl *db, DBKey key) * @private * @see #db_dup_key(DBMap_impl*,DBKey) */ -static void db_dup_key_free(DBMap_impl *db, DBKey key) +static void db_dup_key_free(DBMap_impl* db, DBKey key) { - DB_COUNTSTAT(db_dup_key_free); - switch (db->type) { - case DB_STRING: - case DB_ISTRING: - aFree((char *)key.str); - return; + DB_COUNTSTAT(db_dup_key_free); + switch (db->type) { + case DB_STRING: + case DB_ISTRING: + aFree((char*)key.str); + return; - default: - return; - } + default: + return; + } } /** @@ -692,40 +692,40 @@ static void db_dup_key_free(DBMap_impl *db, DBKey key) * @see #db_obj_remove(DBMap*,DBKey) * @see #db_free_remove(DBMap_impl*,DBNode) */ -static void db_free_add(DBMap_impl *db, DBNode node, DBNode *root) -{ - DBKey old_key; - - DB_COUNTSTAT(db_free_add); - if (db->free_lock == (unsigned int)~0) { - ShowFatalError("db_free_add: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - if (!(db->options&DB_OPT_DUP_KEY)) { // Make sure we have a key until the node is freed - old_key = node->key; - node->key = db_dup_key(db, node->key); - db->release(old_key, node->data, DB_RELEASE_KEY); - } - if (db->free_count == db->free_max) { // No more space, expand free_list - db->free_max = (db->free_max<<2) +3; // = db->free_max*4 +3 - if (db->free_max <= db->free_count) { - if (db->free_count == (unsigned int)~0) { - ShowFatalError("db_free_add: free_count overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - db->free_max = (unsigned int)~0; - } - RECREATE(db->free_list, struct db_free, db->free_max); - } - node->deleted = 1; - db->free_list[db->free_count].node = node; - db->free_list[db->free_count].root = root; - db->free_count++; - db->item_count--; +static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) +{ + DBKey old_key; + + DB_COUNTSTAT(db_free_add); + if (db->free_lock == (unsigned int)~0) { + ShowFatalError("db_free_add: free_lock overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + if (!(db->options&DB_OPT_DUP_KEY)) { // Make sure we have a key until the node is freed + old_key = node->key; + node->key = db_dup_key(db, node->key); + db->release(old_key, node->data, DB_RELEASE_KEY); + } + if (db->free_count == db->free_max) { // No more space, expand free_list + db->free_max = (db->free_max<<2) +3; // = db->free_max*4 +3 + if (db->free_max <= db->free_count) { + if (db->free_count == (unsigned int)~0) { + ShowFatalError("db_free_add: free_count overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + db->free_max = (unsigned int)~0; + } + RECREATE(db->free_list, struct db_free, db->free_max); + } + node->deleted = 1; + db->free_list[db->free_count].node = node; + db->free_list[db->free_count].root = root; + db->free_count++; + db->item_count--; } /** @@ -741,26 +741,26 @@ static void db_free_add(DBMap_impl *db, DBNode node, DBNode *root) * @see #db_obj_put(DBMap*,DBKey,DBData) * @see #db_free_add(DBMap_impl*,DBNode*,DBNode) */ -static void db_free_remove(DBMap_impl *db, DBNode node) +static void db_free_remove(DBMap_impl* db, DBNode node) { - unsigned int i; + unsigned int i; - DB_COUNTSTAT(db_free_remove); - for (i = 0; i < db->free_count; i++) { - if (db->free_list[i].node == node) { - if (i < db->free_count -1) // copy the last item to where the removed one was - memcpy(&db->free_list[i], &db->free_list[db->free_count -1], sizeof(struct db_free)); - db_dup_key_free(db, node->key); - break; - } - } - node->deleted = 0; - if (i == db->free_count) { - ShowWarning("db_free_remove: node was not found - database allocated at %s:%d\n", db->alloc_file, db->alloc_line); - } else { - db->free_count--; - } - db->item_count++; + DB_COUNTSTAT(db_free_remove); + for (i = 0; i < db->free_count; i++) { + if (db->free_list[i].node == node) { + if (i < db->free_count -1) // copy the last item to where the removed one was + memcpy(&db->free_list[i], &db->free_list[db->free_count -1], sizeof(struct db_free)); + db_dup_key_free(db, node->key); + break; + } + } + node->deleted = 0; + if (i == db->free_count) { + ShowWarning("db_free_remove: node was not found - database allocated at %s:%d\n", db->alloc_file, db->alloc_line); + } else { + db->free_count--; + } + db->item_count++; } /** @@ -770,16 +770,16 @@ static void db_free_remove(DBMap_impl *db, DBNode node) * @see DBMap_impl#free_lock * @see #db_unlock(DBMap_impl*) */ -static void db_free_lock(DBMap_impl *db) +static void db_free_lock(DBMap_impl* db) { - DB_COUNTSTAT(db_free_lock); - if (db->free_lock == (unsigned int)~0) { - ShowFatalError("db_free_lock: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - db->free_lock++; + DB_COUNTSTAT(db_free_lock); + if (db->free_lock == (unsigned int)~0) { + ShowFatalError("db_free_lock: free_lock overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + db->free_lock++; } /** @@ -793,28 +793,28 @@ static void db_free_lock(DBMap_impl *db) * @see #db_free_dbn(DBNode) * @see #db_lock(DBMap_impl*) */ -static void db_free_unlock(DBMap_impl *db) +static void db_free_unlock(DBMap_impl* db) { - unsigned int i; + unsigned int i; - DB_COUNTSTAT(db_free_unlock); - if (db->free_lock == 0) { - ShowWarning("db_free_unlock: free_lock was already 0\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - } else { - db->free_lock--; - } - if (db->free_lock) - return; // Not last lock + DB_COUNTSTAT(db_free_unlock); + if (db->free_lock == 0) { + ShowWarning("db_free_unlock: free_lock was already 0\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + } else { + db->free_lock--; + } + if (db->free_lock) + return; // Not last lock - for (i = 0; i < db->free_count ; i++) { - db_rebalance_erase(db->free_list[i].node, db->free_list[i].root); - db_dup_key_free(db, db->free_list[i].node->key); - DB_COUNTSTAT(db_node_free); - ers_free(db->nodes, db->free_list[i].node); - } - db->free_count = 0; + for (i = 0; i < db->free_count ; i++) { + db_rebalance_erase(db->free_list[i].node, db->free_list[i].root); + db_dup_key_free(db, db->free_list[i].node->key); + DB_COUNTSTAT(db_node_free); + ers_free(db->nodes, db->free_list[i].node); + } + db->free_count = 0; } /*****************************************************************************\ @@ -850,11 +850,11 @@ static void db_free_unlock(DBMap_impl *db) */ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_int_cmp); - if (key1.i < key2.i) return -1; - if (key1.i > key2.i) return 1; - return 0; + (void)maxlen;//not used + DB_COUNTSTAT(db_int_cmp); + if (key1.i < key2.i) return -1; + if (key1.i > key2.i) return 1; + return 0; } /** @@ -872,11 +872,11 @@ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_uint_cmp); - if (key1.ui < key2.ui) return -1; - if (key1.ui > key2.ui) return 1; - return 0; + (void)maxlen;//not used + DB_COUNTSTAT(db_uint_cmp); + if (key1.ui < key2.ui) return -1; + if (key1.ui > key2.ui) return 1; + return 0; } /** @@ -893,8 +893,8 @@ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - DB_COUNTSTAT(db_string_cmp); - return strncmp((const char *)key1.str, (const char *)key2.str, maxlen); + DB_COUNTSTAT(db_string_cmp); + return strncmp((const char *)key1.str, (const char *)key2.str, maxlen); } /** @@ -911,8 +911,8 @@ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - DB_COUNTSTAT(db_istring_cmp); - return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen); + DB_COUNTSTAT(db_istring_cmp); + return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen); } /** @@ -928,9 +928,9 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_int_hash); - return (unsigned int)key.i; + (void)maxlen;//not used + DB_COUNTSTAT(db_int_hash); + return (unsigned int)key.i; } /** @@ -946,9 +946,9 @@ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_uint_hash); - return key.ui; + (void)maxlen;//not used + DB_COUNTSTAT(db_uint_hash); + return key.ui; } /** @@ -962,20 +962,20 @@ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) { - const char *k = key.str; - unsigned int hash = 0; - unsigned short i; + const char *k = key.str; + unsigned int hash = 0; + unsigned short i; - DB_COUNTSTAT(db_string_hash); + DB_COUNTSTAT(db_string_hash); - for (i = 0; *k; ++i) { - hash = (hash*33 + ((unsigned char)*k))^(hash>>24); - k++; - if (i == maxlen) - break; - } + for (i = 0; *k; ++i) { + hash = (hash*33 + ((unsigned char)*k))^(hash>>24); + k++; + if (i == maxlen) + break; + } - return hash; + return hash; } /** @@ -988,20 +988,20 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) { - const char *k = key.str; - unsigned int hash = 0; - unsigned short i; + const char *k = key.str; + unsigned int hash = 0; + unsigned short i; - DB_COUNTSTAT(db_istring_hash); + DB_COUNTSTAT(db_istring_hash); - for (i = 0; *k; i++) { - hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24); - k++; - if (i == maxlen) - break; - } + for (i = 0; *k; i++) { + hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24); + k++; + if (i == maxlen) + break; + } - return hash; + return hash; } /** @@ -1015,10 +1015,8 @@ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) */ static void db_release_nothing(DBKey key, DBData data, DBRelease which) { - (void)key; - (void)data; - (void)which;//not used - DB_COUNTSTAT(db_release_nothing); + (void)key;(void)data;(void)which;//not used + DB_COUNTSTAT(db_release_nothing); } /** @@ -1032,9 +1030,9 @@ static void db_release_nothing(DBKey key, DBData data, DBRelease which) */ static void db_release_key(DBKey key, DBData data, DBRelease which) { - (void)data;//not used - DB_COUNTSTAT(db_release_key); - if (which&DB_RELEASE_KEY) aFree((char *)key.str); // needs to be a pointer + (void)data;//not used + DB_COUNTSTAT(db_release_key); + if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer } /** @@ -1050,9 +1048,9 @@ static void db_release_key(DBKey key, DBData data, DBRelease which) */ static void db_release_data(DBKey key, DBData data, DBRelease which) { - (void)key;//not used - DB_COUNTSTAT(db_release_data); - if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); + (void)key;//not used + DB_COUNTSTAT(db_release_data); + if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); } /** @@ -1069,9 +1067,9 @@ static void db_release_data(DBKey key, DBData data, DBRelease which) */ static void db_release_both(DBKey key, DBData data, DBRelease which) { - DB_COUNTSTAT(db_release_both); - if (which&DB_RELEASE_KEY) aFree((char *)key.str); // needs to be a pointer - if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); + DB_COUNTSTAT(db_release_both); + if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer + if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); } /*****************************************************************************\ @@ -1117,16 +1115,16 @@ static void db_release_both(DBKey key, DBData data, DBRelease which) * @protected * @see DBIterator#first */ -DBData *dbit_obj_first(DBIterator *self, DBKey *out_key) +DBData* dbit_obj_first(DBIterator* self, DBKey* out_key) { - DBIterator_impl *it = (DBIterator_impl *)self; - - DB_COUNTSTAT(dbit_first); - // position before the first entry - it->ht_index = -1; - it->node = NULL; - // get next entry - return self->next(self, out_key); + DBIterator_impl* it = (DBIterator_impl*)self; + + DB_COUNTSTAT(dbit_first); + // position before the first entry + it->ht_index = -1; + it->node = NULL; + // get next entry + return self->next(self, out_key); } /** @@ -1139,16 +1137,16 @@ DBData *dbit_obj_first(DBIterator *self, DBKey *out_key) * @protected * @see DBIterator#last */ -DBData *dbit_obj_last(DBIterator *self, DBKey *out_key) +DBData* dbit_obj_last(DBIterator* self, DBKey* out_key) { - DBIterator_impl *it = (DBIterator_impl *)self; - - DB_COUNTSTAT(dbit_last); - // position after the last entry - it->ht_index = HASH_SIZE; - it->node = NULL; - // get previous entry - return self->prev(self, out_key); + DBIterator_impl* it = (DBIterator_impl*)self; + + DB_COUNTSTAT(dbit_last); + // position after the last entry + it->ht_index = HASH_SIZE; + it->node = NULL; + // get previous entry + return self->prev(self, out_key); } /** @@ -1161,67 +1159,70 @@ DBData *dbit_obj_last(DBIterator *self, DBKey *out_key) * @protected * @see DBIterator#next */ -DBData *dbit_obj_next(DBIterator *self, DBKey *out_key) -{ - DBIterator_impl *it = (DBIterator_impl *)self; - DBNode node; - DBNode parent; - struct dbn fake; - - DB_COUNTSTAT(dbit_next); - if (it->ht_index < 0) { - // get first node - it->ht_index = 0; - it->node = NULL; - } - node = it->node; - memset(&fake, 0, sizeof(fake)); - for (; it->ht_index < HASH_SIZE; ++(it->ht_index)) { - // Iterate in the order: left tree, current node, right tree - if (node == NULL) { - // prepare initial node of this hash - node = it->db->ht[it->ht_index]; - if (node == NULL) - continue;// next hash - fake.right = node; - node = &fake; - } - - while (node) { - // next node - if (node->right) { - // continue in the right subtree - node = node->right; - while (node->left) - node = node->left;// get leftmost node - } else { - // continue to the next parent (recursive) - parent = node->parent; - while (parent) { - if (parent->right != node) - break; - node = parent; - parent = node->parent; - } - if (parent == NULL) { - // next hash - node = NULL; - break; - } - node = parent; - } - - if (!node->deleted) { - // found next entry - it->node = node; - if (out_key) - memcpy(out_key, &node->key, sizeof(DBKey)); - return &node->data; - } - } - } - it->node = NULL; - return NULL;// not found +DBData* dbit_obj_next(DBIterator* self, DBKey* out_key) +{ + DBIterator_impl* it = (DBIterator_impl*)self; + DBNode node; + DBNode parent; + struct dbn fake; + + DB_COUNTSTAT(dbit_next); + if( it->ht_index < 0 ) + {// get first node + it->ht_index = 0; + it->node = NULL; + } + node = it->node; + memset(&fake, 0, sizeof(fake)); + for( ; it->ht_index < HASH_SIZE; ++(it->ht_index) ) + { + // Iterate in the order: left tree, current node, right tree + if( node == NULL ) + {// prepare initial node of this hash + node = it->db->ht[it->ht_index]; + if( node == NULL ) + continue;// next hash + fake.right = node; + node = &fake; + } + + while( node ) + {// next node + if( node->right ) + {// continue in the right subtree + node = node->right; + while( node->left ) + node = node->left;// get leftmost node + } + else + {// continue to the next parent (recursive) + parent = node->parent; + while( parent ) + { + if( parent->right != node ) + break; + node = parent; + parent = node->parent; + } + if( parent == NULL ) + {// next hash + node = NULL; + break; + } + node = parent; + } + + if( !node->deleted ) + {// found next entry + it->node = node; + if( out_key ) + memcpy(out_key, &node->key, sizeof(DBKey)); + return &node->data; + } + } + } + it->node = NULL; + return NULL;// not found } /** @@ -1234,90 +1235,93 @@ DBData *dbit_obj_next(DBIterator *self, DBKey *out_key) * @protected * @see DBIterator#prev */ -DBData *dbit_obj_prev(DBIterator *self, DBKey *out_key) -{ - DBIterator_impl *it = (DBIterator_impl *)self; - DBNode node; - DBNode parent; - struct dbn fake; - - DB_COUNTSTAT(dbit_prev); - if (it->ht_index >= HASH_SIZE) { - // get last node - it->ht_index = HASH_SIZE-1; - it->node = NULL; - } - node = it->node; - memset(&fake, 0, sizeof(fake)); - for (; it->ht_index >= 0; --(it->ht_index)) { - // Iterate in the order: right tree, current node, left tree - if (node == NULL) { - // prepare initial node of this hash - node = it->db->ht[it->ht_index]; - if (node == NULL) - continue;// next hash - fake.left = node; - node = &fake; - } - - - while (node) { - // next node - if (node->left) { - // continue in the left subtree - node = node->left; - while (node->right) - node = node->right;// get rightmost node - } else { - // continue to the next parent (recursive) - parent = node->parent; - while (parent) { - if (parent->left != node) - break; - node = parent; - parent = node->parent; - } - if (parent == NULL) { - // next hash - node = NULL; - break; - } - node = parent; - } - - if (!node->deleted) { - // found previous entry - it->node = node; - if (out_key) - memcpy(out_key, &node->key, sizeof(DBKey)); - return &node->data; - } - } - } - it->node = NULL; - return NULL;// not found +DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key) +{ + DBIterator_impl* it = (DBIterator_impl*)self; + DBNode node; + DBNode parent; + struct dbn fake; + + DB_COUNTSTAT(dbit_prev); + if( it->ht_index >= HASH_SIZE ) + {// get last node + it->ht_index = HASH_SIZE-1; + it->node = NULL; + } + node = it->node; + memset(&fake, 0, sizeof(fake)); + for( ; it->ht_index >= 0; --(it->ht_index) ) + { + // Iterate in the order: right tree, current node, left tree + if( node == NULL ) + {// prepare initial node of this hash + node = it->db->ht[it->ht_index]; + if( node == NULL ) + continue;// next hash + fake.left = node; + node = &fake; + } + + + while( node ) + {// next node + if( node->left ) + {// continue in the left subtree + node = node->left; + while( node->right ) + node = node->right;// get rightmost node + } + else + {// continue to the next parent (recursive) + parent = node->parent; + while( parent ) + { + if( parent->left != node ) + break; + node = parent; + parent = node->parent; + } + if( parent == NULL ) + {// next hash + node = NULL; + break; + } + node = parent; + } + + if( !node->deleted ) + {// found previous entry + it->node = node; + if( out_key ) + memcpy(out_key, &node->key, sizeof(DBKey)); + return &node->data; + } + } + } + it->node = NULL; + return NULL;// not found } /** * Returns true if the fetched entry exists. - * The databases entries might have NULL data, so use this to to test if + * The databases entries might have NULL data, so use this to to test if * the iterator is done. * @param self Iterator * @return true if the entry exists * @protected * @see DBIterator#exists */ -bool dbit_obj_exists(DBIterator *self) +bool dbit_obj_exists(DBIterator* self) { - DBIterator_impl *it = (DBIterator_impl *)self; + DBIterator_impl* it = (DBIterator_impl*)self; - DB_COUNTSTAT(dbit_exists); - return (it->node && !it->node->deleted); + DB_COUNTSTAT(dbit_exists); + return (it->node && !it->node->deleted); } /** * Removes the current entry from the database. - * NOTE: {@link DBIterator#exists} will return false until another entry + * NOTE: {@link DBIterator#exists} will return false until another entry * is fetched * Puts data of the removed entry in out_data, if out_data is not NULL. * @param self Iterator @@ -1327,25 +1331,26 @@ bool dbit_obj_exists(DBIterator *self) * @see DBMap#remove * @see DBIterator#remove */ -int dbit_obj_remove(DBIterator *self, DBData *out_data) +int dbit_obj_remove(DBIterator* self, DBData *out_data) { - DBIterator_impl *it = (DBIterator_impl *)self; - DBNode node; - int retval = 0; + DBIterator_impl* it = (DBIterator_impl*)self; + DBNode node; + int retval = 0; - DB_COUNTSTAT(dbit_remove); - node = it->node; - if (node && !node->deleted) { - DBMap_impl *db = it->db; - if (db->cache == node) - db->cache = NULL; - if (out_data) - memcpy(out_data, &node->data, sizeof(DBData)); - retval = 1; - db->release(node->key, node->data, DB_RELEASE_DATA); - db_free_add(db, node, &db->ht[it->ht_index]); - } - return retval; + DB_COUNTSTAT(dbit_remove); + node = it->node; + if( node && !node->deleted ) + { + DBMap_impl* db = it->db; + if( db->cache == node ) + db->cache = NULL; + if( out_data ) + memcpy(out_data, &node->data, sizeof(DBData)); + retval = 1; + db->release(node->key, node->data, DB_RELEASE_DATA); + db_free_add(db, node, &db->ht[it->ht_index]); + } + return retval; } /** @@ -1353,48 +1358,48 @@ int dbit_obj_remove(DBIterator *self, DBData *out_data) * @param self Iterator * @protected */ -void dbit_obj_destroy(DBIterator *self) +void dbit_obj_destroy(DBIterator* self) { - DBIterator_impl *it = (DBIterator_impl *)self; + DBIterator_impl* it = (DBIterator_impl*)self; - DB_COUNTSTAT(dbit_destroy); - // unlock the database - db_free_unlock(it->db); - // free iterator - aFree(self); + DB_COUNTSTAT(dbit_destroy); + // unlock the database + db_free_unlock(it->db); + // free iterator + aFree(self); } /** * Returns a new iterator for this database. * The iterator keeps the database locked until it is destroyed. - * The database will keep functioning normally but will only free internal + * The database will keep functioning normally but will only free internal * memory when unlocked, so destroy the iterator as soon as possible. * @param self Database * @return New iterator * @protected */ -static DBIterator *db_obj_iterator(DBMap *self) +static DBIterator* db_obj_iterator(DBMap* self) { - DBMap_impl *db = (DBMap_impl *)self; - DBIterator_impl *it; + DBMap_impl* db = (DBMap_impl*)self; + DBIterator_impl* it; - DB_COUNTSTAT(db_iterator); - CREATE(it, struct DBIterator_impl, 1); - /* Interface of the iterator **/ - it->vtable.first = dbit_obj_first; - it->vtable.last = dbit_obj_last; - it->vtable.next = dbit_obj_next; - it->vtable.prev = dbit_obj_prev; - it->vtable.exists = dbit_obj_exists; - it->vtable.remove = dbit_obj_remove; - it->vtable.destroy = dbit_obj_destroy; - /* Initial state (before the first entry) */ - it->db = db; - it->ht_index = -1; - it->node = NULL; - /* Lock the database */ - db_free_lock(db); - return &it->vtable; + DB_COUNTSTAT(db_iterator); + CREATE(it, struct DBIterator_impl, 1); + /* Interface of the iterator **/ + it->vtable.first = dbit_obj_first; + it->vtable.last = dbit_obj_last; + it->vtable.next = dbit_obj_next; + it->vtable.prev = dbit_obj_prev; + it->vtable.exists = dbit_obj_exists; + it->vtable.remove = dbit_obj_remove; + it->vtable.destroy = dbit_obj_destroy; + /* Initial state (before the first entry) */ + it->db = db; + it->ht_index = -1; + it->node = NULL; + /* Lock the database */ + db_free_lock(db); + return &it->vtable; } /** @@ -1405,47 +1410,47 @@ static DBIterator *db_obj_iterator(DBMap *self) * @protected * @see DBMap#exists */ -static bool db_obj_exists(DBMap *self, DBKey key) +static bool db_obj_exists(DBMap* self, DBKey key) { - DBMap_impl *db = (DBMap_impl *)self; - DBNode node; - int c; - bool found = false; + DBMap_impl* db = (DBMap_impl*)self; + DBNode node; + int c; + bool found = false; - DB_COUNTSTAT(db_exists); - if (db == NULL) return false; // nullpo candidate - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - return false; // nullpo candidate - } + DB_COUNTSTAT(db_exists); + if (db == NULL) return false; // nullpo candidate + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + return false; // nullpo candidate + } - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { #if defined(DEBUG) - if (db->cache->deleted) { - ShowDebug("db_exists: Cache contains a deleted node. Please report this!!!\n"); - return false; - } + if (db->cache->deleted) { + ShowDebug("db_exists: Cache contains a deleted node. Please report this!!!\n"); + return false; + } #endif - return true; // cache hit - } - - db_free_lock(db); - node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - db->cache = node; - found = true; - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return found; + return true; // cache hit + } + + db_free_lock(db); + node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + db->cache = node; + found = true; + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return found; } /** @@ -1456,48 +1461,48 @@ static bool db_obj_exists(DBMap *self, DBKey key) * @protected * @see DBMap#get */ -static DBData *db_obj_get(DBMap *self, DBKey key) +static DBData* db_obj_get(DBMap* self, DBKey key) { - DBMap_impl *db = (DBMap_impl *)self; - DBNode node; - int c; - DBData *data = NULL; + DBMap_impl* db = (DBMap_impl*)self; + DBNode node; + int c; + DBData *data = NULL; - DB_COUNTSTAT(db_get); - if (db == NULL) return NULL; // nullpo candidate - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_get: Attempted to retrieve non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } + DB_COUNTSTAT(db_get); + if (db == NULL) return NULL; // nullpo candidate + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_get: Attempted to retrieve non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { #if defined(DEBUG) - if (db->cache->deleted) { - ShowDebug("db_get: Cache contains a deleted node. Please report this!!!\n"); - return NULL; - } + if (db->cache->deleted) { + ShowDebug("db_get: Cache contains a deleted node. Please report this!!!\n"); + return NULL; + } #endif - return &db->cache->data; // cache hit - } - - db_free_lock(db); - node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - data = &node->data; - db->cache = node; - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return data; + return &db->cache->data; // cache hit + } + + db_free_lock(db); + node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + data = &node->data; + db->cache = node; + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return data; } /** @@ -1505,7 +1510,7 @@ static DBData *db_obj_get(DBMap *self, DBKey key) * It puts a maximum of max entries into buf. * If buf is NULL, it only counts the matches. * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the + * NOTE: if the value returned is greater than max, only the * first max entries found are put into the buffer. * @param self Interface of the database * @param buf Buffer to put the data of the matched entries @@ -1516,58 +1521,58 @@ static DBData *db_obj_get(DBMap *self, DBKey key) * @protected * @see DBMap#vgetall */ -static unsigned int db_obj_vgetall(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, va_list args) -{ - DBMap_impl *db = (DBMap_impl *)self; - unsigned int i; - DBNode node; - DBNode parent; - unsigned int ret = 0; - - DB_COUNTSTAT(db_vgetall); - if (db == NULL) return 0; // nullpo candidate - if (match == NULL) return 0; // nullpo candidate - - db_free_lock(db); - for (i = 0; i < HASH_SIZE; i++) { - // Match in the order: current node, left tree, right tree - node = db->ht[i]; - while (node) { - - if (!(node->deleted)) { - va_list argscopy; - va_copy(argscopy, args); - if (match(node->key, node->data, argscopy) == 0) { - if (buf && ret < max) - buf[ret] = &node->data; - ret++; - } - va_end(argscopy); - } - - if (node->left) { - node = node->left; - continue; - } - - if (node->right) { - node = node->right; - continue; - } - - while (node) { - parent = node->parent; - if (parent && parent->right && parent->left == node) { - node = parent->right; - break; - } - node = parent; - } - - } - } - db_free_unlock(db); - return ret; +static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, va_list args) +{ + DBMap_impl* db = (DBMap_impl*)self; + unsigned int i; + DBNode node; + DBNode parent; + unsigned int ret = 0; + + DB_COUNTSTAT(db_vgetall); + if (db == NULL) return 0; // nullpo candidate + if (match == NULL) return 0; // nullpo candidate + + db_free_lock(db); + for (i = 0; i < HASH_SIZE; i++) { + // Match in the order: current node, left tree, right tree + node = db->ht[i]; + while (node) { + + if (!(node->deleted)) { + va_list argscopy; + va_copy(argscopy, args); + if (match(node->key, node->data, argscopy) == 0) { + if (buf && ret < max) + buf[ret] = &node->data; + ret++; + } + va_end(argscopy); + } + + if (node->left) { + node = node->left; + continue; + } + + if (node->right) { + node = node->right; + continue; + } + + while (node) { + parent = node->parent; + if (parent && parent->right && parent->left == node) { + node = parent->right; + break; + } + node = parent; + } + + } + } + db_free_unlock(db); + return ret; } /** @@ -1576,7 +1581,7 @@ static unsigned int db_obj_vgetall(DBMap *self, DBData **buf, unsigned int max, * It puts a maximum of max entries into buf. * If buf is NULL, it only counts the matches. * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the + * NOTE: if the value returned is greater than max, only the * first max entries found are put into the buffer. * @param self Interface of the database * @param buf Buffer to put the data of the matched entries @@ -1588,23 +1593,23 @@ static unsigned int db_obj_vgetall(DBMap *self, DBData **buf, unsigned int max, * @see DBMap#vgetall * @see DBMap#getall */ -static unsigned int db_obj_getall(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, ...) +static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, ...) { - va_list args; - unsigned int ret; + va_list args; + unsigned int ret; - DB_COUNTSTAT(db_getall); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_getall); + if (self == NULL) return 0; // nullpo candidate - va_start(args, match); - ret = self->vgetall(self, buf, max, match, args); - va_end(args); - return ret; + va_start(args, match); + ret = self->vgetall(self, buf, max, match, args); + va_end(args); + return ret; } /** * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by + * If the entry does not exist, an entry is added with the data returned by * create. * @param self Interface of the database * @param key Key that identifies the entry @@ -1614,96 +1619,96 @@ static unsigned int db_obj_getall(DBMap *self, DBData **buf, unsigned int max, D * @protected * @see DBMap#vensure */ -static DBData *db_obj_vensure(DBMap *self, DBKey key, DBCreateData create, va_list args) -{ - DBMap_impl *db = (DBMap_impl *)self; - DBNode node; - DBNode parent = NULL; - unsigned int hash; - int c = 0; - DBData *data = NULL; - - DB_COUNTSTAT(db_vensure); - if (db == NULL) return NULL; // nullpo candidate - if (create == NULL) { - ShowError("db_ensure: Create function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_ensure: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } - - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) - return &db->cache->data; // cache hit - - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - node = db->ht[hash]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - break; - } - parent = node; - if (c < 0) - node = node->left; - else - node = node->right; - } - // Create node if necessary - if (node == NULL) { - va_list argscopy; - if (db->item_count == UINT32_MAX) { - ShowError("db_vensure: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); - return NULL; - } - DB_COUNTSTAT(db_node_alloc); - node = ers_alloc(db->nodes, struct dbn); - node->left = NULL; - node->right = NULL; - node->deleted = 0; - db->item_count++; - if (c == 0) { // hash entry is empty - node->color = BLACK; - node->parent = NULL; - db->ht[hash] = node; - } else { - node->color = RED; - if (c < 0) { // put at the left - parent->left = node; - node->parent = parent; - } else { // put at the right - parent->right = node; - node->parent = parent; - } - if (parent->color == RED) // two consecutive RED nodes, must rebalance - db_rebalance(node, &db->ht[hash]); - } - // put key and data in the node - if (db->options&DB_OPT_DUP_KEY) { - node->key = db_dup_key(db, key); - if (db->options&DB_OPT_RELEASE_KEY) - db->release(key, *data, DB_RELEASE_KEY); - } else { - node->key = key; - } - va_copy(argscopy, args); - node->data = create(key, argscopy); - va_end(argscopy); - } - data = &node->data; - db->cache = node; - db_free_unlock(db); - return data; +static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_list args) +{ + DBMap_impl* db = (DBMap_impl*)self; + DBNode node; + DBNode parent = NULL; + unsigned int hash; + int c = 0; + DBData *data = NULL; + + DB_COUNTSTAT(db_vensure); + if (db == NULL) return NULL; // nullpo candidate + if (create == NULL) { + ShowError("db_ensure: Create function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_ensure: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } + + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) + return &db->cache->data; // cache hit + + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + node = db->ht[hash]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + break; + } + parent = node; + if (c < 0) + node = node->left; + else + node = node->right; + } + // Create node if necessary + if (node == NULL) { + va_list argscopy; + if (db->item_count == UINT32_MAX) { + ShowError("db_vensure: item_count overflow, aborting item insertion.\n" + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); + return NULL; + } + DB_COUNTSTAT(db_node_alloc); + node = ers_alloc(db->nodes, struct dbn); + node->left = NULL; + node->right = NULL; + node->deleted = 0; + db->item_count++; + if (c == 0) { // hash entry is empty + node->color = BLACK; + node->parent = NULL; + db->ht[hash] = node; + } else { + node->color = RED; + if (c < 0) { // put at the left + parent->left = node; + node->parent = parent; + } else { // put at the right + parent->right = node; + node->parent = parent; + } + if (parent->color == RED) // two consecutive RED nodes, must rebalance + db_rebalance(node, &db->ht[hash]); + } + // put key and data in the node + if (db->options&DB_OPT_DUP_KEY) { + node->key = db_dup_key(db, key); + if (db->options&DB_OPT_RELEASE_KEY) + db->release(key, *data, DB_RELEASE_KEY); + } else { + node->key = key; + } + va_copy(argscopy, args); + node->data = create(key, argscopy); + va_end(argscopy); + } + data = &node->data; + db->cache = node; + db_free_unlock(db); + return data; } /** * Just calls {@link DBMap#vensure}. * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by + * If the entry does not exist, an entry is added with the data returned by * create. * @param self Interface of the database * @param key Key that identifies the entry @@ -1714,18 +1719,18 @@ static DBData *db_obj_vensure(DBMap *self, DBKey key, DBCreateData create, va_li * @see DBMap#vensure * @see DBMap#ensure */ -static DBData *db_obj_ensure(DBMap *self, DBKey key, DBCreateData create, ...) +static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...) { - va_list args; - DBData *ret = NULL; + va_list args; + DBData *ret = NULL; - DB_COUNTSTAT(db_ensure); - if (self == NULL) return NULL; // nullpo candidate + DB_COUNTSTAT(db_ensure); + if (self == NULL) return NULL; // nullpo candidate - va_start(args, create); - ret = self->vensure(self, key, create, args); - va_end(args); - return ret; + va_start(args, create); + ret = self->vensure(self, key, create, args); + va_end(args); + return ret; } /** @@ -1741,97 +1746,97 @@ static DBData *db_obj_ensure(DBMap *self, DBKey key, DBCreateData create, ...) * @see #db_malloc_dbn(void) * @see DBMap#put */ -static int db_obj_put(DBMap *self, DBKey key, DBData data, DBData *out_data) -{ - DBMap_impl *db = (DBMap_impl *)self; - DBNode node; - DBNode parent = NULL; - int c = 0, retval = 0; - unsigned int hash; - - DB_COUNTSTAT(db_put); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_put: Database is being destroyed, aborting entry insertion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_put: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_DATA) && (data.type == DB_DATA_PTR && data.u.ptr == NULL)) { - ShowError("db_put: Attempted to use non-allowed NULL data for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - if (db->item_count == UINT32_MAX) { - ShowError("db_put: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); - return 0; - } - // search for an equal node - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - for (node = db->ht[hash]; node;) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { // equal entry, replace - if (node->deleted) { - db_free_remove(db, node); - } else { - db->release(node->key, node->data, DB_RELEASE_BOTH); - if (out_data) - memcpy(out_data, &node->data, sizeof(*out_data)); - retval = 1; - } - break; - } - parent = node; - if (c < 0) { - node = node->left; - } else { - node = node->right; - } - } - // allocate a new node if necessary - if (node == NULL) { - DB_COUNTSTAT(db_node_alloc); - node = ers_alloc(db->nodes, struct dbn); - node->left = NULL; - node->right = NULL; - node->deleted = 0; - db->item_count++; - if (c == 0) { // hash entry is empty - node->color = BLACK; - node->parent = NULL; - db->ht[hash] = node; - } else { - node->color = RED; - if (c < 0) { // put at the left - parent->left = node; - node->parent = parent; - } else { // put at the right - parent->right = node; - node->parent = parent; - } - if (parent->color == RED) // two consecutive RED nodes, must rebalance - db_rebalance(node, &db->ht[hash]); - } - } - // put key and data in the node - if (db->options&DB_OPT_DUP_KEY) { - node->key = db_dup_key(db, key); - if (db->options&DB_OPT_RELEASE_KEY) - db->release(key, data, DB_RELEASE_KEY); - } else { - node->key = key; - } - node->data = data; - db->cache = node; - db_free_unlock(db); - return retval; +static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) +{ + DBMap_impl* db = (DBMap_impl*)self; + DBNode node; + DBNode parent = NULL; + int c = 0, retval = 0; + unsigned int hash; + + DB_COUNTSTAT(db_put); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_put: Database is being destroyed, aborting entry insertion.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_put: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_DATA) && (data.type == DB_DATA_PTR && data.u.ptr == NULL)) { + ShowError("db_put: Attempted to use non-allowed NULL data for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + if (db->item_count == UINT32_MAX) { + ShowError("db_put: item_count overflow, aborting item insertion.\n" + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); + return 0; + } + // search for an equal node + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + for (node = db->ht[hash]; node; ) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { // equal entry, replace + if (node->deleted) { + db_free_remove(db, node); + } else { + db->release(node->key, node->data, DB_RELEASE_BOTH); + if (out_data) + memcpy(out_data, &node->data, sizeof(*out_data)); + retval = 1; + } + break; + } + parent = node; + if (c < 0) { + node = node->left; + } else { + node = node->right; + } + } + // allocate a new node if necessary + if (node == NULL) { + DB_COUNTSTAT(db_node_alloc); + node = ers_alloc(db->nodes, struct dbn); + node->left = NULL; + node->right = NULL; + node->deleted = 0; + db->item_count++; + if (c == 0) { // hash entry is empty + node->color = BLACK; + node->parent = NULL; + db->ht[hash] = node; + } else { + node->color = RED; + if (c < 0) { // put at the left + parent->left = node; + node->parent = parent; + } else { // put at the right + parent->right = node; + node->parent = parent; + } + if (parent->color == RED) // two consecutive RED nodes, must rebalance + db_rebalance(node, &db->ht[hash]); + } + } + // put key and data in the node + if (db->options&DB_OPT_DUP_KEY) { + node->key = db_dup_key(db, key); + if (db->options&DB_OPT_RELEASE_KEY) + db->release(key, data, DB_RELEASE_KEY); + } else { + node->key = key; + } + node->data = data; + db->cache = node; + db_free_unlock(db); + return retval; } /** @@ -1846,49 +1851,49 @@ static int db_obj_put(DBMap *self, DBKey key, DBData data, DBData *out_data) * @see #db_free_add(DBMap_impl*,DBNode,DBNode *) * @see DBMap#remove */ -static int db_obj_remove(DBMap *self, DBKey key, DBData *out_data) -{ - DBMap_impl *db = (DBMap_impl *)self; - DBNode node; - unsigned int hash; - int c = 0, retval = 0; - - DB_COUNTSTAT(db_remove); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_remove: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - for (node = db->ht[hash]; node;) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - if (db->cache == node) - db->cache = NULL; - if (out_data) - memcpy(out_data, &node->data, sizeof(*out_data)); - retval = 1; - db->release(node->key, node->data, DB_RELEASE_DATA); - db_free_add(db, node, &db->ht[hash]); - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return retval; +static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) +{ + DBMap_impl* db = (DBMap_impl*)self; + DBNode node; + unsigned int hash; + int c = 0, retval = 0; + + DB_COUNTSTAT(db_remove); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_remove: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + for(node = db->ht[hash]; node; ){ + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + if (db->cache == node) + db->cache = NULL; + if (out_data) + memcpy(out_data, &node->data, sizeof(*out_data)); + retval = 1; + db->release(node->key, node->data, DB_RELEASE_DATA); + db_free_add(db, node, &db->ht[hash]); + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return retval; } /** @@ -1901,52 +1906,52 @@ static int db_obj_remove(DBMap *self, DBKey key, DBData *out_data) * @protected * @see DBMap#vforeach */ -static int db_obj_vforeach(DBMap *self, DBApply func, va_list args) -{ - DBMap_impl *db = (DBMap_impl *)self; - unsigned int i; - int sum = 0; - DBNode node; - DBNode parent; - - DB_COUNTSTAT(db_vforeach); - if (db == NULL) return 0; // nullpo candidate - if (func == NULL) { - ShowError("db_foreach: Passed function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - db_free_lock(db); - for (i = 0; i < HASH_SIZE; i++) { - // Apply func in the order: current node, left node, right node - node = db->ht[i]; - while (node) { - if (!(node->deleted)) { - va_list argscopy; - va_copy(argscopy, args); - sum += func(node->key, &node->data, argscopy); - va_end(argscopy); - } - if (node->left) { - node = node->left; - continue; - } - if (node->right) { - node = node->right; - continue; - } - while (node) { - parent = node->parent; - if (parent && parent->right && parent->left == node) { - node = parent->right; - break; - } - node = parent; - } - } - } - db_free_unlock(db); - return sum; +static int db_obj_vforeach(DBMap* self, DBApply func, va_list args) +{ + DBMap_impl* db = (DBMap_impl*)self; + unsigned int i; + int sum = 0; + DBNode node; + DBNode parent; + + DB_COUNTSTAT(db_vforeach); + if (db == NULL) return 0; // nullpo candidate + if (func == NULL) { + ShowError("db_foreach: Passed function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + db_free_lock(db); + for (i = 0; i < HASH_SIZE; i++) { + // Apply func in the order: current node, left node, right node + node = db->ht[i]; + while (node) { + if (!(node->deleted)) { + va_list argscopy; + va_copy(argscopy, args); + sum += func(node->key, &node->data, argscopy); + va_end(argscopy); + } + if (node->left) { + node = node->left; + continue; + } + if (node->right) { + node = node->right; + continue; + } + while (node) { + parent = node->parent; + if (parent && parent->right && parent->left == node) { + node = parent->right; + break; + } + node = parent; + } + } + } + db_free_unlock(db); + return sum; } /** @@ -1961,18 +1966,18 @@ static int db_obj_vforeach(DBMap *self, DBApply func, va_list args) * @see DBMap#vforeach * @see DBMap#foreach */ -static int db_obj_foreach(DBMap *self, DBApply func, ...) +static int db_obj_foreach(DBMap* self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_foreach); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_foreach); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vforeach(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vforeach(self, func, args); + va_end(args); + return ret; } /** @@ -1987,61 +1992,62 @@ static int db_obj_foreach(DBMap *self, DBApply func, ...) * @protected * @see DBMap#vclear */ -static int db_obj_vclear(DBMap *self, DBApply func, va_list args) -{ - DBMap_impl *db = (DBMap_impl *)self; - int sum = 0; - unsigned int i; - DBNode node; - DBNode parent; - - DB_COUNTSTAT(db_vclear); - if (db == NULL) return 0; // nullpo candidate - - db_free_lock(db); - db->cache = NULL; - for (i = 0; i < HASH_SIZE; i++) { - // Apply the func and delete in the order: left tree, right tree, current node - node = db->ht[i]; - db->ht[i] = NULL; - while (node) { - parent = node->parent; - if (node->left) { - node = node->left; - continue; - } - if (node->right) { - node = node->right; - continue; - } - if (node->deleted) { - db_dup_key_free(db, node->key); - } else { - if (func) { - va_list argscopy; - va_copy(argscopy, args); - sum += func(node->key, &node->data, argscopy); - va_end(argscopy); - } - db->release(node->key, node->data, DB_RELEASE_BOTH); - node->deleted = 1; - } - DB_COUNTSTAT(db_node_free); - if (parent) { - if (parent->left == node) - parent->left = NULL; - else - parent->right = NULL; - } - ers_free(db->nodes, node); - node = parent; - } - db->ht[i] = NULL; - } - db->free_count = 0; - db->item_count = 0; - db_free_unlock(db); - return sum; +static int db_obj_vclear(DBMap* self, DBApply func, va_list args) +{ + DBMap_impl* db = (DBMap_impl*)self; + int sum = 0; + unsigned int i; + DBNode node; + DBNode parent; + + DB_COUNTSTAT(db_vclear); + if (db == NULL) return 0; // nullpo candidate + + db_free_lock(db); + db->cache = NULL; + for (i = 0; i < HASH_SIZE; i++) { + // Apply the func and delete in the order: left tree, right tree, current node + node = db->ht[i]; + db->ht[i] = NULL; + while (node) { + parent = node->parent; + if (node->left) { + node = node->left; + continue; + } + if (node->right) { + node = node->right; + continue; + } + if (node->deleted) { + db_dup_key_free(db, node->key); + } else { + if (func) + { + va_list argscopy; + va_copy(argscopy, args); + sum += func(node->key, &node->data, argscopy); + va_end(argscopy); + } + db->release(node->key, node->data, DB_RELEASE_BOTH); + node->deleted = 1; + } + DB_COUNTSTAT(db_node_free); + if (parent) { + if (parent->left == node) + parent->left = NULL; + else + parent->right = NULL; + } + ers_free(db->nodes, node); + node = parent; + } + db->ht[i] = NULL; + } + db->free_count = 0; + db->item_count = 0; + db_free_unlock(db); + return sum; } /** @@ -2050,7 +2056,7 @@ static int db_obj_vclear(DBMap *self, DBApply func, va_list args) * Before deleting an entry, func is applied to it. * Releases the key and the data. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted (except for clearing). * @param self Interface of the database * @param func Function to be applied to every entry before deleting @@ -2060,25 +2066,25 @@ static int db_obj_vclear(DBMap *self, DBApply func, va_list args) * @see DBMap#vclear * @see DBMap#clear */ -static int db_obj_clear(DBMap *self, DBApply func, ...) +static int db_obj_clear(DBMap* self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_clear); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_clear); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vclear(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vclear(self, func, args); + va_end(args); + return ret; } /** * Finalize the database, feeing all the memory it uses. * Before deleting an entry, func is applied to it. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted (except for clearing). * @param self Interface of the database * @param func Function to be applied to every entry before deleting @@ -2087,50 +2093,42 @@ static int db_obj_clear(DBMap *self, DBApply func, ...) * @protected * @see DBMap#vdestroy */ -static int db_obj_vdestroy(DBMap *self, DBApply func, va_list args) +static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) { - DBMap_impl *db = (DBMap_impl *)self; - int sum; + DBMap_impl* db = (DBMap_impl*)self; + int sum; - DB_COUNTSTAT(db_vdestroy); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; - } - if (db->free_lock) - ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n" - "Database allocated at %s:%d\n", - db->free_lock, db->alloc_file, db->alloc_line); + DB_COUNTSTAT(db_vdestroy); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; + } + if (db->free_lock) + ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n" + "Database allocated at %s:%d\n", + db->free_lock, db->alloc_file, db->alloc_line); #ifdef DB_ENABLE_STATS - switch (db->type) { - case DB_INT: - DB_COUNTSTAT(db_int_destroy); - break; - case DB_UINT: - DB_COUNTSTAT(db_uint_destroy); - break; - case DB_STRING: - DB_COUNTSTAT(db_string_destroy); - break; - case DB_ISTRING: - DB_COUNTSTAT(db_istring_destroy); - break; - } + switch (db->type) { + case DB_INT: DB_COUNTSTAT(db_int_destroy); break; + case DB_UINT: DB_COUNTSTAT(db_uint_destroy); break; + case DB_STRING: DB_COUNTSTAT(db_string_destroy); break; + case DB_ISTRING: DB_COUNTSTAT(db_istring_destroy); break; + } #endif /* DB_ENABLE_STATS */ - db_free_lock(db); - db->global_lock = 1; - sum = self->vclear(self, func, args); - aFree(db->free_list); - db->free_list = NULL; - db->free_max = 0; - ers_destroy(db->nodes); - db_free_unlock(db); - aFree(db); - return sum; + db_free_lock(db); + db->global_lock = 1; + sum = self->vclear(self, func, args); + aFree(db->free_list); + db->free_list = NULL; + db->free_max = 0; + ers_destroy(db->nodes); + db_free_unlock(db); + aFree(db); + return sum; } /** @@ -2139,7 +2137,7 @@ static int db_obj_vdestroy(DBMap *self, DBApply func, va_list args) * Before deleting an entry, func is applied to it. * Releases the key and the data. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted. * @param self Database * @param func Function to be applied to every entry before deleting @@ -2149,18 +2147,18 @@ static int db_obj_vdestroy(DBMap *self, DBApply func, va_list args) * @see DBMap#vdestroy * @see DBMap#destroy */ -static int db_obj_destroy(DBMap *self, DBApply func, ...) +static int db_obj_destroy(DBMap* self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_destroy); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_destroy); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vdestroy(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vdestroy(self, func, args); + va_end(args); + return ret; } /** @@ -2171,19 +2169,19 @@ static int db_obj_destroy(DBMap *self, DBApply func, ...) * @see DBMap_impl#item_count * @see DBMap#size */ -static unsigned int db_obj_size(DBMap *self) +static unsigned int db_obj_size(DBMap* self) { - DBMap_impl *db = (DBMap_impl *)self; - unsigned int item_count; + DBMap_impl* db = (DBMap_impl*)self; + unsigned int item_count; - DB_COUNTSTAT(db_size); - if (db == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_size); + if (db == NULL) return 0; // nullpo candidate - db_free_lock(db); - item_count = db->item_count; - db_free_unlock(db); + db_free_lock(db); + item_count = db->item_count; + db_free_unlock(db); - return item_count; + return item_count; } /** @@ -2194,19 +2192,19 @@ static unsigned int db_obj_size(DBMap *self) * @see DBMap_impl#type * @see DBMap#type */ -static DBType db_obj_type(DBMap *self) +static DBType db_obj_type(DBMap* self) { - DBMap_impl *db = (DBMap_impl *)self; - DBType type; + DBMap_impl* db = (DBMap_impl*)self; + DBType type; - DB_COUNTSTAT(db_type); - if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return? + DB_COUNTSTAT(db_type); + if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return? - db_free_lock(db); - type = db->type; - db_free_unlock(db); + db_free_lock(db); + type = db->type; + db_free_unlock(db); - return type; + return type; } /** @@ -2217,19 +2215,19 @@ static DBType db_obj_type(DBMap *self) * @see DBMap_impl#options * @see DBMap#options */ -static DBOptions db_obj_options(DBMap *self) +static DBOptions db_obj_options(DBMap* self) { - DBMap_impl *db = (DBMap_impl *)self; - DBOptions options; + DBMap_impl* db = (DBMap_impl*)self; + DBOptions options; - DB_COUNTSTAT(db_options); - if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return? + DB_COUNTSTAT(db_options); + if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return? - db_free_lock(db); - options = db->options; - db_free_unlock(db); + db_free_lock(db); + options = db->options; + db_free_unlock(db); - return options; + return options; } /*****************************************************************************\ @@ -2266,18 +2264,18 @@ static DBOptions db_obj_options(DBMap *self) */ DBOptions db_fix_options(DBType type, DBOptions options) { - DB_COUNTSTAT(db_fix_options); - switch (type) { - case DB_INT: - case DB_UINT: // Numeric database, do nothing with the keys - return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)); + DB_COUNTSTAT(db_fix_options); + switch (type) { + case DB_INT: + case DB_UINT: // Numeric database, do nothing with the keys + return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)); - default: - ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options); - case DB_STRING: - case DB_ISTRING: // String databases, no fix required - return options; - } + default: + ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options); + case DB_STRING: + case DB_ISTRING: // String databases, no fix required + return options; + } } /** @@ -2292,20 +2290,16 @@ DBOptions db_fix_options(DBType type, DBOptions options) */ DBComparator db_default_cmp(DBType type) { - DB_COUNTSTAT(db_default_cmp); - switch (type) { - case DB_INT: - return &db_int_cmp; - case DB_UINT: - return &db_uint_cmp; - case DB_STRING: - return &db_string_cmp; - case DB_ISTRING: - return &db_istring_cmp; - default: - ShowError("db_default_cmp: Unknown database type %u\n", type); - return NULL; - } + DB_COUNTSTAT(db_default_cmp); + switch (type) { + case DB_INT: return &db_int_cmp; + case DB_UINT: return &db_uint_cmp; + case DB_STRING: return &db_string_cmp; + case DB_ISTRING: return &db_istring_cmp; + default: + ShowError("db_default_cmp: Unknown database type %u\n", type); + return NULL; + } } /** @@ -2320,24 +2314,20 @@ DBComparator db_default_cmp(DBType type) */ DBHasher db_default_hash(DBType type) { - DB_COUNTSTAT(db_default_hash); - switch (type) { - case DB_INT: - return &db_int_hash; - case DB_UINT: - return &db_uint_hash; - case DB_STRING: - return &db_string_hash; - case DB_ISTRING: - return &db_istring_hash; - default: - ShowError("db_default_hash: Unknown database type %u\n", type); - return NULL; - } + DB_COUNTSTAT(db_default_hash); + switch (type) { + case DB_INT: return &db_int_hash; + case DB_UINT: return &db_uint_hash; + case DB_STRING: return &db_string_hash; + case DB_ISTRING: return &db_istring_hash; + default: + ShowError("db_default_hash: Unknown database type %u\n", type); + return NULL; + } } /** - * Returns the default releaser for the specified type of database with the + * Returns the default releaser for the specified type of database with the * specified options. * NOTE: the options are fixed with {@link #db_fix_options(DBType,DBOptions)} * before choosing the releaser. @@ -2353,16 +2343,16 @@ DBHasher db_default_hash(DBType type) */ DBReleaser db_default_release(DBType type, DBOptions options) { - DB_COUNTSTAT(db_default_release); - options = db_fix_options(type, options); - if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key? - if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) - return &db_release_both; // Release both key and data - return &db_release_data; // Only release data - } - if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) - return &db_release_key; // Only release key - return &db_release_nothing; // Release nothing + DB_COUNTSTAT(db_default_release); + options = db_fix_options(type, options); + if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key? + if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) + return &db_release_both; // Release both key and data + return &db_release_data; // Only release data + } + if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) + return &db_release_key; // Only release key + return &db_release_nothing; // Release nothing } /** @@ -2378,20 +2368,16 @@ DBReleaser db_default_release(DBType type, DBOptions options) */ DBReleaser db_custom_release(DBRelease which) { - DB_COUNTSTAT(db_custom_release); - switch (which) { - case DB_RELEASE_NOTHING: - return &db_release_nothing; - case DB_RELEASE_KEY: - return &db_release_key; - case DB_RELEASE_DATA: - return &db_release_data; - case DB_RELEASE_BOTH: - return &db_release_both; - default: - ShowError("db_custom_release: Unknown release options %u\n", which); - return NULL; - } + DB_COUNTSTAT(db_custom_release); + switch (which) { + case DB_RELEASE_NOTHING: return &db_release_nothing; + case DB_RELEASE_KEY: return &db_release_key; + case DB_RELEASE_DATA: return &db_release_data; + case DB_RELEASE_BOTH: return &db_release_both; + default: + ShowError("db_custom_release: Unknown release options %u\n", which); + return NULL; + } } /** @@ -2402,83 +2388,75 @@ DBReleaser db_custom_release(DBRelease which) * @param line Line of the file where the database is being allocated * @param type Type of database * @param options Options of the database - * @param maxlen Maximum length of the string to be used as key in string + * @param maxlen Maximum length of the string to be used as key in string * databases. If 0, the maximum number of maxlen is used (64K). * @return The interface of the database * @public * @see #DBMap_impl * @see #db_fix_options(DBType,DBOptions) */ -DBMap *db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) +DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) { - DBMap_impl *db; - unsigned int i; + DBMap_impl* db; + unsigned int i; #ifdef DB_ENABLE_STATS - DB_COUNTSTAT(db_alloc); - switch (type) { - case DB_INT: - DB_COUNTSTAT(db_int_alloc); - break; - case DB_UINT: - DB_COUNTSTAT(db_uint_alloc); - break; - case DB_STRING: - DB_COUNTSTAT(db_string_alloc); - break; - case DB_ISTRING: - DB_COUNTSTAT(db_istring_alloc); - break; - } + DB_COUNTSTAT(db_alloc); + switch (type) { + case DB_INT: DB_COUNTSTAT(db_int_alloc); break; + case DB_UINT: DB_COUNTSTAT(db_uint_alloc); break; + case DB_STRING: DB_COUNTSTAT(db_string_alloc); break; + case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break; + } #endif /* DB_ENABLE_STATS */ - CREATE(db, struct DBMap_impl, 1); - - options = db_fix_options(type, options); - /* Interface of the database */ - db->vtable.iterator = db_obj_iterator; - db->vtable.exists = db_obj_exists; - db->vtable.get = db_obj_get; - db->vtable.getall = db_obj_getall; - db->vtable.vgetall = db_obj_vgetall; - db->vtable.ensure = db_obj_ensure; - db->vtable.vensure = db_obj_vensure; - db->vtable.put = db_obj_put; - db->vtable.remove = db_obj_remove; - db->vtable.foreach = db_obj_foreach; - db->vtable.vforeach = db_obj_vforeach; - db->vtable.clear = db_obj_clear; - db->vtable.vclear = db_obj_vclear; - db->vtable.destroy = db_obj_destroy; - db->vtable.vdestroy = db_obj_vdestroy; - db->vtable.size = db_obj_size; - db->vtable.type = db_obj_type; - db->vtable.options = db_obj_options; - /* File and line of allocation */ - db->alloc_file = file; - db->alloc_line = line; - /* Lock system */ - db->free_list = NULL; - db->free_count = 0; - db->free_max = 0; - db->free_lock = 0; - /* Other */ - db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); - db->cmp = db_default_cmp(type); - db->hash = db_default_hash(type); - db->release = db_default_release(type, options); - for (i = 0; i < HASH_SIZE; i++) - db->ht[i] = NULL; - db->cache = NULL; - db->type = type; - db->options = options; - db->item_count = 0; - db->maxlen = maxlen; - db->global_lock = 0; - - if (db->maxlen == 0 && (type == DB_STRING || type == DB_ISTRING)) - db->maxlen = UINT16_MAX; - - return &db->vtable; + CREATE(db, struct DBMap_impl, 1); + + options = db_fix_options(type, options); + /* Interface of the database */ + db->vtable.iterator = db_obj_iterator; + db->vtable.exists = db_obj_exists; + db->vtable.get = db_obj_get; + db->vtable.getall = db_obj_getall; + db->vtable.vgetall = db_obj_vgetall; + db->vtable.ensure = db_obj_ensure; + db->vtable.vensure = db_obj_vensure; + db->vtable.put = db_obj_put; + db->vtable.remove = db_obj_remove; + db->vtable.foreach = db_obj_foreach; + db->vtable.vforeach = db_obj_vforeach; + db->vtable.clear = db_obj_clear; + db->vtable.vclear = db_obj_vclear; + db->vtable.destroy = db_obj_destroy; + db->vtable.vdestroy = db_obj_vdestroy; + db->vtable.size = db_obj_size; + db->vtable.type = db_obj_type; + db->vtable.options = db_obj_options; + /* File and line of allocation */ + db->alloc_file = file; + db->alloc_line = line; + /* Lock system */ + db->free_list = NULL; + db->free_count = 0; + db->free_max = 0; + db->free_lock = 0; + /* Other */ + db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); + db->cmp = db_default_cmp(type); + db->hash = db_default_hash(type); + db->release = db_default_release(type, options); + for (i = 0; i < HASH_SIZE; i++) + db->ht[i] = NULL; + db->cache = NULL; + db->type = type; + db->options = options; + db->item_count = 0; + db->maxlen = maxlen; + db->global_lock = 0; + + if( db->maxlen == 0 && (type == DB_STRING || type == DB_ISTRING) ) + db->maxlen = UINT16_MAX; + + return &db->vtable; } /** @@ -2489,11 +2467,11 @@ DBMap *db_alloc(const char *file, int line, DBType type, DBOptions options, unsi */ DBKey db_i2key(int key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_i2key); - ret.i = key; - return ret; + DB_COUNTSTAT(db_i2key); + ret.i = key; + return ret; } /** @@ -2504,11 +2482,11 @@ DBKey db_i2key(int key) */ DBKey db_ui2key(unsigned int key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_ui2key); - ret.ui = key; - return ret; + DB_COUNTSTAT(db_ui2key); + ret.ui = key; + return ret; } /** @@ -2519,11 +2497,11 @@ DBKey db_ui2key(unsigned int key) */ DBKey db_str2key(const char *key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_str2key); - ret.str = key; - return ret; + DB_COUNTSTAT(db_str2key); + ret.str = key; + return ret; } /** @@ -2534,12 +2512,12 @@ DBKey db_str2key(const char *key) */ DBData db_i2data(int data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_i2data); - ret.type = DB_DATA_INT; - ret.u.i = data; - return ret; + DB_COUNTSTAT(db_i2data); + ret.type = DB_DATA_INT; + ret.u.i = data; + return ret; } /** @@ -2550,12 +2528,12 @@ DBData db_i2data(int data) */ DBData db_ui2data(unsigned int data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_ui2data); - ret.type = DB_DATA_UINT; - ret.u.ui = data; - return ret; + DB_COUNTSTAT(db_ui2data); + ret.type = DB_DATA_UINT; + ret.u.ui = data; + return ret; } /** @@ -2566,12 +2544,12 @@ DBData db_ui2data(unsigned int data) */ DBData db_ptr2data(void *data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_ptr2data); - ret.type = DB_DATA_PTR; - ret.u.ptr = data; - return ret; + DB_COUNTSTAT(db_ptr2data); + ret.type = DB_DATA_PTR; + ret.u.ptr = data; + return ret; } /** @@ -2583,10 +2561,10 @@ DBData db_ptr2data(void *data) */ int db_data2i(DBData *data) { - DB_COUNTSTAT(db_data2i); - if (data && DB_DATA_INT == data->type) - return data->u.i; - return 0; + DB_COUNTSTAT(db_data2i); + if (data && DB_DATA_INT == data->type) + return data->u.i; + return 0; } /** @@ -2598,10 +2576,10 @@ int db_data2i(DBData *data) */ unsigned int db_data2ui(DBData *data) { - DB_COUNTSTAT(db_data2ui); - if (data && DB_DATA_UINT == data->type) - return data->u.ui; - return 0; + DB_COUNTSTAT(db_data2ui); + if (data && DB_DATA_UINT == data->type) + return data->u.ui; + return 0; } /** @@ -2611,12 +2589,12 @@ unsigned int db_data2ui(DBData *data) * @return Void* value of the data. * @public */ -void *db_data2ptr(DBData *data) +void* db_data2ptr(DBData *data) { - DB_COUNTSTAT(db_data2ptr); - if (data && DB_DATA_PTR == data->type) - return data->u.ptr; - return NULL; + DB_COUNTSTAT(db_data2ptr); + if (data && DB_DATA_PTR == data->type) + return data->u.ptr; + return NULL; } /** @@ -2626,7 +2604,7 @@ void *db_data2ptr(DBData *data) */ void db_init(void) { - DB_COUNTSTAT(db_init); + DB_COUNTSTAT(db_init); } /** @@ -2637,208 +2615,208 @@ void db_init(void) void db_final(void) { #ifdef DB_ENABLE_STATS - DB_COUNTSTAT(db_final); - ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n" - "allocated %u, freed %u\n", - stats.db_node_alloc, stats.db_node_free); - ShowInfo(CL_WHITE"Database types"CL_RESET":\n" - "DB_INT : allocated %10u, destroyed %10u\n" - "DB_UINT : allocated %10u, destroyed %10u\n" - "DB_STRING : allocated %10u, destroyed %10u\n" - "DB_ISTRING : allocated %10u, destroyed %10u\n", - stats.db_int_alloc, stats.db_int_destroy, - stats.db_uint_alloc, stats.db_uint_destroy, - stats.db_string_alloc, stats.db_string_destroy, - stats.db_istring_alloc, stats.db_istring_destroy); - ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n" - "db_rotate_left %10u, db_rotate_right %10u,\n" - "db_rebalance %10u, db_rebalance_erase %10u,\n" - "db_is_key_null %10u,\n" - "db_dup_key %10u, db_dup_key_free %10u,\n" - "db_free_add %10u, db_free_remove %10u,\n" - "db_free_lock %10u, db_free_unlock %10u,\n" - "db_int_cmp %10u, db_uint_cmp %10u,\n" - "db_string_cmp %10u, db_istring_cmp %10u,\n" - "db_int_hash %10u, db_uint_hash %10u,\n" - "db_string_hash %10u, db_istring_hash %10u,\n" - "db_release_nothing %10u, db_release_key %10u,\n" - "db_release_data %10u, db_release_both %10u,\n" - "dbit_first %10u, dbit_last %10u,\n" - "dbit_next %10u, dbit_prev %10u,\n" - "dbit_exists %10u, dbit_remove %10u,\n" - "dbit_destroy %10u, db_iterator %10u,\n" - "db_exits %10u, db_get %10u,\n" - "db_getall %10u, db_vgetall %10u,\n" - "db_ensure %10u, db_vensure %10u,\n" - "db_put %10u, db_remove %10u,\n" - "db_foreach %10u, db_vforeach %10u,\n" - "db_clear %10u, db_vclear %10u,\n" - "db_destroy %10u, db_vdestroy %10u,\n" - "db_size %10u, db_type %10u,\n" - "db_options %10u, db_fix_options %10u,\n" - "db_default_cmp %10u, db_default_hash %10u,\n" - "db_default_release %10u, db_custom_release %10u,\n" - "db_alloc %10u, db_i2key %10u,\n" - "db_ui2key %10u, db_str2key %10u,\n" - "db_i2data %10u, db_ui2data %10u,\n" - "db_ptr2data %10u, db_data2i %10u,\n" - "db_data2ui %10u, db_data2ptr %10u,\n" - "db_init %10u, db_final %10u\n", - stats.db_rotate_left, stats.db_rotate_right, - stats.db_rebalance, stats.db_rebalance_erase, - stats.db_is_key_null, - stats.db_dup_key, stats.db_dup_key_free, - stats.db_free_add, stats.db_free_remove, - stats.db_free_lock, stats.db_free_unlock, - stats.db_int_cmp, stats.db_uint_cmp, - stats.db_string_cmp, stats.db_istring_cmp, - stats.db_int_hash, stats.db_uint_hash, - stats.db_string_hash, stats.db_istring_hash, - stats.db_release_nothing, stats.db_release_key, - stats.db_release_data, stats.db_release_both, - stats.dbit_first, stats.dbit_last, - stats.dbit_next, stats.dbit_prev, - stats.dbit_exists, stats.dbit_remove, - stats.dbit_destroy, stats.db_iterator, - stats.db_exists, stats.db_get, - stats.db_getall, stats.db_vgetall, - stats.db_ensure, stats.db_vensure, - stats.db_put, stats.db_remove, - stats.db_foreach, stats.db_vforeach, - stats.db_clear, stats.db_vclear, - stats.db_destroy, stats.db_vdestroy, - stats.db_size, stats.db_type, - stats.db_options, stats.db_fix_options, - stats.db_default_cmp, stats.db_default_hash, - stats.db_default_release, stats.db_custom_release, - stats.db_alloc, stats.db_i2key, - stats.db_ui2key, stats.db_str2key, - stats.db_i2data, stats.db_ui2data, - stats.db_ptr2data, stats.db_data2i, - stats.db_data2ui, stats.db_data2ptr, - stats.db_init, stats.db_final); + DB_COUNTSTAT(db_final); + ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n" + "allocated %u, freed %u\n", + stats.db_node_alloc, stats.db_node_free); + ShowInfo(CL_WHITE"Database types"CL_RESET":\n" + "DB_INT : allocated %10u, destroyed %10u\n" + "DB_UINT : allocated %10u, destroyed %10u\n" + "DB_STRING : allocated %10u, destroyed %10u\n" + "DB_ISTRING : allocated %10u, destroyed %10u\n", + stats.db_int_alloc, stats.db_int_destroy, + stats.db_uint_alloc, stats.db_uint_destroy, + stats.db_string_alloc, stats.db_string_destroy, + stats.db_istring_alloc, stats.db_istring_destroy); + ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n" + "db_rotate_left %10u, db_rotate_right %10u,\n" + "db_rebalance %10u, db_rebalance_erase %10u,\n" + "db_is_key_null %10u,\n" + "db_dup_key %10u, db_dup_key_free %10u,\n" + "db_free_add %10u, db_free_remove %10u,\n" + "db_free_lock %10u, db_free_unlock %10u,\n" + "db_int_cmp %10u, db_uint_cmp %10u,\n" + "db_string_cmp %10u, db_istring_cmp %10u,\n" + "db_int_hash %10u, db_uint_hash %10u,\n" + "db_string_hash %10u, db_istring_hash %10u,\n" + "db_release_nothing %10u, db_release_key %10u,\n" + "db_release_data %10u, db_release_both %10u,\n" + "dbit_first %10u, dbit_last %10u,\n" + "dbit_next %10u, dbit_prev %10u,\n" + "dbit_exists %10u, dbit_remove %10u,\n" + "dbit_destroy %10u, db_iterator %10u,\n" + "db_exits %10u, db_get %10u,\n" + "db_getall %10u, db_vgetall %10u,\n" + "db_ensure %10u, db_vensure %10u,\n" + "db_put %10u, db_remove %10u,\n" + "db_foreach %10u, db_vforeach %10u,\n" + "db_clear %10u, db_vclear %10u,\n" + "db_destroy %10u, db_vdestroy %10u,\n" + "db_size %10u, db_type %10u,\n" + "db_options %10u, db_fix_options %10u,\n" + "db_default_cmp %10u, db_default_hash %10u,\n" + "db_default_release %10u, db_custom_release %10u,\n" + "db_alloc %10u, db_i2key %10u,\n" + "db_ui2key %10u, db_str2key %10u,\n" + "db_i2data %10u, db_ui2data %10u,\n" + "db_ptr2data %10u, db_data2i %10u,\n" + "db_data2ui %10u, db_data2ptr %10u,\n" + "db_init %10u, db_final %10u\n", + stats.db_rotate_left, stats.db_rotate_right, + stats.db_rebalance, stats.db_rebalance_erase, + stats.db_is_key_null, + stats.db_dup_key, stats.db_dup_key_free, + stats.db_free_add, stats.db_free_remove, + stats.db_free_lock, stats.db_free_unlock, + stats.db_int_cmp, stats.db_uint_cmp, + stats.db_string_cmp, stats.db_istring_cmp, + stats.db_int_hash, stats.db_uint_hash, + stats.db_string_hash, stats.db_istring_hash, + stats.db_release_nothing, stats.db_release_key, + stats.db_release_data, stats.db_release_both, + stats.dbit_first, stats.dbit_last, + stats.dbit_next, stats.dbit_prev, + stats.dbit_exists, stats.dbit_remove, + stats.dbit_destroy, stats.db_iterator, + stats.db_exists, stats.db_get, + stats.db_getall, stats.db_vgetall, + stats.db_ensure, stats.db_vensure, + stats.db_put, stats.db_remove, + stats.db_foreach, stats.db_vforeach, + stats.db_clear, stats.db_vclear, + stats.db_destroy, stats.db_vdestroy, + stats.db_size, stats.db_type, + stats.db_options, stats.db_fix_options, + stats.db_default_cmp, stats.db_default_hash, + stats.db_default_release, stats.db_custom_release, + stats.db_alloc, stats.db_i2key, + stats.db_ui2key, stats.db_str2key, + stats.db_i2data, stats.db_ui2data, + stats.db_ptr2data, stats.db_data2i, + stats.db_data2ui, stats.db_data2ptr, + stats.db_init, stats.db_final); #endif /* DB_ENABLE_STATS */ } // Link DB System - jAthena -void linkdb_insert(struct linkdb_node **head, void *key, void *data) -{ - struct linkdb_node *node; - if (head == NULL) return ; - node = (struct linkdb_node *)aMalloc(sizeof(struct linkdb_node)); - if (*head == NULL) { - // first node - *head = node; - node->prev = NULL; - node->next = NULL; - } else { - // link nodes - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - node->key = key; - node->data = data; -} - -void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...) -{ - struct linkdb_node *node; - if (head == NULL) return; - node = *head; - while (node) { - va_list args; - va_start(args, func); - func(node->key, node->data, args); - va_end(args); - node = node->next; - } -} - -void *linkdb_search(struct linkdb_node **head, void *key) -{ - int n = 0; - struct linkdb_node *node; - if (head == NULL) return NULL; - node = *head; - while (node) { - if (node->key == key) { - if (node->prev && n > 5) { - //Moving the head in order to improve processing efficiency - if (node->prev) node->prev->next = node->next; - if (node->next) node->next->prev = node->prev; - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - return node->data; - } - node = node->next; - n++; - } - return NULL; -} - -void *linkdb_erase(struct linkdb_node **head, void *key) -{ - struct linkdb_node *node; - if (head == NULL) return NULL; - node = *head; - while (node) { - if (node->key == key) { - void *data = node->data; - if (node->prev == NULL) - *head = node->next; - else - node->prev->next = node->next; - if (node->next) - node->next->prev = node->prev; - aFree(node); - return data; - } - node = node->next; - } - return NULL; -} - -void linkdb_replace(struct linkdb_node **head, void *key, void *data) -{ - int n = 0; - struct linkdb_node *node; - if (head == NULL) return ; - node = *head; - while (node) { - if (node->key == key) { - if (node->prev && n > 5) { - //Moving the head in order to improve processing efficiency - if (node->prev) node->prev->next = node->next; - if (node->next) node->next->prev = node->prev; - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - node->data = data; - return ; - } - node = node->next; - n++; - } - //Insert because it can not find - linkdb_insert(head, key, data); -} - -void linkdb_final(struct linkdb_node **head) -{ - struct linkdb_node *node, *node2; - if (head == NULL) return ; - node = *head; - while (node) { - node2 = node->next; - aFree(node); - node = node2; - } - *head = NULL; +void linkdb_insert( struct linkdb_node** head, void *key, void* data) +{ + struct linkdb_node *node; + if( head == NULL ) return ; + node = (struct linkdb_node*)aMalloc( sizeof(struct linkdb_node) ); + if( *head == NULL ) { + // first node + *head = node; + node->prev = NULL; + node->next = NULL; + } else { + // link nodes + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + node->key = key; + node->data = data; +} + +void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ) +{ + struct linkdb_node *node; + if( head == NULL ) return; + node = *head; + while ( node ) { + va_list args; + va_start(args, func); + func( node->key, node->data, args ); + va_end(args); + node = node->next; + } +} + +void* linkdb_search( struct linkdb_node** head, void *key) +{ + int n = 0; + struct linkdb_node *node; + if( head == NULL ) return NULL; + node = *head; + while( node ) { + if( node->key == key ) { + if( node->prev && n > 5 ) { + //Moving the head in order to improve processing efficiency + if(node->prev) node->prev->next = node->next; + if(node->next) node->next->prev = node->prev; + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + return node->data; + } + node = node->next; + n++; + } + return NULL; +} + +void* linkdb_erase( struct linkdb_node** head, void *key) +{ + struct linkdb_node *node; + if( head == NULL ) return NULL; + node = *head; + while( node ) { + if( node->key == key ) { + void *data = node->data; + if( node->prev == NULL ) + *head = node->next; + else + node->prev->next = node->next; + if( node->next ) + node->next->prev = node->prev; + aFree( node ); + return data; + } + node = node->next; + } + return NULL; +} + +void linkdb_replace( struct linkdb_node** head, void *key, void *data ) +{ + int n = 0; + struct linkdb_node *node; + if( head == NULL ) return ; + node = *head; + while( node ) { + if( node->key == key ) { + if( node->prev && n > 5 ) { + //Moving the head in order to improve processing efficiency + if(node->prev) node->prev->next = node->next; + if(node->next) node->next->prev = node->prev; + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + node->data = data; + return ; + } + node = node->next; + n++; + } + //Insert because it can not find + linkdb_insert( head, key, data ); +} + +void linkdb_final( struct linkdb_node** head ) +{ + struct linkdb_node *node, *node2; + if( head == NULL ) return ; + node = *head; + while( node ) { + node2 = node->next; + aFree( node ); + node = node2; + } + *head = NULL; } diff --git a/src/common/db.h b/src/common/db.h index eff3b775e..4fe6a93d6 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -69,15 +69,15 @@ * @see #db_custom_release(DBRelease) */ typedef enum DBRelease { - DB_RELEASE_NOTHING = 0, - DB_RELEASE_KEY = 1, - DB_RELEASE_DATA = 2, - DB_RELEASE_BOTH = 3 + DB_RELEASE_NOTHING = 0, + DB_RELEASE_KEY = 1, + DB_RELEASE_DATA = 2, + DB_RELEASE_BOTH = 3 } DBRelease; /** * Supported types of database. - * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the + * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the * types of databases. * @param DB_INT Uses int's for keys * @param DB_UINT Uses unsigned int's for keys @@ -93,22 +93,22 @@ typedef enum DBRelease { * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short) */ typedef enum DBType { - DB_INT, - DB_UINT, - DB_STRING, - DB_ISTRING + DB_INT, + DB_UINT, + DB_STRING, + DB_ISTRING } DBType; /** * Bitfield of options that define the behaviour of the database. - * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the + * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the * types of databases. * @param DB_OPT_BASE Base options: does not duplicate keys, releases nothing * and does not allow NULL keys or NULL data. - * @param DB_OPT_DUP_KEY Duplicates the keys internally. If DB_OPT_RELEASE_KEY + * @param DB_OPT_DUP_KEY Duplicates the keys internally. If DB_OPT_RELEASE_KEY * is defined, the real key is freed as soon as the entry is added. * @param DB_OPT_RELEASE_KEY Releases the key. - * @param DB_OPT_RELEASE_DATA Releases the data whenever an entry is removed + * @param DB_OPT_RELEASE_DATA Releases the data whenever an entry is removed * from the database. * WARNING: for funtions that return the data (like DBMap::remove), * a dangling pointer will be returned. @@ -121,13 +121,13 @@ typedef enum DBType { * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short) */ typedef enum DBOptions { - DB_OPT_BASE = 0, - DB_OPT_DUP_KEY = 1, - DB_OPT_RELEASE_KEY = 2, - DB_OPT_RELEASE_DATA = 4, - DB_OPT_RELEASE_BOTH = 6, - DB_OPT_ALLOW_NULL_KEY = 8, - DB_OPT_ALLOW_NULL_DATA = 16, + DB_OPT_BASE = 0, + DB_OPT_DUP_KEY = 1, + DB_OPT_RELEASE_KEY = 2, + DB_OPT_RELEASE_DATA = 4, + DB_OPT_RELEASE_BOTH = 6, + DB_OPT_ALLOW_NULL_KEY = 8, + DB_OPT_ALLOW_NULL_DATA = 16, } DBOptions; /** @@ -142,9 +142,9 @@ typedef enum DBOptions { * @see DBMap#remove */ typedef union DBKey { - int i; - unsigned int ui; - const char *str; + int i; + unsigned int ui; + const char *str; } DBKey; /** @@ -156,9 +156,9 @@ typedef union DBKey { * @see #DBData */ typedef enum DBDataType { - DB_DATA_INT, - DB_DATA_UINT, - DB_DATA_PTR + DB_DATA_INT, + DB_DATA_UINT, + DB_DATA_PTR } DBDataType; /** @@ -171,16 +171,16 @@ typedef enum DBDataType { * @public */ typedef struct DBData { - DBDataType type; - union { - int i; - unsigned int ui; - void *ptr; - } u; + DBDataType type; + union { + int i; + unsigned int ui; + void *ptr; + } u; } DBData; /** - * Format of functions that create the data for the key when the entry doesn't + * Format of functions that create the data for the key when the entry doesn't * exist in the database yet. * @param key Key of the database entry * @param args Extra arguments of the function @@ -189,12 +189,12 @@ typedef struct DBData { * @see DBMap#vensure * @see DBMap#ensure */ -typedef DBData(*DBCreateData)(DBKey key, va_list args); +typedef DBData (*DBCreateData)(DBKey key, va_list args); /** - * Format of functions to be applied to an unspecified quantity of entries of + * Format of functions to be applied to an unspecified quantity of entries of * a database. - * Any function that applies this function to the database will return the sum + * Any function that applies this function to the database will return the sum * of values returned by this function. * @param key Key of the database entry * @param data Data of the database entry @@ -272,86 +272,87 @@ typedef struct DBMap DBMap; * Database iterator. * Supports forward iteration, backward iteration and removing entries from the database. * The iterator is initially positioned before the first entry of the database. - * While the iterator exists the database is locked internally, so invoke + * While the iterator exists the database is locked internally, so invoke * {@link DBIterator#destroy} as soon as possible. * @public * @see #DBMap */ -struct DBIterator { - - /** - * Fetches the first entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData *(*first)(DBIterator *self, DBKey *out_key); - - /** - * Fetches the last entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData *(*last)(DBIterator *self, DBKey *out_key); - - /** - * Fetches the next entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData *(*next)(DBIterator *self, DBKey *out_key); - - /** - * Fetches the previous entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData *(*prev)(DBIterator *self, DBKey *out_key); - - /** - * Returns true if the fetched entry exists. - * The databases entries might have NULL data, so use this to to test if - * the iterator is done. - * @param self Iterator - * @return true is the entry exists - * @protected - */ - bool (*exists)(DBIterator *self); - - /** - * Removes the current entry from the database. - * NOTE: {@link DBIterator#exists} will return false until another entry - * is fetched - * Puts data of the removed entry in out_data, if out_data is not NULL. - * @param self Iterator - * @param out_data Data of the removed entry. - * @return 1 if entry was removed, 0 otherwise - * @protected - * @see DBMap#remove - */ - int (*remove)(DBIterator *self, DBData *out_data); - - /** - * Destroys this iterator and unlocks the database. - * @param self Iterator - * @protected - */ - void (*destroy)(DBIterator *self); +struct DBIterator +{ + + /** + * Fetches the first entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData* (*first)(DBIterator* self, DBKey* out_key); + + /** + * Fetches the last entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData* (*last)(DBIterator* self, DBKey* out_key); + + /** + * Fetches the next entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData* (*next)(DBIterator* self, DBKey* out_key); + + /** + * Fetches the previous entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData* (*prev)(DBIterator* self, DBKey* out_key); + + /** + * Returns true if the fetched entry exists. + * The databases entries might have NULL data, so use this to to test if + * the iterator is done. + * @param self Iterator + * @return true is the entry exists + * @protected + */ + bool (*exists)(DBIterator* self); + + /** + * Removes the current entry from the database. + * NOTE: {@link DBIterator#exists} will return false until another entry + * is fetched + * Puts data of the removed entry in out_data, if out_data is not NULL. + * @param self Iterator + * @param out_data Data of the removed entry. + * @return 1 if entry was removed, 0 otherwise + * @protected + * @see DBMap#remove + */ + int (*remove)(DBIterator* self, DBData *out_data); + + /** + * Destroys this iterator and unlocks the database. + * @param self Iterator + * @protected + */ + void (*destroy)(DBIterator* self); }; @@ -363,235 +364,235 @@ struct DBIterator { */ struct DBMap { - /** - * Returns a new iterator for this database. - * The iterator keeps the database locked until it is destroyed. - * The database will keep functioning normally but will only free internal - * memory when unlocked, so destroy the iterator as soon as possible. - * @param self Database - * @return New iterator - * @protected - */ - DBIterator *(*iterator)(DBMap *self); - - /** - * Returns true if the entry exists. - * @param self Database - * @param key Key that identifies the entry - * @return true is the entry exists - * @protected - */ - bool (*exists)(DBMap *self, DBKey key); - - /** - * Get the data of the entry identified by the key. - * @param self Database - * @param key Key that identifies the entry - * @return Data of the entry or NULL if not found - * @protected - */ - DBData *(*get)(DBMap *self, DBKey key); - - /** - * Just calls {@link DBMap#vgetall}. - * Get the data of the entries matched by match. - * It puts a maximum of max entries into buf. - * If buf is NULL, it only counts the matches. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the - * first max entries found are put into the buffer. - * @param self Database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see DBMap#vgetall(DBMap*,void **,unsigned int,DBMatcher,va_list) - */ - unsigned int (*getall)(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, ...); - - /** - * Get the data of the entries matched by match. - * It puts a maximum of max entries into buf. - * If buf is NULL, it only counts the matches. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the - * first max entries found are put into the buffer. - * @param self Database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see DBMap#getall(DBMap*,void **,unsigned int,DBMatcher,...) - */ - unsigned int (*vgetall)(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, va_list args); - - /** - * Just calls {@link DBMap#vensure}. - * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by - * create. - * @param self Database - * @param key Key that identifies the entry - * @param create Function used to create the data if the entry doesn't exist - * @param ... Extra arguments for create - * @return Data of the entry - * @protected - * @see DBMap#vensure(DBMap*,DBKey,DBCreateData,va_list) - */ - DBData *(*ensure)(DBMap *self, DBKey key, DBCreateData create, ...); - - /** - * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by - * create. - * @param self Database - * @param key Key that identifies the entry - * @param create Function used to create the data if the entry doesn't exist - * @param args Extra arguments for create - * @return Data of the entry - * @protected - * @see DBMap#ensure(DBMap*,DBKey,DBCreateData,...) - */ - DBData *(*vensure)(DBMap *self, DBKey key, DBCreateData create, va_list args); - - /** - * Put the data identified by the key in the database. - * Puts the previous data in out_data, if out_data is not NULL. - * NOTE: Uses the new key, the old one is released. - * @param self Database - * @param key Key that identifies the data - * @param data Data to be put in the database - * @param out_data Previous data if the entry exists - * @return 1 if if the entry already exists, 0 otherwise - * @protected - */ - int (*put)(DBMap *self, DBKey key, DBData data, DBData *out_data); - - /** - * Remove an entry from the database. - * Puts the previous data in out_data, if out_data is not NULL. - * NOTE: The key (of the database) is released. - * @param self Database - * @param key Key that identifies the entry - * @param out_data Previous data if the entry exists - * @return 1 if if the entry already exists, 0 otherwise - * @protected - */ - int (*remove)(DBMap *self, DBKey key, DBData *out_data); - - /** - * Just calls {@link DBMap#vforeach}. - * Apply func to every entry in the database. - * Returns the sum of values returned by func. - * @param self Database - * @param func Function to be applied - * @param ... Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see DBMap#vforeach(DBMap*,DBApply,va_list) - */ - int (*foreach)(DBMap *self, DBApply func, ...); - - /** - * Apply func to every entry in the database. - * Returns the sum of values returned by func. - * @param self Database - * @param func Function to be applied - * @param args Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see DBMap#foreach(DBMap*,DBApply,...) - */ - int (*vforeach)(DBMap *self, DBApply func, va_list args); - - /** - * Just calls {@link DBMap#vclear}. - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vclear(DBMap*,DBApply,va_list) - */ - int (*clear)(DBMap *self, DBApply func, ...); - - /** - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#clear(DBMap*,DBApply,...) - */ - int (*vclear)(DBMap *self, DBApply func, va_list args); - - /** - * Just calls {@link DBMap#vdestroy}. - * Finalize the database, feeing all the memory it uses. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vdestroy(DBMap*,DBApply,va_list) - */ - int (*destroy)(DBMap *self, DBApply func, ...); - - /** - * Finalize the database, feeing all the memory it uses. - * Before deleting an entry, func is applied to it. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#destroy(DBMap*,DBApply,...) - */ - int (*vdestroy)(DBMap *self, DBApply func, va_list args); - - /** - * Return the size of the database (number of items in the database). - * @param self Database - * @return Size of the database - * @protected - */ - unsigned int (*size)(DBMap *self); - - /** - * Return the type of the database. - * @param self Database - * @return Type of the database - * @protected - */ - DBType(*type)(DBMap *self); - - /** - * Return the options of the database. - * @param self Database - * @return Options of the database - * @protected - */ - DBOptions(*options)(DBMap *self); + /** + * Returns a new iterator for this database. + * The iterator keeps the database locked until it is destroyed. + * The database will keep functioning normally but will only free internal + * memory when unlocked, so destroy the iterator as soon as possible. + * @param self Database + * @return New iterator + * @protected + */ + DBIterator* (*iterator)(DBMap* self); + + /** + * Returns true if the entry exists. + * @param self Database + * @param key Key that identifies the entry + * @return true is the entry exists + * @protected + */ + bool (*exists)(DBMap* self, DBKey key); + + /** + * Get the data of the entry identified by the key. + * @param self Database + * @param key Key that identifies the entry + * @return Data of the entry or NULL if not found + * @protected + */ + DBData* (*get)(DBMap* self, DBKey key); + + /** + * Just calls {@link DBMap#vgetall}. + * Get the data of the entries matched by match. + * It puts a maximum of max entries into buf. + * If buf is NULL, it only counts the matches. + * Returns the number of entries that matched. + * NOTE: if the value returned is greater than max, only the + * first max entries found are put into the buffer. + * @param self Database + * @param buf Buffer to put the data of the matched entries + * @param max Maximum number of data entries to be put into buf + * @param match Function that matches the database entries + * @param ... Extra arguments for match + * @return The number of entries that matched + * @protected + * @see DBMap#vgetall(DBMap*,void **,unsigned int,DBMatcher,va_list) + */ + unsigned int (*getall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, ...); + + /** + * Get the data of the entries matched by match. + * It puts a maximum of max entries into buf. + * If buf is NULL, it only counts the matches. + * Returns the number of entries that matched. + * NOTE: if the value returned is greater than max, only the + * first max entries found are put into the buffer. + * @param self Database + * @param buf Buffer to put the data of the matched entries + * @param max Maximum number of data entries to be put into buf + * @param match Function that matches the database entries + * @param ... Extra arguments for match + * @return The number of entries that matched + * @protected + * @see DBMap#getall(DBMap*,void **,unsigned int,DBMatcher,...) + */ + unsigned int (*vgetall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, va_list args); + + /** + * Just calls {@link DBMap#vensure}. + * Get the data of the entry identified by the key. + * If the entry does not exist, an entry is added with the data returned by + * create. + * @param self Database + * @param key Key that identifies the entry + * @param create Function used to create the data if the entry doesn't exist + * @param ... Extra arguments for create + * @return Data of the entry + * @protected + * @see DBMap#vensure(DBMap*,DBKey,DBCreateData,va_list) + */ + DBData* (*ensure)(DBMap* self, DBKey key, DBCreateData create, ...); + + /** + * Get the data of the entry identified by the key. + * If the entry does not exist, an entry is added with the data returned by + * create. + * @param self Database + * @param key Key that identifies the entry + * @param create Function used to create the data if the entry doesn't exist + * @param args Extra arguments for create + * @return Data of the entry + * @protected + * @see DBMap#ensure(DBMap*,DBKey,DBCreateData,...) + */ + DBData* (*vensure)(DBMap* self, DBKey key, DBCreateData create, va_list args); + + /** + * Put the data identified by the key in the database. + * Puts the previous data in out_data, if out_data is not NULL. + * NOTE: Uses the new key, the old one is released. + * @param self Database + * @param key Key that identifies the data + * @param data Data to be put in the database + * @param out_data Previous data if the entry exists + * @return 1 if if the entry already exists, 0 otherwise + * @protected + */ + int (*put)(DBMap* self, DBKey key, DBData data, DBData *out_data); + + /** + * Remove an entry from the database. + * Puts the previous data in out_data, if out_data is not NULL. + * NOTE: The key (of the database) is released. + * @param self Database + * @param key Key that identifies the entry + * @param out_data Previous data if the entry exists + * @return 1 if if the entry already exists, 0 otherwise + * @protected + */ + int (*remove)(DBMap* self, DBKey key, DBData *out_data); + + /** + * Just calls {@link DBMap#vforeach}. + * Apply func to every entry in the database. + * Returns the sum of values returned by func. + * @param self Database + * @param func Function to be applied + * @param ... Extra arguments for func + * @return Sum of the values returned by func + * @protected + * @see DBMap#vforeach(DBMap*,DBApply,va_list) + */ + int (*foreach)(DBMap* self, DBApply func, ...); + + /** + * Apply func to every entry in the database. + * Returns the sum of values returned by func. + * @param self Database + * @param func Function to be applied + * @param args Extra arguments for func + * @return Sum of the values returned by func + * @protected + * @see DBMap#foreach(DBMap*,DBApply,...) + */ + int (*vforeach)(DBMap* self, DBApply func, va_list args); + + /** + * Just calls {@link DBMap#vclear}. + * Removes all entries from the database. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param ... Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#vclear(DBMap*,DBApply,va_list) + */ + int (*clear)(DBMap* self, DBApply func, ...); + + /** + * Removes all entries from the database. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param args Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#clear(DBMap*,DBApply,...) + */ + int (*vclear)(DBMap* self, DBApply func, va_list args); + + /** + * Just calls {@link DBMap#vdestroy}. + * Finalize the database, feeing all the memory it uses. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * NOTE: This locks the database globally. Any attempt to insert or remove + * a database entry will give an error and be aborted (except for clearing). + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param ... Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#vdestroy(DBMap*,DBApply,va_list) + */ + int (*destroy)(DBMap* self, DBApply func, ...); + + /** + * Finalize the database, feeing all the memory it uses. + * Before deleting an entry, func is applied to it. + * Returns the sum of values returned by func, if it exists. + * NOTE: This locks the database globally. Any attempt to insert or remove + * a database entry will give an error and be aborted (except for clearing). + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param args Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#destroy(DBMap*,DBApply,...) + */ + int (*vdestroy)(DBMap* self, DBApply func, va_list args); + + /** + * Return the size of the database (number of items in the database). + * @param self Database + * @return Size of the database + * @protected + */ + unsigned int (*size)(DBMap* self); + + /** + * Return the type of the database. + * @param self Database + * @return Type of the database + * @protected + */ + DBType (*type)(DBMap* self); + + /** + * Return the options of the database. + * @param self Database + * @return Options of the database + * @protected + */ + DBOptions (*options)(DBMap* self); }; @@ -726,7 +727,7 @@ DBComparator db_default_cmp(DBType type); DBHasher db_default_hash(DBType type); /** - * Returns the default releaser for the specified type of database with the + * Returns the default releaser for the specified type of database with the * specified options. * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} * before choosing the releaser @@ -755,7 +756,7 @@ DBReleaser db_custom_release(DBRelease which); /** * Allocate a new database of the specified type. - * It uses the default comparator, hasher and releaser of the specified + * It uses the default comparator, hasher and releaser of the specified * database type and fixed options. * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} * before creating the database. @@ -763,7 +764,7 @@ DBReleaser db_custom_release(DBRelease which); * @param line Line of the file where the database is being allocated * @param type Type of database * @param options Options of the database - * @param maxlen Maximum length of the string to be used as key in string + * @param maxlen Maximum length of the string to be used as key in string * databases. If 0, the maximum number of maxlen is used (64K). * @return The interface of the database * @public @@ -774,7 +775,7 @@ DBReleaser db_custom_release(DBRelease which); * @see #db_default_release(DBType,DBOptions) * @see #db_fix_options(DBType,DBOptions) */ -DBMap *db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); +DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); /** * Manual cast from 'int' to the union DBKey. @@ -849,7 +850,7 @@ unsigned int db_data2ui(DBData *data); * @return Void* value of the data. * @public */ -void *db_data2ptr(DBData *data); +void* db_data2ptr(DBData *data); /** * Initialize the database system. @@ -868,20 +869,20 @@ void db_final(void); // Link DB System - From jAthena struct linkdb_node { - struct linkdb_node *next; - struct linkdb_node *prev; - void *key; - void *data; + struct linkdb_node *next; + struct linkdb_node *prev; + void *key; + void *data; }; -typedef void (*LinkDBFunc)(void *key, void *data, va_list args); +typedef void (*LinkDBFunc)(void* key, void* data, va_list args); -void linkdb_insert(struct linkdb_node **head, void *key, void *data); // 重複を考慮しない -void linkdb_replace(struct linkdb_node **head, void *key, void *data); // 重複を考慮する -void *linkdb_search(struct linkdb_node **head, void *key); -void *linkdb_erase(struct linkdb_node **head, void *key); -void linkdb_final(struct linkdb_node **head); -void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); +void linkdb_insert ( struct linkdb_node** head, void *key, void* data); // 重複を考慮しない +void linkdb_replace( struct linkdb_node** head, void *key, void* data); // 重複を考慮する +void* linkdb_search ( struct linkdb_node** head, void *key); +void* linkdb_erase ( struct linkdb_node** head, void *key); +void linkdb_final ( struct linkdb_node** head ); +void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); @@ -893,11 +894,11 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __var Index variable /// @param __cmp Expression that returns true when the target entry is found #define ARR_FIND(__start, __end, __var, __cmp) \ - do{ \ - for( (__var) = (__start); (__var) < (__end); ++(__var) ) \ - if( __cmp ) \ - break; \ - }while(0) + do{ \ + for( (__var) = (__start); (__var) < (__end); ++(__var) ) \ + if( __cmp ) \ + break; \ + }while(0) @@ -911,18 +912,18 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVE(__from, __to, __arr, __type) \ - do{ \ - if( (__from) != (__to) ) \ - { \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - if( (__from) < (__to) ) \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - else if( (__from) > (__to) ) \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - } \ - }while(0) + do{ \ + if( (__from) != (__to) ) \ + { \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + if( (__from) < (__to) ) \ + memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ + else if( (__from) > (__to) ) \ + memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + } \ + }while(0) @@ -934,12 +935,12 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVERIGHT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) + do{ \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + }while(0) @@ -951,12 +952,12 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVELEFT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) + do{ \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + }while(0) @@ -970,11 +971,11 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// /// @param __type Type of data #define VECTOR_DECL(__type) \ - struct { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ - } + struct { \ + size_t _max_; \ + size_t _len_; \ + __type* _data_; \ + } @@ -983,11 +984,11 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __name Structure name /// @param __type Type of data #define VECTOR_STRUCT_DECL(__name,__type) \ - struct __name { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ - } + struct __name { \ + size_t _max_; \ + size_t _len_; \ + __type* _data_; \ + } @@ -996,7 +997,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __type Type of data /// @param __var Variable name #define VECTOR_VAR(__type,__var) \ - VECTOR_DECL(__type) __var = {0,0,NULL} + VECTOR_DECL(__type) __var = {0,0,NULL} @@ -1005,7 +1006,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __name Structure name /// @param __var Variable name #define VECTOR_STRUCT_VAR(__name,__var) \ - struct __name __var = {0,0,NULL} + struct __name __var = {0,0,NULL} @@ -1013,7 +1014,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// /// @param __vec Vector #define VECTOR_INIT(__vec) \ - memset(&(__vec), 0, sizeof(__vec)) + memset(&(__vec), 0, sizeof(__vec)) @@ -1022,7 +1023,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @return Array of values #define VECTOR_DATA(__vec) \ - ( (__vec)._data_ ) + ( (__vec)._data_ ) @@ -1031,7 +1032,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @return Length #define VECTOR_LENGTH(__vec) \ - ( (__vec)._len_ ) + ( (__vec)._len_ ) @@ -1040,7 +1041,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @return Capacity #define VECTOR_CAPACITY(__vec) \ - ( (__vec)._max_ ) + ( (__vec)._max_ ) @@ -1051,7 +1052,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __idx Index /// @return Value #define VECTOR_INDEX(__vec,__idx) \ - ( VECTOR_DATA(__vec)[__idx] ) + ( VECTOR_DATA(__vec)[__idx] ) @@ -1061,7 +1062,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @return First value #define VECTOR_FIRST(__vec) \ - ( VECTOR_INDEX(__vec,0) ) + ( VECTOR_INDEX(__vec,0) ) @@ -1071,7 +1072,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @return Last value #define VECTOR_LAST(__vec) \ - ( VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)-1) ) + ( VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)-1) ) @@ -1081,27 +1082,27 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @param __n Size #define VECTOR_RESIZE(__vec,__n) \ - do{ \ - if( (__n) > VECTOR_CAPACITY(__vec) ) \ - { /* increase size */ \ - if( VECTOR_CAPACITY(__vec) == 0 ) SET_POINTER(VECTOR_DATA(__vec), aMalloc((__n)*sizeof(VECTOR_FIRST(__vec)))); /* allocate new */ \ - else SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ - memset(VECTOR_DATA(__vec)+VECTOR_LENGTH(__vec), 0, (VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec))*sizeof(VECTOR_FIRST(__vec))); /* clear new data */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - } \ - else if( (__n) == 0 && VECTOR_CAPACITY(__vec) ) \ - { /* clear vector */ \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* free data */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ - } \ - else if( (__n) < VECTOR_CAPACITY(__vec) ) \ - { /* reduce size */ \ - SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - if( VECTOR_LENGTH(__vec) > (__n) ) VECTOR_LENGTH(__vec) = (__n); /* update length */ \ - } \ - }while(0) + do{ \ + if( (__n) > VECTOR_CAPACITY(__vec) ) \ + { /* increase size */ \ + if( VECTOR_CAPACITY(__vec) == 0 ) SET_POINTER(VECTOR_DATA(__vec), aMalloc((__n)*sizeof(VECTOR_FIRST(__vec)))); /* allocate new */ \ + else SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ + memset(VECTOR_DATA(__vec)+VECTOR_LENGTH(__vec), 0, (VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec))*sizeof(VECTOR_FIRST(__vec))); /* clear new data */ \ + VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ + } \ + else if( (__n) == 0 && VECTOR_CAPACITY(__vec) ) \ + { /* clear vector */ \ + aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* free data */ \ + VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(__vec) = 0; /* clear length */ \ + } \ + else if( (__n) < VECTOR_CAPACITY(__vec) ) \ + { /* reduce size */ \ + SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ + VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ + if( VECTOR_LENGTH(__vec) > (__n) ) VECTOR_LENGTH(__vec) = (__n); /* update length */ \ + } \ + }while(0) @@ -1112,11 +1113,11 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __n Empty positions /// @param __step Increase #define VECTOR_ENSURE(__vec,__n,__step) \ - do{ \ - size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \ - while( (__n) > _empty_ ) _empty_ += (__step); \ - if( _empty_ != VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec) ) VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \ - }while(0) + do{ \ + size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \ + while( (__n) > _empty_ ) _empty_ += (__step); \ + if( _empty_ != VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec) ) VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \ + }while(0) @@ -1126,12 +1127,12 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @param __idx Index #define VECTOR_INSERTZEROED(__vec,__idx) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memset(&VECTOR_INDEX(__vec,__idx), 0, sizeof(VECTOR_INDEX(__vec,__idx))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + memset(&VECTOR_INDEX(__vec,__idx), 0, sizeof(VECTOR_INDEX(__vec,__idx))); /* set zeroed value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1142,12 +1143,12 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __idx Index /// @param __val Value #define VECTOR_INSERT(__vec,__idx,__val) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_INDEX(__vec,__idx) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + VECTOR_INDEX(__vec,__idx) = (__val); /* set value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1158,7 +1159,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __idx Index /// @param __val Value #define VECTOR_INSERTCOPY(__vec,__idx,__val) \ - VECTOR_INSERTARRAY(__vec,__idx,&(__val),1) + VECTOR_INSERTARRAY(__vec,__idx,&(__val),1) @@ -1170,12 +1171,12 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __pval Array of values /// @param __n Number of values #define VECTOR_INSERTARRAY(__vec,__idx,__pval,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+(__n)),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memcpy(&VECTOR_INDEX(__vec,__idx), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+(__n)),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + memcpy(&VECTOR_INDEX(__vec,__idx), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ + VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ + }while(0) @@ -1184,10 +1185,10 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// /// @param __vec Vector #define VECTOR_PUSHZEROED(__vec) \ - do{ \ - memset(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), 0, sizeof(VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + memset(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), 0, sizeof(VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)))); /* set zeroed value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) /// Inserts a value in the end of the vector. (using the '=' operator) @@ -1196,10 +1197,10 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @param __val Value #define VECTOR_PUSH(__vec,__val) \ - do{ \ - VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)) = (__val); /* set value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1209,7 +1210,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @param __val Value #define VECTOR_PUSHCOPY(__vec,__val) \ - VECTOR_PUSHARRAY(__vec,&(__val),1) + VECTOR_PUSHARRAY(__vec,&(__val),1) @@ -1220,10 +1221,10 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __pval Array of values /// @param __n Number of values #define VECTOR_PUSHARRAY(__vec,__pval,__n) \ - do{ \ - memcpy(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) + do{ \ + memcpy(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ + VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ + }while(0) @@ -1233,7 +1234,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @return Removed value #define VECTOR_POP(__vec) \ - ( VECTOR_INDEX(__vec,--VECTOR_LENGTH(__vec)) ) + ( VECTOR_INDEX(__vec,--VECTOR_LENGTH(__vec)) ) @@ -1244,7 +1245,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __n Number of pops /// @return Last removed value #define VECTOR_POPN(__vec,__n) \ - ( VECTOR_INDEX(__vec,(VECTOR_LENGTH(__vec)-=(__n))) ) + ( VECTOR_INDEX(__vec,(VECTOR_LENGTH(__vec)-=(__n))) ) @@ -1254,7 +1255,7 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __vec Vector /// @param __idx Index #define VECTOR_ERASE(__vec,__idx) \ - VECTOR_ERASEN(__vec,__idx,1) + VECTOR_ERASEN(__vec,__idx,1) @@ -1265,11 +1266,11 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __idx Index /// @param __n Number of values #define VECTOR_ERASEN(__vec,__idx,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec)-(__n) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,__idx),&VECTOR_INDEX(__vec,(__idx)+(__n)),(VECTOR_LENGTH(__vec)-((__idx)+(__n)))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_LENGTH(__vec) -= (__n); /* decrease length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec)-(__n) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,__idx),&VECTOR_INDEX(__vec,(__idx)+(__n)),(VECTOR_LENGTH(__vec)-((__idx)+(__n)))*sizeof(VECTOR_FIRST(__vec))); \ + VECTOR_LENGTH(__vec) -= (__n); /* decrease length */ \ + }while(0) @@ -1277,14 +1278,14 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// /// @param __vec Vector #define VECTOR_CLEAR(__vec) \ - do{ \ - if( VECTOR_CAPACITY(__vec) ) \ - { \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* clear allocated array */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ - } \ - }while(0) + do{ \ + if( VECTOR_CAPACITY(__vec) ) \ + { \ + aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* clear allocated array */ \ + VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(__vec) = 0; /* clear length */ \ + } \ + }while(0) @@ -1387,18 +1388,18 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __val Value /// @param __topcmp Comparator #define BHEAP_PUSH(__heap,__val,__topcmp) \ - do{ \ - size_t _i_ = VECTOR_LENGTH(__heap); \ - VECTOR_PUSH(__heap,__val); /* insert at end */ \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ - break; /* done */ \ - swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ - _i_ = _parent_; \ - } \ - }while(0) + do{ \ + size_t _i_ = VECTOR_LENGTH(__heap); \ + VECTOR_PUSH(__heap,__val); /* insert at end */ \ + while( _i_ ) \ + { /* restore heap property in parents */ \ + size_t _parent_ = (_i_-1)/2; \ + if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + break; /* done */ \ + swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _i_ = _parent_; \ + } \ + }while(0) @@ -1428,36 +1429,36 @@ void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); /// @param __idx Index /// @param __topcmp Comparator #define BHEAP_POPINDEX(__heap,__idx,__topcmp) \ - do{ \ - size_t _i_ = __idx; \ - VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ - break; /* done */ \ - swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ - _i_ = _parent_; \ - } \ - while( _i_ < VECTOR_LENGTH(__heap) ) \ - { /* restore heap property in childs */ \ - size_t _lchild_ = _i_*2 + 1; \ - size_t _rchild_ = _i_*2 + 2; \ - if( (_lchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)) <= 0) && \ - (_rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)) <= 0) ) \ - break; /* done */ \ - else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \ - { /* left child */ \ - swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ - _i_ = _lchild_; \ - } \ - else \ - { /* right child */ \ - swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ - _i_ = _rchild_; \ - } \ - } \ - }while(0) + do{ \ + size_t _i_ = __idx; \ + VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \ + while( _i_ ) \ + { /* restore heap property in parents */ \ + size_t _parent_ = (_i_-1)/2; \ + if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + break; /* done */ \ + swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _i_ = _parent_; \ + } \ + while( _i_ < VECTOR_LENGTH(__heap) ) \ + { /* restore heap property in childs */ \ + size_t _lchild_ = _i_*2 + 1; \ + size_t _rchild_ = _i_*2 + 2; \ + if( (_lchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)) <= 0) && \ + (_rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)) <= 0) ) \ + break; /* done */ \ + else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \ + { /* left child */ \ + swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ + _i_ = _lchild_; \ + } \ + else \ + { /* right child */ \ + swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ + _i_ = _rchild_; \ + } \ + } \ + }while(0) diff --git a/src/common/des.c b/src/common/des.c index f2347f3c4..917fc33e0 100644 --- a/src/common/des.c +++ b/src/common/des.c @@ -12,201 +12,207 @@ /// Bitmask for accessing individual bits of a byte. static const uint8_t mask[8] = { - 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /// Initial permutation (IP). -static void IP(BIT64 *src) +static void IP(BIT64* src) { - BIT64 tmp = {{0}}; - - static const uint8_t ip_table[64] = { - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7, - }; - - size_t i; - for (i = 0; i < ARRAYLENGTH(ip_table); ++i) { - uint8_t j = ip_table[i] - 1; - if (src->b[(j >> 3) & 7] & mask[j & 7]) - tmp .b[(i >> 3) & 7] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t ip_table[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + }; + + size_t i; + for( i = 0; i < ARRAYLENGTH(ip_table); ++i ) + { + uint8_t j = ip_table[i] - 1; + if( src->b[(j >> 3) & 7] & mask[j & 7] ) + tmp .b[(i >> 3) & 7] |= mask[i & 7]; + } + + *src = tmp; } /// Final permutation (IP^-1). -static void FP(BIT64 *src) +static void FP(BIT64* src) { - BIT64 tmp = {{0}}; - - static const uint8_t fp_table[64] = { - 40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25, - }; - - size_t i; - for (i = 0; i < ARRAYLENGTH(fp_table); ++i) { - uint8_t j = fp_table[i] - 1; - if (src->b[(j >> 3) & 7] & mask[j & 7]) - tmp .b[(i >> 3) & 7] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t fp_table[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + }; + + size_t i; + for( i = 0; i < ARRAYLENGTH(fp_table); ++i ) + { + uint8_t j = fp_table[i] - 1; + if( src->b[(j >> 3) & 7] & mask[j & 7] ) + tmp .b[(i >> 3) & 7] |= mask[i & 7]; + } + + *src = tmp; } /// Expansion (E). /// Expands upper four 8-bits (32b) into eight 6-bits (48b). -static void E(BIT64 *src) +static void E(BIT64* src) { - BIT64 tmp = {{0}}; - - if (false) { - // original - static const uint8_t expand_table[48] = { - 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1, - }; - - size_t i; - for (i = 0; i < ARRAYLENGTH(expand_table); ++i) { - uint8_t j = expand_table[i] - 1; - if (src->b[j / 8 + 4] & mask[j % 8]) - tmp .b[i / 6 + 0] |= mask[i % 6]; - } - } else { - // optimized - tmp.b[0] = ((src->b[7]<<5) | (src->b[4]>>3)) & 0x3f; // ..0 vutsr - tmp.b[1] = ((src->b[4]<<1) | (src->b[5]>>7)) & 0x3f; // ..srqpo n - tmp.b[2] = ((src->b[4]<<5) | (src->b[5]>>3)) & 0x3f; // ..o nmlkj - tmp.b[3] = ((src->b[5]<<1) | (src->b[6]>>7)) & 0x3f; // ..kjihg f - tmp.b[4] = ((src->b[5]<<5) | (src->b[6]>>3)) & 0x3f; // ..g fedcb - tmp.b[5] = ((src->b[6]<<1) | (src->b[7]>>7)) & 0x3f; // ..cba98 7 - tmp.b[6] = ((src->b[6]<<5) | (src->b[7]>>3)) & 0x3f; // ..8 76543 - tmp.b[7] = ((src->b[7]<<1) | (src->b[4]>>7)) & 0x3f; // ..43210 v - } - - *src = tmp; + BIT64 tmp = {{0}}; + +if( false ) +{// original + static const uint8_t expand_table[48] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1, + }; + + size_t i; + for( i = 0; i < ARRAYLENGTH(expand_table); ++i ) + { + uint8_t j = expand_table[i] - 1; + if( src->b[j / 8 + 4] & mask[j % 8] ) + tmp .b[i / 6 + 0] |= mask[i % 6]; + } +} +else +{// optimized + tmp.b[0] = ((src->b[7]<<5) | (src->b[4]>>3)) & 0x3f; // ..0 vutsr + tmp.b[1] = ((src->b[4]<<1) | (src->b[5]>>7)) & 0x3f; // ..srqpo n + tmp.b[2] = ((src->b[4]<<5) | (src->b[5]>>3)) & 0x3f; // ..o nmlkj + tmp.b[3] = ((src->b[5]<<1) | (src->b[6]>>7)) & 0x3f; // ..kjihg f + tmp.b[4] = ((src->b[5]<<5) | (src->b[6]>>3)) & 0x3f; // ..g fedcb + tmp.b[5] = ((src->b[6]<<1) | (src->b[7]>>7)) & 0x3f; // ..cba98 7 + tmp.b[6] = ((src->b[6]<<5) | (src->b[7]>>3)) & 0x3f; // ..8 76543 + tmp.b[7] = ((src->b[7]<<1) | (src->b[4]>>7)) & 0x3f; // ..43210 v +} + + *src = tmp; } /// Transposition (P-BOX). -static void TP(BIT64 *src) +static void TP(BIT64* src) { - BIT64 tmp = {{0}}; - - static const uint8_t tp_table[32] = { - 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25, - }; - - size_t i; - for (i = 0; i < ARRAYLENGTH(tp_table); ++i) { - uint8_t j = tp_table[i] - 1; - if (src->b[(j >> 3) + 0] & mask[j & 7]) - tmp .b[(i >> 3) + 4] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t tp_table[32] = { + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25, + }; + + size_t i; + for( i = 0; i < ARRAYLENGTH(tp_table); ++i ) + { + uint8_t j = tp_table[i] - 1; + if( src->b[(j >> 3) + 0] & mask[j & 7] ) + tmp .b[(i >> 3) + 4] |= mask[i & 7]; + } + + *src = tmp; } /// Substitution boxes (S-boxes). /// NOTE: This implementation was optimized to process two nibbles in one step (twice as fast). -static void SBOX(BIT64 *src) +static void SBOX(BIT64* src) { - BIT64 tmp = {{0}}; - - static const uint8_t s_table[4][64] = { - { - 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e, - 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85, - 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72, - 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9, - },{ - 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3, - 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19, - 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78, - 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce, - },{ - 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15, - 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68, - 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda, - 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d, - },{ - 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4, - 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62, - 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d, - 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb, - } - }; - - size_t i; - for (i = 0; i < ARRAYLENGTH(s_table); ++i) { - tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0) - | (s_table[i][src->b[i*2+1]] & 0x0f); - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t s_table[4][64] = { + { + 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e, + 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85, + 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72, + 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9, + },{ + 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3, + 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19, + 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78, + 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce, + },{ + 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15, + 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68, + 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda, + 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d, + },{ + 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4, + 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62, + 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d, + 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb, + } + }; + + size_t i; + for( i = 0; i < ARRAYLENGTH(s_table); ++i ) + { + tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0) + | (s_table[i][src->b[i*2+1]] & 0x0f); + } + + *src = tmp; } /// DES round function. /// XORs src[0..3] with TP(SBOX(E(src[4..7]))). -static void RoundFunction(BIT64 *src) +static void RoundFunction(BIT64* src) { - BIT64 tmp = *src; - E(&tmp); - SBOX(&tmp); - TP(&tmp); - - src->b[0] ^= tmp.b[4]; - src->b[1] ^= tmp.b[5]; - src->b[2] ^= tmp.b[6]; - src->b[3] ^= tmp.b[7]; + BIT64 tmp = *src; + E(&tmp); + SBOX(&tmp); + TP(&tmp); + + src->b[0] ^= tmp.b[4]; + src->b[1] ^= tmp.b[5]; + src->b[2] ^= tmp.b[6]; + src->b[3] ^= tmp.b[7]; } -void des_decrypt_block(BIT64 *block) +void des_decrypt_block(BIT64* block) { - IP(block); - RoundFunction(block); - FP(block); + IP(block); + RoundFunction(block); + FP(block); } -void des_decrypt(unsigned char *data, size_t size) +void des_decrypt(unsigned char* data, size_t size) { - BIT64 *p = (BIT64 *)data; - size_t i; + BIT64* p = (BIT64*)data; + size_t i; - for (i = 0; i*8 < size; i += 8) - des_decrypt_block(p); + for( i = 0; i*8 < size; i += 8 ) + des_decrypt_block(p); } diff --git a/src/common/des.h b/src/common/des.h index a13a17165..e42136436 100644 --- a/src/common/des.h +++ b/src/common/des.h @@ -1,17 +1,15 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _DES_H_ -#define _DES_H_ +#ifndef _DES_H_ +#define _DES_H_ /// One 64-bit block. -typedef struct BIT64 { - uint8_t b[8]; -} BIT64; +typedef struct BIT64 { uint8_t b[8]; } BIT64; -void des_decrypt_block(BIT64 *block); -void des_decrypt(unsigned char *data, size_t size); +void des_decrypt_block(BIT64* block); +void des_decrypt(unsigned char* data, size_t size); #endif // _DES_H_ diff --git a/src/common/ers.c b/src/common/ers.c index d75f23f6f..b94b0888d 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -51,51 +51,54 @@ #define ERS_ROOT_SIZE 256 #define ERS_BLOCK_ENTRIES 4096 -struct ers_list { - struct ers_list *Next; +struct ers_list +{ + struct ers_list *Next; }; -typedef struct ers_cache { - // Allocated object size, including ers_list size - unsigned int ObjectSize; - - // Number of ers_instances referencing this - int ReferenceCount; +typedef struct ers_cache +{ + // Allocated object size, including ers_list size + unsigned int ObjectSize; - // Reuse linked list - struct ers_list *ReuseList; + // Number of ers_instances referencing this + int ReferenceCount; - // Memory blocks array - unsigned char **Blocks; + // Reuse linked list + struct ers_list *ReuseList; - // Max number of blocks - unsigned int Max; + // Memory blocks array + unsigned char **Blocks; - // Free objects count - unsigned int Free; + // Max number of blocks + unsigned int Max; - // Used objects count - unsigned int Used; + // Free objects count + unsigned int Free; + + // Used objects count + unsigned int Used; - // Linked list - struct ers_cache *Next, *Prev; + // Linked list + struct ers_cache *Next, *Prev; } ers_cache_t; -typedef struct { - // Interface to ERS - struct eri VTable; - - // Name, used for debbuging purpouses - char *Name; +typedef struct +{ + // Interface to ERS + struct eri VTable; + + // Name, used for debbuging purpouses + char *Name; - // Misc options - enum ERSOptions Options; + // Misc options + enum ERSOptions Options; - // Our cache - ers_cache_t *Cache; + // Our cache + ers_cache_t *Cache; - // Count of objects in use, used for detecting memory leaks - unsigned int Count; + // Count of objects in use, used for detecting memory leaks + unsigned int Count; } ers_instance_t; @@ -104,171 +107,186 @@ static ers_cache_t *CacheList; static ers_cache_t *ers_find_cache(unsigned int size) { - ers_cache_t *cache; - - for (cache = CacheList; cache; cache = cache->Next) - if (cache->ObjectSize == size) - return cache; - - CREATE(cache, ers_cache_t, 1); - cache->ObjectSize = size; - cache->ReferenceCount = 0; - cache->ReuseList = NULL; - cache->Blocks = NULL; - cache->Free = 0; - cache->Used = 0; - cache->Max = 0; - - if (CacheList == NULL) { - CacheList = cache; - } else { - cache->Next = CacheList; - cache->Next->Prev = cache; - CacheList = cache; - CacheList->Prev = NULL; - } - - return cache; + ers_cache_t *cache; + + for (cache = CacheList; cache; cache = cache->Next) + if (cache->ObjectSize == size) + return cache; + + CREATE(cache, ers_cache_t, 1); + cache->ObjectSize = size; + cache->ReferenceCount = 0; + cache->ReuseList = NULL; + cache->Blocks = NULL; + cache->Free = 0; + cache->Used = 0; + cache->Max = 0; + + if (CacheList == NULL) + { + CacheList = cache; + } + else + { + cache->Next = CacheList; + cache->Next->Prev = cache; + CacheList = cache; + CacheList->Prev = NULL; + } + + return cache; } static void ers_free_cache(ers_cache_t *cache, bool remove) { - unsigned int i; + unsigned int i; - for (i = 0; i < cache->Used; i++) - aFree(cache->Blocks[i]); + for (i = 0; i < cache->Used; i++) + aFree(cache->Blocks[i]); - if (cache->Next) - cache->Next->Prev = cache->Prev; + if (cache->Next) + cache->Next->Prev = cache->Prev; - if (cache->Prev) - cache->Prev->Next = cache->Next; - else - CacheList = cache->Next; + if (cache->Prev) + cache->Prev->Next = cache->Next; + else + CacheList = cache->Next; - aFree(cache->Blocks); - aFree(cache); + aFree(cache->Blocks); + aFree(cache); } static void *ers_obj_alloc_entry(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; - void *ret; - - if (instance == NULL) { - ShowError("ers_obj_alloc_entry: NULL object, aborting entry freeing.\n"); - return NULL; - } - - if (instance->Cache->ReuseList != NULL) { - ret = (void *)((unsigned char *)instance->Cache->ReuseList + sizeof(struct ers_list)); - instance->Cache->ReuseList = instance->Cache->ReuseList->Next; - } else if (instance->Cache->Free > 0) { - instance->Cache->Free--; - ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; - } else { - if (instance->Cache->Used == instance->Cache->Max) { - instance->Cache->Max = (instance->Cache->Max * 4) + 3; - RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); - } - - CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * ERS_BLOCK_ENTRIES); - instance->Cache->Used++; - - instance->Cache->Free = ERS_BLOCK_ENTRIES -1; - ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; - } - - instance->Count++; - - return ret; + ers_instance_t *instance = (ers_instance_t *)self; + void *ret; + + if (instance == NULL) + { + ShowError("ers_obj_alloc_entry: NULL object, aborting entry freeing.\n"); + return NULL; + } + + if (instance->Cache->ReuseList != NULL) + { + ret = (void *)((unsigned char *)instance->Cache->ReuseList + sizeof(struct ers_list)); + instance->Cache->ReuseList = instance->Cache->ReuseList->Next; + } + else if (instance->Cache->Free > 0) + { + instance->Cache->Free--; + ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; + } + else + { + if (instance->Cache->Used == instance->Cache->Max) + { + instance->Cache->Max = (instance->Cache->Max * 4) + 3; + RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); + } + + CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * ERS_BLOCK_ENTRIES); + instance->Cache->Used++; + + instance->Cache->Free = ERS_BLOCK_ENTRIES -1; + ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; + } + + instance->Count++; + + return ret; } static void ers_obj_free_entry(ERS self, void *entry) { - ers_instance_t *instance = (ers_instance_t *)self; - struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); - - if (instance == NULL) { - ShowError("ers_obj_free_entry: NULL object, aborting entry freeing.\n"); - return; - } else if (entry == NULL) { - ShowError("ers_obj_free_entry: NULL entry, nothing to free.\n"); - return; - } - - reuse->Next = instance->Cache->ReuseList; - instance->Cache->ReuseList = reuse; - instance->Count--; + ers_instance_t *instance = (ers_instance_t *)self; + struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); + + if (instance == NULL) + { + ShowError("ers_obj_free_entry: NULL object, aborting entry freeing.\n"); + return; + } + else if (entry == NULL) + { + ShowError("ers_obj_free_entry: NULL entry, nothing to free.\n"); + return; + } + + reuse->Next = instance->Cache->ReuseList; + instance->Cache->ReuseList = reuse; + instance->Count--; } static size_t ers_obj_entry_size(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + ers_instance_t *instance = (ers_instance_t *)self; - if (instance == NULL) { - ShowError("ers_obj_entry_size: NULL object, aborting entry freeing.\n"); - return 0; - } + if (instance == NULL) + { + ShowError("ers_obj_entry_size: NULL object, aborting entry freeing.\n"); + return 0; + } - return instance->Cache->ObjectSize; + return instance->Cache->ObjectSize; } static void ers_obj_destroy(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + ers_instance_t *instance = (ers_instance_t *)self; - if (instance == NULL) { - ShowError("ers_obj_destroy: NULL object, aborting entry freeing.\n"); - return; - } + if (instance == NULL) + { + ShowError("ers_obj_destroy: NULL object, aborting entry freeing.\n"); + return; + } - if (instance->Count > 0) - if (!(instance->Options & ERS_OPT_CLEAR)) - ShowWarning("Memory leak detected at ERS '%s', %d objects not freed.\n", instance->Name, instance->Count); + if (instance->Count > 0) + if (!(instance->Options & ERS_OPT_CLEAR)) + ShowWarning("Memory leak detected at ERS '%s', %d objects not freed.\n", instance->Name, instance->Count); - if (--instance->Cache->ReferenceCount <= 0) - ers_free_cache(instance->Cache, true); + if (--instance->Cache->ReferenceCount <= 0) + ers_free_cache(instance->Cache, true); - aFree(instance); + aFree(instance); } ERS ers_new(uint32 size, char *name, enum ERSOptions options) { - ers_instance_t *instance; - CREATE(instance, ers_instance_t, 1); + ers_instance_t *instance; + CREATE(instance, ers_instance_t, 1); - size += sizeof(struct ers_list); - if (size % ERS_ALIGNED) - size += ERS_ALIGNED - size % ERS_ALIGNED; + size += sizeof(struct ers_list); + if (size % ERS_ALIGNED) + size += ERS_ALIGNED - size % ERS_ALIGNED; - instance->VTable.alloc = ers_obj_alloc_entry; - instance->VTable.free = ers_obj_free_entry; - instance->VTable.entry_size = ers_obj_entry_size; - instance->VTable.destroy = ers_obj_destroy; + instance->VTable.alloc = ers_obj_alloc_entry; + instance->VTable.free = ers_obj_free_entry; + instance->VTable.entry_size = ers_obj_entry_size; + instance->VTable.destroy = ers_obj_destroy; - instance->Name = name; - instance->Options = options; + instance->Name = name; + instance->Options = options; - instance->Cache = ers_find_cache(size); - instance->Cache->ReferenceCount++; + instance->Cache = ers_find_cache(size); + instance->Cache->ReferenceCount++; - instance->Count = 0; + instance->Count = 0; - return &instance->VTable; + return &instance->VTable; } void ers_report(void) { - // FIXME: Someone use this? Is it really needed? + // FIXME: Someone use this? Is it really needed? } void ers_force_destroy_all(void) { - ers_cache_t *cache; - - for (cache = CacheList; cache; cache = cache->Next) - ers_free_cache(cache, false); + ers_cache_t *cache; + + for (cache = CacheList; cache; cache = cache->Next) + ers_free_cache(cache, false); } #endif diff --git a/src/common/ers.h b/src/common/ers.h index c8fe2b4af..dc66af5ef 100644 --- a/src/common/ers.h +++ b/src/common/ers.h @@ -55,7 +55,7 @@ /** * Define this to disable the Entry Reusage System. * All code except the typedef of ERInterface will be disabled. - * To allow a smooth transition, + * To allow a smooth transition, */ //#define DISABLE_ERS @@ -63,16 +63,16 @@ * Entries are aligned to ERS_ALIGNED bytes in the blocks of entries. * By default it aligns to one byte, using the "natural order" of the entries. * This should NEVER be set to zero or less. - * If greater than one, some memory can be wasted. This should never be needed + * If greater than one, some memory can be wasted. This should never be needed * but is here just in case some aligment issues arise. */ #ifndef ERS_ALIGNED -# define ERS_ALIGNED 1 +# define ERS_ALIGNED 1 #endif /* not ERS_ALIGN_ENTRY */ enum ERSOptions { - ERS_OPT_NONE = 0, - ERS_OPT_CLEAR = 1,/* silently clears any entries left in the manager upon destruction */ + ERS_OPT_NONE = 0, + ERS_OPT_CLEAR = 1,/* silently clears any entries left in the manager upon destruction */ }; /** @@ -84,65 +84,65 @@ enum ERSOptions { */ typedef struct eri { - /** - * Allocate an entry from this entry manager. - * If there are reusable entries available, it reuses one instead. - * @param self Interface of the entry manager - * @return An entry - */ - void *(*alloc)(struct eri *self); - - /** - * Free an entry allocated from this manager. - * WARNING: Does not check if the entry was allocated by this manager. - * Freeing such an entry can lead to unexpected behaviour. - * @param self Interface of the entry manager - * @param entry Entry to be freed - */ - void (*free)(struct eri *self, void *entry); - - /** - * Return the size of the entries allocated from this manager. - * @param self Interface of the entry manager - * @return Size of the entries of this manager in bytes - */ - size_t (*entry_size)(struct eri *self); - - /** - * Destroy this instance of the manager. - * The manager is actually only destroyed when all the instances are destroyed. - * When destroying the manager a warning is shown if the manager has - * missing/extra entries. - * @param self Interface of the entry manager - */ - void (*destroy)(struct eri *self); + /** + * Allocate an entry from this entry manager. + * If there are reusable entries available, it reuses one instead. + * @param self Interface of the entry manager + * @return An entry + */ + void *(*alloc)(struct eri *self); + + /** + * Free an entry allocated from this manager. + * WARNING: Does not check if the entry was allocated by this manager. + * Freeing such an entry can lead to unexpected behaviour. + * @param self Interface of the entry manager + * @param entry Entry to be freed + */ + void (*free)(struct eri *self, void *entry); + + /** + * Return the size of the entries allocated from this manager. + * @param self Interface of the entry manager + * @return Size of the entries of this manager in bytes + */ + size_t (*entry_size)(struct eri *self); + + /** + * Destroy this instance of the manager. + * The manager is actually only destroyed when all the instances are destroyed. + * When destroying the manager a warning is shown if the manager has + * missing/extra entries. + * @param self Interface of the entry manager + */ + void (*destroy)(struct eri *self); } *ERS; #ifdef DISABLE_ERS // Use memory manager to allocate/free and disable other interface functions -# define ers_alloc(obj,type) (type *)aMalloc(sizeof(type)) -# define ers_free(obj,entry) aFree(entry) -# define ers_entry_size(obj) (size_t)0 -# define ers_destroy(obj) +# define ers_alloc(obj,type) (type *)aMalloc(sizeof(type)) +# define ers_free(obj,entry) aFree(entry) +# define ers_entry_size(obj) (size_t)0 +# define ers_destroy(obj) // Disable the public functions -# define ers_new(size,name,options) NULL -# define ers_report() -# define ers_force_destroy_all() +# define ers_new(size,name,options) NULL +# define ers_report() +# define ers_force_destroy_all() #else /* not DISABLE_ERS */ -// These defines should be used to allow the code to keep working whenever +// These defines should be used to allow the code to keep working whenever // the system is disabled -# define ers_alloc(obj,type) (type *)(obj)->alloc(obj) -# define ers_free(obj,entry) (obj)->free((obj),(entry)) -# define ers_entry_size(obj) (obj)->entry_size(obj) -# define ers_destroy(obj) (obj)->destroy(obj) +# define ers_alloc(obj,type) (type *)(obj)->alloc(obj) +# define ers_free(obj,entry) (obj)->free((obj),(entry)) +# define ers_entry_size(obj) (obj)->entry_size(obj) +# define ers_destroy(obj) (obj)->destroy(obj) /** * Get a new instance of the manager that handles the specified entry size. * Size has to greater than 0. - * If the specified size is smaller than a pointer, the size of a pointer is + * If the specified size is smaller than a pointer, the size of a pointer is * used instead. - * It's also aligned to ERS_ALIGNED bytes, so the smallest multiple of + * It's also aligned to ERS_ALIGNED bytes, so the smallest multiple of * ERS_ALIGNED that is greater or equal to size is what's actually used. * @param The requested size of the entry in bytes * @return Interface of the object @@ -152,7 +152,7 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options); /** * Print a report about the current state of the Entry Reusage System. * Shows information about the global system and each entry manager. - * The number of entries are checked and a warning is shown if extra reusable + * The number of entries are checked and a warning is shown if extra reusable * entries are found. * The extra entries are included in the count of reusable entries. */ @@ -163,7 +163,7 @@ void ers_report(void); * The system is left as if no instances or entries had ever been allocated. * All previous entries and instances of the managers become invalid. * The use of this is NOT recommended. - * It should only be used in extreme situations to make shure all the memory + * It should only be used in extreme situations to make shure all the memory * allocated by this system is released. */ void ers_force_destroy_all(void); diff --git a/src/common/evdp.h b/src/common/evdp.h index c9cff9e2b..bc3454686 100644 --- a/src/common/evdp.h +++ b/src/common/evdp.h @@ -8,27 +8,27 @@ typedef struct EVDP_DATA EVDP_DATA; //#idef EVDP_EPOLL #include -struct EVDP_DATA { - struct epoll_event ev_data; - bool ev_added; +struct EVDP_DATA{ + struct epoll_event ev_data; + bool ev_added; }; //#endif -enum EVDP_EVENTFLAGS { - EVDP_EVENT_IN = 1, // Incomming data - EVDP_EVENT_OUT = 2, // Connection accepts writing. - EVDP_EVENT_HUP = 4 // Connection Closed. +enum EVDP_EVENTFLAGS{ + EVDP_EVENT_IN = 1, // Incomming data + EVDP_EVENT_OUT = 2, // Connection accepts writing. + EVDP_EVENT_HUP = 4 // Connection Closed. }; -typedef struct EVDP_EVENT { - int32 events; // due to performance reasons, this should be the first member. - int32 fd; // Connection Identifier +typedef struct EVDP_EVENT{ + int32 events; // due to performance reasons, this should be the first member. + int32 fd; // Connection Identifier } EVDP_EVENT; -/** +/** * Network Event Dispatcher Initialization / Finalization routines */ void evdp_init(); @@ -38,56 +38,56 @@ void evdp_final(); /** * Will Wait for events. * - * @param *out_ev pointer to array in size at least of max_events. - * @param max_events max no of events to report with this call (coalesc) - * @param timeout_ticks max time to wait in ticks (milliseconds) + * @param *out_ev pointer to array in size at least of max_events. + * @param max_events max no of events to report with this call (coalesc) + * @param timeout_ticks max time to wait in ticks (milliseconds) * * @Note: - * The function will block until an event has occured on one of the monitored connections - * or the timeout of timeout_ticks has passed by. - * Upon successfull call (changed connections) this function will write the connection - * Identifier & event to the out_fds array. + * The function will block until an event has occured on one of the monitored connections + * or the timeout of timeout_ticks has passed by. + * Upon successfull call (changed connections) this function will write the connection + * Identifier & event to the out_fds array. * - * @return 0 -> Timeout, > 0 no of changed connections. + * @return 0 -> Timeout, > 0 no of changed connections. */ -int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks); +int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks); -/** +/** * Applys the given mask on the given connection. - * - * @param fd connection identifier - * @param *ep event data pointer for the connection - * @param mask new event mask we're monitoring for. + * + * @param fd connection identifier + * @param *ep event data pointer for the connection + * @param mask new event mask we're monitoring for. */ -//void evdp_apply(int32 fd, EVDP_DATA *ep, int32 mask); +//void evdp_apply(int32 fd, EVDP_DATA *ep, int32 mask); -/** +/** * Adds a connection (listner) to the event notification system. * - * @param fd connection identifier - * @param *ep event data pointer for the connection + * @param fd connection identifier + * @param *ep event data pointer for the connection * - * @note: - * Listener type sockets are edge triggered, (see epoll manual for more information) + * @note: + * Listener type sockets are edge triggered, (see epoll manual for more information) * - This basicaly means that youll receive one event, adn you have to accept until accept returns an error (nothing to accept) * * MONITORS by default: IN - * + * * @return success indicator. - */ + */ bool evdp_addlistener(int32 fd, EVDP_DATA *ep); /** * Adds a connection (client connectioN) to the event notification system * - * @param fd connection identifier - * @param *ep event data pointr for the connection - * + * @param fd connection identifier + * @param *ep event data pointr for the connection + * * @note: - * - * MONITORS by default: IN, HUP + * + * MONITORS by default: IN, HUP * * @return success indicator. */ @@ -96,17 +96,17 @@ bool evdp_addclient(int32 fd, EVDP_DATA *ep); /** * Adds a connection (pending / outgoing connection!) to the event notification system. * - * @param fd connection identifier - * @param *ep event data pointer for the conneciton. + * @param fd connection identifier + * @param *ep event data pointer for the conneciton. * * @note: - * Outgoing connection type sockets are getting monitored for connection established - * successfull - * - if the connection has been established - we're generitng a writable notification .. (send) - * this is typical for BSD / posix conform network stacks. - * - Additinionally its edge triggered. + * Outgoing connection type sockets are getting monitored for connection established + * successfull + * - if the connection has been established - we're generitng a writable notification .. (send) + * this is typical for BSD / posix conform network stacks. + * - Additinionally its edge triggered. * - * @see evdp_outgoingconnection_established + * @see evdp_outgoingconnection_established * * * @return success indicator @@ -114,14 +114,14 @@ bool evdp_addclient(int32 fd, EVDP_DATA *ep); bool evdp_addconnecting(int32 fd, EVDP_DATA *ep); /** - * Adds an outgoing connection to the normal event notification system after it has been successfully established. - * - * @param fd connection identifier - * @param *ep event data pointer for the conneciton. - - * @note - * after this call, its handled like a normal "client" connection (incomming) - * + * Adds an outgoing connection to the normal event notification system after it has been successfully established. + * + * @param fd connection identifier + * @param *ep event data pointer for the conneciton. + + * @note + * after this call, its handled like a normal "client" connection (incomming) + * * @rturn success indicator */ bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep); @@ -129,24 +129,24 @@ bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep); /** * Marks a connection to be monitored for writable. * - * @param fd connection identifier - * @param *ep event data pointer for the connection + * @param fd connection identifier + * @param *ep event data pointer for the connection * * @note: - * the connection must be already added (as client or listener) - * + * the connection must be already added (as client or listener) + * * * @return sucess indicator */ bool evdp_writable_add(int32 fd, EVDP_DATA *ep); -/** +/** * Removes the connection from writable notification monitoring * - * @param fd connection identifier - * @param *ep event data pointr for the connection + * @param fd connection identifier + * @param *ep event data pointr for the connection * - */ + */ void evdp_writable_remove(int32 fd, EVDP_DATA *ep); /** @@ -157,11 +157,11 @@ void evdp_writable_remove(int32 fd, EVDP_DATA *ep); * * * @note: - * this will also clear the given EVENT_DATA block - * so the connection slot is in an "initial" blank status / ready to get reused. + * this will also clear the given EVENT_DATA block + * so the connection slot is in an "initial" blank status / ready to get reused. * */ -void evdp_remove(int32 fd, EVDP_DATA *ep); +void evdp_remove(int32 fd, EVDP_DATA *ep); diff --git a/src/common/evdp_epoll.c b/src/common/evdp_epoll.c index 9f7c3d8ea..0357dfc66 100644 --- a/src/common/evdp_epoll.c +++ b/src/common/evdp_epoll.c @@ -1,5 +1,5 @@ // -// Event Dispatcher Abstraction for EPOLL +// Event Dispatcher Abstraction for EPOLL // // Author: Florian Wilkemeyer // @@ -23,220 +23,210 @@ #include "../common/evdp.h" -#define EPOLL_MAX_PER_CYCLE 10 // Max Events to coalesc. per cycle. +#define EPOLL_MAX_PER_CYCLE 10 // Max Events to coalesc. per cycle. static int epoll_fd = -1; -void evdp_init() -{ - - epoll_fd = epoll_create(EPOLL_MAX_PER_CYCLE); - if (epoll_fd == -1) { - ShowFatalError("evdp [EPOLL]: Cannot create event dispatcher (errno: %u / %s)\n", errno, strerror(errno)); - exit(1); - } - +void evdp_init(){ + + epoll_fd = epoll_create( EPOLL_MAX_PER_CYCLE ); + if(epoll_fd == -1){ + ShowFatalError("evdp [EPOLL]: Cannot create event dispatcher (errno: %u / %s)\n", errno, strerror(errno) ); + exit(1); + } + }//end: evdp_init() -void evdp_final() -{ - - if (epoll_fd != -1) { - close(epoll_fd); - epoll_fd = -1; - } - +void evdp_final(){ + + if(epoll_fd != -1){ + close(epoll_fd); + epoll_fd = -1; + } + }//end: evdp_final() -int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks) -{ - struct epoll_event l_events[EPOLL_MAX_PER_CYCLE]; - register struct epoll_event *ev; - register int nfds, n; - - if (max_events > EPOLL_MAX_PER_CYCLE) - max_events = EPOLL_MAX_PER_CYCLE; - - nfds = epoll_wait(epoll_fd, l_events, max_events, timeout_ticks); - if (nfds == -1) { - // @TODO: check if core is in shutdown mode. if - ignroe error. - - ShowFatalError("evdp [EPOLL]: epoll_wait returned bad / unexpected status (errno: %u / %s)\n", errno, strerror(errno)); - exit(1); //.. - } - - // Loop thru all events and copy it to the local ra evdp_event.. struct. - for (n = 0; n < nfds; n++) { - ev = &l_events[n]; - - out_fds->fd = ev->data.fd; - out_fds->events = 0; // clear - - if (ev->events & EPOLLHUP) - out_fds->events |= EVDP_EVENT_HUP; - - if (ev->events & EPOLLIN) - out_fds->events |= EVDP_EVENT_IN; - - if (ev->events & EPOLLOUT) - out_fds->events |= EVDP_EVENT_OUT; - - out_fds++; - } - - return nfds; // 0 on timeout or > 0 .. +int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks){ + struct epoll_event l_events[EPOLL_MAX_PER_CYCLE]; + register struct epoll_event *ev; + register int nfds, n; + + if(max_events > EPOLL_MAX_PER_CYCLE) + max_events = EPOLL_MAX_PER_CYCLE; + + nfds = epoll_wait( epoll_fd, l_events, max_events, timeout_ticks); + if(nfds == -1){ + // @TODO: check if core is in shutdown mode. if - ignroe error. + + ShowFatalError("evdp [EPOLL]: epoll_wait returned bad / unexpected status (errno: %u / %s)\n", errno, strerror(errno)); + exit(1); //.. + } + + // Loop thru all events and copy it to the local ra evdp_event.. struct. + for(n = 0; n < nfds; n++){ + ev = &l_events[n]; + + out_fds->fd = ev->data.fd; + out_fds->events = 0; // clear + + if(ev->events & EPOLLHUP) + out_fds->events |= EVDP_EVENT_HUP; + + if(ev->events & EPOLLIN) + out_fds->events |= EVDP_EVENT_IN; + + if(ev->events & EPOLLOUT) + out_fds->events |= EVDP_EVENT_OUT; + + out_fds++; + } + + return nfds; // 0 on timeout or > 0 .. }//end: evdp_wait() -void evdp_remove(int32 fd, EVDP_DATA *ep) -{ - - if (ep->ev_added == true) { - - if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ep->ev_data) != 0) { - ShowError("evdp [EPOLL]: evdp_remove - epoll_ctl (EPOLL_CTL_DEL) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - } - - ep->ev_data.events = 0; // clear struct. - ep->ev_data.data.fd = -1; // .. clear struct .. - - ep->ev_added = false; // not added! - } +void evdp_remove(int32 fd, EVDP_DATA *ep){ + + if(ep->ev_added == true){ + + if( epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ep->ev_data) != 0){ + ShowError("evdp [EPOLL]: evdp_remove - epoll_ctl (EPOLL_CTL_DEL) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + } + + ep->ev_data.events = 0; // clear struct. + ep->ev_data.data.fd = -1; // .. clear struct .. + ep->ev_added = false; // not added! + } + }//end: evdp_remove() -bool evdp_addlistener(int32 fd, EVDP_DATA *ep) -{ - - ep->ev_data.events = EPOLLET|EPOLLIN; - ep->ev_data.data.fd = fd; - - // No check here for 'added ?' - // listeners cannot be added twice. - // - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { - ShowError("evdp [EPOLL]: evdp_addlistener - epoll_ctl (EPOLL_CTL_ADD) faield! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - return false; - } - - ep->ev_added = true; - - return true; +bool evdp_addlistener(int32 fd, EVDP_DATA *ep){ + + ep->ev_data.events = EPOLLET|EPOLLIN; + ep->ev_data.data.fd = fd; + + // No check here for 'added ?' + // listeners cannot be added twice. + // + if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0 ){ + ShowError("evdp [EPOLL]: evdp_addlistener - epoll_ctl (EPOLL_CTL_ADD) faield! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + return false; + } + + ep->ev_added = true; + + return true; }//end: evdp_addlistener() -bool evdp_addclient(int32 fd, EVDP_DATA *ep) -{ - - ep->ev_data.events = EPOLLIN | EPOLLHUP; - ep->ev_data.data.fd = fd; - - // No check for "added?" here, - // this function only gets called upon accpept. - // - - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { - ShowError("evdp [EPOLL]: evdp_addclient - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - return false; - } - - ep->ev_added = true; - - return true; +bool evdp_addclient(int32 fd, EVDP_DATA *ep){ + + ep->ev_data.events = EPOLLIN | EPOLLHUP; + ep->ev_data.data.fd = fd; + + // No check for "added?" here, + // this function only gets called upon accpept. + // + + if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0){ + ShowError("evdp [EPOLL]: evdp_addclient - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + return false; + } + + ep->ev_added = true; + + return true; }//end: evdp_addclient() -bool evdp_addconnecting(int32 fd, EVDP_DATA *ep) -{ - - ep->ev_data.events = EPOLLET | EPOLLOUT | EPOLLHUP; - ep->ev_data.data.fd = fd; - - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { - ShowError("evdp [EPOLL]: evdp_addconnecting - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - } - - ep->ev_added = true; - - return true; +bool evdp_addconnecting(int32 fd, EVDP_DATA *ep){ + + ep->ev_data.events = EPOLLET | EPOLLOUT | EPOLLHUP; + ep->ev_data.data.fd = fd; + + if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0){ + ShowError("evdp [EPOLL]: evdp_addconnecting - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + } + + ep->ev_added = true; + + return true; }//end: evdp_addconnecting() -bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep) -{ - int32 saved_mask; - - if (ep->ev_added != true) { - // ! - ShowError("evdp [EPOLL]: evdp_outgoingconnection_established fd #%u is not added to event dispatcher! invalid call.\n", fd); - return false; - } - - saved_mask = ep->ev_data.events; - - ep->ev_data.events = EPOLLIN | EPOLLHUP; - - if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { - ep->ev_data.events = saved_mask; // restore old mask. - ShowError("evdp [EPOLL]: evdp_outgoingconnection_established - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - return false; - } - - return true; +bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep){ + int32 saved_mask; + + if(ep->ev_added != true){ + // ! + ShowError("evdp [EPOLL]: evdp_outgoingconnection_established fd #%u is not added to event dispatcher! invalid call.\n", fd); + return false; + } + + saved_mask = ep->ev_data.events; + + ep->ev_data.events = EPOLLIN | EPOLLHUP; + + if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0){ + ep->ev_data.events = saved_mask; // restore old mask. + ShowError("evdp [EPOLL]: evdp_outgoingconnection_established - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + return false; + } + + return true; }//end: evdp_outgoingconnection_established() -bool evdp_writable_add(int32 fd, EVDP_DATA *ep) -{ - - if (ep->ev_added != true) { - ShowError("evdp [EPOLL]: evdp_writable_add - tried to add not added fd #%u\n",fd); - return false; - } - - if (!(ep->ev_data.events & EPOLLOUT)) { // - - ep->ev_data.events |= EPOLLOUT; - if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { - ShowError("evdp [EPOLL]: evdp_writable_add - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno: %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events &= ~EPOLLOUT; // remove from local flagmask due to failed syscall. - return false; - } - } - - return true; +bool evdp_writable_add(int32 fd, EVDP_DATA *ep){ + + if(ep->ev_added != true){ + ShowError("evdp [EPOLL]: evdp_writable_add - tried to add not added fd #%u\n",fd); + return false; + } + + if(! (ep->ev_data.events & EPOLLOUT) ){ // + + ep->ev_data.events |= EPOLLOUT; + if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0 ){ + ShowError("evdp [EPOLL]: evdp_writable_add - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno: %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events &= ~EPOLLOUT; // remove from local flagmask due to failed syscall. + return false; + } + } + + return true; }//end: evdp_writable_add() -void evdp_writable_remove(int32 fd, EVDP_DATA *ep) -{ - - if (ep->ev_added != true) { - ShowError("evdp [EPOLL]: evdp_writable_remove - tried to remove not added fd #%u\n", fd); - return; - } - - if (ep->ev_data.events & EPOLLOUT) { - - ep->ev_data.events &= ~EPOLLOUT; - if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { - ShowError("evdp [EPOLL]: evdp_writable_remove - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events |= EPOLLOUT; // add back to local flagmask because of failed syscall. - return; - } - } - - return; +void evdp_writable_remove(int32 fd, EVDP_DATA *ep){ + + if(ep->ev_added != true){ + ShowError("evdp [EPOLL]: evdp_writable_remove - tried to remove not added fd #%u\n", fd); + return; + } + + if( ep->ev_data.events & EPOLLOUT ){ + + ep->ev_data.events &= ~EPOLLOUT; + if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0){ + ShowError("evdp [EPOLL]: evdp_writable_remove - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events |= EPOLLOUT; // add back to local flagmask because of failed syscall. + return; + } + } + + return; }//end: evdp_writable_remove() diff --git a/src/common/grfio.c b/src/common/grfio.c index f86f9c1cb..8f430cfb9 100644 --- a/src/common/grfio.c +++ b/src/common/grfio.c @@ -16,18 +16,18 @@ #include //---------------------------- -// file entry table struct +// file entry table struct //---------------------------- typedef struct _FILELIST { - int srclen; // compressed size - int srclen_aligned; - int declen; // original size - int srcpos; // position of entry in grf - int next; // index of next filelist entry with same hash (-1: end of entry chain) - char type; - char fn[128-4*5]; // file name - char *fnd; // if the file was cloned, contains name of original file - char gentry; // read grf file select + int srclen; // compressed size + int srclen_aligned; + int declen; // original size + int srcpos; // position of entry in grf + int next; // index of next filelist entry with same hash (-1: end of entry chain) + char type; + char fn[128-4*5]; // file name + char* fnd; // if the file was cloned, contains name of original file + char gentry; // read grf file select } FILELIST; #define FILELIST_TYPE_FILE 0x01 // entry is a file @@ -45,33 +45,34 @@ typedef struct _FILELIST { // stores info about every loaded file -FILELIST *filelist = NULL; -int filelist_entrys = 0; -int filelist_maxentry = 0; +FILELIST* filelist = NULL; +int filelist_entrys = 0; +int filelist_maxentry = 0; // stores grf file names -char **gentry_table = NULL; -int gentry_entrys = 0; -int gentry_maxentry = 0; +char** gentry_table = NULL; +int gentry_entrys = 0; +int gentry_maxentry = 0; // the path to the data directory char data_dir[1024] = ""; // little endian char array to uint conversion -static unsigned int getlong(unsigned char *p) +static unsigned int getlong(unsigned char* p) { - return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); + return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); } -static void NibbleSwap(unsigned char *src, int len) +static void NibbleSwap(unsigned char* src, int len) { - while (len > 0) { - *src = (*src >> 4) | (*src << 4); - ++src; - --len; - } + while( len > 0 ) + { + *src = (*src >> 4) | (*src << 4); + ++src; + --len; + } } @@ -79,142 +80,114 @@ static void NibbleSwap(unsigned char *src, int len) /// NOTE: Operation is symmetric (calling it twice gives back the original input). static uint8_t grf_substitution(uint8_t in) { - uint8_t out; - - switch (in) { - case 0x00: - out = 0x2B; - break; - case 0x2B: - out = 0x00; - break; - case 0x6C: - out = 0x80; - break; - case 0x01: - out = 0x68; - break; - case 0x68: - out = 0x01; - break; - case 0x48: - out = 0x77; - break; - case 0x60: - out = 0xFF; - break; - case 0x77: - out = 0x48; - break; - case 0xB9: - out = 0xC0; - break; - case 0xC0: - out = 0xB9; - break; - case 0xFE: - out = 0xEB; - break; - case 0xEB: - out = 0xFE; - break; - case 0x80: - out = 0x6C; - break; - case 0xFF: - out = 0x60; - break; - default: - out = in; - break; - } - - return out; + uint8_t out; + + switch( in ) + { + case 0x00: out = 0x2B; break; + case 0x2B: out = 0x00; break; + case 0x6C: out = 0x80; break; + case 0x01: out = 0x68; break; + case 0x68: out = 0x01; break; + case 0x48: out = 0x77; break; + case 0x60: out = 0xFF; break; + case 0x77: out = 0x48; break; + case 0xB9: out = 0xC0; break; + case 0xC0: out = 0xB9; break; + case 0xFE: out = 0xEB; break; + case 0xEB: out = 0xFE; break; + case 0x80: out = 0x6C; break; + case 0xFF: out = 0x60; break; + default: out = in; break; + } + + return out; } /* this is not used anywhere, is it ok to delete? */ //static void grf_shuffle_enc(BIT64* src) { -// BIT64 out; +// BIT64 out; // -// out.b[0] = src->b[3]; -// out.b[1] = src->b[4]; -// out.b[2] = src->b[5]; -// out.b[3] = src->b[0]; -// out.b[4] = src->b[1]; -// out.b[5] = src->b[6]; -// out.b[6] = src->b[2]; -// out.b[7] = grf_substitution(src->b[7]); +// out.b[0] = src->b[3]; +// out.b[1] = src->b[4]; +// out.b[2] = src->b[5]; +// out.b[3] = src->b[0]; +// out.b[4] = src->b[1]; +// out.b[5] = src->b[6]; +// out.b[6] = src->b[2]; +// out.b[7] = grf_substitution(src->b[7]); // -// *src = out; +// *src = out; //} -static void grf_shuffle_dec(BIT64 *src) +static void grf_shuffle_dec(BIT64* src) { - BIT64 out; - - out.b[0] = src->b[3]; - out.b[1] = src->b[4]; - out.b[2] = src->b[6]; - out.b[3] = src->b[0]; - out.b[4] = src->b[1]; - out.b[5] = src->b[2]; - out.b[6] = src->b[5]; - out.b[7] = grf_substitution(src->b[7]); - - *src = out; + BIT64 out; + + out.b[0] = src->b[3]; + out.b[1] = src->b[4]; + out.b[2] = src->b[6]; + out.b[3] = src->b[0]; + out.b[4] = src->b[1]; + out.b[5] = src->b[2]; + out.b[6] = src->b[5]; + out.b[7] = grf_substitution(src->b[7]); + + *src = out; } -static void grf_decode_header(unsigned char *buf, size_t len) +static void grf_decode_header(unsigned char* buf, size_t len) { - BIT64 *p = (BIT64 *)buf; - size_t nblocks = len / sizeof(BIT64); - size_t i; + BIT64* p = (BIT64*)buf; + size_t nblocks = len / sizeof(BIT64); + size_t i; - // first 20 blocks are all des-encrypted - for (i = 0; i < 20 && i < nblocks; ++i) - des_decrypt_block(&p[i]); + // first 20 blocks are all des-encrypted + for( i = 0; i < 20 && i < nblocks; ++i ) + des_decrypt_block(&p[i]); - // the rest is plaintext, done. + // the rest is plaintext, done. } -static void grf_decode_full(unsigned char *buf, size_t len, int cycle) +static void grf_decode_full(unsigned char* buf, size_t len, int cycle) { - BIT64 *p = (BIT64 *)buf; - size_t nblocks = len / sizeof(BIT64); - int dcycle, scycle; - size_t i, j; - - // first 20 blocks are all des-encrypted - for (i = 0; i < 20 && i < nblocks; ++i) - des_decrypt_block(&p[i]); - - // after that only one of every 'dcycle' blocks is des-encrypted - dcycle = cycle; - - // and one of every 'scycle' plaintext blocks is shuffled (starting from the 0th but skipping the 0th) - scycle = 7; - - // so decrypt/de-shuffle periodically - j = -1; // 0, adjusted to fit the ++j step - for (i = 20; i < nblocks; ++i) { - if (i % dcycle == 0) { - // decrypt block - des_decrypt_block(&p[i]); - continue; - } - - ++j; - if (j % scycle == 0 && j != 0) { - // de-shuffle block - grf_shuffle_dec(&p[i]); - continue; - } - - // plaintext, do nothing. - } + BIT64* p = (BIT64*)buf; + size_t nblocks = len / sizeof(BIT64); + int dcycle, scycle; + size_t i, j; + + // first 20 blocks are all des-encrypted + for( i = 0; i < 20 && i < nblocks; ++i ) + des_decrypt_block(&p[i]); + + // after that only one of every 'dcycle' blocks is des-encrypted + dcycle = cycle; + + // and one of every 'scycle' plaintext blocks is shuffled (starting from the 0th but skipping the 0th) + scycle = 7; + + // so decrypt/de-shuffle periodically + j = -1; // 0, adjusted to fit the ++j step + for( i = 20; i < nblocks; ++i ) + { + if( i % dcycle == 0 ) + {// decrypt block + des_decrypt_block(&p[i]); + continue; + } + + ++j; + if( j % scycle == 0 && j != 0 ) + {// de-shuffle block + grf_shuffle_dec(&p[i]); + continue; + } + + // plaintext, do nothing. + } } @@ -223,35 +196,38 @@ static void grf_decode_full(unsigned char *buf, size_t len, int cycle) /// @param len length of the data /// @param entry_type flags associated with the data /// @param entry_len true (unaligned) length of the data -static void grf_decode(unsigned char *buf, size_t len, char entry_type, int entry_len) +static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entry_len) { - if (entry_type & FILELIST_TYPE_ENCRYPT_MIXED) { - // fully encrypted - int digits; - int cycle; - int i; - - // compute number of digits of the entry length - digits = 1; - for (i = 10; i <= entry_len; i *= 10) - ++digits; - - // choose size of gap between two encrypted blocks - // digits: 0 1 2 3 4 5 6 7 8 9 ... - // cycle: 1 1 1 4 5 14 15 22 23 24 ... - cycle = (digits < 3) ? 1 - : (digits < 5) ? digits + 1 - : (digits < 7) ? digits + 9 - : digits + 15; - - grf_decode_full(buf, len, cycle); - } else if (entry_type & FILELIST_TYPE_ENCRYPT_HEADER) { - // header encrypted - grf_decode_header(buf, len); - } else { - // plaintext - ; - } + if( entry_type & FILELIST_TYPE_ENCRYPT_MIXED ) + {// fully encrypted + int digits; + int cycle; + int i; + + // compute number of digits of the entry length + digits = 1; + for( i = 10; i <= entry_len; i *= 10 ) + ++digits; + + // choose size of gap between two encrypted blocks + // digits: 0 1 2 3 4 5 6 7 8 9 ... + // cycle: 1 1 1 4 5 14 15 22 23 24 ... + cycle = ( digits < 3 ) ? 1 + : ( digits < 5 ) ? digits + 1 + : ( digits < 7 ) ? digits + 9 + : digits + 15; + + grf_decode_full(buf, len, cycle); + } + else + if( entry_type & FILELIST_TYPE_ENCRYPT_HEADER ) + {// header encrypted + grf_decode_header(buf, len); + } + else + {// plaintext + ; + } } @@ -260,23 +236,23 @@ static void grf_decode(unsigned char *buf, size_t len, char entry_type, int entr ******************************************************/ /// zlib crc32 -unsigned long grfio_crc32(const unsigned char *buf, unsigned int len) +unsigned long grfio_crc32(const unsigned char* buf, unsigned int len) { - return crc32(crc32(0L, Z_NULL, 0), buf, len); + return crc32(crc32(0L, Z_NULL, 0), buf, len); } /// zlib uncompress -int decode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen) +int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) { - return uncompress((Bytef *)dest, destLen, (const Bytef *)source, sourceLen); + return uncompress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); } /// zlib compress -int encode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen) +int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) { - return compress((Bytef *)dest, destLen, (const Bytef *)source, sourceLen); + return compress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); } @@ -289,94 +265,94 @@ int filelist_hash[256]; // initializes the table that holds the first elements of all hash chains static void hashinit(void) { - int i; - for (i = 0; i < 256; i++) - filelist_hash[i] = -1; + int i; + for (i = 0; i < 256; i++) + filelist_hash[i] = -1; } // hashes a filename string into a number from {0..255} -static int filehash(const char *fname) +static int filehash(const char* fname) { - unsigned int hash = 0; - while (*fname) { - hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname); - fname++; - } - return hash & 255; + unsigned int hash = 0; + while(*fname) { + hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname); + fname++; + } + return hash & 255; } // finds a FILELIST entry with the specified file name -static FILELIST *filelist_find(const char *fname) +static FILELIST* filelist_find(const char* fname) { - int hash, index; + int hash, index; - if (!filelist) - return NULL; + if (!filelist) + return NULL; - hash = filelist_hash[filehash(fname)]; - for (index = hash; index != -1; index = filelist[index].next) - if (!strcmpi(filelist[index].fn, fname)) - break; + hash = filelist_hash[filehash(fname)]; + for (index = hash; index != -1; index = filelist[index].next) + if(!strcmpi(filelist[index].fn, fname)) + break; - return (index >= 0) ? &filelist[index] : NULL; + return (index >= 0) ? &filelist[index] : NULL; } // returns the original file name -char *grfio_find_file(const char *fname) +char* grfio_find_file(const char* fname) { - FILELIST *filelist = filelist_find(fname); - if (!filelist) return NULL; - return (!filelist->fnd ? filelist->fn : filelist->fnd); + FILELIST *filelist = filelist_find(fname); + if (!filelist) return NULL; + return (!filelist->fnd ? filelist->fn : filelist->fnd); } // adds a FILELIST entry into the list of loaded files -static FILELIST *filelist_add(FILELIST *entry) +static FILELIST* filelist_add(FILELIST* entry) { - int hash; + int hash; -#define FILELIST_ADDS 1024 // number increment of file lists ` + #define FILELIST_ADDS 1024 // number increment of file lists ` - if (filelist_entrys >= filelist_maxentry) { - filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST)); - memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST)); - filelist_maxentry += FILELIST_ADDS; - } + if (filelist_entrys >= filelist_maxentry) { + filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST)); + memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST)); + filelist_maxentry += FILELIST_ADDS; + } - memcpy(&filelist[filelist_entrys], entry, sizeof(FILELIST)); + memcpy (&filelist[filelist_entrys], entry, sizeof(FILELIST)); - hash = filehash(entry->fn); - filelist[filelist_entrys].next = filelist_hash[hash]; - filelist_hash[hash] = filelist_entrys; + hash = filehash(entry->fn); + filelist[filelist_entrys].next = filelist_hash[hash]; + filelist_hash[hash] = filelist_entrys; - filelist_entrys++; + filelist_entrys++; - return &filelist[filelist_entrys - 1]; + return &filelist[filelist_entrys - 1]; } // adds a new FILELIST entry or overwrites an existing one -static FILELIST *filelist_modify(FILELIST *entry) +static FILELIST* filelist_modify(FILELIST* entry) { - FILELIST *fentry = filelist_find(entry->fn); - if (fentry != NULL) { - int tmp = fentry->next; - memcpy(fentry, entry, sizeof(FILELIST)); - fentry->next = tmp; - } else { - fentry = filelist_add(entry); - } - return fentry; + FILELIST* fentry = filelist_find(entry->fn); + if (fentry != NULL) { + int tmp = fentry->next; + memcpy(fentry, entry, sizeof(FILELIST)); + fentry->next = tmp; + } else { + fentry = filelist_add(entry); + } + return fentry; } // shrinks the file list array if too long static void filelist_compact(void) { - if (filelist == NULL) - return; + if (filelist == NULL) + return; - if (filelist_entrys < filelist_maxentry) { - filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST)); - filelist_maxentry = filelist_entrys; - } + if (filelist_entrys < filelist_maxentry) { + filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST)); + filelist_maxentry = filelist_entrys; + } } @@ -386,448 +362,457 @@ static void filelist_compact(void) /// Combines are resource path with the data folder location to create local resource path. -static void grfio_localpath_create(char *buffer, size_t size, const char *filename) +static void grfio_localpath_create(char* buffer, size_t size, const char* filename) { - unsigned int i; - size_t len; - - len = strlen(data_dir); - - if (data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\') { - safesnprintf(buffer, size, "%s%s", data_dir, filename); - } else { - safesnprintf(buffer, size, "%s/%s", data_dir, filename); - } - - // normalize path - for (i = 0; buffer[i] != '\0'; ++i) - if (buffer[i] == '\\') - buffer[i] = '/'; + unsigned int i; + size_t len; + + len = strlen(data_dir); + + if( data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\' ) + { + safesnprintf(buffer, size, "%s%s", data_dir, filename); + } + else + { + safesnprintf(buffer, size, "%s/%s", data_dir, filename); + } + + // normalize path + for( i = 0; buffer[i] != '\0'; ++i ) + if( buffer[i] == '\\' ) + buffer[i] = '/'; } /// Reads a file into a newly allocated buffer (from grf or data directory). -void *grfio_reads(const char *fname, int *size) +void* grfio_reads(const char* fname, int* size) { - unsigned char *buf2 = NULL; - - FILELIST *entry = filelist_find(fname); - if (entry == NULL || entry->gentry <= 0) { // LocalFileCheck - char lfname[256]; - int declen; - FILE *in; - grfio_localpath_create(lfname, sizeof(lfname), (entry && entry->fnd) ? entry->fnd : fname); - - in = fopen(lfname, "rb"); - if (in != NULL) { - fseek(in,0,SEEK_END); - declen = ftell(in); - fseek(in,0,SEEK_SET); - buf2 = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination - if (fread(buf2, 1, declen, in) != declen) ShowError("An error occured in fread grfio_reads, fname=%s \n",fname); - fclose(in); - - if (size) - *size = declen; - } else { - if (entry != NULL && entry->gentry < 0) { - entry->gentry = -entry->gentry; // local file checked - } else { - ShowError("grfio_reads: %s not found (local file: %s)\n", fname, lfname); - return NULL; - } - } - } - - if (entry != NULL && entry->gentry > 0) { // Archive[GRF] File Read - char *grfname = gentry_table[entry->gentry - 1]; - FILE *in = fopen(grfname, "rb"); - if (in != NULL) { - int fsize = entry->srclen_aligned; - unsigned char *buf = (unsigned char *)aMalloc(fsize); - fseek(in, entry->srcpos, 0); - if (fread(buf, 1, fsize, in) != fsize) ShowError("An error occured in fread in grfio_reads, grfname=%s\n",grfname); - fclose(in); - - buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination - if (entry->type & FILELIST_TYPE_FILE) { - // file - uLongf len; - grf_decode(buf, fsize, entry->type, entry->srclen); - len = entry->declen; - decode_zip(buf2, &len, buf, entry->srclen); - if (len != (uLong)entry->declen) { - ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen); - aFree(buf); - aFree(buf2); - return NULL; - } - } else {// directory? - memcpy(buf2, buf, entry->declen); - } - - if (size) - *size = entry->declen; - - aFree(buf); - } else { - ShowError("grfio_reads: %s not found (GRF file: %s)\n", fname, grfname); - return NULL; - } - } - - return buf2; + unsigned char* buf2 = NULL; + + FILELIST* entry = filelist_find(fname); + if( entry == NULL || entry->gentry <= 0 ) {// LocalFileCheck + char lfname[256]; + int declen; + FILE* in; + grfio_localpath_create(lfname, sizeof(lfname), ( entry && entry->fnd ) ? entry->fnd : fname); + + in = fopen(lfname, "rb"); + if( in != NULL ) { + fseek(in,0,SEEK_END); + declen = ftell(in); + fseek(in,0,SEEK_SET); + buf2 = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination + if(fread(buf2, 1, declen, in) != declen) ShowError("An error occured in fread grfio_reads, fname=%s \n",fname); + fclose(in); + + if( size ) + *size = declen; + } else { + if (entry != NULL && entry->gentry < 0) { + entry->gentry = -entry->gentry; // local file checked + } else { + ShowError("grfio_reads: %s not found (local file: %s)\n", fname, lfname); + return NULL; + } + } + } + + if( entry != NULL && entry->gentry > 0 ) {// Archive[GRF] File Read + char* grfname = gentry_table[entry->gentry - 1]; + FILE* in = fopen(grfname, "rb"); + if( in != NULL ) { + int fsize = entry->srclen_aligned; + unsigned char *buf = (unsigned char *)aMalloc(fsize); + fseek(in, entry->srcpos, 0); + if(fread(buf, 1, fsize, in) != fsize) ShowError("An error occured in fread in grfio_reads, grfname=%s\n",grfname); + fclose(in); + + buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination + if( entry->type & FILELIST_TYPE_FILE ) + {// file + uLongf len; + grf_decode(buf, fsize, entry->type, entry->srclen); + len = entry->declen; + decode_zip(buf2, &len, buf, entry->srclen); + if (len != (uLong)entry->declen) { + ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen); + aFree(buf); + aFree(buf2); + return NULL; + } + } else {// directory? + memcpy(buf2, buf, entry->declen); + } + + if( size ) + *size = entry->declen; + + aFree(buf); + } else { + ShowError("grfio_reads: %s not found (GRF file: %s)\n", fname, grfname); + return NULL; + } + } + + return buf2; } /// Decodes encrypted filename from a version 01xx grf index. -static char *decode_filename(unsigned char *buf, int len) +static char* decode_filename(unsigned char* buf, int len) { - int lop; - for (lop=0; lop> 8; - - if (grf_version == 0x01) { // ****** Grf version 01xx ****** - list_size = grf_size - ftell(fp); - grf_filelist = (unsigned char *) aMalloc(list_size); - if (fread(grf_filelist,1,list_size,fp) != list_size) { - ShowError("Couldn't read all grf_filelist element of %s \n", grfname); - } - fclose(fp); - - entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7; - - // Get an entry - for (entry = 0, ofs = 0; entry < entrys; ++entry) { - FILELIST aentry; - - int ofs2 = ofs+getlong(grf_filelist+ofs)+4; - unsigned char type = grf_filelist[ofs2+12]; - if (type & FILELIST_TYPE_FILE) { - char *fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); - int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; - - if (strlen(fname) > sizeof(aentry.fn) - 1) { - ShowFatalError("GRF file name %s is too long\n", fname); - aFree(grf_filelist); - exit(EXIT_FAILURE); - } - - type |= (isFullEncrypt(fname)) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; - - aentry.srclen = srclen; - aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; - aentry.declen = getlong(grf_filelist+ofs2+8); - aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.type = type; - safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); - aentry.fnd = NULL; -#ifdef GRFIO_LOCAL - aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck + long grf_size,list_size; + unsigned char grf_header[0x2e]; + int entry,entrys,ofs,grf_version; + unsigned char *grf_filelist; + + FILE* fp = fopen(grfname, "rb"); + if( fp == NULL ) { + ShowWarning("GRF data file not found: '%s'\n",grfname); + return 1; // 1:not found error + } else + ShowInfo("GRF data file found: '%s'\n",grfname); + + fseek(fp,0,SEEK_END); + grf_size = ftell(fp); + fseek(fp,0,SEEK_SET); + + if(fread(grf_header,1,0x2e,fp) != 0x2e) { ShowError("Couldn't read all grf_header element of %s \n", grfname); } + if( strcmp((const char*)grf_header,"Master of Magic") != 0 || fseek(fp,getlong(grf_header+0x1e),SEEK_CUR) != 0 ) { + fclose(fp); + ShowError("GRF %s read error\n", grfname); + return 2; // 2:file format error + } + + grf_version = getlong(grf_header+0x2a) >> 8; + + if( grf_version == 0x01 ) {// ****** Grf version 01xx ****** + list_size = grf_size - ftell(fp); + grf_filelist = (unsigned char *) aMalloc(list_size); + if(fread(grf_filelist,1,list_size,fp) != list_size) { ShowError("Couldn't read all grf_filelist element of %s \n", grfname); } + fclose(fp); + + entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7; + + // Get an entry + for( entry = 0, ofs = 0; entry < entrys; ++entry ) { + FILELIST aentry; + + int ofs2 = ofs+getlong(grf_filelist+ofs)+4; + unsigned char type = grf_filelist[ofs2+12]; + if( type & FILELIST_TYPE_FILE ) { + char* fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); + int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; + + if( strlen(fname) > sizeof(aentry.fn) - 1 ) { + ShowFatalError("GRF file name %s is too long\n", fname); + aFree(grf_filelist); + exit(EXIT_FAILURE); + } + + type |= ( isFullEncrypt(fname) ) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; + + aentry.srclen = srclen; + aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; + aentry.declen = getlong(grf_filelist+ofs2+8); + aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; + aentry.type = type; + safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); + aentry.fnd = NULL; +#ifdef GRFIO_LOCAL + aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else - aentry.gentry = gentry+1; // With no first time LocalFileCheck + aentry.gentry = gentry+1; // With no first time LocalFileCheck #endif - filelist_modify(&aentry); - } - - ofs = ofs2 + 17; - } - - aFree(grf_filelist); - } else if (grf_version == 0x02) { // ****** Grf version 02xx ****** - unsigned char eheader[8]; - unsigned char *rBuf; - uLongf rSize, eSize; - - if (fread(eheader,1,8,fp) != 8) ShowError("An error occured in fread while reading eheader buffer\n"); - rSize = getlong(eheader); // Read Size - eSize = getlong(eheader+4); // Extend Size - - if ((long)rSize > grf_size-ftell(fp)) { - fclose(fp); - ShowError("Illegal data format: GRF compress entry size\n"); - return 4; - } - - rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size - grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size - if (fread(rBuf,1,rSize,fp) != rSize) ShowError("An error occured in fread \n"); - fclose(fp); - decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function - aFree(rBuf); - - entrys = getlong(grf_header+0x26) - 7; - - // Get an entry - for (entry = 0, ofs = 0; entry < entrys; ++entry) { - FILELIST aentry; - - char *fname = (char *)(grf_filelist+ofs); - int ofs2 = ofs + (int)strlen(fname)+1; - int type = grf_filelist[ofs2+12]; - - if (strlen(fname) > sizeof(aentry.fn)-1) { - ShowFatalError("GRF file name %s is too long\n", fname); - aFree(grf_filelist); - exit(EXIT_FAILURE); - } - - if (type & FILELIST_TYPE_FILE) { // file - aentry.srclen = getlong(grf_filelist+ofs2+0); - aentry.srclen_aligned = getlong(grf_filelist+ofs2+4); - aentry.declen = getlong(grf_filelist+ofs2+8); - aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.type = type; - safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); - aentry.fnd = NULL; -#ifdef GRFIO_LOCAL - aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck + filelist_modify(&aentry); + } + + ofs = ofs2 + 17; + } + + aFree(grf_filelist); + } else if( grf_version == 0x02 ) {// ****** Grf version 02xx ****** + unsigned char eheader[8]; + unsigned char *rBuf; + uLongf rSize, eSize; + + if(fread(eheader,1,8,fp) != 8) ShowError("An error occured in fread while reading eheader buffer\n"); + rSize = getlong(eheader); // Read Size + eSize = getlong(eheader+4); // Extend Size + + if( (long)rSize > grf_size-ftell(fp) ) { + fclose(fp); + ShowError("Illegal data format: GRF compress entry size\n"); + return 4; + } + + rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size + grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size + if(fread(rBuf,1,rSize,fp) != rSize) ShowError("An error occured in fread \n"); + fclose(fp); + decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function + aFree(rBuf); + + entrys = getlong(grf_header+0x26) - 7; + + // Get an entry + for( entry = 0, ofs = 0; entry < entrys; ++entry ) { + FILELIST aentry; + + char* fname = (char*)(grf_filelist+ofs); + int ofs2 = ofs + (int)strlen(fname)+1; + int type = grf_filelist[ofs2+12]; + + if( strlen(fname) > sizeof(aentry.fn)-1 ) { + ShowFatalError("GRF file name %s is too long\n", fname); + aFree(grf_filelist); + exit(EXIT_FAILURE); + } + + if( type & FILELIST_TYPE_FILE ) {// file + aentry.srclen = getlong(grf_filelist+ofs2+0); + aentry.srclen_aligned = getlong(grf_filelist+ofs2+4); + aentry.declen = getlong(grf_filelist+ofs2+8); + aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; + aentry.type = type; + safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); + aentry.fnd = NULL; +#ifdef GRFIO_LOCAL + aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else - aentry.gentry = gentry+1; // With no first time LocalFileCheck + aentry.gentry = gentry+1; // With no first time LocalFileCheck #endif - filelist_modify(&aentry); - } + filelist_modify(&aentry); + } - ofs = ofs2 + 17; - } + ofs = ofs2 + 17; + } - aFree(grf_filelist); - } else {// ****** Grf Other version ****** - fclose(fp); - ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); - return 4; - } + aFree(grf_filelist); + } else {// ****** Grf Other version ****** + fclose(fp); + ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); + return 4; + } - filelist_compact(); // Unnecessary area release of filelist + filelist_compact(); // Unnecessary area release of filelist - return 0; // 0:no error + return 0; // 0:no error } -static bool grfio_parse_restable_row(const char *row) +static bool grfio_parse_restable_row(const char* row) { - char w1[256], w2[256]; - char src[256], dst[256]; - char local[256]; - FILELIST *entry; - - if (sscanf(row, "%[^#\r\n]#%[^#\r\n]#", w1, w2) != 2) - return false; - - if (strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL) - return false; // we only need the maps' GAT and RSW files - - sprintf(src, "data\\%s", w1); - sprintf(dst, "data\\%s", w2); - - entry = filelist_find(dst); - if (entry != NULL) { - // alias for GRF resource - FILELIST fentry; - memcpy(&fentry, entry, sizeof(FILELIST)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - return true; - } - - grfio_localpath_create(local, sizeof(local), dst); - if (exists(local)) { - // alias for local resource - FILELIST fentry; - memset(&fentry, 0, sizeof(fentry)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - return true; - } - - return false; + char w1[256], w2[256]; + char src[256], dst[256]; + char local[256]; + FILELIST* entry; + + if( sscanf(row, "%[^#\r\n]#%[^#\r\n]#", w1, w2) != 2 ) + return false; + + if( strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL ) + return false; // we only need the maps' GAT and RSW files + + sprintf(src, "data\\%s", w1); + sprintf(dst, "data\\%s", w2); + + entry = filelist_find(dst); + if( entry != NULL ) + {// alias for GRF resource + FILELIST fentry; + memcpy(&fentry, entry, sizeof(FILELIST)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + grfio_localpath_create(local, sizeof(local), dst); + if( exists(local) ) + {// alias for local resource + FILELIST fentry; + memset(&fentry, 0, sizeof(fentry)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + return false; } /// Grfio Resource file check. static void grfio_resourcecheck(void) { - char restable[256]; - char *ptr, *buf; - int size; - FILE *fp; - int i = 0; - - // read resnametable from data directory and return if successful - grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); - - fp = fopen(restable, "rb"); - if (fp != NULL) { - char line[256]; - while (fgets(line, sizeof(line), fp)) { - if (grfio_parse_restable_row(line)) - ++i; - } - - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); - return; // we're done here! - } - - // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory - buf = (char *)grfio_reads("data\\resnametable.txt", &size); - if (buf != NULL) { - buf[size] = '\0'; - - ptr = buf; - while (ptr - buf < size) { - if (grfio_parse_restable_row(ptr)) - ++i; - - ptr = strchr(ptr, '\n'); - if (ptr == NULL) break; - ptr++; - } - - aFree(buf); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); - return; - } + char restable[256]; + char *ptr, *buf; + int size; + FILE* fp; + int i = 0; + + // read resnametable from data directory and return if successful + grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); + + fp = fopen(restable, "rb"); + if( fp != NULL ) + { + char line[256]; + while( fgets(line, sizeof(line), fp) ) + { + if( grfio_parse_restable_row(line) ) + ++i; + } + + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); + return; // we're done here! + } + + // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory + buf = (char *)grfio_reads("data\\resnametable.txt", &size); + if( buf != NULL ) + { + buf[size] = '\0'; + + ptr = buf; + while( ptr - buf < size ) + { + if( grfio_parse_restable_row(ptr) ) + ++i; + + ptr = strchr(ptr, '\n'); + if( ptr == NULL ) break; + ptr++; + } + + aFree(buf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); + return; + } } /// Reads a grf file and adds it to the list. -static int grfio_add(const char *fname) +static int grfio_add(const char* fname) { - if (gentry_entrys >= gentry_maxentry) { -#define GENTRY_ADDS 4 // The number increment of gentry_table entries - gentry_maxentry += GENTRY_ADDS; - gentry_table = (char **)aRealloc(gentry_table, gentry_maxentry * sizeof(char *)); - memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char *) * GENTRY_ADDS); - } + if( gentry_entrys >= gentry_maxentry ) + { + #define GENTRY_ADDS 4 // The number increment of gentry_table entries + gentry_maxentry += GENTRY_ADDS; + gentry_table = (char**)aRealloc(gentry_table, gentry_maxentry * sizeof(char*)); + memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS); + } - gentry_table[gentry_entrys++] = aStrdup(fname); + gentry_table[gentry_entrys++] = aStrdup(fname); - return grfio_entryread(fname, gentry_entrys - 1); + return grfio_entryread(fname, gentry_entrys - 1); } /// Finalizes grfio. void grfio_final(void) { - if (filelist != NULL) { - int i; - for (i = 0; i < filelist_entrys; i++) - if (filelist[i].fnd != NULL) - aFree(filelist[i].fnd); - - aFree(filelist); - filelist = NULL; - } - filelist_entrys = filelist_maxentry = 0; - - if (gentry_table != NULL) { - int i; - for (i = 0; i < gentry_entrys; i++) - if (gentry_table[i] != NULL) - aFree(gentry_table[i]); - - aFree(gentry_table); - gentry_table = NULL; - } - gentry_entrys = gentry_maxentry = 0; + if (filelist != NULL) { + int i; + for (i = 0; i < filelist_entrys; i++) + if (filelist[i].fnd != NULL) + aFree(filelist[i].fnd); + + aFree(filelist); + filelist = NULL; + } + filelist_entrys = filelist_maxentry = 0; + + if (gentry_table != NULL) { + int i; + for (i = 0; i < gentry_entrys; i++) + if (gentry_table[i] != NULL) + aFree(gentry_table[i]); + + aFree(gentry_table); + gentry_table = NULL; + } + gentry_entrys = gentry_maxentry = 0; } /// Initializes grfio. -void grfio_init(const char *fname) +void grfio_init(const char* fname) { - FILE *data_conf; - int grf_num = 0; - - hashinit(); // hash table initialization - - data_conf = fopen(fname, "r"); - if (data_conf != NULL) { - char line[1024]; - while (fgets(line, sizeof(line), data_conf)) { - char w1[1024], w2[1024]; - - if (line[0] == '/' && line[1] == '/') - continue; // skip comments - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; // skip unrecognized lines - - // Entry table reading - if (strcmp(w1, "grf") == 0) { // GRF file - if (grfio_add(w2) == 0) - ++grf_num; - } else if (strcmp(w1,"data_dir") == 0) { // Data directory - safestrncpy(data_dir, w2, sizeof(data_dir)); - } - } - - fclose(data_conf); - ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); - } - - if (grf_num == 0) - ShowInfo("No GRF loaded, using default data directory\n"); - - // Unneccessary area release of filelist - filelist_compact(); - - // Resource check - grfio_resourcecheck(); + FILE* data_conf; + int grf_num = 0; + + hashinit(); // hash table initialization + + data_conf = fopen(fname, "r"); + if( data_conf != NULL ) + { + char line[1024]; + while( fgets(line, sizeof(line), data_conf) ) + { + char w1[1024], w2[1024]; + + if( line[0] == '/' && line[1] == '/' ) + continue; // skip comments + + if( sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2 ) + continue; // skip unrecognized lines + + // Entry table reading + if( strcmp(w1, "grf") == 0 ) // GRF file + { + if( grfio_add(w2) == 0 ) + ++grf_num; + } + else if( strcmp(w1,"data_dir") == 0 ) // Data directory + { + safestrncpy(data_dir, w2, sizeof(data_dir)); + } + } + + fclose(data_conf); + ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); + } + + if( grf_num == 0 ) + ShowInfo("No GRF loaded, using default data directory\n"); + + // Unneccessary area release of filelist + filelist_compact(); + + // Resource check + grfio_resourcecheck(); } diff --git a/src/common/grfio.h b/src/common/grfio.h index ae2fbd67c..c5a56a14e 100644 --- a/src/common/grfio.h +++ b/src/common/grfio.h @@ -1,17 +1,17 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _GRFIO_H_ -#define _GRFIO_H_ +#ifndef _GRFIO_H_ +#define _GRFIO_H_ -void grfio_init(const char *fname); +void grfio_init(const char* fname); void grfio_final(void); -void *grfio_reads(const char *fname, int *size); -char *grfio_find_file(const char *fname); +void* grfio_reads(const char* fname, int* size); +char* grfio_find_file(const char* fname); #define grfio_read(fn) grfio_reads(fn, NULL) unsigned long grfio_crc32(const unsigned char *buf, unsigned int len); -int decode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); -int encode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); +int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); +int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); #endif /* _GRFIO_H_ */ diff --git a/src/common/malloc.c b/src/common/malloc.c index 396ec33cb..9976a28d5 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -14,109 +14,109 @@ #if defined(MEMWATCH) -# include -# include "memwatch.h" -# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line)) -# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line)) -# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line)) -# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line)) -# define FREE(p,file,line,func) mwFree((p),(file),(line)) -# define MEMORY_USAGE() 0 -# define MEMORY_VERIFY(ptr) mwIsSafeAddr(ptr, 1) -# define MEMORY_CHECK() CHECK() +# include +# include "memwatch.h" +# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line)) +# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line)) +# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line)) +# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line)) +# define FREE(p,file,line,func) mwFree((p),(file),(line)) +# define MEMORY_USAGE() 0 +# define MEMORY_VERIFY(ptr) mwIsSafeAddr(ptr, 1) +# define MEMORY_CHECK() CHECK() #elif defined(DMALLOC) -# include -# include -# include "dmalloc.h" -# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0) -# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0) -# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0) -# define STRDUP(p,file,line,func) strdup(p) -# define FREE(p,file,line,func) free(p) -# define MEMORY_USAGE() dmalloc_memory_allocated() -# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR) -# define MEMORY_CHECK() dmalloc_log_stats(); dmalloc_log_unfreed() +# include +# include +# include "dmalloc.h" +# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0) +# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0) +# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0) +# define STRDUP(p,file,line,func) strdup(p) +# define FREE(p,file,line,func) free(p) +# define MEMORY_USAGE() dmalloc_memory_allocated() +# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR) +# define MEMORY_CHECK() dmalloc_log_stats(); dmalloc_log_unfreed() #elif defined(GCOLLECT) -# include "gc.h" -# ifdef GC_ADD_CALLER -# define RETURN_ADDR 0, -# else -# define RETURN_ADDR -# endif -# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line)) -# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line)) -# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line)) -# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line)) -# define FREE(p,file,line,func) GC_debug_free(p) -# define MEMORY_USAGE() GC_get_heap_size() -# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL) -# define MEMORY_CHECK() GC_gcollect() +# include "gc.h" +# ifdef GC_ADD_CALLER +# define RETURN_ADDR 0, +# else +# define RETURN_ADDR +# endif +# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line)) +# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line)) +# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line)) +# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line)) +# define FREE(p,file,line,func) GC_debug_free(p) +# define MEMORY_USAGE() GC_get_heap_size() +# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL) +# define MEMORY_CHECK() GC_gcollect() #else -# define MALLOC(n,file,line,func) malloc(n) -# define CALLOC(m,n,file,line,func) calloc((m),(n)) -# define REALLOC(p,n,file,line,func) realloc((p),(n)) -# define STRDUP(p,file,line,func) strdup(p) -# define FREE(p,file,line,func) free(p) -# define MEMORY_USAGE() 0 -# define MEMORY_VERIFY(ptr) true -# define MEMORY_CHECK() +# define MALLOC(n,file,line,func) malloc(n) +# define CALLOC(m,n,file,line,func) calloc((m),(n)) +# define REALLOC(p,n,file,line,func) realloc((p),(n)) +# define STRDUP(p,file,line,func) strdup(p) +# define FREE(p,file,line,func) free(p) +# define MEMORY_USAGE() 0 +# define MEMORY_VERIFY(ptr) true +# define MEMORY_CHECK() #endif -void *aMalloc_(size_t size, const char *file, int line, const char *func) +void* aMalloc_(size_t size, const char *file, int line, const char *func) { - void *ret = MALLOC(size, file, line, func); - // ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size); - if (ret == NULL) { - ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func); - exit(EXIT_FAILURE); - } - - return ret; + void *ret = MALLOC(size, file, line, func); + // ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size); + if (ret == NULL){ + ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func); + exit(EXIT_FAILURE); + } + + return ret; } -void *aCalloc_(size_t num, size_t size, const char *file, int line, const char *func) +void* aCalloc_(size_t num, size_t size, const char *file, int line, const char *func) { - void *ret = CALLOC(num, size, file, line, func); - // ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size); - if (ret == NULL) { - ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func); - exit(EXIT_FAILURE); - } - return ret; + void *ret = CALLOC(num, size, file, line, func); + // ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size); + if (ret == NULL){ + ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func); + exit(EXIT_FAILURE); + } + return ret; } -void *aRealloc_(void *p, size_t size, const char *file, int line, const char *func) +void* aRealloc_(void *p, size_t size, const char *file, int line, const char *func) { - void *ret = REALLOC(p, size, file, line, func); - // ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size); - if (ret == NULL) { - ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func); - exit(EXIT_FAILURE); - } - return ret; + void *ret = REALLOC(p, size, file, line, func); + // ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size); + if (ret == NULL){ + ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func); + exit(EXIT_FAILURE); + } + return ret; } -char *aStrdup_(const char *p, const char *file, int line, const char *func) +char* aStrdup_(const char *p, const char *file, int line, const char *func) { - char *ret = STRDUP(p, file, line, func); - // ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p); - if (ret == NULL) { - ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func); - exit(EXIT_FAILURE); - } - return ret; + char *ret = STRDUP(p, file, line, func); + // ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p); + if (ret == NULL){ + ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func); + exit(EXIT_FAILURE); + } + return ret; } void aFree_(void *p, const char *file, int line, const char *func) { - // ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p); - if (p) - FREE(p, file, line, func); + // ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p); + if (p) + FREE(p, file, line, func); - p = NULL; + p = NULL; } @@ -146,397 +146,405 @@ void aFree_(void *p, const char *file, int line, const char *func) */ /* ブロックのアライメント */ -#define BLOCK_ALIGNMENT1 16 -#define BLOCK_ALIGNMENT2 64 +#define BLOCK_ALIGNMENT1 16 +#define BLOCK_ALIGNMENT2 64 /* ブロックに入るデータ量 */ -#define BLOCK_DATA_COUNT1 128 -#define BLOCK_DATA_COUNT2 608 +#define BLOCK_DATA_COUNT1 128 +#define BLOCK_DATA_COUNT2 608 /* ブロックの大きさ: 16*128 + 64*576 = 40KB */ -#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) -#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) -#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) +#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) +#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) +#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) /* 一度に確保するブロックの数。 */ -#define BLOCK_ALLOC 104 +#define BLOCK_ALLOC 104 /* ブロック */ struct block { - struct block *block_next; /* 次に確保した領域 */ - struct block *unfill_prev; /* 次の埋まっていない領域 */ - struct block *unfill_next; /* 次の埋まっていない領域 */ - unsigned short unit_size; /* ユニットの大きさ */ - unsigned short unit_hash; /* ユニットのハッシュ */ - unsigned short unit_count; /* ユニットの個数 */ - unsigned short unit_used; /* 使用ユニット数 */ - unsigned short unit_unfill; /* 未使用ユニットの場所 */ - unsigned short unit_maxused; /* 使用ユニットの最大値 */ - char data[ BLOCK_DATA_SIZE ]; + struct block* block_next; /* 次に確保した領域 */ + struct block* unfill_prev; /* 次の埋まっていない領域 */ + struct block* unfill_next; /* 次の埋まっていない領域 */ + unsigned short unit_size; /* ユニットの大きさ */ + unsigned short unit_hash; /* ユニットのハッシュ */ + unsigned short unit_count; /* ユニットの個数 */ + unsigned short unit_used; /* 使用ユニット数 */ + unsigned short unit_unfill; /* 未使用ユニットの場所 */ + unsigned short unit_maxused; /* 使用ユニットの最大値 */ + char data[ BLOCK_DATA_SIZE ]; }; struct unit_head { - struct block *block; - const char *file; - unsigned short line; - unsigned short size; - long checksum; + struct block *block; + const char* file; + unsigned short line; + unsigned short size; + long checksum; }; -static struct block *hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; -static struct block *block_first, *block_last, block_head; +static struct block* hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; +static struct block* block_first, *block_last, block_head; /* メモリを使い回せない領域用のデータ */ struct unit_head_large { - size_t size; - struct unit_head_large *prev; - struct unit_head_large *next; - struct unit_head unit_head; + size_t size; + struct unit_head_large* prev; + struct unit_head_large* next; + struct unit_head unit_head; }; static struct unit_head_large *unit_head_large_first = NULL; -static struct block *block_malloc(unsigned short hash); -static void block_free(struct block *p); +static struct block* block_malloc(unsigned short hash); +static void block_free(struct block* p); static size_t memmgr_usage_bytes; #define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ])) #define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0) -static unsigned short size2hash(size_t size) +static unsigned short size2hash( size_t size ) { - if (size <= BLOCK_DATA_SIZE1) { - return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; - } else if (size <= BLOCK_DATA_SIZE) { - return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 - + BLOCK_DATA_COUNT1; - } else { - return 0xffff; // ブロック長を超える場合は hash にしない - } + if( size <= BLOCK_DATA_SIZE1 ) { + return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; + } else if( size <= BLOCK_DATA_SIZE ){ + return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 + + BLOCK_DATA_COUNT1; + } else { + return 0xffff; // ブロック長を超える場合は hash にしない + } } -static size_t hash2size(unsigned short hash) +static size_t hash2size( unsigned short hash ) { - if (hash <= BLOCK_DATA_COUNT1) { - return hash * BLOCK_ALIGNMENT1; - } else { - return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1; - } + if( hash <= BLOCK_DATA_COUNT1) { + return hash * BLOCK_ALIGNMENT1; + } else { + return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1; + } } -void *_mmalloc(size_t size, const char *file, int line, const char *func) +void* _mmalloc(size_t size, const char *file, int line, const char *func ) { - struct block *block; - short size_hash = size2hash(size); - struct unit_head *head; - - if (((long) size) < 0) { - ShowError("_mmalloc: %d\n", size); - return NULL; - } - - if (size == 0) { - return NULL; - } - memmgr_usage_bytes += size; - - /* ブロック長を超える領域の確保には、malloc() を用いる */ - /* その際、unit_head.block に NULL を代入して区別する */ - if (hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { - struct unit_head_large *p = (struct unit_head_large *)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); - if (p != NULL) { - p->size = size; - p->unit_head.block = NULL; - p->unit_head.size = 0; - p->unit_head.file = file; - p->unit_head.line = line; - p->prev = NULL; - if (unit_head_large_first == NULL) - p->next = NULL; - else { - unit_head_large_first->prev = p; - p->next = unit_head_large_first; - } - unit_head_large_first = p; - *(long *)((char *)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf; - return (char *)p + sizeof(struct unit_head_large) - sizeof(long); - } else { - ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line); - exit(EXIT_FAILURE); - } - } - - /* 同一サイズのブロックが確保されていない時、新たに確保する */ - if (hash_unfill[size_hash]) { - block = hash_unfill[size_hash]; - } else { - block = block_malloc(size_hash); - } - - if (block->unit_unfill == 0xFFFF) { - // free済み領域が残っていない - memmgr_assert(block->unit_used < block->unit_count); - memmgr_assert(block->unit_used == block->unit_maxused); - head = block2unit(block, block->unit_maxused); - block->unit_used++; - block->unit_maxused++; - } else { - head = block2unit(block, block->unit_unfill); - block->unit_unfill = head->size; - block->unit_used++; - } - - if (block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { - // ユニットを使い果たしたので、unfillリストから削除 - if (block->unfill_prev == &block_head) { - hash_unfill[ size_hash ] = block->unfill_next; - } else { - block->unfill_prev->unfill_next = block->unfill_next; - } - if (block->unfill_next) { - block->unfill_next->unfill_prev = block->unfill_prev; - } - block->unfill_prev = NULL; - } + struct block *block; + short size_hash = size2hash( size ); + struct unit_head *head; + + if (((long) size) < 0) { + ShowError("_mmalloc: %d\n", size); + return NULL; + } + + if(size == 0) { + return NULL; + } + memmgr_usage_bytes += size; + + /* ブロック長を超える領域の確保には、malloc() を用いる */ + /* その際、unit_head.block に NULL を代入して区別する */ + if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { + struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); + if(p != NULL) { + p->size = size; + p->unit_head.block = NULL; + p->unit_head.size = 0; + p->unit_head.file = file; + p->unit_head.line = line; + p->prev = NULL; + if (unit_head_large_first == NULL) + p->next = NULL; + else { + unit_head_large_first->prev = p; + p->next = unit_head_large_first; + } + unit_head_large_first = p; + *(long*)((char*)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)p + sizeof(struct unit_head_large) - sizeof(long); + } else { + ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line); + exit(EXIT_FAILURE); + } + } + + /* 同一サイズのブロックが確保されていない時、新たに確保する */ + if(hash_unfill[size_hash]) { + block = hash_unfill[size_hash]; + } else { + block = block_malloc(size_hash); + } + + if( block->unit_unfill == 0xFFFF ) { + // free済み領域が残っていない + memmgr_assert(block->unit_used < block->unit_count); + memmgr_assert(block->unit_used == block->unit_maxused); + head = block2unit(block, block->unit_maxused); + block->unit_used++; + block->unit_maxused++; + } else { + head = block2unit(block, block->unit_unfill); + block->unit_unfill = head->size; + block->unit_used++; + } + + if( block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { + // ユニットを使い果たしたので、unfillリストから削除 + if( block->unfill_prev == &block_head) { + hash_unfill[ size_hash ] = block->unfill_next; + } else { + block->unfill_prev->unfill_next = block->unfill_next; + } + if( block->unfill_next ) { + block->unfill_next->unfill_prev = block->unfill_prev; + } + block->unfill_prev = NULL; + } #ifdef DEBUG_MEMMGR - { - size_t i, sz = hash2size(size_hash); - for (i=0; iline != 0xfdfd) { - ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line); - } else { - ShowError("Memory manager: not-allocated-data is changed.\n"); - } - break; - } - } - memset((char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz); - } + { + size_t i, sz = hash2size( size_hash ); + for( i=0; iline != 0xfdfd ) + { + ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line); + } + else + { + ShowError("Memory manager: not-allocated-data is changed.\n"); + } + break; + } + } + memset( (char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz ); + } #endif - head->block = block; - head->file = file; - head->line = line; - head->size = (unsigned short)size; - *(long *)((char *)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf; - return (char *)head + sizeof(struct unit_head) - sizeof(long); + head->block = block; + head->file = file; + head->line = line; + head->size = (unsigned short)size; + *(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)head + sizeof(struct unit_head) - sizeof(long); } -void *_mcalloc(size_t num, size_t size, const char *file, int line, const char *func) +void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func ) { - void *p = _mmalloc(num * size,file,line,func); - memset(p,0,num * size); - return p; + void *p = _mmalloc(num * size,file,line,func); + memset(p,0,num * size); + return p; } -void *_mrealloc(void *memblock, size_t size, const char *file, int line, const char *func) +void* _mrealloc(void *memblock, size_t size, const char *file, int line, const char *func ) { - size_t old_size; - if (memblock == NULL) { - return _mmalloc(size,file,line,func); - } - - old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; - if (old_size == 0) { - old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; - } - if (old_size > size) { - // サイズ縮小 -> そのまま返す(手抜き) - return memblock; - } else { - // サイズ拡大 - void *p = _mmalloc(size,file,line,func); - if (p != NULL) { - memcpy(p,memblock,old_size); - } - _mfree(memblock,file,line,func); - return p; - } + size_t old_size; + if(memblock == NULL) { + return _mmalloc(size,file,line,func); + } + + old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; + if( old_size == 0 ) { + old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; + } + if(old_size > size) { + // サイズ縮小 -> そのまま返す(手抜き) + return memblock; + } else { + // サイズ拡大 + void *p = _mmalloc(size,file,line,func); + if(p != NULL) { + memcpy(p,memblock,old_size); + } + _mfree(memblock,file,line,func); + return p; + } } -char *_mstrdup(const char *p, const char *file, int line, const char *func) +char* _mstrdup(const char *p, const char *file, int line, const char *func ) { - if (p == NULL) { - return NULL; - } else { - size_t len = strlen(p); - char *string = (char *)_mmalloc(len + 1,file,line,func); - memcpy(string,p,len+1); - return string; - } + if(p == NULL) { + return NULL; + } else { + size_t len = strlen(p); + char *string = (char *)_mmalloc(len + 1,file,line,func); + memcpy(string,p,len+1); + return string; + } } -void _mfree(void *ptr, const char *file, int line, const char *func) +void _mfree(void *ptr, const char *file, int line, const char *func ) { - struct unit_head *head; - - if (ptr == NULL) - return; - - head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); - if (head->size == 0) { - /* malloc() で直に確保された領域 */ - struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); - if ( - *(long *)((char *)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) - != 0xdeadbeaf) { - ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); - } else { - head->size = 0xFFFF; - if (head_large->prev) { - head_large->prev->next = head_large->next; - } else { - unit_head_large_first = head_large->next; - } - if (head_large->next) { - head_large->next->prev = head_large->prev; - } - memmgr_usage_bytes -= head_large->size; + struct unit_head *head; + + if (ptr == NULL) + return; + + head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); + if(head->size == 0) { + /* malloc() で直に確保された領域 */ + struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); + if( + *(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) + != 0xdeadbeaf) + { + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); + } else { + head->size = 0xFFFF; + if(head_large->prev) { + head_large->prev->next = head_large->next; + } else { + unit_head_large_first = head_large->next; + } + if(head_large->next) { + head_large->next->prev = head_large->prev; + } + memmgr_usage_bytes -= head_large->size; #ifdef DEBUG_MEMMGR - // set freed memory to 0xfd - memset(ptr, 0xfd, head_large->size); + // set freed memory to 0xfd + memset(ptr, 0xfd, head_large->size); #endif - FREE(head_large,file,line,func); - } - } else { - /* ユニット解放 */ - struct block *block = head->block; - if ((char *)head - (char *)block > sizeof(struct block)) { - ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); - } else if (head->block == NULL) { - ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func); - } else if (*(long *)((char *)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { - ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); - } else { - memmgr_usage_bytes -= head->size; - head->block = NULL; + FREE(head_large,file,line,func); + } + } else { + /* ユニット解放 */ + struct block *block = head->block; + if( (char*)head - (char*)block > sizeof(struct block) ) { + ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); + } else if(head->block == NULL) { + ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func); + } else if(*(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); + } else { + memmgr_usage_bytes -= head->size; + head->block = NULL; #ifdef DEBUG_MEMMGR - memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long)); - head->file = file; - head->line = line; + memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long) ); + head->file = file; + head->line = line; #endif - memmgr_assert(block->unit_used > 0); - if (--block->unit_used == 0) { - /* ブロックの解放 */ - block_free(block); - } else { - if (block->unfill_prev == NULL) { - // unfill リストに追加 - if (hash_unfill[ block->unit_hash ]) { - hash_unfill[ block->unit_hash ]->unfill_prev = block; - } - block->unfill_prev = &block_head; - block->unfill_next = hash_unfill[ block->unit_hash ]; - hash_unfill[ block->unit_hash ] = block; - } - head->size = block->unit_unfill; - block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size); - } - } - } + memmgr_assert( block->unit_used > 0 ); + if(--block->unit_used == 0) { + /* ブロックの解放 */ + block_free(block); + } else { + if( block->unfill_prev == NULL) { + // unfill リストに追加 + if( hash_unfill[ block->unit_hash ] ) { + hash_unfill[ block->unit_hash ]->unfill_prev = block; + } + block->unfill_prev = &block_head; + block->unfill_next = hash_unfill[ block->unit_hash ]; + hash_unfill[ block->unit_hash ] = block; + } + head->size = block->unit_unfill; + block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size); + } + } + } } /* ブロックを確保する */ -static struct block *block_malloc(unsigned short hash) { - int i; - struct block *p; - if (hash_unfill[0] != NULL) { - /* ブロック用の領域は確保済み */ - p = hash_unfill[0]; - hash_unfill[0] = hash_unfill[0]->unfill_next; - } else { - /* ブロック用の領域を新たに確保する */ - p = (struct block *)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__); - if (p == NULL) { - ShowFatalError("Memory manager::block_alloc failed.\n"); - exit(EXIT_FAILURE); - } - - if (block_first == NULL) { - /* 初回確保 */ - block_first = p; - } else { - block_last->block_next = p; - } - block_last = &p[BLOCK_ALLOC - 1]; - block_last->block_next = NULL; - /* ブロックを連結させる */ - for (i=0; iunfill_prev = &block_head; - p->unfill_next = NULL; - p->unit_size = (unsigned short)(hash2size(hash) + sizeof(struct unit_head)); - p->unit_hash = hash; - p->unit_count = BLOCK_DATA_SIZE / p->unit_size; - p->unit_used = 0; - p->unit_unfill = 0xFFFF; - p->unit_maxused = 0; +static struct block* block_malloc(unsigned short hash) +{ + int i; + struct block *p; + if(hash_unfill[0] != NULL) { + /* ブロック用の領域は確保済み */ + p = hash_unfill[0]; + hash_unfill[0] = hash_unfill[0]->unfill_next; + } else { + /* ブロック用の領域を新たに確保する */ + p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ ); + if(p == NULL) { + ShowFatalError("Memory manager::block_alloc failed.\n"); + exit(EXIT_FAILURE); + } + + if(block_first == NULL) { + /* 初回確保 */ + block_first = p; + } else { + block_last->block_next = p; + } + block_last = &p[BLOCK_ALLOC - 1]; + block_last->block_next = NULL; + /* ブロックを連結させる */ + for(i=0;iunfill_prev = &block_head; + p->unfill_next = NULL; + p->unit_size = (unsigned short)(hash2size( hash ) + sizeof(struct unit_head)); + p->unit_hash = hash; + p->unit_count = BLOCK_DATA_SIZE / p->unit_size; + p->unit_used = 0; + p->unit_unfill = 0xFFFF; + p->unit_maxused = 0; #ifdef DEBUG_MEMMGR - memset(p->data, 0xfd, sizeof(p->data)); + memset( p->data, 0xfd, sizeof(p->data) ); #endif - return p; + return p; } -static void block_free(struct block *p) +static void block_free(struct block* p) { - if (p->unfill_prev) { - if (p->unfill_prev == &block_head) { - hash_unfill[ p->unit_hash ] = p->unfill_next; - } else { - p->unfill_prev->unfill_next = p->unfill_next; - } - if (p->unfill_next) { - p->unfill_next->unfill_prev = p->unfill_prev; - } - p->unfill_prev = NULL; - } - - p->unfill_next = hash_unfill[0]; - hash_unfill[0] = p; + if( p->unfill_prev ) { + if( p->unfill_prev == &block_head) { + hash_unfill[ p->unit_hash ] = p->unfill_next; + } else { + p->unfill_prev->unfill_next = p->unfill_next; + } + if( p->unfill_next ) { + p->unfill_next->unfill_prev = p->unfill_prev; + } + p->unfill_prev = NULL; + } + + p->unfill_next = hash_unfill[0]; + hash_unfill[0] = p; } -size_t memmgr_usage(void) +size_t memmgr_usage (void) { - return memmgr_usage_bytes / 1024; + return memmgr_usage_bytes / 1024; } #ifdef LOG_MEMMGR static char memmer_logfile[128]; static FILE *log_fp; -static void memmgr_log(char *buf) +static void memmgr_log (char *buf) { - if (!log_fp) { - time_t raw; - struct tm *t; - - log_fp = fopen(memmer_logfile,"at"); - if (!log_fp) log_fp = stdout; - - time(&raw); - t = localtime(&raw); - fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", - (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); - } - fprintf(log_fp, "%s", buf); - return; + if( !log_fp ) + { + time_t raw; + struct tm* t; + + log_fp = fopen(memmer_logfile,"at"); + if (!log_fp) log_fp = stdout; + + time(&raw); + t = localtime(&raw); + fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", + (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); + } + fprintf(log_fp, "%s", buf); + return; } #endif /* LOG_MEMMGR */ @@ -545,105 +553,107 @@ static void memmgr_log(char *buf) /// /// @param ptr Pointer to the memory /// @return true if the memory is active -bool memmgr_verify(void *ptr) +bool memmgr_verify(void* ptr) { - struct block *block = block_first; - struct unit_head_large *large = unit_head_large_first; - - if (ptr == NULL) - return false;// never valid - - // search small blocks - while (block) { - if ((char *)ptr >= (char *)block && (char *)ptr < ((char *)block) + sizeof(struct block)) { - // found memory block - if (block->unit_used && (char *)ptr >= block->data) { - // memory block is being used and ptr points to a sub-unit - size_t i = (size_t)((char *)ptr - block->data)/block->unit_size; - struct unit_head *head = block2unit(block, i); - if (i < block->unit_maxused && head->block != NULL) { - // memory unit is allocated, check if ptr points to the usable part - return ((char *)ptr >= ((char *)head) + sizeof(struct unit_head) - sizeof(long) - && (char *)ptr < ((char *)head) + sizeof(struct unit_head) - sizeof(long) + head->size); - } - } - return false; - } - block = block->block_next; - } - - // search large blocks - while (large) { - if ((char *)ptr >= (char *)large && (char *)ptr < ((char *)large) + large->size) { - // found memory block, check if ptr points to the usable part - return ((char *)ptr >= ((char *)large) + sizeof(struct unit_head_large) - sizeof(long) - && (char *)ptr < ((char *)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size); - } - large = large->next; - } - return false; + struct block* block = block_first; + struct unit_head_large* large = unit_head_large_first; + + if( ptr == NULL ) + return false;// never valid + + // search small blocks + while( block ) + { + if( (char*)ptr >= (char*)block && (char*)ptr < ((char*)block) + sizeof(struct block) ) + {// found memory block + if( block->unit_used && (char*)ptr >= block->data ) + {// memory block is being used and ptr points to a sub-unit + size_t i = (size_t)((char*)ptr - block->data)/block->unit_size; + struct unit_head* head = block2unit(block, i); + if( i < block->unit_maxused && head->block != NULL ) + {// memory unit is allocated, check if ptr points to the usable part + return ( (char*)ptr >= ((char*)head) + sizeof(struct unit_head) - sizeof(long) + && (char*)ptr < ((char*)head) + sizeof(struct unit_head) - sizeof(long) + head->size ); + } + } + return false; + } + block = block->block_next; + } + + // search large blocks + while( large ) + { + if( (char*)ptr >= (char*)large && (char*)ptr < ((char*)large) + large->size ) + {// found memory block, check if ptr points to the usable part + return ( (char*)ptr >= ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) + && (char*)ptr < ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size ); + } + large = large->next; + } + return false; } -static void memmgr_final(void) +static void memmgr_final (void) { - struct block *block = block_first; - struct unit_head_large *large = unit_head_large_first; + struct block *block = block_first; + struct unit_head_large *large = unit_head_large_first; #ifdef LOG_MEMMGR - int count = 0; + int count = 0; #endif /* LOG_MEMMGR */ - while (block) { - if (block->unit_used) { - int i; - for (i = 0; i < block->unit_maxused; i++) { - struct unit_head *head = block2unit(block, i); - if (head->block != NULL) { - char *ptr = (char *)head + sizeof(struct unit_head) - sizeof(long); + while (block) { + if (block->unit_used) { + int i; + for (i = 0; i < block->unit_maxused; i++) { + struct unit_head *head = block2unit(block, i); + if(head->block != NULL) { + char* ptr = (char *)head + sizeof(struct unit_head) - sizeof(long); #ifdef LOG_MEMMGR - char buf[1024]; - sprintf(buf, - "%04d : %s line %d size %lu address 0x%p\n", ++count, - head->file, head->line, (unsigned long)head->size, ptr); - memmgr_log(buf); + char buf[1024]; + sprintf (buf, + "%04d : %s line %d size %lu address 0x%p\n", ++count, + head->file, head->line, (unsigned long)head->size, ptr); + memmgr_log (buf); #endif /* LOG_MEMMGR */ - // get block pointer and free it [celest] - _mfree(ptr, ALC_MARK); - } - } - } - block = block->block_next; - } - - while (large) { - struct unit_head_large *large2; + // get block pointer and free it [celest] + _mfree(ptr, ALC_MARK); + } + } + } + block = block->block_next; + } + + while(large) { + struct unit_head_large *large2; #ifdef LOG_MEMMGR - char buf[1024]; - sprintf(buf, - "%04d : %s line %d size %lu address 0x%p\n", ++count, - large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum); - memmgr_log(buf); + char buf[1024]; + sprintf (buf, + "%04d : %s line %d size %lu address 0x%p\n", ++count, + large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum); + memmgr_log (buf); #endif /* LOG_MEMMGR */ - large2 = large->next; - FREE(large,file,line,func); - large = large2; - } + large2 = large->next; + FREE(large,file,line,func); + large = large2; + } #ifdef LOG_MEMMGR - if (count == 0) { - ShowInfo("Memory manager: No memory leaks found.\n"); - } else { - ShowWarning("Memory manager: Memory leaks found and fixed.\n"); - fclose(log_fp); - } + if(count == 0) { + ShowInfo("Memory manager: No memory leaks found.\n"); + } else { + ShowWarning("Memory manager: Memory leaks found and fixed.\n"); + fclose(log_fp); + } #endif /* LOG_MEMMGR */ } -static void memmgr_init(void) +static void memmgr_init (void) { #ifdef LOG_MEMMGR - sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); - ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); - memset(hash_unfill, 0, sizeof(hash_unfill)); + sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); + ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); + memset(hash_unfill, 0, sizeof(hash_unfill)); #endif /* LOG_MEMMGR */ } #endif /* USE_MEMMGR */ @@ -658,51 +668,51 @@ static void memmgr_init(void) /// Tests the memory for errors and memory leaks. void malloc_memory_check(void) { - MEMORY_CHECK(); + MEMORY_CHECK(); } /// Returns true if a pointer is valid. /// The check is best-effort, false positives are possible. -bool malloc_verify_ptr(void *ptr) +bool malloc_verify_ptr(void* ptr) { #ifdef USE_MEMMGR - return memmgr_verify(ptr) && MEMORY_VERIFY(ptr); + return memmgr_verify(ptr) && MEMORY_VERIFY(ptr); #else - return MEMORY_VERIFY(ptr); + return MEMORY_VERIFY(ptr); #endif } -size_t malloc_usage(void) +size_t malloc_usage (void) { #ifdef USE_MEMMGR - return memmgr_usage(); + return memmgr_usage (); #else - return MEMORY_USAGE(); + return MEMORY_USAGE(); #endif } -void malloc_final(void) +void malloc_final (void) { #ifdef USE_MEMMGR - memmgr_final(); + memmgr_final (); #endif - MEMORY_CHECK(); + MEMORY_CHECK(); } -void malloc_init(void) +void malloc_init (void) { #if defined(DMALLOC) && defined(CYGWIN) - // http://dmalloc.com/docs/latest/online/dmalloc_19.html - dmalloc_debug_setup(getenv("DMALLOC_OPTIONS")); + // http://dmalloc.com/docs/latest/online/dmalloc_19.html + dmalloc_debug_setup(getenv("DMALLOC_OPTIONS")); #endif #ifdef GCOLLECT - // don't garbage collect, only report inaccessible memory that was not deallocated - GC_find_leak = 1; - GC_INIT(); + // don't garbage collect, only report inaccessible memory that was not deallocated + GC_find_leak = 1; + GC_INIT(); #endif #ifdef USE_MEMMGR - memmgr_init(); + memmgr_init (); #endif } diff --git a/src/common/malloc.h b/src/common/malloc.h index 58dcee6d7..6b4e8e5c4 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -33,31 +33,31 @@ #undef LOG_MEMMGR #endif -# define aMalloc(n) _mmalloc(n,ALC_MARK) -# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK) -# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK) -# define aStrdup(p) _mstrdup(p,ALC_MARK) -# define aFree(p) _mfree(p,ALC_MARK) - -void *_mmalloc(size_t size, const char *file, int line, const char *func); -void *_mcalloc(size_t num, size_t size, const char *file, int line, const char *func); -void *_mrealloc(void *p, size_t size, const char *file, int line, const char *func); -char *_mstrdup(const char *p, const char *file, int line, const char *func); -void _mfree(void *p, const char *file, int line, const char *func); +# define aMalloc(n) _mmalloc(n,ALC_MARK) +# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK) +# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK) +# define aStrdup(p) _mstrdup(p,ALC_MARK) +# define aFree(p) _mfree(p,ALC_MARK) + + void* _mmalloc (size_t size, const char *file, int line, const char *func); + void* _mcalloc (size_t num, size_t size, const char *file, int line, const char *func); + void* _mrealloc (void *p, size_t size, const char *file, int line, const char *func); + char* _mstrdup (const char *p, const char *file, int line, const char *func); + void _mfree (void *p, const char *file, int line, const char *func); #else -# define aMalloc(n) aMalloc_((n),ALC_MARK) -# define aCalloc(m,n) aCalloc_((m),(n),ALC_MARK) -# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) -# define aStrdup(p) aStrdup_(p,ALC_MARK) -# define aFree(p) aFree_(p,ALC_MARK) +# define aMalloc(n) aMalloc_((n),ALC_MARK) +# define aCalloc(m,n) aCalloc_((m),(n),ALC_MARK) +# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) +# define aStrdup(p) aStrdup_(p,ALC_MARK) +# define aFree(p) aFree_(p,ALC_MARK) -void *aMalloc_(size_t size, const char *file, int line, const char *func); -void *aCalloc_(size_t num, size_t size, const char *file, int line, const char *func); -void *aRealloc_(void *p, size_t size, const char *file, int line, const char *func); -char *aStrdup_(const char *p, const char *file, int line, const char *func); -void aFree_(void *p, const char *file, int line, const char *func); + void* aMalloc_ (size_t size, const char *file, int line, const char *func); + void* aCalloc_ (size_t num, size_t size, const char *file, int line, const char *func); + void* aRealloc_ (void *p, size_t size, const char *file, int line, const char *func); + char* aStrdup_ (const char *p, const char *file, int line, const char *func); + void aFree_ (void *p, const char *file, int line, const char *func); #endif @@ -66,13 +66,13 @@ void aFree_(void *p, const char *file, int line, const char *func); #ifdef __GNUC__ // GCC has variable length arrays -#define CREATE_BUFFER(name, type, size) type name[size] -#define DELETE_BUFFER(name) + #define CREATE_BUFFER(name, type, size) type name[size] + #define DELETE_BUFFER(name) #else // others don't, so we emulate them -#define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) -#define DELETE_BUFFER(name) aFree(name) + #define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) + #define DELETE_BUFFER(name) aFree(name) #endif @@ -84,9 +84,9 @@ void aFree_(void *p, const char *file, int line, const char *func); //////////////////////////////////////////////// void malloc_memory_check(void); -bool malloc_verify_ptr(void *ptr); -size_t malloc_usage(void); -void malloc_init(void); -void malloc_final(void); +bool malloc_verify_ptr(void* ptr); +size_t malloc_usage (void); +void malloc_init (void); +void malloc_final (void); #endif /* _MALLOC_H_ */ diff --git a/src/common/mapindex.c b/src/common/mapindex.c index 62d14590e..d46047833 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -12,7 +12,7 @@ #include struct _indexes { - char name[MAP_NAME_LENGTH]; //Stores map name + char name[MAP_NAME_LENGTH]; //Stores map name } indexes[MAX_MAPINDEX]; int max_index = 0; @@ -23,158 +23,161 @@ char mapindex_cfgfile[80] = "db/map_index.txt"; /// Retrieves the map name from 'string' (removing .gat extension if present). /// Result gets placed either into 'buf' or in a static local buffer. -const char *mapindex_getmapname(const char *string, char *output) +const char* mapindex_getmapname(const char* string, char* output) { - static char buf[MAP_NAME_LENGTH]; - char *dest = (output != NULL) ? output : buf; - - size_t len = strnlen(string, MAP_NAME_LENGTH_EXT); - if (len == MAP_NAME_LENGTH_EXT) { - ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH_EXT, string); - len--; - } - if (len >= 4 && stricmp(&string[len-4], ".gat") == 0) - len -= 4; // strip .gat extension - - len = min(len, MAP_NAME_LENGTH-1); - strncpy(dest, string, len+1); - memset(&dest[len], '\0', MAP_NAME_LENGTH-len); - - return dest; + static char buf[MAP_NAME_LENGTH]; + char* dest = (output != NULL) ? output : buf; + + size_t len = strnlen(string, MAP_NAME_LENGTH_EXT); + if (len == MAP_NAME_LENGTH_EXT) { + ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH_EXT, string); + len--; + } + if (len >= 4 && stricmp(&string[len-4], ".gat") == 0) + len -= 4; // strip .gat extension + + len = min(len, MAP_NAME_LENGTH-1); + strncpy(dest, string, len+1); + memset(&dest[len], '\0', MAP_NAME_LENGTH-len); + + return dest; } /// Retrieves the map name from 'string' (adding .gat extension if not already present). /// Result gets placed either into 'buf' or in a static local buffer. -const char *mapindex_getmapname_ext(const char *string, char *output) +const char* mapindex_getmapname_ext(const char* string, char* output) { - static char buf[MAP_NAME_LENGTH_EXT]; - char *dest = (output != NULL) ? output : buf; + static char buf[MAP_NAME_LENGTH_EXT]; + char* dest = (output != NULL) ? output : buf; - size_t len; + size_t len; - strcpy(buf,string); - sscanf(string,"%*[^#]%*[#]%s",buf); + strcpy(buf,string); + sscanf(string,"%*[^#]%*[#]%s",buf); - len = safestrnlen(buf, MAP_NAME_LENGTH); + len = safestrnlen(buf, MAP_NAME_LENGTH); - if (len == MAP_NAME_LENGTH) { - ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf); - len--; - } - strncpy(dest, buf, len+1); + if (len == MAP_NAME_LENGTH) { + ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf); + len--; + } + strncpy(dest, buf, len+1); - if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) { - strcpy(&dest[len], ".gat"); - len += 4; // add .gat extension - } + if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) { + strcpy(&dest[len], ".gat"); + len += 4; // add .gat extension + } - memset(&dest[len], '\0', MAP_NAME_LENGTH_EXT-len); - - return dest; + memset(&dest[len], '\0', MAP_NAME_LENGTH_EXT-len); + + return dest; } /// Adds a map to the specified index /// Returns 1 if successful, 0 oherwise -int mapindex_addmap(int index, const char *name) +int mapindex_addmap(int index, const char* name) { - char map_name[MAP_NAME_LENGTH]; - - if (index == -1) { - for (index = 1; index < max_index; index++) { - //if (strcmp(indexes[index].name,"#CLEARED#")==0) - if (indexes[index].name[0] == '\0') - break; - } - } - - if (index < 0 || index >= MAX_MAPINDEX) { - ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX); - return 0; - } - - mapindex_getmapname(name, map_name); - - if (map_name[0] == '\0') { - ShowError("(mapindex_add) Cannot add maps with no name.\n"); - return 0; - } - - if (strlen(map_name) >= MAP_NAME_LENGTH) { - ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH); - return 0; - } - - if (mapindex_exists(index)) - ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name); - - safestrncpy(indexes[index].name, map_name, MAP_NAME_LENGTH); - if (max_index <= index) - max_index = index+1; - - return index; + char map_name[MAP_NAME_LENGTH]; + + if (index == -1){ + for (index = 1; index < max_index; index++) + { + //if (strcmp(indexes[index].name,"#CLEARED#")==0) + if (indexes[index].name[0] == '\0') + break; + } + } + + if (index < 0 || index >= MAX_MAPINDEX) { + ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX); + return 0; + } + + mapindex_getmapname(name, map_name); + + if (map_name[0] == '\0') { + ShowError("(mapindex_add) Cannot add maps with no name.\n"); + return 0; + } + + if (strlen(map_name) >= MAP_NAME_LENGTH) { + ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH); + return 0; + } + + if (mapindex_exists(index)) + ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name); + + safestrncpy(indexes[index].name, map_name, MAP_NAME_LENGTH); + if (max_index <= index) + max_index = index+1; + + return index; } -unsigned short mapindex_name2id(const char *name) +unsigned short mapindex_name2id(const char* name) { - //TODO: Perhaps use a db to speed this up? [Skotlex] - int i; - - char map_name[MAP_NAME_LENGTH]; - mapindex_getmapname(name, map_name); - - for (i = 1; i < max_index; i++) { - if (strcmpi(indexes[i].name,map_name)==0) - return i; - } - ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); - return 0; + //TODO: Perhaps use a db to speed this up? [Skotlex] + int i; + + char map_name[MAP_NAME_LENGTH]; + mapindex_getmapname(name, map_name); + + for (i = 1; i < max_index; i++) + { + if (strcmpi(indexes[i].name,map_name)==0) + return i; + } + ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); + return 0; } -const char *mapindex_id2name(unsigned short id) +const char* mapindex_id2name(unsigned short id) { - if (id > MAX_MAPINDEX || !mapindex_exists(id)) { - ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id); - return indexes[0].name; // dummy empty string so that the callee doesn't crash - } - return indexes[id].name; + if (id > MAX_MAPINDEX || !mapindex_exists(id)) { + ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id); + return indexes[0].name; // dummy empty string so that the callee doesn't crash + } + return indexes[id].name; } void mapindex_init(void) { - FILE *fp; - char line[1024]; - int last_index = -1; - int index; - char map_name[1024]; - - memset(&indexes, 0, sizeof(indexes)); - fp=fopen(mapindex_cfgfile,"r"); - if (fp==NULL) { - ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile); - exit(EXIT_FAILURE); //Server can't really run without this file. - } - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - switch (sscanf(line, "%1023s\t%d", map_name, &index)) { - case 1: //Map with no ID given, auto-assign - index = last_index+1; - case 2: //Map with ID given - mapindex_addmap(index,map_name); - break; - default: - continue; - } - last_index = index; - } - fclose(fp); + FILE *fp; + char line[1024]; + int last_index = -1; + int index; + char map_name[1024]; + + memset (&indexes, 0, sizeof (indexes)); + fp=fopen(mapindex_cfgfile,"r"); + if(fp==NULL){ + ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile); + exit(EXIT_FAILURE); //Server can't really run without this file. + } + while(fgets(line, sizeof(line), fp)) + { + if(line[0] == '/' && line[1] == '/') + continue; + + switch (sscanf(line, "%1023s\t%d", map_name, &index)) + { + case 1: //Map with no ID given, auto-assign + index = last_index+1; + case 2: //Map with ID given + mapindex_addmap(index,map_name); + break; + default: + continue; + } + last_index = index; + } + fclose(fp); } -int mapindex_removemap(int index) -{ - indexes[index].name[0] = '\0'; - return 0; +int mapindex_removemap(int index){ + indexes[index].name[0] = '\0'; + return 0; } void mapindex_final(void) diff --git a/src/common/mapindex.h b/src/common/mapindex.h index 4889d20f1..75cb254c0 100644 --- a/src/common/mapindex.h +++ b/src/common/mapindex.h @@ -47,14 +47,14 @@ extern char mapindex_cfgfile[80]; #define MAP_MALAYA "malaya" #define MAP_ECLAGE "eclage" -const char *mapindex_getmapname(const char *string, char *output); -const char *mapindex_getmapname_ext(const char *string, char *output); -unsigned short mapindex_name2id(const char *); -const char *mapindex_id2name(unsigned short); +const char* mapindex_getmapname(const char* string, char* output); +const char* mapindex_getmapname_ext(const char* string, char* output); +unsigned short mapindex_name2id(const char*); +const char* mapindex_id2name(unsigned short); void mapindex_init(void); void mapindex_final(void); -int mapindex_addmap(int index, const char *name); +int mapindex_addmap(int index, const char* name); int mapindex_removemap(int index); #endif /* _MAPINDEX_H_ */ diff --git a/src/common/md5calc.c b/src/common/md5calc.c index bd4b59ad0..05fde42cc 100644 --- a/src/common/md5calc.c +++ b/src/common/md5calc.c @@ -21,22 +21,22 @@ static unsigned int *pX; // String Table static const unsigned int T[] = { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, //20 - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, //40 - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60 + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, //20 + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, //40 + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60 }; // ROTATE_LEFT The left is made to rotate x [ n-bit ]. This is diverted as it is from RFC. @@ -45,244 +45,196 @@ static const unsigned int T[] = { // The function used for other calculation static unsigned int F(unsigned int X, unsigned int Y, unsigned int Z) { - return (X & Y) | (~X & Z); + return (X & Y) | (~X & Z); } static unsigned int G(unsigned int X, unsigned int Y, unsigned int Z) { - return (X & Z) | (Y & ~Z); + return (X & Z) | (Y & ~Z); } static unsigned int H(unsigned int X, unsigned int Y, unsigned int Z) { - return X ^ Y ^ Z; + return X ^ Y ^ Z; } static unsigned int I(unsigned int X, unsigned int Y, unsigned int Z) { - return Y ^ (X | ~Z); + return Y ^ (X | ~Z); } static unsigned int Round(unsigned int a, unsigned int b, unsigned int FGHI, - unsigned int k, unsigned int s, unsigned int i) + unsigned int k, unsigned int s, unsigned int i) { - return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s); + return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s); } static void Round1(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, F(b,c,d), k, s, i); + *a = Round(*a, b, F(b,c,d), k, s, i); } static void Round2(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, G(b,c,d), k, s, i); + *a = Round(*a, b, G(b,c,d), k, s, i); } static void Round3(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, H(b,c,d), k, s, i); + *a = Round(*a, b, H(b,c,d), k, s, i); } static void Round4(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, I(b,c,d), k, s, i); + *a = Round(*a, b, I(b,c,d), k, s, i); } static void MD5_Round_Calculate(const unsigned char *block, - unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2) + unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2) { - //create X It is since it is required. - unsigned int X[16]; //512bit 64byte - int j,k; - - //Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D) - unsigned int A=*A2, B=*B2, C=*C2, D=*D2; - unsigned int AA = A,BB = B,CC = C,DD = D; - - //It is a large region variable reluctantly because of calculation of a round. . . for Round1...4 - pX = X; - - //Copy block(padding_message) i into X - for (j=0,k=0; j<64; j+=4,k++) - X[k] = ((unsigned int)block[j]) // 8byte*4 -> 32byte conversion - | (((unsigned int)block[j+1]) << 8) // A function called Decode as used in the field of RFC - | (((unsigned int)block[j+2]) << 16) - | (((unsigned int)block[j+3]) << 24); - - - //Round 1 - Round1(&A,B,C,D, 0, 7, 0); - Round1(&D,A,B,C, 1, 12, 1); - Round1(&C,D,A,B, 2, 17, 2); - Round1(&B,C,D,A, 3, 22, 3); - Round1(&A,B,C,D, 4, 7, 4); - Round1(&D,A,B,C, 5, 12, 5); - Round1(&C,D,A,B, 6, 17, 6); - Round1(&B,C,D,A, 7, 22, 7); - Round1(&A,B,C,D, 8, 7, 8); - Round1(&D,A,B,C, 9, 12, 9); - Round1(&C,D,A,B, 10, 17, 10); - Round1(&B,C,D,A, 11, 22, 11); - Round1(&A,B,C,D, 12, 7, 12); - Round1(&D,A,B,C, 13, 12, 13); - Round1(&C,D,A,B, 14, 17, 14); - Round1(&B,C,D,A, 15, 22, 15); - - //Round 2 - Round2(&A,B,C,D, 1, 5, 16); - Round2(&D,A,B,C, 6, 9, 17); - Round2(&C,D,A,B, 11, 14, 18); - Round2(&B,C,D,A, 0, 20, 19); - Round2(&A,B,C,D, 5, 5, 20); - Round2(&D,A,B,C, 10, 9, 21); - Round2(&C,D,A,B, 15, 14, 22); - Round2(&B,C,D,A, 4, 20, 23); - Round2(&A,B,C,D, 9, 5, 24); - Round2(&D,A,B,C, 14, 9, 25); - Round2(&C,D,A,B, 3, 14, 26); - Round2(&B,C,D,A, 8, 20, 27); - Round2(&A,B,C,D, 13, 5, 28); - Round2(&D,A,B,C, 2, 9, 29); - Round2(&C,D,A,B, 7, 14, 30); - Round2(&B,C,D,A, 12, 20, 31); - - //Round 3 - Round3(&A,B,C,D, 5, 4, 32); - Round3(&D,A,B,C, 8, 11, 33); - Round3(&C,D,A,B, 11, 16, 34); - Round3(&B,C,D,A, 14, 23, 35); - Round3(&A,B,C,D, 1, 4, 36); - Round3(&D,A,B,C, 4, 11, 37); - Round3(&C,D,A,B, 7, 16, 38); - Round3(&B,C,D,A, 10, 23, 39); - Round3(&A,B,C,D, 13, 4, 40); - Round3(&D,A,B,C, 0, 11, 41); - Round3(&C,D,A,B, 3, 16, 42); - Round3(&B,C,D,A, 6, 23, 43); - Round3(&A,B,C,D, 9, 4, 44); - Round3(&D,A,B,C, 12, 11, 45); - Round3(&C,D,A,B, 15, 16, 46); - Round3(&B,C,D,A, 2, 23, 47); - - //Round 4 - Round4(&A,B,C,D, 0, 6, 48); - Round4(&D,A,B,C, 7, 10, 49); - Round4(&C,D,A,B, 14, 15, 50); - Round4(&B,C,D,A, 5, 21, 51); - Round4(&A,B,C,D, 12, 6, 52); - Round4(&D,A,B,C, 3, 10, 53); - Round4(&C,D,A,B, 10, 15, 54); - Round4(&B,C,D,A, 1, 21, 55); - Round4(&A,B,C,D, 8, 6, 56); - Round4(&D,A,B,C, 15, 10, 57); - Round4(&C,D,A,B, 6, 15, 58); - Round4(&B,C,D,A, 13, 21, 59); - Round4(&A,B,C,D, 4, 6, 60); - Round4(&D,A,B,C, 11, 10, 61); - Round4(&C,D,A,B, 2, 15, 62); - Round4(&B,C,D,A, 9, 21, 63); - - // Then perform the following additions. (let's add) - *A2 = A + AA; - *B2 = B + BB; - *C2 = C + CC; - *D2 = D + DD; - - //The clearance of confidential information - memset(pX, 0, sizeof(X)); + //create X It is since it is required. + unsigned int X[16]; //512bit 64byte + int j,k; + + //Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D) + unsigned int A=*A2, B=*B2, C=*C2, D=*D2; + unsigned int AA = A,BB = B,CC = C,DD = D; + + //It is a large region variable reluctantly because of calculation of a round. . . for Round1...4 + pX = X; + + //Copy block(padding_message) i into X + for (j=0,k=0; j<64; j+=4,k++) + X[k] = ( (unsigned int )block[j] ) // 8byte*4 -> 32byte conversion + | ( ((unsigned int )block[j+1]) << 8 ) // A function called Decode as used in the field of RFC + | ( ((unsigned int )block[j+2]) << 16 ) + | ( ((unsigned int )block[j+3]) << 24 ); + + + //Round 1 + Round1(&A,B,C,D, 0, 7, 0); Round1(&D,A,B,C, 1, 12, 1); Round1(&C,D,A,B, 2, 17, 2); Round1(&B,C,D,A, 3, 22, 3); + Round1(&A,B,C,D, 4, 7, 4); Round1(&D,A,B,C, 5, 12, 5); Round1(&C,D,A,B, 6, 17, 6); Round1(&B,C,D,A, 7, 22, 7); + Round1(&A,B,C,D, 8, 7, 8); Round1(&D,A,B,C, 9, 12, 9); Round1(&C,D,A,B, 10, 17, 10); Round1(&B,C,D,A, 11, 22, 11); + Round1(&A,B,C,D, 12, 7, 12); Round1(&D,A,B,C, 13, 12, 13); Round1(&C,D,A,B, 14, 17, 14); Round1(&B,C,D,A, 15, 22, 15); + + //Round 2 + Round2(&A,B,C,D, 1, 5, 16); Round2(&D,A,B,C, 6, 9, 17); Round2(&C,D,A,B, 11, 14, 18); Round2(&B,C,D,A, 0, 20, 19); + Round2(&A,B,C,D, 5, 5, 20); Round2(&D,A,B,C, 10, 9, 21); Round2(&C,D,A,B, 15, 14, 22); Round2(&B,C,D,A, 4, 20, 23); + Round2(&A,B,C,D, 9, 5, 24); Round2(&D,A,B,C, 14, 9, 25); Round2(&C,D,A,B, 3, 14, 26); Round2(&B,C,D,A, 8, 20, 27); + Round2(&A,B,C,D, 13, 5, 28); Round2(&D,A,B,C, 2, 9, 29); Round2(&C,D,A,B, 7, 14, 30); Round2(&B,C,D,A, 12, 20, 31); + + //Round 3 + Round3(&A,B,C,D, 5, 4, 32); Round3(&D,A,B,C, 8, 11, 33); Round3(&C,D,A,B, 11, 16, 34); Round3(&B,C,D,A, 14, 23, 35); + Round3(&A,B,C,D, 1, 4, 36); Round3(&D,A,B,C, 4, 11, 37); Round3(&C,D,A,B, 7, 16, 38); Round3(&B,C,D,A, 10, 23, 39); + Round3(&A,B,C,D, 13, 4, 40); Round3(&D,A,B,C, 0, 11, 41); Round3(&C,D,A,B, 3, 16, 42); Round3(&B,C,D,A, 6, 23, 43); + Round3(&A,B,C,D, 9, 4, 44); Round3(&D,A,B,C, 12, 11, 45); Round3(&C,D,A,B, 15, 16, 46); Round3(&B,C,D,A, 2, 23, 47); + + //Round 4 + Round4(&A,B,C,D, 0, 6, 48); Round4(&D,A,B,C, 7, 10, 49); Round4(&C,D,A,B, 14, 15, 50); Round4(&B,C,D,A, 5, 21, 51); + Round4(&A,B,C,D, 12, 6, 52); Round4(&D,A,B,C, 3, 10, 53); Round4(&C,D,A,B, 10, 15, 54); Round4(&B,C,D,A, 1, 21, 55); + Round4(&A,B,C,D, 8, 6, 56); Round4(&D,A,B,C, 15, 10, 57); Round4(&C,D,A,B, 6, 15, 58); Round4(&B,C,D,A, 13, 21, 59); + Round4(&A,B,C,D, 4, 6, 60); Round4(&D,A,B,C, 11, 10, 61); Round4(&C,D,A,B, 2, 15, 62); Round4(&B,C,D,A, 9, 21, 63); + + // Then perform the following additions. (let's add) + *A2 = A + AA; + *B2 = B + BB; + *C2 = C + CC; + *D2 = D + DD; + + //The clearance of confidential information + memset(pX, 0, sizeof(X)); } -static void MD5_String2binary(const char *string, unsigned char *output) +static void MD5_String2binary(const char * string, unsigned char * output) { - //var - /*8bit*/ - unsigned char padding_message[64]; //Extended message 512bit 64byte - unsigned char *pstring; //The position of string in the present scanning notes is held. - - /*32bit*/ - unsigned int string_byte_len, //The byte chief of string is held. - string_bit_len, //The bit length of string is held. - copy_len, //The number of bytes which is used by 1-3 and which remained - msg_digest[4]; //Message digest 128bit 4byte - unsigned int *A = &msg_digest[0], //The message digest in accordance with RFC (reference) - *B = &msg_digest[1], - *C = &msg_digest[2], - *D = &msg_digest[3]; - int i; - - //prog - //Step 3.Initialize MD Buffer (although it is the initialization; step 3 of A, B, C, and D -- unavoidable -- a head) - *A = 0x67452301; - *B = 0xefcdab89; - *C = 0x98badcfe; - *D = 0x10325476; - - //Step 1.Append Padding Bits (extension of a mark bit) - //1-1 - string_byte_len = (unsigned int)strlen(string); //The byte chief of a character sequence is acquired. - pstring = (unsigned char *)string; //The position of the present character sequence is set. - - //1-2 Repeat calculation until length becomes less than 64 bytes. - for (i=string_byte_len; 64<=i; i-=64,pstring+=64) +//var + /*8bit*/ + unsigned char padding_message[64]; //Extended message 512bit 64byte + unsigned char *pstring; //The position of string in the present scanning notes is held. + + /*32bit*/ + unsigned int string_byte_len, //The byte chief of string is held. + string_bit_len, //The bit length of string is held. + copy_len, //The number of bytes which is used by 1-3 and which remained + msg_digest[4]; //Message digest 128bit 4byte + unsigned int *A = &msg_digest[0], //The message digest in accordance with RFC (reference) + *B = &msg_digest[1], + *C = &msg_digest[2], + *D = &msg_digest[3]; + int i; + +//prog + //Step 3.Initialize MD Buffer (although it is the initialization; step 3 of A, B, C, and D -- unavoidable -- a head) + *A = 0x67452301; + *B = 0xefcdab89; + *C = 0x98badcfe; + *D = 0x10325476; + + //Step 1.Append Padding Bits (extension of a mark bit) + //1-1 + string_byte_len = (unsigned int)strlen(string); //The byte chief of a character sequence is acquired. + pstring = (unsigned char *)string; //The position of the present character sequence is set. + + //1-2 Repeat calculation until length becomes less than 64 bytes. + for (i=string_byte_len; 64<=i; i-=64,pstring+=64) MD5_Round_Calculate(pstring, A,B,C,D); - //1-3 - copy_len = string_byte_len % 64; //The number of bytes which remained is computed. - strncpy((char *)padding_message, (char *)pstring, copy_len); //A message is copied to an extended bit sequence. - memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length. - padding_message[copy_len] |= 0x80; //The next of a message is 1. - - //1-4 - //If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes. - if (56 <= copy_len) { - MD5_Round_Calculate(padding_message, A,B,C,D); - memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0. - } - - //Step 2.Append Length (the information on length is added) - string_bit_len = string_byte_len * 8; //From the byte chief to bit length (32 bytes of low rank) - memcpy(&padding_message[56], &string_bit_len, 4); //32 bytes of low rank is set. - - //When bit length cannot be expressed in 32 bytes of low rank, it is a beam raising to a higher rank. - if (UINT_MAX / 8 < string_byte_len) { - unsigned int high = (string_byte_len - UINT_MAX / 8) * 8; - memcpy(&padding_message[60], &high, 4); - } else - memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0. - - //Step 4.Process Message in 16-Word Blocks (calculation of MD5) - MD5_Round_Calculate(padding_message, A,B,C,D); - - //Step 5.Output (output) - memcpy(output,msg_digest,16); + //1-3 + copy_len = string_byte_len % 64; //The number of bytes which remained is computed. + strncpy((char *)padding_message, (char *)pstring, copy_len); //A message is copied to an extended bit sequence. + memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length. + padding_message[copy_len] |= 0x80; //The next of a message is 1. + + //1-4 + //If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes. + if (56 <= copy_len) { + MD5_Round_Calculate(padding_message, A,B,C,D); + memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0. + } + + //Step 2.Append Length (the information on length is added) + string_bit_len = string_byte_len * 8; //From the byte chief to bit length (32 bytes of low rank) + memcpy(&padding_message[56], &string_bit_len, 4); //32 bytes of low rank is set. + + //When bit length cannot be expressed in 32 bytes of low rank, it is a beam raising to a higher rank. + if (UINT_MAX / 8 < string_byte_len) { + unsigned int high = (string_byte_len - UINT_MAX / 8) * 8; + memcpy(&padding_message[60], &high, 4); + } else + memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0. + + //Step 4.Process Message in 16-Word Blocks (calculation of MD5) + MD5_Round_Calculate(padding_message, A,B,C,D); + + //Step 5.Output (output) + memcpy(output,msg_digest,16); } //------------------------------------------------------------------- // The function for the exteriors /** output is the coded binary in the character sequence which wants to code string. */ -void MD5_Binary(const char *string, unsigned char *output) +void MD5_Binary(const char * string, unsigned char * output) { - MD5_String2binary(string,output); + MD5_String2binary(string,output); } /** output is the coded character sequence in the character sequence which wants to code string. */ -void MD5_String(const char *string, char *output) +void MD5_String(const char * string, char * output) { - unsigned char digest[16]; - - MD5_String2binary(string,digest); - sprintf(output, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - digest[ 0], digest[ 1], digest[ 2], digest[ 3], - digest[ 4], digest[ 5], digest[ 6], digest[ 7], - digest[ 8], digest[ 9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15]); + unsigned char digest[16]; + + MD5_String2binary(string,digest); + sprintf(output, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + digest[ 0], digest[ 1], digest[ 2], digest[ 3], + digest[ 4], digest[ 5], digest[ 6], digest[ 7], + digest[ 8], digest[ 9], digest[10], digest[11], + digest[12], digest[13], digest[14], digest[15]); } /** output is a sequence of non-zero characters to be used as password salt. */ -void MD5_Salt(unsigned int len, char *output) +void MD5_Salt(unsigned int len, char * output) { - unsigned int i; - for (i = 0; i < len; ++i) - output[i] = (char)(1 + rnd() % 255); + unsigned int i; + for( i = 0; i < len; ++i ) + output[i] = (char)(1 + rnd() % 255); } diff --git a/src/common/md5calc.h b/src/common/md5calc.h index 4a112a660..323affa2c 100644 --- a/src/common/md5calc.h +++ b/src/common/md5calc.h @@ -1,8 +1,8 @@ #ifndef _MD5CALC_H_ #define _MD5CALC_H_ -void MD5_String(const char *string, char *output); -void MD5_Binary(const char *string, unsigned char *output); -void MD5_Salt(unsigned int len, char *output); +void MD5_String(const char * string, char * output); +void MD5_Binary(const char * string, unsigned char * output); +void MD5_Salt(unsigned int len, char * output); #endif /* _MD5CALC_H_ */ diff --git a/src/common/mempool.c b/src/common/mempool.c index 62db7b9e3..35b03034d 100644 --- a/src/common/mempool.c +++ b/src/common/mempool.c @@ -30,9 +30,9 @@ #include "../common/malloc.h" #include "../common/mutex.h" -#define ALIGN16 ra_align(16) +#define ALIGN16 ra_align(16) #define ALIGN_TO(x, a) (x + ( a - ( x % a) ) ) -#define ALIGN_TO_16(x) ALIGN_TO(x, 16) +#define ALIGN_TO_16(x) ALIGN_TO(x, 16) #undef MEMPOOL_DEBUG #define MEMPOOLASSERT @@ -40,532 +40,523 @@ #define NODE_TO_DATA(x) ( ((char*)x) + sizeof(struct node) ) #define DATA_TO_NODE(x) ( (struct node*)(((char*)x) - sizeof(struct node)) ) -struct ra_align(16) node { - void *next; - void *segment; +struct ra_align(16) node{ + void *next; + void *segment; #ifdef MEMPOOLASSERT - bool used; - uint64 magic; -#define NODE_MAGIC 0xBEEF00EAEACAFE07ll + bool used; + uint64 magic; + #define NODE_MAGIC 0xBEEF00EAEACAFE07ll #endif }; // The Pointer to this struct is the base address of the segment itself. -struct pool_segment { - mempool pool; // pool, this segment belongs to - struct pool_segment *next; - int64 num_nodes_total; - int64 num_bytes; +struct pool_segment{ + mempool pool; // pool, this segment belongs to + struct pool_segment *next; + int64 num_nodes_total; + int64 num_bytes; }; -struct mempool { - // Settings - char *name; - uint64 elem_size; - uint64 elem_realloc_step; - int64 elem_realloc_thresh; - - // Callbacks that get called for every node that gets allocated - // Example usage: initialization of mutex/lock for each node. - memPoolOnNodeAllocationProc onalloc; - memPoolOnNodeDeallocationProc ondealloc; - - // Locks - SPIN_LOCK segmentLock; - SPIN_LOCK nodeLock; - - - // Internal - struct pool_segment *segments; - struct node *free_list; - - volatile int64 num_nodes_total; - volatile int64 num_nodes_free; - - volatile int64 num_segments; - volatile int64 num_bytes_total; - - volatile int64 peak_nodes_used; // Peak Node Usage - volatile int64 num_realloc_events; // Number of reallocations done. (allocate additional nodes) - - // list (used for global management such as allocator..) - struct mempool *next; +struct mempool{ + // Settings + char *name; + uint64 elem_size; + uint64 elem_realloc_step; + int64 elem_realloc_thresh; + + // Callbacks that get called for every node that gets allocated + // Example usage: initialization of mutex/lock for each node. + memPoolOnNodeAllocationProc onalloc; + memPoolOnNodeDeallocationProc ondealloc; + + // Locks + SPIN_LOCK segmentLock; + SPIN_LOCK nodeLock; + + + // Internal + struct pool_segment *segments; + struct node *free_list; + + volatile int64 num_nodes_total; + volatile int64 num_nodes_free; + + volatile int64 num_segments; + volatile int64 num_bytes_total; + + volatile int64 peak_nodes_used; // Peak Node Usage + volatile int64 num_realloc_events; // Number of reallocations done. (allocate additional nodes) + + // list (used for global management such as allocator..) + struct mempool *next; } ra_align(8); // Dont touch the alignment, otherwise interlocked functions are broken .. -/// +/// // Implementation: // static void segment_allocate_add(mempool p, uint64 count); static SPIN_LOCK l_mempoolListLock; -static mempool l_mempoolList = NULL; +static mempool l_mempoolList = NULL; static rAthread l_async_thread = NULL; -static ramutex l_async_lock = NULL; -static racond l_async_cond = NULL; +static ramutex l_async_lock = NULL; +static racond l_async_cond = NULL; static volatile int32 l_async_terminate = 0; -static void *mempool_async_allocator(void *x) -{ - mempool p; - - - while (1) { - if (l_async_terminate > 0) - break; - - EnterSpinLock(&l_mempoolListLock); - - for (p = l_mempoolList; p != NULL; p = p->next) { - - if (p->num_nodes_free < p->elem_realloc_thresh) { - // add new segment. - segment_allocate_add(p, p->elem_realloc_step); - // increase stats counter - InterlockedIncrement64(&p->num_realloc_events); - } - - } - - LeaveSpinLock(&l_mempoolListLock); - - ramutex_lock(l_async_lock); - racond_wait(l_async_cond, l_async_lock, -1); - ramutex_unlock(l_async_lock); - } - - - return NULL; +static void *mempool_async_allocator(void *x){ + mempool p; + + + while(1){ + if(l_async_terminate > 0) + break; + + EnterSpinLock(&l_mempoolListLock); + + for(p = l_mempoolList; p != NULL; p = p->next){ + + if(p->num_nodes_free < p->elem_realloc_thresh){ + // add new segment. + segment_allocate_add(p, p->elem_realloc_step); + // increase stats counter + InterlockedIncrement64(&p->num_realloc_events); + } + + } + + LeaveSpinLock(&l_mempoolListLock); + + ramutex_lock( l_async_lock ); + racond_wait( l_async_cond, l_async_lock, -1 ); + ramutex_unlock( l_async_lock ); + } + + + return NULL; }//end: mempool_async_allocator() -void mempool_init() -{ - - if (sizeof(struct node)%16 != 0) { - ShowFatalError("mempool_init: struct node alignment failure. %u != multiple of 16\n", sizeof(struct node)); - exit(EXIT_FAILURE); - } - - // Global List start - InitializeSpinLock(&l_mempoolListLock); - l_mempoolList = NULL; - - // Initialize mutex + stuff needed for async allocator worker. - l_async_terminate = 0; - l_async_lock = ramutex_create(); - l_async_cond = racond_create(); - - l_async_thread = rathread_createEx(mempool_async_allocator, NULL, 1024*1024, RAT_PRIO_NORMAL); - if (l_async_thread == NULL) { - ShowFatalError("mempool_init: cannot spawn Async Allocator Thread.\n"); - exit(EXIT_FAILURE); - } +void mempool_init(){ + + if(sizeof(struct node)%16 != 0 ){ + ShowFatalError("mempool_init: struct node alignment failure. %u != multiple of 16\n", sizeof(struct node)); + exit(EXIT_FAILURE); + } + + // Global List start + InitializeSpinLock(&l_mempoolListLock); + l_mempoolList = NULL; + + // Initialize mutex + stuff needed for async allocator worker. + l_async_terminate = 0; + l_async_lock = ramutex_create(); + l_async_cond = racond_create(); + + l_async_thread = rathread_createEx(mempool_async_allocator, NULL, 1024*1024, RAT_PRIO_NORMAL); + if(l_async_thread == NULL){ + ShowFatalError("mempool_init: cannot spawn Async Allocator Thread.\n"); + exit(EXIT_FAILURE); + } }//end: mempool_init() -void mempool_final() -{ - mempool p, pn; - - ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); - - // Terminate worker / wait until its terminated. - InterlockedIncrement(&l_async_terminate); - racond_signal(l_async_cond); - rathread_wait(l_async_thread, NULL); - - // Destroy cond var and mutex. - racond_destroy(l_async_cond); - ramutex_destroy(l_async_lock); - - // Free remaining mempools - // ((bugged code! this should halppen, every mempool should - // be freed by the subsystem that has allocated it.) - // - EnterSpinLock(&l_mempoolListLock); - p = l_mempoolList; - while (1) { - if (p == NULL) - break; - - pn = p->next; - - ShowWarning("Mempool [%s] was not properly destroyed - forcing destroy.\n", p->name); - mempool_destroy(p); - - p = pn; - } - LeaveSpinLock(&l_mempoolListLock); - +void mempool_final(){ + mempool p, pn; + + ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); + + // Terminate worker / wait until its terminated. + InterlockedIncrement(&l_async_terminate); + racond_signal(l_async_cond); + rathread_wait(l_async_thread, NULL); + + // Destroy cond var and mutex. + racond_destroy( l_async_cond ); + ramutex_destroy( l_async_lock ); + + // Free remaining mempools + // ((bugged code! this should halppen, every mempool should + // be freed by the subsystem that has allocated it.) + // + EnterSpinLock(&l_mempoolListLock); + p = l_mempoolList; + while(1){ + if(p == NULL) + break; + + pn = p->next; + + ShowWarning("Mempool [%s] was not properly destroyed - forcing destroy.\n", p->name); + mempool_destroy(p); + + p = pn; + } + LeaveSpinLock(&l_mempoolListLock); + }//end: mempool_final() -static void segment_allocate_add(mempool p, uint64 count) -{ - - // Required Memory: - // sz( segment ) - // count * sz( real_node_size ) - // - // where real node size is: - // ALIGN_TO_16( sz( node ) ) + p->elem_size - // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) - // - size_t total_sz; - struct pool_segment *seg = NULL; - struct node *nodeList = NULL; - struct node *node = NULL; - char *ptr = NULL; - uint64 i; - - total_sz = ALIGN_TO_16(sizeof(struct pool_segment)) - + ((size_t)count * (sizeof(struct node) + (size_t)p->elem_size)) ; +static void segment_allocate_add(mempool p, uint64 count){ + + // Required Memory: + // sz( segment ) + // count * sz( real_node_size ) + // + // where real node size is: + // ALIGN_TO_16( sz( node ) ) + p->elem_size + // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) + // + size_t total_sz; + struct pool_segment *seg = NULL; + struct node *nodeList = NULL; + struct node *node = NULL; + char *ptr = NULL; + uint64 i; + + total_sz = ALIGN_TO_16( sizeof(struct pool_segment) ) + + ( (size_t)count * (sizeof(struct node) + (size_t)p->elem_size) ) ; #ifdef MEMPOOL_DEBUG - ShowDebug("Mempool [%s] Segment AllocateAdd (num: %u, total size: %0.2fMiB)\n", p->name, count, (float)total_sz/1024.f/1024.f); + ShowDebug("Mempool [%s] Segment AllocateAdd (num: %u, total size: %0.2fMiB)\n", p->name, count, (float)total_sz/1024.f/1024.f); #endif - // allocate! (spin forever until weve got the memory.) - i=0; - while (1) { - ptr = (char *)aMalloc(total_sz); - if (ptr != NULL) break; - - i++; // increase failcount. - if (!(i & 7)) { - ShowWarning("Mempool [%s] Segment AllocateAdd => System seems to be Out of Memory (%0.2f MiB). Try #%u\n", (float)total_sz/1024.f/1024.f, i); + // allocate! (spin forever until weve got the memory.) + i=0; + while(1){ + ptr = (char*)aMalloc(total_sz); + if(ptr != NULL) break; + + i++; // increase failcount. + if(!(i & 7)){ + ShowWarning("Mempool [%s] Segment AllocateAdd => System seems to be Out of Memory (%0.2f MiB). Try #%u\n", (float)total_sz/1024.f/1024.f, i); #ifdef WIN32 - Sleep(1000); + Sleep(1000); #else - sleep(1); + sleep(1); #endif - } else { - rathread_yield(); /// allow/force vuln. ctxswitch - } - }//endwhile: allocation spinloop. - - // Clear Memory. - memset(ptr, 0x00, total_sz); - - // Initialize segment struct. - seg = (struct pool_segment *)ptr; - ptr += ALIGN_TO_16(sizeof(struct pool_segment)); - - seg->pool = p; - seg->num_nodes_total = count; - seg->num_bytes = total_sz; - - - // Initialze nodes! - nodeList = NULL; - for (i = 0; i < count; i++) { - node = (struct node *)ptr; - ptr += sizeof(struct node); - ptr += p->elem_size; - - node->segment = seg; + }else{ + rathread_yield(); /// allow/force vuln. ctxswitch + } + }//endwhile: allocation spinloop. + + // Clear Memory. + memset(ptr, 0x00, total_sz); + + // Initialize segment struct. + seg = (struct pool_segment*)ptr; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + + seg->pool = p; + seg->num_nodes_total = count; + seg->num_bytes = total_sz; + + + // Initialze nodes! + nodeList = NULL; + for(i = 0; i < count; i++){ + node = (struct node*)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; + + node->segment = seg; #ifdef MEMPOOLASSERT - node->used = false; - node->magic = NODE_MAGIC; + node->used = false; + node->magic = NODE_MAGIC; #endif - if (p->onalloc != NULL) p->onalloc(NODE_TO_DATA(node)); - - node->next = nodeList; - nodeList = node; - } - - - - // Link in Segment. - EnterSpinLock(&p->segmentLock); - seg->next = p->segments; - p->segments = seg; - LeaveSpinLock(&p->segmentLock); - - // Link in Nodes - EnterSpinLock(&p->nodeLock); - nodeList->next = p->free_list; - p->free_list = nodeList; - LeaveSpinLock(&p->nodeLock); - - - // Increase Stats: - InterlockedExchangeAdd64(&p->num_nodes_total, count); - InterlockedExchangeAdd64(&p->num_nodes_free, count); - InterlockedIncrement64(&p->num_segments); - InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); - + if(p->onalloc != NULL) p->onalloc( NODE_TO_DATA(node) ); + + node->next = nodeList; + nodeList = node; + } + + + + // Link in Segment. + EnterSpinLock(&p->segmentLock); + seg->next = p->segments; + p->segments = seg; + LeaveSpinLock(&p->segmentLock); + + // Link in Nodes + EnterSpinLock(&p->nodeLock); + nodeList->next = p->free_list; + p->free_list = nodeList; + LeaveSpinLock(&p->nodeLock); + + + // Increase Stats: + InterlockedExchangeAdd64(&p->num_nodes_total, count); + InterlockedExchangeAdd64(&p->num_nodes_free, count); + InterlockedIncrement64(&p->num_segments); + InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); + }//end: segment_allocate_add() mempool mempool_create(const char *name, - uint64 elem_size, - uint64 initial_count, - uint64 realloc_count, - memPoolOnNodeAllocationProc onNodeAlloc, - memPoolOnNodeDeallocationProc onNodeDealloc) -{ - //.. - uint64 realloc_thresh; - mempool pool; - pool = (mempool)aCalloc(1, sizeof(struct mempool)); - - if (pool == NULL) { - ShowFatalError("mempool_create: Failed to allocate %u bytes memory.\n", sizeof(struct mempool)); - exit(EXIT_FAILURE); - } - - // Check minimum initial count / realloc count requirements. - if (initial_count < 50) - initial_count = 50; - if (realloc_count < 50) - realloc_count = 50; - - // Set Reallocation threshold to 5% of realloc_count, at least 10. - realloc_thresh = (realloc_count/100)*5; // - if (realloc_thresh < 10) - realloc_thresh = 10; - - // Initialize members.. - pool->name = aStrdup(name); - pool->elem_size = ALIGN_TO_16(elem_size); - pool->elem_realloc_step = realloc_count; - pool->elem_realloc_thresh = realloc_thresh; - pool->onalloc = onNodeAlloc; - pool->ondealloc = onNodeDealloc; - - InitializeSpinLock(&pool->segmentLock); - InitializeSpinLock(&pool->nodeLock); - - // Initial Statistic values: - pool->num_nodes_total = 0; - pool->num_nodes_free = 0; - pool->num_segments = 0; - pool->num_bytes_total = 0; - pool->peak_nodes_used = 0; - pool->num_realloc_events = 0; - - // + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc){ + //.. + uint64 realloc_thresh; + mempool pool; + pool = (mempool)aCalloc( 1, sizeof(struct mempool) ); + + if(pool == NULL){ + ShowFatalError("mempool_create: Failed to allocate %u bytes memory.\n", sizeof(struct mempool) ); + exit(EXIT_FAILURE); + } + + // Check minimum initial count / realloc count requirements. + if(initial_count < 50) + initial_count = 50; + if(realloc_count < 50) + realloc_count = 50; + + // Set Reallocation threshold to 5% of realloc_count, at least 10. + realloc_thresh = (realloc_count/100)*5; // + if(realloc_thresh < 10) + realloc_thresh = 10; + + // Initialize members.. + pool->name = aStrdup(name); + pool->elem_size = ALIGN_TO_16(elem_size); + pool->elem_realloc_step = realloc_count; + pool->elem_realloc_thresh = realloc_thresh; + pool->onalloc = onNodeAlloc; + pool->ondealloc = onNodeDealloc; + + InitializeSpinLock(&pool->segmentLock); + InitializeSpinLock(&pool->nodeLock); + + // Initial Statistic values: + pool->num_nodes_total = 0; + pool->num_nodes_free = 0; + pool->num_segments = 0; + pool->num_bytes_total = 0; + pool->peak_nodes_used = 0; + pool->num_realloc_events = 0; + + // #ifdef MEMPOOL_DEBUG - ShowDebug("Mempool [%s] Init (ElemSize: %u, Initial Count: %u, Realloc Count: %u)\n", pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); + ShowDebug("Mempool [%s] Init (ElemSize: %u, Initial Count: %u, Realloc Count: %u)\n", pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); #endif - // Allocate first segment directly :) - segment_allocate_add(pool, initial_count); - - - // Add Pool to the global pool list - EnterSpinLock(&l_mempoolListLock); - pool->next = l_mempoolList; - l_mempoolList = pool; - LeaveSpinLock(&l_mempoolListLock); + // Allocate first segment directly :) + segment_allocate_add(pool, initial_count); + + // Add Pool to the global pool list + EnterSpinLock(&l_mempoolListLock); + pool->next = l_mempoolList; + l_mempoolList = pool; + LeaveSpinLock(&l_mempoolListLock); - return pool; + + return pool; }//end: mempool_create() -void mempool_destroy(mempool p) -{ - struct pool_segment *seg, *segnext; - struct node *niter; - mempool piter, pprev; - char *ptr; - int64 i; +void mempool_destroy(mempool p){ + struct pool_segment *seg, *segnext; + struct node *niter; + mempool piter, pprev; + char *ptr; + int64 i; #ifdef MEMPOOL_DEBUG ShowDebug("Mempool [%s] Destroy\n", p->name); #endif - - // Unlink from global list. - EnterSpinLock(&l_mempoolListLock); - piter = l_mempoolList; - pprev = l_mempoolList; - while (1) { - if (piter == NULL) - break; - - - if (piter == p) { - // unlink from list, - // - if (pprev == l_mempoolList) { - // this (p) is list begin. so set next as head. - l_mempoolList = p->next; - } else { - // replace prevs next wuth our next. - pprev->next = p->next; - } - break; - } - - pprev = piter; - piter = piter->next; - } - - p->next = NULL; - LeaveSpinLock(&l_mempoolListLock); - - - // Get both locks. - EnterSpinLock(&p->segmentLock); - EnterSpinLock(&p->nodeLock); - - - if (p->num_nodes_free != p->num_nodes_total) - ShowWarning("Mempool [%s] Destroy - %u nodes are not freed properly!\n", p->name, (p->num_nodes_total - p->num_nodes_free)); - - // Free All Segments (this will also free all nodes) - // The segment pointer is the base pointer to the whole segment. - seg = p->segments; - while (1) { - if (seg == NULL) - break; - - segnext = seg->next; - - // .. - if (p->ondealloc != NULL) { - // walk over the segment, and call dealloc callback! - ptr = (char *)seg; - ptr += ALIGN_TO_16(sizeof(struct pool_segment)); - for (i = 0; i < seg->num_nodes_total; i++) { - niter = (struct node *)ptr; - ptr += sizeof(struct node); - ptr += p->elem_size; + + // Unlink from global list. + EnterSpinLock(&l_mempoolListLock); + piter = l_mempoolList; + pprev = l_mempoolList; + while(1){ + if(piter == NULL) + break; + + + if(piter == p){ + // unlink from list, + // + if(pprev == l_mempoolList){ + // this (p) is list begin. so set next as head. + l_mempoolList = p->next; + }else{ + // replace prevs next wuth our next. + pprev->next = p->next; + } + break; + } + + pprev = piter; + piter = piter->next; + } + + p->next = NULL; + LeaveSpinLock(&l_mempoolListLock); + + + // Get both locks. + EnterSpinLock(&p->segmentLock); + EnterSpinLock(&p->nodeLock); + + + if(p->num_nodes_free != p->num_nodes_total) + ShowWarning("Mempool [%s] Destroy - %u nodes are not freed properly!\n", p->name, (p->num_nodes_total - p->num_nodes_free) ); + + // Free All Segments (this will also free all nodes) + // The segment pointer is the base pointer to the whole segment. + seg = p->segments; + while(1){ + if(seg == NULL) + break; + + segnext = seg->next; + + // .. + if(p->ondealloc != NULL){ + // walk over the segment, and call dealloc callback! + ptr = (char*)seg; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + for(i = 0; i < seg->num_nodes_total; i++){ + niter = (struct node*)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; #ifdef MEMPOOLASSERT - if (niter->magic != NODE_MAGIC) { - ShowError("Mempool [%s] Destroy - walk over segment - node %p invalid magic!\n", p->name, niter); - continue; - } + if(niter->magic != NODE_MAGIC){ + ShowError("Mempool [%s] Destroy - walk over segment - node %p invalid magic!\n", p->name, niter); + continue; + } #endif - - p->ondealloc(NODE_TO_DATA(niter)); - - - } - }//endif: ondealloc callback? - - // simple .. - aFree(seg); - - seg = segnext; - } - - // Clear node ptr - p->free_list = NULL; - InterlockedExchange64(&p->num_nodes_free, 0); - InterlockedExchange64(&p->num_nodes_total, 0); - InterlockedExchange64(&p->num_segments, 0); - InterlockedExchange64(&p->num_bytes_total, 0); - - LeaveSpinLock(&p->nodeLock); - LeaveSpinLock(&p->segmentLock); - - // Free pool itself :D - aFree(p->name); - aFree(p); + + p->ondealloc( NODE_TO_DATA(niter) ); + + + } + }//endif: ondealloc callback? + + // simple .. + aFree(seg); + + seg = segnext; + } + + // Clear node ptr + p->free_list = NULL; + InterlockedExchange64(&p->num_nodes_free, 0); + InterlockedExchange64(&p->num_nodes_total, 0); + InterlockedExchange64(&p->num_segments, 0); + InterlockedExchange64(&p->num_bytes_total, 0); + + LeaveSpinLock(&p->nodeLock); + LeaveSpinLock(&p->segmentLock); + + // Free pool itself :D + aFree(p->name); + aFree(p); }//end: mempool_destroy() -void *mempool_node_get(mempool p) -{ - struct node *node; - int64 num_used; - - if (p->num_nodes_free < p->elem_realloc_thresh) - racond_signal(l_async_cond); - - while (1) { - - EnterSpinLock(&p->nodeLock); - - node = p->free_list; - if (node != NULL) - p->free_list = node->next; - - LeaveSpinLock(&p->nodeLock); - - if (node != NULL) - break; - - rathread_yield(); - } - - InterlockedDecrement64(&p->num_nodes_free); - - // Update peak value - num_used = (p->num_nodes_total - p->num_nodes_free); - if (num_used > p->peak_nodes_used) { - InterlockedExchange64(&p->peak_nodes_used, num_used); - } - +void *mempool_node_get(mempool p){ + struct node *node; + int64 num_used; + + if(p->num_nodes_free < p->elem_realloc_thresh) + racond_signal(l_async_cond); + + while(1){ + + EnterSpinLock(&p->nodeLock); + + node = p->free_list; + if(node != NULL) + p->free_list = node->next; + + LeaveSpinLock(&p->nodeLock); + + if(node != NULL) + break; + + rathread_yield(); + } + + InterlockedDecrement64(&p->num_nodes_free); + + // Update peak value + num_used = (p->num_nodes_total - p->num_nodes_free); + if(num_used > p->peak_nodes_used){ + InterlockedExchange64(&p->peak_nodes_used, num_used); + } + #ifdef MEMPOOLASSERT - node->used = true; + node->used = true; #endif - return NODE_TO_DATA(node); + return NODE_TO_DATA(node); }//end: mempool_node_get() -void mempool_node_put(mempool p, void *data) -{ - struct node *node; - - node = DATA_TO_NODE(data); +void mempool_node_put(mempool p, void *data){ + struct node *node; + + node = DATA_TO_NODE(data); #ifdef MEMPOOLASSERT - if (node->magic != NODE_MAGIC) { - ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); - return; // lost, - } - - { - struct pool_segment *node_seg = node->segment; - if (node_seg->pool != p) { - ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); - return; - } - } - - // reset used flag. - node->used = false; + if(node->magic != NODE_MAGIC){ + ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); + return; // lost, + } + + { + struct pool_segment *node_seg = node->segment; + if(node_seg->pool != p){ + ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); + return; + } + } + + // reset used flag. + node->used = false; #endif - // - EnterSpinLock(&p->nodeLock); - node->next = p->free_list; - p->free_list = node; - LeaveSpinLock(&p->nodeLock); - - InterlockedIncrement64(&p->num_nodes_free); + // + EnterSpinLock(&p->nodeLock); + node->next = p->free_list; + p->free_list = node; + LeaveSpinLock(&p->nodeLock); + + InterlockedIncrement64(&p->num_nodes_free); }//end: mempool_node_put() -mempool_stats mempool_get_stats(mempool pool) -{ - mempool_stats stats; - - // initialize all with zeros - memset(&stats, 0x00, sizeof(mempool_stats)); - - stats.num_nodes_total = pool->num_nodes_total; - stats.num_nodes_free = pool->num_nodes_free; - stats.num_nodes_used = (stats.num_nodes_total - stats.num_nodes_free); - stats.num_segments = pool->num_segments; - stats.num_realloc_events= pool->num_realloc_events; - stats.peak_nodes_used = pool->peak_nodes_used; - stats.num_bytes_total = pool->num_bytes_total; - - // Pushing such a large block over the stack as return value isnt nice - // but lazy :) and should be okay in this case (Stats / Debug..) - // if you dont like it - feel free and refactor it. - return stats; +mempool_stats mempool_get_stats(mempool pool){ + mempool_stats stats; + + // initialize all with zeros + memset(&stats, 0x00, sizeof(mempool_stats)); + + stats.num_nodes_total = pool->num_nodes_total; + stats.num_nodes_free = pool->num_nodes_free; + stats.num_nodes_used = (stats.num_nodes_total - stats.num_nodes_free); + stats.num_segments = pool->num_segments; + stats.num_realloc_events= pool->num_realloc_events; + stats.peak_nodes_used = pool->peak_nodes_used; + stats.num_bytes_total = pool->num_bytes_total; + + // Pushing such a large block over the stack as return value isnt nice + // but lazy :) and should be okay in this case (Stats / Debug..) + // if you dont like it - feel free and refactor it. + return stats; }//end: mempool_get_stats() diff --git a/src/common/mempool.h b/src/common/mempool.h index 9c4f1563e..aeaebe7fe 100644 --- a/src/common/mempool.h +++ b/src/common/mempool.h @@ -8,67 +8,67 @@ typedef struct mempool *mempool; typedef void (*memPoolOnNodeAllocationProc)(void *ptr); typedef void (*memPoolOnNodeDeallocationProc)(void *ptr); -typedef struct mempool_stats { - int64 num_nodes_total; - int64 num_nodes_free; - int64 num_nodes_used; - - int64 num_segments; - int64 num_realloc_events; - - int64 peak_nodes_used; - - int64 num_bytes_total; +typedef struct mempool_stats{ + int64 num_nodes_total; + int64 num_nodes_free; + int64 num_nodes_used; + + int64 num_segments; + int64 num_realloc_events; + + int64 peak_nodes_used; + + int64 num_bytes_total; } mempool_stats; -// +// void mempool_init(); void mempool_final(); -/** +/** * Creates a new Mempool * * @param name - Name of the pool (used for debug / error messages) * @param elem_size - size of each element - * @param initial_count - preallocation count + * @param initial_count - preallocation count * @param realloc_count - #no of nodes being allocated when pool is running empty. * @param onNodeAlloc - Node Allocation callback (see @note!) * @param onNodeDealloc - Node Deallocation callback (see @note!) * * @note: - * The onNode(De)alloc callbacks are only called once during segment allocation - * (pool initialization / rallocation ) + * The onNode(De)alloc callbacks are only called once during segment allocation + * (pool initialization / rallocation ) * you can use this callbacks for example to initlaize a mutex or somethingelse - * you definitly need during runtime + * you definitly need during runtime * * @return not NULL */ mempool mempool_create(const char *name, - uint64 elem_size, - uint64 initial_count, - uint64 realloc_count, - - memPoolOnNodeAllocationProc onNodeAlloc, - memPoolOnNodeDeallocationProc onNodeDealloc); - - + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc); + + /** * Destroys a Mempool - * + * * @param pool - the mempool to destroy * * @note: - * Everything gets deallocated, regardless if everything was freed properly! - * So you have to ensure that all references are cleared properly! + * Everything gets deallocated, regardless if everything was freed properly! + * So you have to ensure that all references are cleared properly! */ void mempool_destroy(mempool pool); /** * Gets a new / empty node from the given mempool. - * + * * @param pool - the pool to get an empty node from. * * @return Address of empty Node @@ -80,12 +80,12 @@ void *mempool_node_get(mempool pool); * Returns the given node to the given mempool * * @param pool - the pool to put the node, to - * @param node - the node to return + * @param node - the node to return */ void mempool_node_put(mempool pool, void *node); -/** +/** * Returns Statistics for the given mempool * * @param pool - the pool to get thats for diff --git a/src/common/mmo.h b/src/common/mmo.h index 4236eb4c6..5f6108b33 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _MMO_H_ -#define _MMO_H_ +#ifndef _MMO_H_ +#define _MMO_H_ #include "cbasetypes.h" #include @@ -46,25 +46,25 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER -#define PACKETVER 20120410 -//#define PACKETVER 20111116 + #define PACKETVER 20120410 + //#define PACKETVER 20111116 #endif //Remove/Comment this line to disable sc_data saving. [Skotlex] -#define ENABLE_SC_SAVING +#define ENABLE_SC_SAVING //Remove/Comment this line to disable server-side hot-key saving support [Skotlex] //Note that newer clients no longer save hotkeys in the registry! #define HOTKEY_SAVING #if PACKETVER < 20090603 -// (27 = 9 skills x 3 bars) (0x02b9,191) -#define MAX_HOTKEYS 27 + // (27 = 9 skills x 3 bars) (0x02b9,191) + #define MAX_HOTKEYS 27 #elif PACKETVER < 20090617 -// (36 = 9 skills x 4 bars) (0x07d9,254) -#define MAX_HOTKEYS 36 + // (36 = 9 skills x 4 bars) (0x07d9,254) + #define MAX_HOTKEYS 36 #else -// (38 = 9 skills x 4 bars & 2 Quickslots)(0x07d9,268) -#define MAX_HOTKEYS 38 + // (38 = 9 skills x 4 bars & 2 Quickslots)(0x07d9,268) + #define MAX_HOTKEYS 38 #endif #define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps @@ -91,13 +91,13 @@ #define MAX_STORAGE 600 #define MAX_GUILD_STORAGE 600 #define MAX_PARTY 12 -#define MAX_GUILD 16+10*6 // increased max guild members +6 per 1 extension levels [Lupus] -#define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] +#define MAX_GUILD 16+10*6 // increased max guild members +6 per 1 extension levels [Lupus] +#define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] #define MAX_GUILDEXPULSION 32 #define MAX_GUILDALLIANCE 16 -#define MAX_GUILDSKILL 15 // increased max guild skills because of new skills [Sara-chan] +#define MAX_GUILDSKILL 15 // increased max guild skills because of new skills [Sara-chan] #define MAX_GUILDLEVEL 50 -#define MAX_GUARDIANS 8 //Local max per castle. [Skotlex] +#define MAX_GUARDIANS 8 //Local max per castle. [Skotlex] #define MAX_QUEST_DB 2000 //Max quests that the server will load #define MAX_QUEST_OBJECTIVES 3 //Max quest objectives for a quest @@ -140,7 +140,7 @@ //Base Homun skill. #define HM_SKILLBASE 8001 #define MAX_HOMUNSKILL 43 -#define MAX_HOMUNCULUS_CLASS 52 //[orn], Increased to 60 from 16 to allow new Homun-S. +#define MAX_HOMUNCULUS_CLASS 52 //[orn], Increased to 60 from 16 to allow new Homun-S. #define HM_CLASS_BASE 6001 #define HM_CLASS_MAX (HM_CLASS_BASE+MAX_HOMUNCULUS_CLASS-1) @@ -163,20 +163,20 @@ #define EL_CLASS_MAX (EL_CLASS_BASE+MAX_ELEMENTAL_CLASS-1) enum item_types { - IT_HEALING = 0, - IT_UNKNOWN, //1 - IT_USABLE, //2 - IT_ETC, //3 - IT_WEAPON, //4 - IT_ARMOR, //5 - IT_CARD, //6 - IT_PETEGG, //7 - IT_PETARMOR,//8 - IT_UNKNOWN2,//9 - IT_AMMO, //10 - IT_DELAYCONSUME,//11 - IT_CASH = 18, - IT_MAX + IT_HEALING = 0, + IT_UNKNOWN, //1 + IT_USABLE, //2 + IT_ETC, //3 + IT_WEAPON, //4 + IT_ARMOR, //5 + IT_CARD, //6 + IT_PETEGG, //7 + IT_PETARMOR,//8 + IT_UNKNOWN2,//9 + IT_AMMO, //10 + IT_DELAYCONSUME,//11 + IT_CASH = 18, + IT_MAX }; @@ -184,555 +184,556 @@ enum item_types { typedef enum quest_state { Q_INACTIVE, Q_ACTIVE, Q_COMPLETE } quest_state; struct quest { - int quest_id; - unsigned int time; - int count[MAX_QUEST_OBJECTIVES]; - quest_state state; + int quest_id; + unsigned int time; + int count[MAX_QUEST_OBJECTIVES]; + quest_state state; }; struct item { - int id; - short nameid; - short amount; - unsigned short equip; // location(s) where item is equipped (using enum equip_pos for bitmasking) - char identify; - char refine; - char attribute; - short card[MAX_SLOTS]; - unsigned int expire_time; - char favorite; + int id; + short nameid; + short amount; + unsigned short equip; // location(s) where item is equipped (using enum equip_pos for bitmasking) + char identify; + char refine; + char attribute; + short card[MAX_SLOTS]; + unsigned int expire_time; + char favorite; }; struct point { - unsigned short map; - short x,y; + unsigned short map; + short x,y; }; -enum e_skill_flag { - SKILL_FLAG_PERMANENT, - SKILL_FLAG_TEMPORARY, - SKILL_FLAG_PLAGIARIZED, - SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0' - //... +enum e_skill_flag +{ + SKILL_FLAG_PERMANENT, + SKILL_FLAG_TEMPORARY, + SKILL_FLAG_PLAGIARIZED, + SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0' + //... }; struct s_skill { - unsigned short id; - unsigned char lv; - unsigned char flag; // see enum e_skill_flag + unsigned short id; + unsigned char lv; + unsigned char flag; // see enum e_skill_flag }; struct global_reg { - char str[32]; - char value[256]; + char str[32]; + char value[256]; }; //Holds array of global registries, used by the char server and converter. struct accreg { - int account_id, char_id; - int reg_num; - struct global_reg reg[MAX_REG_NUM]; + int account_id, char_id; + int reg_num; + struct global_reg reg[MAX_REG_NUM]; }; //For saving status changes across sessions. [Skotlex] struct status_change_data { - unsigned short type; //SC_type - long val1, val2, val3, val4, tick; //Remaining duration. + unsigned short type; //SC_type + long val1, val2, val3, val4, tick; //Remaining duration. }; struct storage_data { - int storage_amount; - struct item items[MAX_STORAGE]; + int storage_amount; + struct item items[MAX_STORAGE]; }; struct guild_storage { - int dirty; - int guild_id; - short storage_status; - short storage_amount; - struct item items[MAX_GUILD_STORAGE]; + int dirty; + int guild_id; + short storage_status; + short storage_amount; + struct item items[MAX_GUILD_STORAGE]; }; struct s_pet { - int account_id; - int char_id; - int pet_id; - short class_; - short level; - short egg_id;//pet egg id - short equip;//pet equip name_id - short intimate;//pet friendly - short hungry;//pet hungry - char name[NAME_LENGTH]; - char rename_flag; - char incuvate; -}; - -struct s_homunculus { //[orn] - char name[NAME_LENGTH]; - int hom_id; - int char_id; - short class_; - short prev_class; - int hp,max_hp,sp,max_sp; - unsigned int intimacy; //[orn] - short hunger; - struct s_skill hskill[MAX_HOMUNSKILL]; //albator - short skillpts; - short level; - unsigned int exp; - short rename_flag; - short vaporize; //albator - int str ; - int agi ; - int vit ; - int int_ ; - int dex ; - int luk ; + int account_id; + int char_id; + int pet_id; + short class_; + short level; + short egg_id;//pet egg id + short equip;//pet equip name_id + short intimate;//pet friendly + short hungry;//pet hungry + char name[NAME_LENGTH]; + char rename_flag; + char incuvate; +}; + +struct s_homunculus { //[orn] + char name[NAME_LENGTH]; + int hom_id; + int char_id; + short class_; + short prev_class; + int hp,max_hp,sp,max_sp; + unsigned int intimacy; //[orn] + short hunger; + struct s_skill hskill[MAX_HOMUNSKILL]; //albator + short skillpts; + short level; + unsigned int exp; + short rename_flag; + short vaporize; //albator + int str ; + int agi ; + int vit ; + int int_ ; + int dex ; + int luk ; }; struct s_mercenary { - int mercenary_id; - int char_id; - short class_; - int hp, sp; - unsigned int kill_count; - unsigned int life_time; + int mercenary_id; + int char_id; + short class_; + int hp, sp; + unsigned int kill_count; + unsigned int life_time; }; struct s_elemental { - int elemental_id; - int char_id; - short class_; - int mode; - int hp, sp, max_hp, max_sp, str, agi, vit, int_, dex, luk; - int life_time; + int elemental_id; + int char_id; + short class_; + int mode; + int hp, sp, max_hp, max_sp, str, agi, vit, int_, dex, luk; + int life_time; }; struct s_friend { - int account_id; - int char_id; - char name[NAME_LENGTH]; + int account_id; + int char_id; + char name[NAME_LENGTH]; }; #ifdef HOTKEY_SAVING struct hotkey { - unsigned int id; - unsigned short lv; - unsigned char type; // 0: item, 1: skill + unsigned int id; + unsigned short lv; + unsigned char type; // 0: item, 1: skill }; #endif struct mmo_charstatus { - int char_id; - int account_id; - int partner_id; - int father; - int mother; - int child; - - unsigned int base_exp,job_exp; - int zeny; - - short class_; - unsigned int status_point,skill_point; - int hp,max_hp,sp,max_sp; - unsigned int option; - short manner; - unsigned char karma; - short hair,hair_color,clothes_color; - int party_id,guild_id,pet_id,hom_id,mer_id,ele_id; - int fame; - - // Mercenary Guilds Rank - int arch_faith, arch_calls; - int spear_faith, spear_calls; - int sword_faith, sword_calls; - - short weapon; // enum weapon_type - short shield; // view-id - short head_top,head_mid,head_bottom; - short robe; - - char name[NAME_LENGTH]; - unsigned int base_level,job_level; - short str,agi,vit,int_,dex,luk; - unsigned char slot,sex; - - uint32 mapip; - uint16 mapport; - - struct point last_point,save_point,memo_point[MAX_MEMOPOINTS]; - struct item inventory[MAX_INVENTORY],cart[MAX_CART]; - struct storage_data storage; - struct s_skill skill[MAX_SKILL]; - - struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex] + int char_id; + int account_id; + int partner_id; + int father; + int mother; + int child; + + unsigned int base_exp,job_exp; + int zeny; + + short class_; + unsigned int status_point,skill_point; + int hp,max_hp,sp,max_sp; + unsigned int option; + short manner; + unsigned char karma; + short hair,hair_color,clothes_color; + int party_id,guild_id,pet_id,hom_id,mer_id,ele_id; + int fame; + + // Mercenary Guilds Rank + int arch_faith, arch_calls; + int spear_faith, spear_calls; + int sword_faith, sword_calls; + + short weapon; // enum weapon_type + short shield; // view-id + short head_top,head_mid,head_bottom; + short robe; + + char name[NAME_LENGTH]; + unsigned int base_level,job_level; + short str,agi,vit,int_,dex,luk; + unsigned char slot,sex; + + uint32 mapip; + uint16 mapport; + + struct point last_point,save_point,memo_point[MAX_MEMOPOINTS]; + struct item inventory[MAX_INVENTORY],cart[MAX_CART]; + struct storage_data storage; + struct s_skill skill[MAX_SKILL]; + + struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex] #ifdef HOTKEY_SAVING - struct hotkey hotkeys[MAX_HOTKEYS]; + struct hotkey hotkeys[MAX_HOTKEYS]; #endif - bool show_equip; - short rename; + bool show_equip; + short rename; - time_t delete_date; + time_t delete_date; }; typedef enum mail_status { - MAIL_NEW, - MAIL_UNREAD, - MAIL_READ, + MAIL_NEW, + MAIL_UNREAD, + MAIL_READ, } mail_status; struct mail_message { - int id; - int send_id; - char send_name[NAME_LENGTH]; - int dest_id; - char dest_name[NAME_LENGTH]; - char title[MAIL_TITLE_LENGTH]; - char body[MAIL_BODY_LENGTH]; + int id; + int send_id; + char send_name[NAME_LENGTH]; + int dest_id; + char dest_name[NAME_LENGTH]; + char title[MAIL_TITLE_LENGTH]; + char body[MAIL_BODY_LENGTH]; - mail_status status; - time_t timestamp; // marks when the message was sent + mail_status status; + time_t timestamp; // marks when the message was sent - int zeny; - struct item item; + int zeny; + struct item item; }; struct mail_data { - short amount; - bool full; - short unchecked, unread; - struct mail_message msg[MAIL_MAX_INBOX]; + short amount; + bool full; + short unchecked, unread; + struct mail_message msg[MAIL_MAX_INBOX]; }; struct auction_data { - unsigned int auction_id; - int seller_id; - char seller_name[NAME_LENGTH]; - int buyer_id; - char buyer_name[NAME_LENGTH]; - - struct item item; - // This data is required for searching, as itemdb is not read by char server - char item_name[ITEM_NAME_LENGTH]; - short type; - - unsigned short hours; - int price, buynow; - time_t timestamp; // auction's end time - int auction_end_timer; + unsigned int auction_id; + int seller_id; + char seller_name[NAME_LENGTH]; + int buyer_id; + char buyer_name[NAME_LENGTH]; + + struct item item; + // This data is required for searching, as itemdb is not read by char server + char item_name[ITEM_NAME_LENGTH]; + short type; + + unsigned short hours; + int price, buynow; + time_t timestamp; // auction's end time + int auction_end_timer; }; struct registry { - int global_num; - struct global_reg global[GLOBAL_REG_NUM]; - int account_num; - struct global_reg account[ACCOUNT_REG_NUM]; - int account2_num; - struct global_reg account2[ACCOUNT_REG2_NUM]; + int global_num; + struct global_reg global[GLOBAL_REG_NUM]; + int account_num; + struct global_reg account[ACCOUNT_REG_NUM]; + int account2_num; + struct global_reg account2[ACCOUNT_REG2_NUM]; }; struct party_member { - int account_id; - int char_id; - char name[NAME_LENGTH]; - unsigned short class_; - unsigned short map; - unsigned short lv; - unsigned leader : 1, - online : 1; + int account_id; + int char_id; + char name[NAME_LENGTH]; + unsigned short class_; + unsigned short map; + unsigned short lv; + unsigned leader : 1, + online : 1; }; struct party { - int party_id; - char name[NAME_LENGTH]; - unsigned char count; //Count of online characters. - unsigned exp : 1, - item : 2; //&1: Party-Share (round-robin), &2: pickup style: shared. - struct party_member member[MAX_PARTY]; + int party_id; + char name[NAME_LENGTH]; + unsigned char count; //Count of online characters. + unsigned exp : 1, + item : 2; //&1: Party-Share (round-robin), &2: pickup style: shared. + struct party_member member[MAX_PARTY]; }; struct map_session_data; struct guild_member { - int account_id, char_id; - short hair,hair_color,gender,class_,lv; - uint64 exp; - int exp_payper; - short online,position; - char name[NAME_LENGTH]; - struct map_session_data *sd; - unsigned char modified; + int account_id, char_id; + short hair,hair_color,gender,class_,lv; + uint64 exp; + int exp_payper; + short online,position; + char name[NAME_LENGTH]; + struct map_session_data *sd; + unsigned char modified; }; struct guild_position { - char name[NAME_LENGTH]; - int mode; - int exp_mode; - unsigned char modified; + char name[NAME_LENGTH]; + int mode; + int exp_mode; + unsigned char modified; }; struct guild_alliance { - int opposition; - int guild_id; - char name[NAME_LENGTH]; + int opposition; + int guild_id; + char name[NAME_LENGTH]; }; struct guild_expulsion { - char name[NAME_LENGTH]; - char mes[40]; - int account_id; + char name[NAME_LENGTH]; + char mes[40]; + int account_id; }; struct guild_skill { - int id,lv; + int id,lv; }; struct guild { - int guild_id; - short guild_lv, connect_member, max_member, average_lv; - uint64 exp; - unsigned int next_exp; - int skill_point; - char name[NAME_LENGTH],master[NAME_LENGTH]; - struct guild_member member[MAX_GUILD]; - struct guild_position position[MAX_GUILDPOSITION]; - char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2]; - int emblem_len,emblem_id; - char emblem_data[2048]; - struct guild_alliance alliance[MAX_GUILDALLIANCE]; - struct guild_expulsion expulsion[MAX_GUILDEXPULSION]; - struct guild_skill skill[MAX_GUILDSKILL]; - - unsigned short save_flag; // for TXT saving + int guild_id; + short guild_lv, connect_member, max_member, average_lv; + uint64 exp; + unsigned int next_exp; + int skill_point; + char name[NAME_LENGTH],master[NAME_LENGTH]; + struct guild_member member[MAX_GUILD]; + struct guild_position position[MAX_GUILDPOSITION]; + char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2]; + int emblem_len,emblem_id; + char emblem_data[2048]; + struct guild_alliance alliance[MAX_GUILDALLIANCE]; + struct guild_expulsion expulsion[MAX_GUILDEXPULSION]; + struct guild_skill skill[MAX_GUILDSKILL]; + + unsigned short save_flag; // for TXT saving }; struct guild_castle { - int castle_id; - int mapindex; - char castle_name[NAME_LENGTH]; - char castle_event[NAME_LENGTH]; - int guild_id; - int economy; - int defense; - int triggerE; - int triggerD; - int nextTime; - int payTime; - int createTime; - int visibleC; - struct { - unsigned visible : 1; - int id; // object id - } guardian[MAX_GUARDIANS]; - int *temp_guardians; // ids of temporary guardians (mobs) - int temp_guardians_max; + int castle_id; + int mapindex; + char castle_name[NAME_LENGTH]; + char castle_event[NAME_LENGTH]; + int guild_id; + int economy; + int defense; + int triggerE; + int triggerD; + int nextTime; + int payTime; + int createTime; + int visibleC; + struct { + unsigned visible : 1; + int id; // object id + } guardian[MAX_GUARDIANS]; + int* temp_guardians; // ids of temporary guardians (mobs) + int temp_guardians_max; }; struct fame_list { - int id; - int fame; - char name[NAME_LENGTH]; + int id; + int fame; + char name[NAME_LENGTH]; }; -enum { //Change Guild Infos - GBI_EXP =1, // Guild Experience (EXP) - GBI_GUILDLV, // Guild level - GBI_SKILLPOINT, // Guild skillpoints - GBI_SKILLLV, // Guild skilllv ?? seem unused +enum { //Change Guild Infos + GBI_EXP =1, // Guild Experience (EXP) + GBI_GUILDLV, // Guild level + GBI_SKILLPOINT, // Guild skillpoints + GBI_SKILLLV, // Guild skilllv ?? seem unused }; enum { //Change Member Infos - GMI_POSITION =0, - GMI_EXP, - GMI_HAIR, - GMI_HAIR_COLOR, - GMI_GENDER, - GMI_CLASS, - GMI_LEVEL, + GMI_POSITION =0, + GMI_EXP, + GMI_HAIR, + GMI_HAIR_COLOR, + GMI_GENDER, + GMI_CLASS, + GMI_LEVEL, }; enum { - GD_SKILLBASE=10000, - GD_APPROVAL=10000, - GD_KAFRACONTRACT=10001, - GD_GUARDRESEARCH=10002, - GD_GUARDUP=10003, - GD_EXTENSION=10004, - GD_GLORYGUILD=10005, - GD_LEADERSHIP=10006, - GD_GLORYWOUNDS=10007, - GD_SOULCOLD=10008, - GD_HAWKEYES=10009, - GD_BATTLEORDER=10010, - GD_REGENERATION=10011, - GD_RESTORE=10012, - GD_EMERGENCYCALL=10013, - GD_DEVELOPMENT=10014, - GD_MAX, + GD_SKILLBASE=10000, + GD_APPROVAL=10000, + GD_KAFRACONTRACT=10001, + GD_GUARDRESEARCH=10002, + GD_GUARDUP=10003, + GD_EXTENSION=10004, + GD_GLORYGUILD=10005, + GD_LEADERSHIP=10006, + GD_GLORYWOUNDS=10007, + GD_SOULCOLD=10008, + GD_HAWKEYES=10009, + GD_BATTLEORDER=10010, + GD_REGENERATION=10011, + GD_RESTORE=10012, + GD_EMERGENCYCALL=10013, + GD_DEVELOPMENT=10014, + GD_MAX, }; //These mark the ID of the jobs, as expected by the client. [Skotlex] enum { - JOB_NOVICE, - JOB_SWORDMAN, - JOB_MAGE, - JOB_ARCHER, - JOB_ACOLYTE, - JOB_MERCHANT, - JOB_THIEF, - JOB_KNIGHT, - JOB_PRIEST, - JOB_WIZARD, - JOB_BLACKSMITH, - JOB_HUNTER, - JOB_ASSASSIN, - JOB_KNIGHT2, - JOB_CRUSADER, - JOB_MONK, - JOB_SAGE, - JOB_ROGUE, - JOB_ALCHEMIST, - JOB_BARD, - JOB_DANCER, - JOB_CRUSADER2, - JOB_WEDDING, - JOB_SUPER_NOVICE, - JOB_GUNSLINGER, - JOB_NINJA, - JOB_XMAS, - JOB_SUMMER, - JOB_MAX_BASIC, - - JOB_NOVICE_HIGH = 4001, - JOB_SWORDMAN_HIGH, - JOB_MAGE_HIGH, - JOB_ARCHER_HIGH, - JOB_ACOLYTE_HIGH, - JOB_MERCHANT_HIGH, - JOB_THIEF_HIGH, - JOB_LORD_KNIGHT, - JOB_HIGH_PRIEST, - JOB_HIGH_WIZARD, - JOB_WHITESMITH, - JOB_SNIPER, - JOB_ASSASSIN_CROSS, - JOB_LORD_KNIGHT2, - JOB_PALADIN, - JOB_CHAMPION, - JOB_PROFESSOR, - JOB_STALKER, - JOB_CREATOR, - JOB_CLOWN, - JOB_GYPSY, - JOB_PALADIN2, - - JOB_BABY, - JOB_BABY_SWORDMAN, - JOB_BABY_MAGE, - JOB_BABY_ARCHER, - JOB_BABY_ACOLYTE, - JOB_BABY_MERCHANT, - JOB_BABY_THIEF, - JOB_BABY_KNIGHT, - JOB_BABY_PRIEST, - JOB_BABY_WIZARD, - JOB_BABY_BLACKSMITH, - JOB_BABY_HUNTER, - JOB_BABY_ASSASSIN, - JOB_BABY_KNIGHT2, - JOB_BABY_CRUSADER, - JOB_BABY_MONK, - JOB_BABY_SAGE, - JOB_BABY_ROGUE, - JOB_BABY_ALCHEMIST, - JOB_BABY_BARD, - JOB_BABY_DANCER, - JOB_BABY_CRUSADER2, - JOB_SUPER_BABY, - - JOB_TAEKWON, - JOB_STAR_GLADIATOR, - JOB_STAR_GLADIATOR2, - JOB_SOUL_LINKER, - - JOB_GANGSI, - JOB_DEATH_KNIGHT, - JOB_DARK_COLLECTOR, - - JOB_RUNE_KNIGHT = 4054, - JOB_WARLOCK, - JOB_RANGER, - JOB_ARCH_BISHOP, - JOB_MECHANIC, - JOB_GUILLOTINE_CROSS, - - JOB_RUNE_KNIGHT_T, - JOB_WARLOCK_T, - JOB_RANGER_T, - JOB_ARCH_BISHOP_T, - JOB_MECHANIC_T, - JOB_GUILLOTINE_CROSS_T, - - JOB_ROYAL_GUARD, - JOB_SORCERER, - JOB_MINSTREL, - JOB_WANDERER, - JOB_SURA, - JOB_GENETIC, - JOB_SHADOW_CHASER, - - JOB_ROYAL_GUARD_T, - JOB_SORCERER_T, - JOB_MINSTREL_T, - JOB_WANDERER_T, - JOB_SURA_T, - JOB_GENETIC_T, - JOB_SHADOW_CHASER_T, - - JOB_RUNE_KNIGHT2, - JOB_RUNE_KNIGHT_T2, - JOB_ROYAL_GUARD2, - JOB_ROYAL_GUARD_T2, - JOB_RANGER2, - JOB_RANGER_T2, - JOB_MECHANIC2, - JOB_MECHANIC_T2, - - JOB_BABY_RUNE = 4096, - JOB_BABY_WARLOCK, - JOB_BABY_RANGER, - JOB_BABY_BISHOP, - JOB_BABY_MECHANIC, - JOB_BABY_CROSS, - - JOB_BABY_GUARD, - JOB_BABY_SORCERER, - JOB_BABY_MINSTREL, - JOB_BABY_WANDERER, - JOB_BABY_SURA, - JOB_BABY_GENETIC, - JOB_BABY_CHASER, - - JOB_BABY_RUNE2, - JOB_BABY_GUARD2, - JOB_BABY_RANGER2, - JOB_BABY_MECHANIC2, - - JOB_SUPER_NOVICE_E = 4190, - JOB_SUPER_BABY_E, - - JOB_KAGEROU = 4211, - JOB_OBORO, - - JOB_MAX, + JOB_NOVICE, + JOB_SWORDMAN, + JOB_MAGE, + JOB_ARCHER, + JOB_ACOLYTE, + JOB_MERCHANT, + JOB_THIEF, + JOB_KNIGHT, + JOB_PRIEST, + JOB_WIZARD, + JOB_BLACKSMITH, + JOB_HUNTER, + JOB_ASSASSIN, + JOB_KNIGHT2, + JOB_CRUSADER, + JOB_MONK, + JOB_SAGE, + JOB_ROGUE, + JOB_ALCHEMIST, + JOB_BARD, + JOB_DANCER, + JOB_CRUSADER2, + JOB_WEDDING, + JOB_SUPER_NOVICE, + JOB_GUNSLINGER, + JOB_NINJA, + JOB_XMAS, + JOB_SUMMER, + JOB_MAX_BASIC, + + JOB_NOVICE_HIGH = 4001, + JOB_SWORDMAN_HIGH, + JOB_MAGE_HIGH, + JOB_ARCHER_HIGH, + JOB_ACOLYTE_HIGH, + JOB_MERCHANT_HIGH, + JOB_THIEF_HIGH, + JOB_LORD_KNIGHT, + JOB_HIGH_PRIEST, + JOB_HIGH_WIZARD, + JOB_WHITESMITH, + JOB_SNIPER, + JOB_ASSASSIN_CROSS, + JOB_LORD_KNIGHT2, + JOB_PALADIN, + JOB_CHAMPION, + JOB_PROFESSOR, + JOB_STALKER, + JOB_CREATOR, + JOB_CLOWN, + JOB_GYPSY, + JOB_PALADIN2, + + JOB_BABY, + JOB_BABY_SWORDMAN, + JOB_BABY_MAGE, + JOB_BABY_ARCHER, + JOB_BABY_ACOLYTE, + JOB_BABY_MERCHANT, + JOB_BABY_THIEF, + JOB_BABY_KNIGHT, + JOB_BABY_PRIEST, + JOB_BABY_WIZARD, + JOB_BABY_BLACKSMITH, + JOB_BABY_HUNTER, + JOB_BABY_ASSASSIN, + JOB_BABY_KNIGHT2, + JOB_BABY_CRUSADER, + JOB_BABY_MONK, + JOB_BABY_SAGE, + JOB_BABY_ROGUE, + JOB_BABY_ALCHEMIST, + JOB_BABY_BARD, + JOB_BABY_DANCER, + JOB_BABY_CRUSADER2, + JOB_SUPER_BABY, + + JOB_TAEKWON, + JOB_STAR_GLADIATOR, + JOB_STAR_GLADIATOR2, + JOB_SOUL_LINKER, + + JOB_GANGSI, + JOB_DEATH_KNIGHT, + JOB_DARK_COLLECTOR, + + JOB_RUNE_KNIGHT = 4054, + JOB_WARLOCK, + JOB_RANGER, + JOB_ARCH_BISHOP, + JOB_MECHANIC, + JOB_GUILLOTINE_CROSS, + + JOB_RUNE_KNIGHT_T, + JOB_WARLOCK_T, + JOB_RANGER_T, + JOB_ARCH_BISHOP_T, + JOB_MECHANIC_T, + JOB_GUILLOTINE_CROSS_T, + + JOB_ROYAL_GUARD, + JOB_SORCERER, + JOB_MINSTREL, + JOB_WANDERER, + JOB_SURA, + JOB_GENETIC, + JOB_SHADOW_CHASER, + + JOB_ROYAL_GUARD_T, + JOB_SORCERER_T, + JOB_MINSTREL_T, + JOB_WANDERER_T, + JOB_SURA_T, + JOB_GENETIC_T, + JOB_SHADOW_CHASER_T, + + JOB_RUNE_KNIGHT2, + JOB_RUNE_KNIGHT_T2, + JOB_ROYAL_GUARD2, + JOB_ROYAL_GUARD_T2, + JOB_RANGER2, + JOB_RANGER_T2, + JOB_MECHANIC2, + JOB_MECHANIC_T2, + + JOB_BABY_RUNE = 4096, + JOB_BABY_WARLOCK, + JOB_BABY_RANGER, + JOB_BABY_BISHOP, + JOB_BABY_MECHANIC, + JOB_BABY_CROSS, + + JOB_BABY_GUARD, + JOB_BABY_SORCERER, + JOB_BABY_MINSTREL, + JOB_BABY_WANDERER, + JOB_BABY_SURA, + JOB_BABY_GENETIC, + JOB_BABY_CHASER, + + JOB_BABY_RUNE2, + JOB_BABY_GUARD2, + JOB_BABY_RANGER2, + JOB_BABY_MECHANIC2, + + JOB_SUPER_NOVICE_E = 4190, + JOB_SUPER_BABY_E, + + JOB_KAGEROU = 4211, + JOB_OBORO, + + JOB_MAX, }; enum { - SEX_FEMALE = 0, - SEX_MALE, - SEX_SERVER + SEX_FEMALE = 0, + SEX_MALE, + SEX_SERVER }; // sanity checks... diff --git a/src/common/mutex.c b/src/common/mutex.c index 813bef31b..6b4f55119 100644 --- a/src/common/mutex.c +++ b/src/common/mutex.c @@ -15,26 +15,26 @@ #include "../common/timer.h" #include "../common/mutex.h" -struct ramutex { +struct ramutex{ #ifdef WIN32 - CRITICAL_SECTION hMutex; + CRITICAL_SECTION hMutex; #else - pthread_mutex_t hMutex; + pthread_mutex_t hMutex; #endif }; -struct racond { +struct racond{ #ifdef WIN32 - HANDLE events[2]; - ra_align(8) volatile LONG nWaiters; - CRITICAL_SECTION waiters_lock; + HANDLE events[2]; + ra_align(8) volatile LONG nWaiters; + CRITICAL_SECTION waiters_lock; #define EVENT_COND_SIGNAL 0 #define EVENT_COND_BROADCAST 1 #else - pthread_cond_t hCond; + pthread_cond_t hCond; #endif }; @@ -46,73 +46,68 @@ struct racond { // -ramutex ramutex_create() -{ - struct ramutex *m; - - m = (struct ramutex *)aMalloc(sizeof(struct ramutex)); - if (m == NULL) { - ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex)); - return NULL; - } - +ramutex ramutex_create(){ + struct ramutex *m; + + m = (struct ramutex*)aMalloc( sizeof(struct ramutex) ); + if(m == NULL){ + ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex)); + return NULL; + } + #ifdef WIN32 - InitializeCriticalSection(&m->hMutex); + InitializeCriticalSection(&m->hMutex); #else - pthread_mutex_init(&m->hMutex, NULL); + pthread_mutex_init(&m->hMutex, NULL); #endif - - return m; + + return m; }//end: ramutex_create() -void ramutex_destroy(ramutex m) -{ +void ramutex_destroy( ramutex m ){ #ifdef WIN32 - DeleteCriticalSection(&m->hMutex); + DeleteCriticalSection(&m->hMutex); #else - pthread_mutex_destroy(&m->hMutex); + pthread_mutex_destroy(&m->hMutex); #endif - aFree(m); + aFree(m); }//end: ramutex_destroy() -void ramutex_lock(ramutex m) -{ +void ramutex_lock( ramutex m ){ #ifdef WIN32 - EnterCriticalSection(&m->hMutex); + EnterCriticalSection(&m->hMutex); #else - pthread_mutex_lock(&m->hMutex); + pthread_mutex_lock(&m->hMutex); #endif }//end: ramutex_lock -bool ramutex_trylock(ramutex m) -{ +bool ramutex_trylock( ramutex m ){ #ifdef WIN32 - if (TryEnterCriticalSection(&m->hMutex) == TRUE) - return true; + if(TryEnterCriticalSection(&m->hMutex) == TRUE) + return true; - return false; + return false; #else - if (pthread_mutex_trylock(&m->hMutex) == 0) - return true; - - return false; + if(pthread_mutex_trylock(&m->hMutex) == 0) + return true; + + return false; #endif }//end: ramutex_trylock() -void ramutex_unlock(ramutex m) -{ +void ramutex_unlock( ramutex m ){ #ifdef WIN32 - LeaveCriticalSection(&m->hMutex); + LeaveCriticalSection(&m->hMutex); #else - pthread_mutex_unlock(&m->hMutex); + pthread_mutex_unlock(&m->hMutex); #endif }//end: ramutex_unlock() @@ -121,136 +116,131 @@ void ramutex_unlock(ramutex m) /////////////// // Condition Variables -// +// // Implementation: // -racond racond_create() -{ - struct racond *c; - - c = (struct racond *)aMalloc(sizeof(struct racond)); - if (c == NULL) { - ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond)); - return NULL; - } +racond racond_create(){ + struct racond *c; + + c = (struct racond*)aMalloc( sizeof(struct racond) ); + if(c == NULL){ + ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond)); + return NULL; + } #ifdef WIN32 - c->nWaiters = 0; - c->events[ EVENT_COND_SIGNAL ] = CreateEvent(NULL, FALSE, FALSE, NULL); - c->events[ EVENT_COND_BROADCAST ] = CreateEvent(NULL, TRUE, FALSE, NULL); - InitializeCriticalSection(&c->waiters_lock); + c->nWaiters = 0; + c->events[ EVENT_COND_SIGNAL ] = CreateEvent( NULL, FALSE, FALSE, NULL ); + c->events[ EVENT_COND_BROADCAST ] = CreateEvent( NULL, TRUE, FALSE, NULL ); + InitializeCriticalSection( &c->waiters_lock ); #else - pthread_cond_init(&c->hCond, NULL); + pthread_cond_init(&c->hCond, NULL); #endif - - return c; + + return c; }//end: racond_create() -void racond_destroy(racond c) -{ +void racond_destroy( racond c ){ #ifdef WIN32 - CloseHandle(c->events[ EVENT_COND_SIGNAL ]); - CloseHandle(c->events[ EVENT_COND_BROADCAST ]); - DeleteCriticalSection(&c->waiters_lock); + CloseHandle( c->events[ EVENT_COND_SIGNAL ] ); + CloseHandle( c->events[ EVENT_COND_BROADCAST ] ); + DeleteCriticalSection( &c->waiters_lock ); #else - pthread_cond_destroy(&c->hCond); + pthread_cond_destroy(&c->hCond); #endif - aFree(c); + aFree(c); }//end: racond_destroy() -void racond_wait(racond c, ramutex m, sysint timeout_ticks) -{ +void racond_wait( racond c, ramutex m, sysint timeout_ticks){ #ifdef WIN32 - register DWORD ms; - int result; - bool is_last = false; + register DWORD ms; + int result; + bool is_last = false; - EnterCriticalSection(&c->waiters_lock); - c->nWaiters++; - LeaveCriticalSection(&c->waiters_lock); + EnterCriticalSection(&c->waiters_lock); + c->nWaiters++; + LeaveCriticalSection(&c->waiters_lock); - if (timeout_ticks < 0) - ms = INFINITE; - else - ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks; + if(timeout_ticks < 0) + ms = INFINITE; + else + ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks; + + + // we can release the mutex (m) here, cause win's + // manual reset events maintain state when used with + // SetEvent() + ramutex_unlock(m); + result = WaitForMultipleObjects(2, c->events, FALSE, ms); + + + EnterCriticalSection(&c->waiters_lock); + c->nWaiters--; + if( (result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0) ) + is_last = true; // Broadcast called! + LeaveCriticalSection(&c->waiters_lock); - // we can release the mutex (m) here, cause win's - // manual reset events maintain state when used with - // SetEvent() - ramutex_unlock(m); + - result = WaitForMultipleObjects(2, c->events, FALSE, ms); + // we are the last waiter that has to be notified, or to stop waiting + // so we have to do a manual reset + if(is_last == true) + ResetEvent( c->events[EVENT_COND_BROADCAST] ); - EnterCriticalSection(&c->waiters_lock); - c->nWaiters--; - if ((result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0)) - is_last = true; // Broadcast called! - LeaveCriticalSection(&c->waiters_lock); - - - - // we are the last waiter that has to be notified, or to stop waiting - // so we have to do a manual reset - if (is_last == true) - ResetEvent(c->events[EVENT_COND_BROADCAST]); - - - ramutex_lock(m); + ramutex_lock(m); #else - if (timeout_ticks < 0) { - pthread_cond_wait(&c->hCond, &m->hMutex); - } else { - struct timespec wtime; - int64 exact_timeout = gettick() + timeout_ticks; - - wtime.tv_sec = exact_timeout/1000; - wtime.tv_nsec = (exact_timeout%1000)*1000000; - - pthread_cond_timedwait(&c->hCond, &m->hMutex, &wtime); - } + if(timeout_ticks < 0){ + pthread_cond_wait( &c->hCond, &m->hMutex ); + }else{ + struct timespec wtime; + int64 exact_timeout = gettick() + timeout_ticks; + + wtime.tv_sec = exact_timeout/1000; + wtime.tv_nsec = (exact_timeout%1000)*1000000; + + pthread_cond_timedwait( &c->hCond, &m->hMutex, &wtime); + } #endif }//end: racond_wait() -void racond_signal(racond c) -{ +void racond_signal( racond c ){ #ifdef WIN32 - // bool has_waiters = false; - // EnterCriticalSection(&c->waiters_lock); - // if(c->nWaiters > 0) - // has_waiters = true; - // LeaveCriticalSection(&c->waiters_lock); - - // if(has_waiters == true) - SetEvent(c->events[ EVENT_COND_SIGNAL ]); +// bool has_waiters = false; +// EnterCriticalSection(&c->waiters_lock); +// if(c->nWaiters > 0) +// has_waiters = true; +// LeaveCriticalSection(&c->waiters_lock); + +// if(has_waiters == true) + SetEvent( c->events[ EVENT_COND_SIGNAL ] ); #else - pthread_cond_signal(&c->hCond); + pthread_cond_signal(&c->hCond); #endif }//end: racond_signal() -void racond_broadcast(racond c) -{ +void racond_broadcast( racond c ){ #ifdef WIN32 - // bool has_waiters = false; - // EnterCriticalSection(&c->waiters_lock); - // if(c->nWaiters > 0) - // has_waiters = true; - // LeaveCriticalSection(&c->waiters_lock); - - // if(has_waiters == true) - SetEvent(c->events[ EVENT_COND_BROADCAST ]); +// bool has_waiters = false; +// EnterCriticalSection(&c->waiters_lock); +// if(c->nWaiters > 0) +// has_waiters = true; +// LeaveCriticalSection(&c->waiters_lock); + +// if(has_waiters == true) + SetEvent( c->events[ EVENT_COND_BROADCAST ] ); #else - pthread_cond_broadcast(&c->hCond); + pthread_cond_broadcast(&c->hCond); #endif }//end: racond_broadcast() diff --git a/src/common/mutex.h b/src/common/mutex.h index abef731f4..1999627cd 100644 --- a/src/common/mutex.h +++ b/src/common/mutex.h @@ -1,5 +1,5 @@ // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// For more information, see LICENCE in the main folder #ifndef _rA_MUTEX_H_ #define _rA_MUTEX_H_ @@ -9,67 +9,67 @@ typedef struct ramutex *ramutex; // Mutex typedef struct racond *racond; // Condition Var /** - * Creates a Mutex + * Creates a Mutex * * @return not NULL */ ramutex ramutex_create(); -/** +/** * Destroys a Mutex - * + * * @param m - the mutex to destroy */ -void ramutex_destroy(ramutex m); +void ramutex_destroy( ramutex m ); -/** +/** * Gets a lock * * @param m - the mutex to lock */ -void ramutex_lock(ramutex m); +void ramutex_lock( ramutex m); -/** +/** * Trys to get the Lock - * + * * @param m - the mutex try to lock - * + * * @return boolean (true = got the lock) */ -bool ramutex_trylock(ramutex m); +bool ramutex_trylock( ramutex m ); -/** +/** * Unlocks a mutex * * @param m - the mutex to unlock */ -void ramutex_unlock(ramutex m); +void ramutex_unlock( ramutex m); -/** +/** * Creates a Condition variable * * @return not NULL */ racond racond_create(); -/** +/** * Destroy a Condition variable * * @param c - the condition varaible to destroy */ -void racond_destroy(racond c); +void racond_destroy( racond c ); /** * Waits Until state is signalled - * - * @param c - the condition var to wait for signalled state + * + * @param c - the condition var to wait for signalled state * @param m - the mutex used for syncronization * @param timeout_ticks - timeout in ticks ( -1 = INFINITE ) */ -void racond_wait(racond c, ramutex m, sysint timeout_ticks); +void racond_wait( racond c, ramutex m, sysint timeout_ticks); -/** +/** * Sets the given condition var to signalled state * * @param c - condition var to set in signalled state. @@ -77,16 +77,16 @@ void racond_wait(racond c, ramutex m, sysint timeout_ticks); * @note: * Only one waiter gets notified. */ -void racond_signal(racond c); +void racond_signal( racond c ); -/** +/** * Sets notifys all waiting threads thats signalled. * @param c - condition var to set in signalled state - * + * * @note: * All Waiters getting notified. - */ -void racond_broadcast(racond c); + */ +void racond_broadcast( racond c ); #endif diff --git a/src/common/netbuffer.c b/src/common/netbuffer.c index 9ce13ffc3..57742d612 100644 --- a/src/common/netbuffer.c +++ b/src/common/netbuffer.c @@ -26,10 +26,10 @@ #include "../common/netbuffer.h" -// +// // Buffers are available in the following sizes: -// 48, 192, 2048, 8192 -// 65536 (inter server connects may use it for charstatus struct..) +// 48, 192, 2048, 8192 +// 65536 (inter server connects may use it for charstatus struct..) // @@ -42,197 +42,180 @@ static sysint *l_poolElemSize = NULL; static mempool *l_pool = NULL; -void netbuffer_init() -{ - char localsection[32]; - raconf conf; - sysint i; - - // Initialize Statistic counters: - l_nEmergencyAllocations = 0; - - // Set localsection name according to running serverype. - switch (SERVER_TYPE) { - case ATHENA_SERVER_LOGIN: - strcpy(localsection, "login-netbuffer"); - break; - case ATHENA_SERVER_CHAR: - strcpy(localsection, "char-netbuffer"); - break; - case ATHENA_SERVER_INTER: - strcpy(localsection, "inter-netbuffer"); - break; - case ATHENA_SERVER_MAP: - strcpy(localsection, "map-netbuffer"); - break; - default: - strcpy(localsection, "unsupported_type"); - break; - } - - - conf = raconf_parse("conf/network.conf"); - if (conf == NULL) { - ShowFatalError("Failed to Parse required Configuration (conf/network.conf)"); - exit(EXIT_FAILURE); - } - - // Get Values from config file - l_nPools = (sysint)raconf_getintEx(conf, localsection, "netbuffer", "num", 0); - if (l_nPools == 0) { - ShowFatalError("Netbuffer (network.conf) failure - requires at least 1 Pool.\n"); - exit(EXIT_FAILURE); - } - - // Allocate arrays. - l_poolElemSize = (sysint *)aCalloc(l_nPools, sizeof(sysint)); - l_pool = (mempool *)aCalloc(l_nPools, sizeof(mempool)); - - - for (i = 0; i < l_nPools; i++) { - int64 num_prealloc, num_realloc; - char key[32]; - - sprintf(key, "pool_%u_size", (uint32)i+1); - l_poolElemSize[i] = (sysint)raconf_getintEx(conf, localsection, "netbuffer", key, 4096); - if (l_poolElemSize[i] < 32) { - ShowWarning("Netbuffer (network.conf) failure - minimum allowed buffer size is 32 byte) - fixed.\n"); - l_poolElemSize[i] = 32; - } - - sprintf(key, "pool_%u_prealloc", (uint32)i+1); - num_prealloc = raconf_getintEx(conf, localsection, "netbuffer", key, 150); - - sprintf(key, "pool_%u_realloc_step", (uint32)i+1); - num_realloc = raconf_getintEx(conf, localsection, "netbuffer", key, 100); - - // Create Pool! - sprintf(key, "Netbuffer %u", (uint32)l_poolElemSize[i]); // name. - - // Info - ShowInfo("NetBuffer: Creating Pool %u (Prealloc: %u, Realloc Step: %u) - %0.2f MiB\n", l_poolElemSize[i], num_prealloc, num_realloc, (float)((sizeof(struct netbuf) + l_poolElemSize[i] - 32)* num_prealloc)/1024.0f/1024.0f); - - // - // Size Calculation: - // struct netbuf + requested buffer size - 32 (because the struct already contains 32 byte buffer space at the end of struct) - l_pool[i] = mempool_create(key, (sizeof(struct netbuf) + l_poolElemSize[i] - 32), num_prealloc, num_realloc, NULL, NULL); - if (l_pool[i] == NULL) { - ShowFatalError("Netbuffer: cannot create Pool for %u byte buffers.\n", l_poolElemSize[i]); - // @leak: clean everything :D - exit(EXIT_FAILURE); - } - - }// - - - raconf_destroy(conf); +void netbuffer_init(){ + char localsection[32]; + raconf conf; + sysint i; + + // Initialize Statistic counters: + l_nEmergencyAllocations = 0; + + // Set localsection name according to running serverype. + switch(SERVER_TYPE){ + case ATHENA_SERVER_LOGIN: strcpy(localsection, "login-netbuffer"); break; + case ATHENA_SERVER_CHAR: strcpy(localsection, "char-netbuffer"); break; + case ATHENA_SERVER_INTER: strcpy(localsection, "inter-netbuffer"); break; + case ATHENA_SERVER_MAP: strcpy(localsection, "map-netbuffer"); break; + default: strcpy(localsection, "unsupported_type"); break; + } + + + conf = raconf_parse("conf/network.conf"); + if(conf == NULL){ + ShowFatalError("Failed to Parse required Configuration (conf/network.conf)"); + exit(EXIT_FAILURE); + } + + // Get Values from config file + l_nPools = (sysint)raconf_getintEx(conf, localsection, "netbuffer", "num", 0); + if(l_nPools == 0){ + ShowFatalError("Netbuffer (network.conf) failure - requires at least 1 Pool.\n"); + exit(EXIT_FAILURE); + } + + // Allocate arrays. + l_poolElemSize = (sysint*)aCalloc( l_nPools, sizeof(sysint) ); + l_pool = (mempool*)aCalloc( l_nPools, sizeof(mempool) ); + + + for(i = 0; i < l_nPools; i++){ + int64 num_prealloc, num_realloc; + char key[32]; + + sprintf(key, "pool_%u_size", (uint32)i+1); + l_poolElemSize[i] = (sysint)raconf_getintEx(conf, localsection, "netbuffer", key, 4096); + if(l_poolElemSize[i] < 32){ + ShowWarning("Netbuffer (network.conf) failure - minimum allowed buffer size is 32 byte) - fixed.\n"); + l_poolElemSize[i] = 32; + } + + sprintf(key, "pool_%u_prealloc", (uint32)i+1); + num_prealloc = raconf_getintEx(conf, localsection, "netbuffer", key, 150); + + sprintf(key, "pool_%u_realloc_step", (uint32)i+1); + num_realloc = raconf_getintEx(conf, localsection, "netbuffer", key, 100); + + // Create Pool! + sprintf(key, "Netbuffer %u", (uint32)l_poolElemSize[i]); // name. + + // Info + ShowInfo("NetBuffer: Creating Pool %u (Prealloc: %u, Realloc Step: %u) - %0.2f MiB\n", l_poolElemSize[i], num_prealloc, num_realloc, (float)((sizeof(struct netbuf) + l_poolElemSize[i] - 32)* num_prealloc)/1024.0f/1024.0f); + + // + // Size Calculation: + // struct netbuf + requested buffer size - 32 (because the struct already contains 32 byte buffer space at the end of struct) + l_pool[i] = mempool_create(key, (sizeof(struct netbuf) + l_poolElemSize[i] - 32), num_prealloc, num_realloc, NULL, NULL); + if(l_pool[i] == NULL){ + ShowFatalError("Netbuffer: cannot create Pool for %u byte buffers.\n", l_poolElemSize[i]); + // @leak: clean everything :D + exit(EXIT_FAILURE); + } + + }// + + + raconf_destroy(conf); }//end: netbuffer_init() -void netbuffer_final() -{ - sysint i; - - if (l_nPools > 0) { - /// .. finalize mempools - for (i = 0; i < l_nPools; i++) { - mempool_stats stats = mempool_get_stats(l_pool[i]); - - ShowInfo("Netbuffer: Freeing Pool %u (Peak Usage: %u, Realloc Events: %u)\n", l_poolElemSize[i], stats.peak_nodes_used, stats.num_realloc_events); - - mempool_destroy(l_pool[i]); - } - - if (l_nEmergencyAllocations > 0) { - ShowWarning("Netbuffer: did %u Emergency Allocations, please tune your network.conf!\n", l_nEmergencyAllocations); - l_nEmergencyAllocations = 0; - } - - aFree(l_poolElemSize); - l_poolElemSize = NULL; - aFree(l_pool); - l_pool = NULL; - l_nPools = 0; - } - - +void netbuffer_final(){ + sysint i; + + if(l_nPools > 0){ + /// .. finalize mempools + for(i = 0; i < l_nPools; i++){ + mempool_stats stats = mempool_get_stats(l_pool[i]); + + ShowInfo("Netbuffer: Freeing Pool %u (Peak Usage: %u, Realloc Events: %u)\n", l_poolElemSize[i], stats.peak_nodes_used, stats.num_realloc_events); + + mempool_destroy(l_pool[i]); + } + + if(l_nEmergencyAllocations > 0){ + ShowWarning("Netbuffer: did %u Emergency Allocations, please tune your network.conf!\n", l_nEmergencyAllocations); + l_nEmergencyAllocations = 0; + } + + aFree(l_poolElemSize); l_poolElemSize = NULL; + aFree(l_pool); l_pool = NULL; + l_nPools = 0; + } + + }//end: netbuffer_final() -netbuf netbuffer_get(sysint sz) -{ - sysint i; - netbuf nb = NULL; - - // Search an appropriate pool - for (i = 0; i < l_nPools; i++) { - if (sz <= l_poolElemSize[i]) { - // match - - nb = (netbuf)mempool_node_get(l_pool[i]); - nb->pool = i; - - break; - } - } - - // No Bufferpool found that mets there quirements?.. (thats bad..) - if (nb == NULL) { - ShowWarning("Netbuffer: get(%u): => no appropriate pool found - emergency allocation required.\n", sz); - ShowWarning("Please reconfigure your network.conf!"); - - InterlockedIncrement(&l_nEmergencyAllocations); - - // .. better to check (netbuf struct provides 32 byte bufferspace itself. - if (sz < 32) sz = 32; - - // allocate memory using malloc .. - while (1) { - nb = (netbuf) aMalloc((sizeof(struct netbuf) + sz - 32)); - if (nb != NULL) { - memset(nb, 0x00, (sizeof(struct netbuf) + sz - 32)); // zero memory! (to enforce commit @ os.) - nb->pool = -1; // emergency alloc. - break; - } - - rathread_yield(); - }// spin allocation. - - } - - - nb->refcnt = 1; // Initial refcount is 1 - - return nb; +netbuf netbuffer_get( sysint sz ){ + sysint i; + netbuf nb = NULL; + + // Search an appropriate pool + for(i = 0; i < l_nPools; i++){ + if(sz <= l_poolElemSize[i]){ + // match + + nb = (netbuf)mempool_node_get(l_pool[i]); + nb->pool = i; + + break; + } + } + + // No Bufferpool found that mets there quirements?.. (thats bad..) + if(nb == NULL){ + ShowWarning("Netbuffer: get(%u): => no appropriate pool found - emergency allocation required.\n", sz); + ShowWarning("Please reconfigure your network.conf!"); + + InterlockedIncrement(&l_nEmergencyAllocations); + + // .. better to check (netbuf struct provides 32 byte bufferspace itself. + if(sz < 32) sz = 32; + + // allocate memory using malloc .. + while(1){ + nb = (netbuf) aMalloc( (sizeof(struct netbuf) + sz - 32) ); + if(nb != NULL){ + memset(nb, 0x00, (sizeof(struct netbuf) + sz - 32) ); // zero memory! (to enforce commit @ os.) + nb->pool = -1; // emergency alloc. + break; + } + + rathread_yield(); + }// spin allocation. + + } + + + nb->refcnt = 1; // Initial refcount is 1 + + return nb; }//end: netbuffer_get() -void netbuffer_put(netbuf nb) -{ - - // Decrement reference counter, if > 0 do nothing :) - if (InterlockedDecrement(&nb->refcnt) > 0) - return; - - // Is this buffer an emergency allocated buffer? - if (nb->pool == -1) { - aFree(nb); - return; - } - - - // Otherwise its a normal mempool based buffer - // return it to the according mempool: - mempool_node_put(l_pool[nb->pool], nb); - - +void netbuffer_put( netbuf nb ){ + + // Decrement reference counter, if > 0 do nothing :) + if( InterlockedDecrement(&nb->refcnt) > 0 ) + return; + + // Is this buffer an emergency allocated buffer? + if(nb->pool == -1){ + aFree(nb); + return; + } + + + // Otherwise its a normal mempool based buffer + // return it to the according mempool: + mempool_node_put( l_pool[nb->pool], nb); + + }//end: netbuffer_put() -void netbuffer_incref(netbuf nb) -{ - - InterlockedIncrement(&nb->refcnt); - +void netbuffer_incref( netbuf nb ){ + + InterlockedIncrement(&nb->refcnt); + }//end: netbuf_incref() diff --git a/src/common/netbuffer.h b/src/common/netbuffer.h index a4feb7287..844241226 100644 --- a/src/common/netbuffer.h +++ b/src/common/netbuffer.h @@ -6,37 +6,37 @@ #include "../common/cbasetypes.h" -typedef struct netbuf { - sysint pool; // The pool ID this buffer belongs to, - // is set to -1 if its an emergency allocated buffer - - struct netbuf *next; // Used by Network system. - - volatile int32 refcnt; // Internal Refcount, it gets lowered every call to netbuffer_put, - // if its getting zero, the buffer will returned back to the pool - // and can be reused. - - int32 dataPos; // Current Offset - // Used only for Reading (recv job) - // write cases are using the sessions local datapos member due to - // shared write buffer support. - - int32 dataLen; // read buffer case: - // The length expected to read to. - // when this->dataPos == dateLen, read job has been completed. - // write buffer case: - // The lngth of data in te buffer - // when s->dataPos == dataLen, write job has been completed - // - // Note: - // leftBytes = (dateLen - dataPos) - // - // Due to shared buffer support - // dataPos gets not used in write case (each connection has its local offset) - // - - // The Bufferspace itself. - char buf[32]; +typedef struct netbuf{ + sysint pool; // The pool ID this buffer belongs to, + // is set to -1 if its an emergency allocated buffer + + struct netbuf *next; // Used by Network system. + + volatile int32 refcnt; // Internal Refcount, it gets lowered every call to netbuffer_put, + // if its getting zero, the buffer will returned back to the pool + // and can be reused. + + int32 dataPos; // Current Offset + // Used only for Reading (recv job) + // write cases are using the sessions local datapos member due to + // shared write buffer support. + + int32 dataLen; // read buffer case: + // The length expected to read to. + // when this->dataPos == dateLen, read job has been completed. + // write buffer case: + // The lngth of data in te buffer + // when s->dataPos == dataLen, write job has been completed + // + // Note: + // leftBytes = (dateLen - dataPos) + // + // Due to shared buffer support + // dataPos gets not used in write case (each connection has its local offset) + // + + // The Bufferspace itself. + char buf[32]; } *netbuf; @@ -47,29 +47,29 @@ void netbuffer_final(); * Gets a netbuffer that has atleast (sz) byes space. * * @note: The netbuffer system guarantees that youll always recevie a buffer. - * no check for null is required! + * no check for null is required! * * @param sz - minimum size needed. * * @return pointer to netbuf struct */ -netbuf netbuffer_get(sysint sz); +netbuf netbuffer_get( sysint sz ); -/** +/** * Returns the given netbuffer (decreases refcount, if its 0 - the buffer will get returned to the pool) * - * @param buf - the buffer to return + * @param buf - the buffer to return */ -void netbuffer_put(netbuf buf); +void netbuffer_put( netbuf buf ); -/** - * Increases the Refcount on the given buffer +/** + * Increases the Refcount on the given buffer * (used for areasends .. etc) * */ -void netbuffer_incref(netbuf buf); +void netbuffer_incref( netbuf buf ); // Some Useful macros diff --git a/src/common/network.c b/src/common/network.c index 1c968200d..1f1621363 100644 --- a/src/common/network.c +++ b/src/common/network.c @@ -51,1020 +51,1011 @@ static bool onSend(int32 fd); #define _network_free_netbuf_async( buf ) add_timer( 0, _network_async_free_netbuf_proc, 0, (intptr_t) buf) -static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data) -{ - // netbuf is in data - netbuffer_put((netbuf)data); +static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data){ + // netbuf is in data + netbuffer_put( (netbuf)data ); - return 0; + return 0; }//end: _network_async_free_netbuf_proc() -void network_init() -{ - SESSION *s; - int32 i; - - memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN)); - - for (i = 0; i < MAXCONN; i++) { - s = &g_Session[i]; - - s->type = NST_FREE; - s->disconnect_in_progress = false; - - } - - // Initialize the correspondig event dispatcher - evdp_init(); - - // - add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); - +void network_init(){ + SESSION *s; + int32 i; + + memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN) ); + + for(i = 0; i < MAXCONN; i++){ + s = &g_Session[i]; + + s->type = NST_FREE; + s->disconnect_in_progress = false; + + } + + // Initialize the correspondig event dispatcher + evdp_init(); + + // + add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); + }//end: network_init() -void network_final() -{ - - // @TODO: - // .. disconnect and cleanup everything! +void network_final(){ - evdp_final(); + // @TODO: + // .. disconnect and cleanup everything! + + evdp_final(); }//end: network_final() -void network_do() -{ - struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; - register struct EVDP_EVENT *ev; - register int n, nfds; - register SESSION *s; - - nfds = evdp_wait(l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() - - for (n = 0; n < nfds; n++) { - ev = &l_events[n]; - s = &g_Session[ ev->fd ]; - - if (ev->events & EVDP_EVENT_HUP) { - network_disconnect(ev->fd); - continue; // no further event processing. - }// endif vent is HUP (disconnect) - - - if (ev->events & EVDP_EVENT_IN) { - - if (s->onRecv != NULL) { - if (false == s->onRecv(ev->fd)) { - network_disconnect(ev->fd); - continue; // .. - } - } else { - ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - - }// endif event is IN (recv) - - - if (ev->events & EVDP_EVENT_OUT) { - if (s->onSend != NULL) { - if (false == s->onSend(ev->fd)) { - network_disconnect(ev->fd); - continue; - } - } else { - ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - }// endif event is OUT (send) - - }//endfor - +void network_do(){ + struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; + register struct EVDP_EVENT *ev; + register int n, nfds; + register SESSION *s; + + nfds = evdp_wait( l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() + + for(n = 0; n < nfds; n++){ + ev = &l_events[n]; + s = &g_Session[ ev->fd ]; + + if(ev->events & EVDP_EVENT_HUP){ + network_disconnect( ev->fd ); + continue; // no further event processing. + }// endif vent is HUP (disconnect) + + + if(ev->events & EVDP_EVENT_IN){ + + if(s->onRecv != NULL){ + if( false == s->onRecv(ev->fd) ){ + network_disconnect(ev->fd); + continue; // .. + } + }else{ + ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + + }// endif event is IN (recv) + + + if(ev->events & EVDP_EVENT_OUT){ + if(s->onSend != NULL){ + if( false == s->onSend(ev->fd) ){ + network_disconnect(ev->fd); + continue; + } + }else{ + ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + }// endif event is OUT (send) + + }//endfor + }//end: network_do() -static bool _setnonblock(int32 fd) -{ - int flags = fcntl(fd, F_GETFL, 0); - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) - return false; +static bool _setnonblock(int32 fd){ + int flags = fcntl(fd, F_GETFL, 0); + if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) + return false; - return true; + return true; }//end: _setnonblock() -static bool _network_accept(int32 fd) -{ - SESSION *listener = &g_Session[fd]; - SESSION *s; - union { - struct sockaddr_in v4; +static bool _network_accept(int32 fd){ + SESSION *listener = &g_Session[fd]; + SESSION *s; + union{ + struct sockaddr_in v4; #ifdef ENABLE_IPV6 - struct sockaddr_in6 v6; + struct sockaddr_in6 v6; #endif - } _addr; - int newfd; - socklen_t addrlen; - struct sockaddr *addr; - - // Accept until OS returns - nothing to accept anymore - // - this is required due to our EVDP abstraction. (which handles on listening sockets similar to epoll's EPOLLET flag.) - while (1) { + } _addr; + int newfd; + socklen_t addrlen; + struct sockaddr *addr; + + // Accept until OS returns - nothing to accept anymore + // - this is required due to our EVDP abstraction. (which handles on listening sockets similar to epoll's EPOLLET flag.) + while(1){ #ifdef ENABLE_IPV6 - if (listener->v6 == true) { - addrlen = sizeof(_addr.v6); - addr = (struct sockaddr *)&_addr.v6; - } else { + if(listener->v6 == true){ + addrlen = sizeof(_addr.v6); + addr = (struct sockaddr*)&_addr.v6; + }else{ #endif - addrlen = sizeof(_addr.v4); - addr = (struct sockaddr *)&_addr.v4; + addrlen = sizeof(_addr.v4); + addr = (struct sockaddr*)&_addr.v4; #ifdef ENABLE_IPV6 - } + } #endif #ifdef HAVE_ACCEPT4 - newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); + newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); #else - newfd = accept(fd, addr, &addrlen); + newfd = accept(fd, addr, &addrlen); #endif - if (newfd == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - break; // this is fully valid & whished., se explaination on top of while(1) - - // Otherwis .. we have serious problems :( seems tahat our listner has gone away.. - // @TODO handle this .. - ShowError("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); + if(newfd == -1){ + if(errno == EAGAIN || errno == EWOULDBLOCK) + break; // this is fully valid & whished., se explaination on top of while(1) + + // Otherwis .. we have serious problems :( seems tahat our listner has gone away.. + // @TODO handle this .. + ShowError("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); - return false; // will call disconnect after return. - //break; - } + return false; // will call disconnect after return. + //break; + } #ifndef HAVE_ACCEPT4 // no accept4 means, we have to set nonblock by ourself. .. - if (_setnonblock(newfd) == false) { - ShowError("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); - close(newfd); - continue; - } + if(_setnonblock(newfd) == false){ + ShowError("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); + close(newfd); + continue; + } #endif - // Check connection limits. - if (newfd >= MAXCONN) { - ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", MAXCONN); - close(newfd); - continue; // we have to loop over the events (and disconnect them too ..) but otherwise we would leak event notifications. - } - - - // Create new Session. - s = &g_Session[newfd]; - s->type = NST_CLIENT; - - // The new connection inherits listenr's handlers. - s->onDisconnect = listener->onDisconnect; - s->onConnect = listener->onConnect; // maybe useless but .. fear the future .. :~ - - // Register the new connection @ EVDP - if (evdp_addclient(newfd, &s->evdp_data) == false) { - ShowError("_network_accept: failed to accept connection - event subsystem returned an error.\n"); - close(newfd); - s->type = NST_FREE; - } - - // Call the onConnect handler on the listener. - if (listener->onConnect(newfd) == false) { - // Resfused by onConnect handler.. - evdp_remove(newfd, &s->evdp_data); - - close(newfd); - s->type = NST_FREE; - - s->data = NULL; // be on the safe side ~ ! - continue; - } - - - } - - return true; + // Check connection limits. + if(newfd >= MAXCONN){ + ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", MAXCONN); + close(newfd); + continue; // we have to loop over the events (and disconnect them too ..) but otherwise we would leak event notifications. + } + + + // Create new Session. + s = &g_Session[newfd]; + s->type = NST_CLIENT; + + // The new connection inherits listenr's handlers. + s->onDisconnect = listener->onDisconnect; + s->onConnect = listener->onConnect; // maybe useless but .. fear the future .. :~ + + // Register the new connection @ EVDP + if( evdp_addclient(newfd, &s->evdp_data) == false){ + ShowError("_network_accept: failed to accept connection - event subsystem returned an error.\n"); + close(newfd); + s->type = NST_FREE; + } + + // Call the onConnect handler on the listener. + if( listener->onConnect(newfd) == false ){ + // Resfused by onConnect handler.. + evdp_remove(newfd, &s->evdp_data); + + close(newfd); + s->type = NST_FREE; + + s->data = NULL; // be on the safe side ~ ! + continue; + } + + + } + + return true; }//end: _network_accept() -void network_disconnect(int32 fd) -{ - SESSION *s = &g_Session[fd]; - netbuf b, bn; - - // Prevent recursive calls - // by wrong implemented on disconnect handlers.. and such.. - if (s->disconnect_in_progress == true) - return; - - s->disconnect_in_progress = true; - - - // Disconnect Todo: - // - Call onDisconnect Handler - // - Release all Assigned buffers. - // - remove from event system (notifications) - // - cleanup session structure - // - close connection. - // - - if (s->onDisconnect != NULL && - s->type != NST_LISTENER) { - - s->onDisconnect(fd); - } - - // Read Buffer - if (s->read.buf != NULL) { - netbuffer_put(s->read.buf); - s->read.buf = NULL; - } - - // Write Buffer(s) - b = s->write.buf; - while (1) { - if (b == NULL) break; - - bn = b->next; - - netbuffer_put(b); - - b = bn; - } - s->write.buf = NULL; - s->write.buf_last = NULL; - - s->write.n_outstanding = 0; - s->write.max_outstanding = 0; - - - // Remove from event system. - evdp_remove(fd, &s->evdp_data); - - // Cleanup Session Structure. - s->type = NST_FREE; - s->data = NULL; // no application level data assigned - s->disconnect_in_progress = false; - - - // Close connection - close(fd); - +void network_disconnect(int32 fd){ + SESSION *s = &g_Session[fd]; + netbuf b, bn; + + // Prevent recursive calls + // by wrong implemented on disconnect handlers.. and such.. + if(s->disconnect_in_progress == true) + return; + + s->disconnect_in_progress = true; + + + // Disconnect Todo: + // - Call onDisconnect Handler + // - Release all Assigned buffers. + // - remove from event system (notifications) + // - cleanup session structure + // - close connection. + // + + if(s->onDisconnect != NULL && + s->type != NST_LISTENER){ + + s->onDisconnect( fd ); + } + + // Read Buffer + if(s->read.buf != NULL){ + netbuffer_put(s->read.buf); + s->read.buf = NULL; + } + + // Write Buffer(s) + b = s->write.buf; + while(1){ + if(b == NULL) break; + + bn = b->next; + + netbuffer_put(b); + + b = bn; + } + s->write.buf = NULL; + s->write.buf_last = NULL; + + s->write.n_outstanding = 0; + s->write.max_outstanding = 0; + + + // Remove from event system. + evdp_remove(fd, &s->evdp_data); + + // Cleanup Session Structure. + s->type = NST_FREE; + s->data = NULL; // no application level data assigned + s->disconnect_in_progress = false; + + + // Close connection + close(fd); + }//end: network_disconnect() -int32 network_addlistener(bool v6, const char *addr, uint16 port) -{ - SESSION *s; - int optval, fd; +int32 network_addlistener(bool v6, const char *addr, uint16 port){ + SESSION *s; + int optval, fd; #if !defined(ENABLE_IPV6) - if (v6 == true) { - ShowError("network_addlistener(%c, '%s', %u): this release has no IPV6 support.\n", (v6==true?'t':'f'), addr, port); - return -1; - } + if(v6 == true){ + ShowError("network_addlistener(%c, '%s', %u): this release has no IPV6 support.\n", (v6==true?'t':'f'), addr, port); + return -1; + } #endif #ifdef ENABLE_IPV6 - if (v6 == true) - fd = socket(AF_INET6, SOCK_STREAM, 0); - else + if(v6 == true) + fd = socket(AF_INET6, SOCK_STREAM, 0); + else #endif - fd = socket(AF_INET, SOCK_STREAM, 0); - - // Error? - if (fd == -1) { - ShowError("network_addlistener(%c, '%s', %u): socket() failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - return -1; - } - - // Too many connections? - if (fd >= MAXCONN) { - ShowError("network_addlistener(%c, '%s', %u): cannot create listener, exceeds more than supported connections (%u).\n", (v6==true?'t':'f'), addr, port, MAXCONN); - close(fd); - return -1; - } - - - s = &g_Session[fd]; - if (s->type != NST_FREE) { // additional checks.. :) - ShowError("network_addlistener(%c, '%s', %u): failed, got fd #%u which is already in use in local session table?!\n", (v6==true?'t':'f'), addr, port, fd); - close(fd); - return -1; - } - - - // Fill ip addr structs + fd = socket(AF_INET, SOCK_STREAM, 0); + + // Error? + if(fd == -1){ + ShowError("network_addlistener(%c, '%s', %u): socket() failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + return -1; + } + + // Too many connections? + if(fd >= MAXCONN){ + ShowError("network_addlistener(%c, '%s', %u): cannot create listener, exceeds more than supported connections (%u).\n", (v6==true?'t':'f'), addr, port, MAXCONN); + close(fd); + return -1; + } + + + s = &g_Session[fd]; + if(s->type != NST_FREE){ // additional checks.. :) + ShowError("network_addlistener(%c, '%s', %u): failed, got fd #%u which is already in use in local session table?!\n", (v6==true?'t':'f'), addr, port, fd); + close(fd); + return -1; + } + + + // Fill ip addr structs #ifdef ENABLE_IPV6 - if (v6 == true) { - memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); - s->addr.v6.sin6_family = AF_INET6; - s->addr.v6.sin6_port = htons(port); - if (inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1) { - ShowError("network_addlistener(%c, '%s', %u): failed to parse the given IPV6 address.\n", (v6==true?'t':'f'), addr, port); - close(fd); - return -1; - } - - } else { + if(v6 == true){ + memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); + s->addr.v6.sin6_family = AF_INET6; + s->addr.v6.sin6_port = htons(port); + if(inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1){ + ShowError("network_addlistener(%c, '%s', %u): failed to parse the given IPV6 address.\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + }else{ #endif - memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); - s->addr.v4.sin_family = AF_INET; - s->addr.v4.sin_port = htons(port); - s->addr.v4.sin_addr.s_addr = inet_addr(addr); + memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); + s->addr.v4.sin_family = AF_INET; + s->addr.v4.sin_port = htons(port); + s->addr.v4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 - } + } #endif + - - // if OS has support for SO_REUSEADDR, apply the flag - // so the address could be used when there're still time_wait sockets outstanding from previous application run. + // if OS has support for SO_REUSEADDR, apply the flag + // so the address could be used when there're still time_wait sockets outstanding from previous application run. #ifdef SO_REUSEADDR - optval=1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + optval=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); #endif - // Bind + // Bind #ifdef ENABLE_IPV6 - if (v6 == true) { - if (bind(fd, (struct sockaddr *)&s->addr.v6, sizeof(s->addr.v6)) == -1) { - ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - } else { + if(v6 == true){ + if( bind(fd, (struct sockaddr*)&s->addr.v6, sizeof(s->addr.v6)) == -1) { + ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + }else{ #endif - if (bind(fd, (struct sockaddr *)&s->addr.v4, sizeof(s->addr.v4)) == -1) { - ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } + if( bind(fd, (struct sockaddr*)&s->addr.v4, sizeof(s->addr.v4)) == -1) { + ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } #ifdef ENABLE_IPV6 - } + } #endif - if (listen(fd, l_ListenBacklog) == -1) { - ShowError("network_addlistener(%c, '%s', %u): listen failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Set to nonblock! - if (_setnonblock(fd) == false) { - ShowError("network_addlistener(%c, '%s', %u): cannot set to nonblock (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Rgister @ evdp. - if (evdp_addlistener(fd, &s->evdp_data) != true) { - ShowError("network_addlistener(%c, '%s', %u): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); - close(fd); - return -1; - } - - - // Apply flags on Session array for this conneciton. - if (v6 == true) s->v6 = true; - else s->v6 = false; - - s->type = NST_LISTENER; - s->onRecv = _network_accept; - - ShowStatus("Added Listener on '%s':%u\n", addr, port, (v6==true ? "(ipv6)":"(ipv4)")); - - return fd; + if( listen(fd, l_ListenBacklog) == -1){ + ShowError("network_addlistener(%c, '%s', %u): listen failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Set to nonblock! + if(_setnonblock(fd) == false){ + ShowError("network_addlistener(%c, '%s', %u): cannot set to nonblock (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Rgister @ evdp. + if( evdp_addlistener(fd, &s->evdp_data) != true){ + ShowError("network_addlistener(%c, '%s', %u): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + + // Apply flags on Session array for this conneciton. + if(v6 == true) s->v6 = true; + else s->v6 = false; + + s->type = NST_LISTENER; + s->onRecv = _network_accept; + + ShowStatus("Added Listener on '%s':%u\n", addr, port, (v6==true ? "(ipv6)":"(ipv4)") ); + + return fd; }//end: network_addlistener() -static bool _network_connect_establishedHandler(int32 fd) -{ - register SESSION *s = &g_Session[fd]; - int val; - socklen_t val_len; - - if (s->type == NST_FREE) - return true; // due to multiple non coalesced event notifications - // this can happen .. when a previous handled event has already disconnected the connection - // within the same cycle.. - - val = -1; - val_len = sizeof(val); - getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); - - if (val != 0) { - // :( .. cleanup session.. - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we CANT return false, - // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. - } else { - // ok - if (s->onConnect(fd) == false) { - // onConnect handler has refused the connection .. - // cleanup .. and ok - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. - } - - // connection established ! - // - if (evdp_outgoingconnection_established(fd, &s->evdp_data) == false) { - return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. - } - - s->onSend = NULL; - - ShowStatus("#%u connection successfull!\n", fd); - } - - return true; +static bool _network_connect_establishedHandler(int32 fd){ + register SESSION *s = &g_Session[fd]; + int val; + socklen_t val_len; + + if(s->type == NST_FREE) + return true; // due to multiple non coalesced event notifications + // this can happen .. when a previous handled event has already disconnected the connection + // within the same cycle.. + + val = -1; + val_len = sizeof(val); + getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); + + if(val != 0){ + // :( .. cleanup session.. + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we CANT return false, + // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. + }else{ + // ok + if(s->onConnect(fd) == false) { + // onConnect handler has refused the connection .. + // cleanup .. and ok + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. + } + + // connection established ! + // + if( evdp_outgoingconnection_established(fd, &s->evdp_data) == false ){ + return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. + } + + s->onSend = NULL; + + ShowStatus("#%u connection successfull!\n", fd); + } + + return true; }//end: _network_connect_establishedHandler() int32 network_connect(bool v6, - const char *addr, - uint16 port, - const char *from_addr, - uint16 from_port, - bool (*onConnectionEstablishedHandler)(int32 fd), - void (*onConnectionLooseHandler)(int32 fd) - ) -{ - register SESSION *s; - int32 fd, optval, ret; - struct sockaddr_in ip4; + const char *addr, + uint16 port, + const char *from_addr, + uint16 from_port, + bool (*onConnectionEstablishedHandler)(int32 fd), + void (*onConnectionLooseHandler)(int32 fd) +){ + register SESSION *s; + int32 fd, optval, ret; + struct sockaddr_in ip4; #ifdef ENABLE_IPV6 - struct sockaddr_in6 ip6; + struct sockaddr_in6 ip6; #endif #ifdef ENABLE_IPV6 - if (v6 == true) - fd = socket(AF_INET6, SOCK_STREAM, 0); - else + if(v6 == true) + fd = socket(AF_INET6, SOCK_STREAM, 0); + else #endif - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(AF_INET, SOCK_STREAM, 0); #ifndef ENABLE_IPV6 - // check.. - if (v6 == true) { - ShowError("network_connect(%c, '%s', %u...): tried to create an ipv6 connection, IPV6 is not supported in this release.\n", (v6==true?'t':'f'), addr, port); - return -1; - } + // check.. + if(v6 == true){ + ShowError("network_connect(%c, '%s', %u...): tried to create an ipv6 connection, IPV6 is not supported in this release.\n", (v6==true?'t':'f'), addr, port); + return -1; + } #endif - // check connection limits. - if (fd >= MAXCONN) { - ShowError("network_connect(%c, '%s', %u...): cannot create new connection, exceeeds more than supported connections (%u)\n", (v6==true?'t':'f'), addr, port); - close(fd); - return -1; - } - - - // Originating IP/Port pair given ? - if (from_addr != NULL && *from_addr != 0) { - //.. -#ifdef SO_REUSEADDR - optval=1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); -#endif - -#ifdef ENABLE_IPV6 - if (v6 == true) { - memset(&ip6, 0x00, sizeof(ip6)); - ip6.sin6_family = AF_INET6; - ip6.sin6_port = htons(from_port); - - if (inet_pton(AF_INET6, from_addr, &ip6.sin6_addr) != 1) { - ShowError("network_connect(%c, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - ret = bind(fd, (struct sockaddr *)&ip6, sizeof(ip6)); - } else { -#endif - memset(&ip4, 0x00, sizeof(ip4)); - - ip4.sin_family = AF_INET; - ip4.sin_port = htons(from_port); - ip4.sin_addr.s_addr = inet_addr(from_addr); - ret = bind(fd, (struct sockaddr *)&ip4, sizeof(ip4)); + // check connection limits. + if(fd >= MAXCONN){ + ShowError("network_connect(%c, '%s', %u...): cannot create new connection, exceeeds more than supported connections (%u)\n", (v6==true?'t':'f'), addr, port ); + close(fd); + return -1; + } + + + // Originating IP/Port pair given ? + if(from_addr != NULL && *from_addr != 0){ + //.. + #ifdef SO_REUSEADDR + optval=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + #endif + + #ifdef ENABLE_IPV6 + if(v6 == true){ + memset(&ip6, 0x00, sizeof(ip6)); + ip6.sin6_family = AF_INET6; + ip6.sin6_port = htons(from_port); + + if(inet_pton(AF_INET6, from_addr, &ip6.sin6_addr) != 1){ + ShowError("network_connect(%c, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + ret = bind(fd, (struct sockaddr*)&ip6, sizeof(ip6)); + }else{ + #endif + memset(&ip4, 0x00, sizeof(ip4)); + + ip4.sin_family = AF_INET; + ip4.sin_port = htons(from_port); + ip4.sin_addr.s_addr = inet_addr(from_addr); + ret = bind(fd, (struct sockaddr*)&ip4, sizeof(ip4)); + #ifdef ENABLE_IPV6 + } + #endif + + } + + + // Set non block + if(_setnonblock(fd) == false){ + ShowError("network_connect(%c, '%s', %u...): cannot set socket to nonblocking (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Create ip addr block to connect to .. #ifdef ENABLE_IPV6 - } + if(v6 == true){ + memset(&ip6, 0x00, sizeof(ip6)); + ip6.sin6_family = AF_INET6; + ip6.sin6_port = htons(port); + + if(inet_pton(AF_INET6, addr, &ip6.sin6_addr) != 1){ + ShowError("network_connect(%c, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + }else{ #endif - - } - - - // Set non block - if (_setnonblock(fd) == false) { - ShowError("network_connect(%c, '%s', %u...): cannot set socket to nonblocking (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Create ip addr block to connect to .. -#ifdef ENABLE_IPV6 - if (v6 == true) { - memset(&ip6, 0x00, sizeof(ip6)); - ip6.sin6_family = AF_INET6; - ip6.sin6_port = htons(port); - - if (inet_pton(AF_INET6, addr, &ip6.sin6_addr) != 1) { - ShowError("network_connect(%c, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - } else { -#endif - memset(&ip4, 0x00, sizeof(ip4)); - - ip4.sin_family = AF_INET; - ip4.sin_port = htons(port); - ip4.sin_addr.s_addr = inet_addr(addr); + memset(&ip4, 0x00, sizeof(ip4)); + + ip4.sin_family = AF_INET; + ip4.sin_port = htons(port); + ip4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 - } + } #endif - // Assign Session.. - s = &g_Session[fd]; - s->type = NST_OUTGOING; - s->v6 = v6; - s->onConnect = onConnectionEstablishedHandler; - s->onDisconnect = onConnectionLooseHandler; - s->onRecv = NULL; - s->onSend = _network_connect_establishedHandler; + // Assign Session.. + s = &g_Session[fd]; + s->type = NST_OUTGOING; + s->v6 = v6; + s->onConnect = onConnectionEstablishedHandler; + s->onDisconnect = onConnectionLooseHandler; + s->onRecv = NULL; + s->onSend = _network_connect_establishedHandler; #ifdef ENABLE_IPV6 - if (v6 == true) - memcpy(&s->addr.v6, &ip6, sizeof(ip6)); - else + if(v6 == true) + memcpy(&s->addr.v6, &ip6, sizeof(ip6)); + else #endif - memcpy(&s->addr.v4, &ip4, sizeof(ip4)); - - // Register @ EVDP. as outgoing (see doc of the function) - if (evdp_addconnecting(fd, &s->evdp_data) == false) { - ShowError("network_connect(%c, '%s', %u...): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); - - // cleanup session x.x.. - s->type = NST_FREE; - s->onConnect = NULL; - s->onDisconnect = NULL; - s->onSend = NULL; - - // close, return error code. - close(fd); - return -1; - } + memcpy(&s->addr.v4, &ip4, sizeof(ip4)); + + // Register @ EVDP. as outgoing (see doc of the function) + if(evdp_addconnecting(fd, &s->evdp_data) == false){ + ShowError("network_connect(%c, '%s', %u...): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); + + // cleanup session x.x.. + s->type = NST_FREE; + s->onConnect = NULL; + s->onDisconnect = NULL; + s->onSend = NULL; + + // close, return error code. + close(fd); + return -1; + } #ifdef ENABLE_IPV6 - if (v6 == true) - ret = connect(fd, (struct sockaddr *)&ip6, sizeof(ip6)); - else + if(v6 == true) + ret = connect(fd, (struct sockaddr*)&ip6, sizeof(ip6)); + else #endif - ret = connect(fd, (struct sockaddr *)&ip4, sizeof(ip4)); - - - // - if (ret != 0 && errno != EINPROGRESS) { - ShowWarning("network_connect(%c, '%s', %u...): connection failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - - // Cleanup session .. - s->type = NST_FREE; - s->onConnect = NULL; - s->onDisconnect = NULL; - s->onSend = NULL; - - // .. remove from evdp and close fd. - evdp_remove(fd, &s->evdp_data); - close(fd); - return -1; - } - - - // ! The Info Message :~D - ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port); - - return fd; + ret = connect(fd, (struct sockaddr*)&ip4, sizeof(ip4)); + + + // + if(ret != 0 && errno != EINPROGRESS){ + ShowWarning("network_connect(%c, '%s', %u...): connection failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + + // Cleanup session .. + s->type = NST_FREE; + s->onConnect = NULL; + s->onDisconnect = NULL; + s->onSend = NULL; + + // .. remove from evdp and close fd. + evdp_remove(fd, &s->evdp_data); + close(fd); + return -1; + } + + + // ! The Info Message :~D + ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port); + +return fd; }//end: network_connect() -static bool _onSend(int32 fd) -{ - register SESSION *s = &g_Session[fd]; - register netbuf buf, buf_next; - register uint32 szNeeded; - register int wLen; - - if (s->type == NST_FREE) - return true; // Possible due to multipl non coalsced event notifications - // so onSend gets called after disconnect caused by an previous vent. - // we can ignore the call to onSend, then. - - buf = s->write.buf; - while (1) { - if (buf == NULL) - break; - - buf_next = buf->next; - - - szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. - - // try to write. - wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); - if (wLen == 0) { - return false; // eof. - } else if (wLen == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - return true; // dont disconnect / try again later. - - // all other errors. . - return false; - } - - // Wrote data.. => - szNeeded -= wLen; - if (szNeeded > 0) { - // still data left .. - // - s->write.dataPos += wLen; // fix offset. - return true; - } else { - // this buffer has been written successfully - // could be returned to pool. - netbuffer_put(buf); - s->write.n_outstanding--; // When threadsafe -> Interlocked here. - s->write.dataPos = 0; - } - - - buf = buf_next; - } - - // okay, - // reaching this part means: - // while interrupted by break - - // which means all buffers are written, nothing left - // - - s->write.buf_last = NULL; - s->write.buf = NULL; - s->write.n_outstanding = 0; - s->write.dataPos = 0; - - // Remove from event dispatcher (write notification) - // - evdp_writable_remove(fd, &s->evdp_data); - - return true; +static bool _onSend(int32 fd){ + register SESSION *s = &g_Session[fd]; + register netbuf buf, buf_next; + register uint32 szNeeded; + register int wLen; + + if(s->type == NST_FREE) + return true; // Possible due to multipl non coalsced event notifications + // so onSend gets called after disconnect caused by an previous vent. + // we can ignore the call to onSend, then. + + buf = s->write.buf; + while(1){ + if(buf == NULL) + break; + + buf_next = buf->next; + + + szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. + + // try to write. + wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); + if(wLen == 0){ + return false; // eof. + }else if(wLen == -1){ + if(errno == EAGAIN || errno == EWOULDBLOCK) + return true; // dont disconnect / try again later. + + // all other errors. . + return false; + } + + // Wrote data.. => + szNeeded -= wLen; + if(szNeeded > 0){ + // still data left .. + // + s->write.dataPos += wLen; // fix offset. + return true; + }else{ + // this buffer has been written successfully + // could be returned to pool. + netbuffer_put(buf); + s->write.n_outstanding--; // When threadsafe -> Interlocked here. + s->write.dataPos = 0; + } + + + buf = buf_next; + } + + // okay, + // reaching this part means: + // while interrupted by break - + // which means all buffers are written, nothing left + // + + s->write.buf_last = NULL; + s->write.buf = NULL; + s->write.n_outstanding = 0; + s->write.dataPos = 0; + + // Remove from event dispatcher (write notification) + // + evdp_writable_remove(fd, &s->evdp_data); + + return true; }//end: _onSend() -static bool _onRORecv(int32 fd) -{ - register SESSION *s = &g_Session[fd]; - register uint32 szNeeded; - register char *p; - register int rLen; - - if (s->type == NST_FREE) - return true; // Possible due to multiple non coalesced events by evdp. - // simply ignore this call returning positive result. - - // Initialize p and szNeeded depending on change - // - switch (s->read.state) { - case NRS_WAITOP: - szNeeded = s->read.head_left; - p = ((char *)&s->read.head[0]) + (2-szNeeded); - break; - - case NRS_WAITLEN: - szNeeded = s->read.head_left; - p = ((char *)&s->read.head[1]) + (2-szNeeded); - break; - - case NRS_WAITDATA: { - register netbuf buf = s->read.buf; - - szNeeded = (buf->dataLen - buf->dataPos); - p = (char *)&buf->buf[ buf->dataPos ]; - } - break; - - default: - // .. the impossible gets possible .. - ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - // - - rLen = read(fd, p, szNeeded); - if (rLen == 0) { - // eof.. - return false; - } else if (rLen == -1) { - - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) - return true; - } - - // an additional interesting case would be - // EINTR, this 'could' be handled .. but: - // posix says that its possible that data gets currupted during irq - // or data gor read and not reported.., so we'd have a data loss.. - // (which shouldnt happen with stream based protocols such as tcp) - // its better to disonnect the client in that case. - - return false; - } - - // - // Got Data: - // next action also depends on current state .. - // - szNeeded -= rLen; - switch (s->read.state) { - case NRS_WAITOP: - - if (szNeeded > 0) { - // still data missing .. - s->read.head_left = szNeeded; - return true; // wait for completion. - } else { - // complete .. - // next state depends on packet type. - - s->read.head[1] = ((uint16 *)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] - - if (s->read.head[1] == ROPACKET_UNKNOWN) { - // unknown packet - disconnect - ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); - return false; - } else if (s->read.head[1] == ROPACKET_DYNLEN) { - // dynamic length - // next state: requrie len. - s->read.state = NRS_WAITLEN; - s->read.head_left = 2; - return true; // - } else if (s->read.head[1] == 2) { - // packet has no data (only opcode) - register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = 2; - buf->next = NULL; - - // Back to initial state -> Need opcode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine here. - s->onPacketComplete(fd, s->read.head[0], 2, buf); - - return true; // done :) - } else { - // paket needs .. data .. - register netbuf buf = netbuffer_get(s->read.head[1]); - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach buffer. - s->read.buf = buf; - - // set state: - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (opcode read completed?) - - break; - - - case NRS_WAITLEN: - - if (szNeeded > 0) { - // incomplete .. - s->read.head_left = szNeeded; - return true; - } else { - - if (s->read.head[1] == 4) { - // packet has no data (only opcode + length) - register netbuf buf = netbuffer_get(4); - - NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = 4; - buf->next = NULL; - - // set initial state (need opcode) - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // call completion routine. - s->onPacketComplete(fd, s->read.head[0], 4, buf); - - return true; - } else if (s->read.head[1] < 4) { - // invalid header. - ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); - return false; - } else { - // Data needed - // next state -> waitdata! - register netbuf buf = netbuffer_get(s->read.head[1]); - - NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach to session: - s->read.buf = buf; - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (length read complete?) - - break; - - - case NRS_WAITDATA: - - if (szNeeded == 0) { - // Packet finished! - // compltion. - register netbuf buf = s->read.buf; - - // set initial state. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine. - s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); - - return true; - } else { - // still data needed - s->read.buf->dataPos += rLen; - - return true; - } - break; - - - // - default: - ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - return false; +static bool _onRORecv(int32 fd){ + register SESSION *s = &g_Session[fd]; + register uint32 szNeeded; + register char *p; + register int rLen; + + if(s->type == NST_FREE) + return true; // Possible due to multiple non coalesced events by evdp. + // simply ignore this call returning positive result. + + // Initialize p and szNeeded depending on change + // + switch(s->read.state){ + case NRS_WAITOP: + szNeeded = s->read.head_left; + p = ((char*)&s->read.head[0]) + (2-szNeeded); + break; + + case NRS_WAITLEN: + szNeeded = s->read.head_left; + p = ((char*)&s->read.head[1]) + (2-szNeeded); + break; + + case NRS_WAITDATA:{ + register netbuf buf = s->read.buf; + + szNeeded = (buf->dataLen - buf->dataPos); + p = (char*)&buf->buf[ buf->dataPos ]; + } + break; + + default: + // .. the impossible gets possible .. + ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + // + + rLen = read(fd, p, szNeeded); + if(rLen == 0){ + // eof.. + return false; + }else if(rLen == -1){ + + if(errno == EAGAIN || errno == EWOULDBLOCK){ + // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) + return true; + } + + // an additional interesting case would be + // EINTR, this 'could' be handled .. but: + // posix says that its possible that data gets currupted during irq + // or data gor read and not reported.., so we'd have a data loss.. + // (which shouldnt happen with stream based protocols such as tcp) + // its better to disonnect the client in that case. + + return false; + } + + // + // Got Data: + // next action also depends on current state .. + // + szNeeded -= rLen; + switch(s->read.state){ + case NRS_WAITOP: + + if(szNeeded > 0){ + // still data missing .. + s->read.head_left = szNeeded; + return true; // wait for completion. + }else{ + // complete .. + // next state depends on packet type. + + s->read.head[1] = ((uint16*)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] + + if(s->read.head[1] == ROPACKET_UNKNOWN){ + // unknown packet - disconnect + ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); + return false; + } + else if(s->read.head[1] == ROPACKET_DYNLEN){ + // dynamic length + // next state: requrie len. + s->read.state = NRS_WAITLEN; + s->read.head_left = 2; + return true; // + } + else if(s->read.head[1] == 2){ + // packet has no data (only opcode) + register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = 2; + buf->next = NULL; + + // Back to initial state -> Need opcode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine here. + s->onPacketComplete(fd, s->read.head[0], 2, buf); + + return true; // done :) + } + else{ + // paket needs .. data .. + register netbuf buf = netbuffer_get( s->read.head[1] ); + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach buffer. + s->read.buf = buf; + + // set state: + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (opcode read completed?) + + break; + + + case NRS_WAITLEN: + + if(szNeeded > 0){ + // incomplete .. + s->read.head_left = szNeeded; + return true; + }else{ + + if(s->read.head[1] == 4){ + // packet has no data (only opcode + length) + register netbuf buf = netbuffer_get( 4 ); + + NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = 4; + buf->next = NULL; + + // set initial state (need opcode) + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // call completion routine. + s->onPacketComplete(fd, s->read.head[0], 4, buf); + + return true; + } + else if(s->read.head[1] < 4){ + // invalid header. + ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); + return false; + } + else{ + // Data needed + // next state -> waitdata! + register netbuf buf = netbuffer_get( s->read.head[1] ); + + NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach to session: + s->read.buf = buf; + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (length read complete?) + + break; + + + case NRS_WAITDATA: + + if(szNeeded == 0){ + // Packet finished! + // compltion. + register netbuf buf = s->read.buf; + + // set initial state. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine. + s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); + + return true; + }else{ + // still data needed + s->read.buf->dataPos += rLen; + + return true; + } + break; + + + // + default: + ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + return false; }//end: _onRORecv() -void network_send(int32 fd, netbuf buf) -{ - register SESSION *s = &g_Session[fd]; - +void network_send(int32 fd, netbuf buf){ + register SESSION *s = &g_Session[fd]; + #ifdef PARANOID_CHECKS - if (fd >= MAXCONN) { - ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); - _network_free_netbuf_async(buf); - return; - } + if(fd >= MAXCONN){ + ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); + _network_free_netbuf_async(buf); + return; + } #endif - if (s->type == NST_FREE) - return; - - // Check Max Outstanding buffers limit. - if ((s->write.max_outstanding > 0) && - (s->write.n_outstanding >= s->write.max_outstanding)) { - - ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); - network_disconnect(fd); - // - _network_free_netbuf_async(buf); - return; - } - - - // Attach to the end: - buf->next = NULL; - if (s->write.buf_last != NULL) { - s->write.buf_last->next = buf; - s->write.buf_last = buf; - - } else { - // currently no buffer attached. - s->write.buf = s->write.buf_last = buf; - - // register @ evdp for writable notification. - evdp_writable_add(fd, &s->evdp_data); // - } - - - // - s->write.n_outstanding++; - + if(s->type == NST_FREE) + return; + + // Check Max Outstanding buffers limit. + if( (s->write.max_outstanding > 0) && + (s->write.n_outstanding >= s->write.max_outstanding) ){ + + ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); + network_disconnect(fd); + // + _network_free_netbuf_async(buf); + return; + } + + + // Attach to the end: + buf->next = NULL; + if(s->write.buf_last != NULL){ + s->write.buf_last->next = buf; + s->write.buf_last = buf; + + }else{ + // currently no buffer attached. + s->write.buf = s->write.buf_last = buf; + + // register @ evdp for writable notification. + evdp_writable_add(fd, &s->evdp_data); // + } + + + // + s->write.n_outstanding++; + }//end: network_send() void network_parser_set_ro(int32 fd, - int16 *packetlentable, - void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) - ) -{ - register SESSION *s = &g_Session[fd]; - register netbuf b, nb; // used for potential free attached buffers. - - if (s->type == NST_FREE) - return; - - s->onPacketComplete = onPacketCompleteProc; - - s->onRecv = _onRORecv; // .. - s->onSend = _onSend; // Using the normal generic netbuf based send function. - - s->netparser_data = packetlentable; - - // Initial State -> Need Packet OPCode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - - - // Detach (if..) all buffers. - if (s->read.buf != NULL) { - _network_free_netbuf_async(s->read.buf); // - s->read.buf = NULL; - } - - if (s->write.buf != NULL) { - b = s->write.buf; - while (1) { - nb = b->next; - - _network_free_netbuf_async(b); - - b = nb; - } - - s->write.buf = NULL; - s->write.buf_last = NULL; - s->write.n_outstanding = 0; - } - - // not changing any limits on outstanding .. - // - + int16 *packetlentable, + void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) + ){ + register SESSION *s = &g_Session[fd]; + register netbuf b, nb; // used for potential free attached buffers. + + if(s->type == NST_FREE) + return; + + s->onPacketComplete = onPacketCompleteProc; + + s->onRecv = _onRORecv; // .. + s->onSend = _onSend; // Using the normal generic netbuf based send function. + + s->netparser_data = packetlentable; + + // Initial State -> Need Packet OPCode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + + + // Detach (if..) all buffers. + if(s->read.buf != NULL){ + _network_free_netbuf_async(s->read.buf); // + s->read.buf = NULL; + } + + if(s->write.buf != NULL){ + b = s->write.buf; + while(1){ + nb = b->next; + + _network_free_netbuf_async(b); + + b = nb; + } + + s->write.buf = NULL; + s->write.buf_last = NULL; + s->write.n_outstanding = 0; + } + + // not changing any limits on outstanding .. + // + }//end: network_parser_set_ro() diff --git a/src/common/network.h b/src/common/network.h index b883b41e6..d7b463a2f 100644 --- a/src/common/network.h +++ b/src/common/network.h @@ -3,7 +3,7 @@ #include #include "../common/cbasetypes.h" -#include "../common/netbuffer.h" +#include "../common/netbuffer.h" #include "../common/evdp.h" #ifndef MAXCONN @@ -11,79 +11,79 @@ #endif -typedef struct SESSION { - EVDP_DATA evdp_data; // Must be always the frist member! (some evdp's may rely on this fact) - - // Connection Type - enum { NST_FREE=0, NST_LISTENER = 1, NST_CLIENT=2, NST_OUTGOING=3} type; - - // Flags / Settings. - bool v6; // is v6? - bool disconnect_in_progress; // To prevent stack overflows / recursive calls. - - - union { // union to save memory. - struct sockaddr_in v4; - struct sockaddr_in6 v6; - } addr; - - - // "lowlevel" Handlers - // (Implemented by the protocol specific parser) - // - bool (*onRecv)(int32 fd); // return false = disconnect - bool (*onSend)(int32 fd); // return false = disconnect - - // Event Handlers for LISTENER type sockets - // - // onConnect gets Called when a connection has been - // successfully accepted. - // Session entry is available in this Handler! - // A returncode of false will reejct the connection (disconnect) - // Note: When rejecting a connection in onConnect by returning false - // The onDisconnect handler wont get called! - // Note: the onConnect Handler is also responsible for setting - // the appropriate netparser (which implements onRecv/onSend..) [protocol specific] - // - // onDisconnect gets called when a connection gets disconnected - // (by peer as well as by core) - // - bool (*onConnect)(int32 fd); // return false = disconnect (wont accept) - void (*onDisconnect)(int32 fd); - - - // - // Parser specific data - // - void *netparser_data; // incase of RO Packet Parser, pointer to packet len table (uint16array) - void (*onPacketComplete)(int32 fd, uint16 op, uint16 len, netbuf buf); - - - // - // Buffers - // - struct { - enum NETREADSTATE { NRS_WAITOP = 0, NRS_WAITLEN = 1, NRS_WAITDATA = 2} state; - - uint32 head_left; - uint16 head[2]; - - netbuf buf; - } read; - - struct { - uint32 max_outstanding; - uint32 n_outstanding; - - uint32 dataPos; - - netbuf buf, buf_last; - } write; - - // Application Level data Pointer - // (required for backward compatibility with previous athena socket system.) - void *data; - +typedef struct SESSION{ + EVDP_DATA evdp_data; // Must be always the frist member! (some evdp's may rely on this fact) + + // Connection Type + enum{ NST_FREE=0, NST_LISTENER = 1, NST_CLIENT=2, NST_OUTGOING=3} type; + + // Flags / Settings. + bool v6; // is v6? + bool disconnect_in_progress; // To prevent stack overflows / recursive calls. + + + union{ // union to save memory. + struct sockaddr_in v4; + struct sockaddr_in6 v6; + }addr; + + + // "lowlevel" Handlers + // (Implemented by the protocol specific parser) + // + bool (*onRecv)(int32 fd); // return false = disconnect + bool (*onSend)(int32 fd); // return false = disconnect + + // Event Handlers for LISTENER type sockets + // + // onConnect gets Called when a connection has been + // successfully accepted. + // Session entry is available in this Handler! + // A returncode of false will reejct the connection (disconnect) + // Note: When rejecting a connection in onConnect by returning false + // The onDisconnect handler wont get called! + // Note: the onConnect Handler is also responsible for setting + // the appropriate netparser (which implements onRecv/onSend..) [protocol specific] + // + // onDisconnect gets called when a connection gets disconnected + // (by peer as well as by core) + // + bool (*onConnect)(int32 fd); // return false = disconnect (wont accept) + void (*onDisconnect)(int32 fd); + + + // + // Parser specific data + // + void *netparser_data; // incase of RO Packet Parser, pointer to packet len table (uint16array) + void (*onPacketComplete)(int32 fd, uint16 op, uint16 len, netbuf buf); + + + // + // Buffers + // + struct{ + enum NETREADSTATE { NRS_WAITOP = 0, NRS_WAITLEN = 1, NRS_WAITDATA = 2} state; + + uint32 head_left; + uint16 head[2]; + + netbuf buf; + } read; + + struct{ + uint32 max_outstanding; + uint32 n_outstanding; + + uint32 dataPos; + + netbuf buf, buf_last; + } write; + + // Application Level data Pointer + // (required for backward compatibility with previous athena socket system.) + void *data; + } SESSION; @@ -101,12 +101,12 @@ void network_final(); void network_do(); -/** +/** * Adds a new listner. * - * @param v6 v6 listner? - * @param *addr the address to listen on. - * @param port port to listen on + * @param v6 v6 listner? + * @param *addr the address to listen on. + * @param port port to listen on * * @return -1 on error otherwise the identifier of the new listener. */ @@ -116,26 +116,26 @@ int32 network_addlistener(bool v6, const char *addr, uint16 port); /** * Tries to establish an outgoing connection. * - * @param v6 operate with IPv6 addresses? - * @param addr the address to connect to - * @param port the port to connect to - * @param from_addr the address to connect from (local source / optional if auto -> NULL) + * @param v6 operate with IPv6 addresses? + * @param addr the address to connect to + * @param port the port to connect to + * @param from_addr the address to connect from (local source / optional if auto -> NULL) * @param from_port the port to connect from (local source / optional if auto -> 0) - * @param onConnectionEstablishedHandler callback that gets called when the connection is established. - * @param onConnectionLooseHandler callback that gets called when the connection gets disconnected (or the connection couldnt be established) + * @param onConnectionEstablishedHandler callback that gets called when the connection is established. + * @param onConnectionLooseHandler callback that gets called when the connection gets disconnected (or the connection couldnt be established) * * @return -1 on error otherwise the identifier of the new connection */ int32 network_connect(bool v6, - const char *addr, - uint16 port, - const char *from_addr, - uint16 from_port, - bool (*onConnectionEstablishedHandler)(int32 fd), - void (*onConnectionLooseHandler)(int32 fd) - ); - + const char *addr, + uint16 port, + const char *from_addr, + uint16 from_port, + bool (*onConnectionEstablishedHandler)(int32 fd), + void (*onConnectionLooseHandler)(int32 fd) +); + /** * Disconnects the given connection @@ -143,43 +143,43 @@ int32 network_connect(bool v6, * @param fd connection identifier. * * @Note: - * - onDisconnect callback gets called! - * - cleares (returns) all assigned buffers + * - onDisconnect callback gets called! + * - cleares (returns) all assigned buffers * */ void network_disconnect(int32 fd); -/** +/** * Attach's a netbuffer at the end of sending queue to the given connection * - * @param fd connection identifier - * @param buf netbuffer to attach. + * @param fd connection identifier + * @param buf netbuffer to attach. */ void network_send(int32 fd, netbuf buf); /** * Sets the parser to RO Protocol like Packet Parser. - * - * @param fd connection identifier - * @param *packetlentable pointer to array of uint16 in size of UINT16_MAX, - * @param onComplteProc callback for packet completion. + * + * @param fd connection identifier + * @param *packetlentable pointer to array of uint16 in size of UINT16_MAX, + * @param onComplteProc callback for packet completion. * * @note: - * PacketLen Table Fromat: - * each element's offsets represents th ro opcode. - * value is length. - * a length of 0 means the packet is dynamic. - * a length of UINT16_MAX means the packet is unknown. + * PacketLen Table Fromat: + * each element's offsets represents th ro opcode. + * value is length. + * a length of 0 means the packet is dynamic. + * a length of UINT16_MAX means the packet is unknown. * - * Static Packets must contain their hader in len so (0x64 == 55 ..) + * Static Packets must contain their hader in len so (0x64 == 55 ..) * */ void network_parser_set_ro(int32 fd, - int16 *packetlentable, - void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) - ); + int16 *packetlentable, + void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) + ); #define ROPACKET_UNKNOWN UINT16_MAX #define ROPACKET_DYNLEN 0 diff --git a/src/common/nullpo.c b/src/common/nullpo.c index ef2f3cd66..4383109a7 100644 --- a/src/common/nullpo.c +++ b/src/common/nullpo.c @@ -8,7 +8,7 @@ #include "../common/showmsg.h" // #include "logs.h" // 布石してみる -static void nullpo_info_core(const char *file, int line, const char *func, +static void nullpo_info_core(const char *file, int line, const char *func, const char *fmt, va_list ap); /*====================================== @@ -17,73 +17,75 @@ static void nullpo_info_core(const char *file, int line, const char *func, int nullpo_chk_f(const char *file, int line, const char *func, const void *target, const char *fmt, ...) { - va_list ap; - - if (target != NULL) - return 0; - - va_start(ap, fmt); - nullpo_info_core(file, line, func, fmt, ap); - va_end(ap); - return 1; + va_list ap; + + if (target != NULL) + return 0; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); + return 1; } int nullpo_chk(const char *file, int line, const char *func, const void *target) { - if (target != NULL) - return 0; - - nullpo_info_core(file, line, func, NULL, NULL); - return 1; + if (target != NULL) + return 0; + + nullpo_info_core(file, line, func, NULL, NULL); + return 1; } /*====================================== * nullpo情報出力(外部呼出し向けラッパ) *--------------------------------------*/ -void nullpo_info_f(const char *file, int line, const char *func, - const char *fmt, ...) +void nullpo_info_f(const char *file, int line, const char *func, + const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - nullpo_info_core(file, line, func, fmt, ap); - va_end(ap); + va_list ap; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); } void nullpo_info(const char *file, int line, const char *func) { - nullpo_info_core(file, line, func, NULL, NULL); + nullpo_info_core(file, line, func, NULL, NULL); } /*====================================== * nullpo情報出力(Main) *--------------------------------------*/ -static void nullpo_info_core(const char *file, int line, const char *func, +static void nullpo_info_core(const char *file, int line, const char *func, const char *fmt, va_list ap) { - if (file == NULL) - file = "??"; - - func = - func == NULL ? "unknown": - func[0] == '\0' ? "unknown": - func; - - ShowMessage("--- nullpo info --------------------------------------------\n"); - ShowMessage("%s:%d: in func `%s'\n", file, line, func); - if (fmt != NULL) { - if (fmt[0] != '\0') { - vprintf(fmt, ap); - - // 最後に改行したか確認 - if (fmt[strlen(fmt)-1] != '\n') - ShowMessage("\n"); - } - } - ShowMessage("--- end nullpo info ----------------------------------------\n"); - - // ここらでnullpoログをファイルに書き出せたら - // まとめて提出できるなと思っていたり。 + if (file == NULL) + file = "??"; + + func = + func == NULL ? "unknown": + func[0] == '\0' ? "unknown": + func; + + ShowMessage("--- nullpo info --------------------------------------------\n"); + ShowMessage("%s:%d: in func `%s'\n", file, line, func); + if (fmt != NULL) + { + if (fmt[0] != '\0') + { + vprintf(fmt, ap); + + // 最後に改行したか確認 + if (fmt[strlen(fmt)-1] != '\n') + ShowMessage("\n"); + } + } + ShowMessage("--- end nullpo info ----------------------------------------\n"); + + // ここらでnullpoログをファイルに書き出せたら + // まとめて提出できるなと思っていたり。 } diff --git a/src/common/nullpo.h b/src/common/nullpo.h index 67679432f..8ee86a782 100644 --- a/src/common/nullpo.h +++ b/src/common/nullpo.h @@ -71,45 +71,45 @@ #if defined(NULLPO_CHECK) #define nullpo_ret(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);} #define nullpo_retv(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return;} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return;} #define nullpo_retr(ret, t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);} #define nullpo_retb(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {break;} + if (nullpo_chk(NLP_MARK, (void *)(t))) {break;} // 可変引数マクロに関する条件コンパイル #if __STDC_VERSION__ >= 199901L /* C99に対応 */ #define nullpo_ret_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);} #define nullpo_retv_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;} #define nullpo_retr_f(ret, t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);} #define nullpo_retb_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {break;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {break;} #elif __GNUC__ >= 2 /* GCC用 */ #define nullpo_ret_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);} #define nullpo_retv_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;} #define nullpo_retr_f(ret, t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);} #define nullpo_retb_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {break;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {break;} #else @@ -189,7 +189,7 @@ int nullpo_chk(const char *file, int line, const char *func, const void *target) */ int nullpo_chk_f(const char *file, int line, const char *func, const void *target, const char *fmt, ...) -__attribute__((format(printf,5,6))); + __attribute__((format(printf,5,6))); /*====================================== @@ -217,9 +217,9 @@ void nullpo_info(const char *file, int line, const char *func); * 備考や関係変数の書き出しなどに *-------------------------------------- */ -void nullpo_info_f(const char *file, int line, const char *func, +void nullpo_info_f(const char *file, int line, const char *func, const char *fmt, ...) -__attribute__((format(printf,4,5))); + __attribute__((format(printf,4,5))); #endif /* _NULLPO_H_ */ diff --git a/src/common/raconf.c b/src/common/raconf.c index e73154f50..2703560ff 100644 --- a/src/common/raconf.c +++ b/src/common/raconf.c @@ -1,7 +1,7 @@ -// +// // Athena style config parser -// (would be better to have "one" implementation instead of .. 4 :) -// +// (would be better to have "one" implementation instead of .. 4 :) +// // // Author: Florian Wilkemeyer // @@ -25,571 +25,560 @@ #define VARNAME_LEN 64 struct raconf { - DBMap *db; + DBMap *db; }; -struct conf_value { - int64 intval; - bool bval; - double floatval; - size_t strval_len; // not includung \0 - char strval[16]; +struct conf_value{ + int64 intval; + bool bval; + double floatval; + size_t strval_len; // not includung \0 + char strval[16]; }; -static struct conf_value *makeValue(const char *key, char *val, size_t val_len) { - struct conf_value *v; - char *p; - size_t sz; - - sz = sizeof(struct conf_value); - if (val_len >= sizeof(v->strval)) - sz += (val_len - sizeof(v->strval) + 1); - - v = (struct conf_value *)aCalloc(1, sizeof(struct conf_value)); - if (v == NULL) { - ShowFatalError("raconf: makeValue => Out of Memory while allocating new node.\n"); - return NULL; - } - - memcpy(v->strval, val, val_len); - v->strval[val_len+1] = '\0'; - v->strval_len = val_len; - - - // Parse boolean value: - if ((val_len == 4) && (strncmpi("true", val, 4) == 0)) - v->bval = true; - else if ((val_len == 3) && (strncmpi("yes", val, 3) == 0)) - v->bval = true; - else if ((val_len == 3) && (strncmpi("oui", val, 3) == 0)) - v->bval = true; - else if ((val_len == 2) && (strncmpi("si", val, 2) == 0)) - v->bval = true; - else if ((val_len == 2) && (strncmpi("ja", val, 2) == 0)) - v->bval = true; - else if ((val_len == 1) && (*val == '1')) - v->bval = true; - else if ((val_len == 5) && (strncmpi("false", val, 5) == 0)) - v->bval = false; - else if ((val_len == 2) && (strncmpi("no", val, 2) == 0)) - v->bval = false; - else if ((val_len == 3) && (strncmpi("non", val, 3) == 0)) - v->bval = false; - else if ((val_len == 2) && (strncmpi("no", val, 2) == 0)) - v->bval = false; - else if ((val_len == 4) && (strncmpi("nein", val, 4) == 0)) - v->bval = false; - else if ((val_len == 1) && (*val == '0')) - v->bval = false; - else - v->bval = false; // assume false. - - // Parse number - // Supported formats: - // prefix: 0x hex . - // postix: h for hex - // b for bin (dual) - if ((val_len >= 1 && (val[val_len] == 'h')) || (val_len >= 2 && (val[0] == '0' && val[1] == 'x'))) {//HEX! - if (val[val_len] == 'h') { - val[val_len]= '\0'; - v->intval = strtoull(val, NULL, 16); - val[val_len] = 'h'; - } else - v->intval = strtoull(&val[2], NULL, 16); - } else if (val_len >= 1 && (val[val_len] == 'b')) { //BIN - val[val_len] = '\0'; - v->intval = strtoull(val, NULL, 2); - val[val_len] = 'b'; - } else if (*val >='0' && *val <= '9') { // begins with normal digit, so assume its dec. - // is it float? - bool is_float = false; - - for (p = val; *p != '\0'; p++) { - if (*p == '.') { - v->floatval = strtod(val, NULL); - v->intval = (int64) v->floatval; - is_float = true; - break; - } - } - - if (is_float == false) { - v->intval = strtoull(val, NULL, 10); - v->floatval = (double) v->intval; - } - } else { - // Everything else: lets use boolean for fallback - if (v->bval == true) - v->intval = 1; - else - v->intval = 0; - } - - return v; +static struct conf_value *makeValue(const char *key, char *val, size_t val_len){ + struct conf_value *v; + char *p; + size_t sz; + + sz = sizeof(struct conf_value); + if(val_len >= sizeof(v->strval)) + sz += (val_len - sizeof(v->strval) + 1); + + v = (struct conf_value*)aCalloc(1, sizeof(struct conf_value)); + if(v == NULL){ + ShowFatalError("raconf: makeValue => Out of Memory while allocating new node.\n"); + return NULL; + } + + memcpy(v->strval, val, val_len); + v->strval[val_len+1] = '\0'; + v->strval_len = val_len; + + + // Parse boolean value: + if((val_len == 4) && (strncmpi("true", val, 4) == 0)) + v->bval = true; + else if((val_len == 3) && (strncmpi("yes", val, 3) == 0)) + v->bval = true; + else if((val_len == 3) && (strncmpi("oui", val, 3) == 0)) + v->bval = true; + else if((val_len == 2) && (strncmpi("si", val, 2) == 0)) + v->bval = true; + else if((val_len == 2) && (strncmpi("ja", val, 2) == 0)) + v->bval = true; + else if((val_len == 1) && (*val == '1')) + v->bval = true; + else if((val_len == 5) && (strncmpi("false", val, 5) == 0)) + v->bval = false; + else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if((val_len == 3) && (strncmpi("non", val, 3) == 0)) + v->bval = false; + else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if((val_len == 4) && (strncmpi("nein", val, 4) == 0)) + v->bval = false; + else if((val_len == 1) && (*val == '0')) + v->bval = false; + else + v->bval = false; // assume false. + + // Parse number + // Supported formats: + // prefix: 0x hex . + // postix: h for hex + // b for bin (dual) + if( (val_len >= 1 && (val[val_len] == 'h')) || (val_len >= 2 && (val[0] == '0' && val[1] == 'x')) ){//HEX! + if(val[val_len] == 'h'){ + val[val_len]= '\0'; + v->intval = strtoull(val, NULL, 16); + val[val_len] = 'h'; + }else + v->intval = strtoull(&val[2], NULL, 16); + }else if( val_len >= 1 && (val[val_len] == 'b') ){ //BIN + val[val_len] = '\0'; + v->intval = strtoull(val, NULL, 2); + val[val_len] = 'b'; + }else if( *val >='0' && *val <= '9'){ // begins with normal digit, so assume its dec. + // is it float? + bool is_float = false; + + for(p = val; *p != '\0'; p++){ + if(*p == '.'){ + v->floatval = strtod(val, NULL); + v->intval = (int64) v->floatval; + is_float = true; + break; + } + } + + if(is_float == false){ + v->intval = strtoull(val, NULL, 10); + v->floatval = (double) v->intval; + } + }else{ + // Everything else: lets use boolean for fallback + if(v->bval == true) + v->intval = 1; + else + v->intval = 0; + } + + return v; }//end: makeValue() -static bool configParse(raconf inst, const char *fileName) -{ - FILE *fp; - char line[4096]; - char currentSection[SECTION_LEN]; - char *p; - char c; - int linecnt; - size_t linelen; - size_t currentSection_len; - - fp = fopen(fileName, "r"); - if (fp == NULL) { - ShowError("configParse: cannot open '%s' for reading.\n", fileName); - return false; - } - - - // Start with empty section: - currentSection[0] = '\0'; - currentSection_len = 0; - - // - linecnt = 0; - while (1) { - linecnt++; - - if (fgets(line, sizeof(line), fp) != line) - break; - - linelen = strlen(line); - p = line; - - // Skip whitespaces from beginning (space and tab) - _line_begin_skip_whities: - c = *p; - if (c == ' ' || c == '\t') { - p++; - linelen--; - goto _line_begin_skip_whities; - } - - // Remove linebreaks as (cr or lf) and whitespaces from line end! - _line_end_skip_whities_and_breaks: - c = p[linelen-1]; - if (c == '\r' || c == '\n' || c == ' ' || c == '\t') { - p[--linelen] = '\0'; - goto _line_end_skip_whities_and_breaks; - } - - // Empty line? - // or line starts with comment (commented out)? - if (linelen == 0 || (p[0] == '/' && p[1] == '/') || p[0] == ';') - continue; - - // Variable names can contain: - // A-Za-z-_.0-9 - // - // Sections start with [ .. ] (INI Style) - // - c = *p; - - // check what we have.. :) - if (c == '[') { // got section! - // Got Section! - // Search for ] - char *start = (p+1); - - while (1) { - ++p; - c = *p; - - if (c == '\0') { - ShowError("Syntax Error: unterminated Section name in %s:%u (expected ']')\n", fileName, linecnt); - fclose(fp); - return false; - } else if (c == ']') { // closing backet (section name termination) - if ((p - start + 1) > (sizeof(currentSection))) { - ShowError("Syntax Error: Section name in %s:%u is too large (max Supported length: %u chars)\n", fileName, linecnt, sizeof(currentSection)-1); - fclose(fp); - return false; - } - - // Set section! - *p = '\0'; // add termination here. - memcpy(currentSection, start, (p-start)+1); // we'll copy \0, too! (we replaced the ] backet with \0.) - currentSection_len = (p-start); - - break; - - } else if ((c >= '0' && c <= '9') || (c == '-') || (c == ' ') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { - // skip .. (allowed char / specifier) - continue; - } else { - ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Section name.\n", c, fileName, linecnt, (p-line)); - fclose(fp); - return false; - } - - }//endwhile: parse section name - - - } else if ((c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { - // Got variable! - // Search for '=' or ':' wich termiantes the name - char *start = p; - char *valuestart = NULL; - size_t start_len; - - while (1) { - ++p; - c = *p; - - if (c == '\0') { - ShowError("Syntax Error: unterminated Variable name in %s:%u\n", fileName, linecnt); - fclose(fp); - return false; - } else if ((c == '=') || (c == ':')) { - // got name termination - - *p = '\0'; // Terminate it so (start) will hold the pointer to the name. - - break; - - } else if ((c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { - // skip .. allowed char - continue; - } else { - ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Variable name.\n", c, fileName, linecnt, (p-line)); - fclose(fp); - return false; - } - - }//endwhile: parse var name - - start_len = (p-start); - if (start_len >= VARNAME_LEN) { - ShowError("%s:%u Variable length exceeds limit of %u Characters.\n", fileName, linecnt, VARNAME_LEN-1); - fclose(fp); - return false; - } else if (start_len == 0) { - ShowError("%s:%u Empty Variable name is not allowed.\n", fileName, linecnt); - fclose(fp); - return false; - } - - - valuestart = (p+1); - - - // Skip whitespace from begin of value (tab and space) - _skip_value_begin_whities: - c = *valuestart; - if (c == ' ' || c == '\t') { - valuestart++; - goto _skip_value_begin_whities; - } - - // Scan for value termination, - // wich can be \0 or comment start (// or ; (INI) ) - // - p = valuestart; - while (1) { - c = *p; - if (c == '\0') { - // Terminated by line end. - break; - } else if (c == '/' && p[1] == '/') { - // terminated by c++ style comment. - *p = '\0'; - break; - } else if (c == ';') { - // terminated by ini style comment. - *p = '\0'; - break; - } - - p++; - }//endwhile: search var value end. - - - // Strip whitespaces from end of value. - if (valuestart != p) { // not empty! - p--; - _strip_value_end_whities: - c = *p; - if (c == ' ' || c == '\t') { - *p = '\0'; - p--; - goto _strip_value_end_whities; - } - p++; - } - - - // Buildin Hook: - if (stricmp(start, "import") == 0) { - if (configParse(inst, valuestart) != true) { - ShowError("%s:%u - Import of '%s' failed!\n", fileName, linecnt, valuestart); - } - } else { - // put it to db. - struct conf_value *v, *o; - char key[(SECTION_LEN+VARNAME_LEN+1+1) ]; //+1 for delimiter, +1 for termination. - size_t section_len; - - if (*currentSection == '\0') { // empty / none - strncpy(key, "",9); - section_len = 9; - } else { - strncpy(key, currentSection, currentSection_len); - section_len = currentSection_len; - } - - key[section_len] = '.'; // Delim - - strncpy(&key[section_len+1], start, start_len); - - key[section_len + start_len + 1] = '\0'; - - - v = makeValue(key, valuestart, (p-valuestart)); - - // Try to get the old one before - o = strdb_get(inst->db, key); - if (o != NULL) { - strdb_remove(inst->db, key); - aFree(o); // - } - - strdb_put(inst->db, key, v); - } - - - } else { - ShowError("Syntax Error: unexpected Character '%c' in %s:%u (offset %u)\n", c, fileName, linecnt, (p-line)); - fclose(fp); - return false; - } - - - - } - - - - fclose(fp); - return true; +static bool configParse(raconf inst, const char *fileName){ + FILE *fp; + char line[4096]; + char currentSection[SECTION_LEN]; + char *p; + char c; + int linecnt; + size_t linelen; + size_t currentSection_len; + + fp = fopen(fileName, "r"); + if(fp == NULL){ + ShowError("configParse: cannot open '%s' for reading.\n", fileName); + return false; + } + + + // Start with empty section: + currentSection[0] = '\0'; + currentSection_len = 0; + + // + linecnt = 0; + while(1){ + linecnt++; + + if(fgets(line, sizeof(line), fp) != line) + break; + + linelen = strlen(line); + p = line; + + // Skip whitespaces from beginning (space and tab) + _line_begin_skip_whities: + c = *p; + if(c == ' ' || c == '\t'){ + p++; + linelen--; + goto _line_begin_skip_whities; + } + + // Remove linebreaks as (cr or lf) and whitespaces from line end! + _line_end_skip_whities_and_breaks: + c = p[linelen-1]; + if(c == '\r' || c == '\n' || c == ' ' || c == '\t'){ + p[--linelen] = '\0'; + goto _line_end_skip_whities_and_breaks; + } + + // Empty line? + // or line starts with comment (commented out)? + if(linelen == 0 || (p[0] == '/' && p[1] == '/') || p[0] == ';') + continue; + + // Variable names can contain: + // A-Za-z-_.0-9 + // + // Sections start with [ .. ] (INI Style) + // + c = *p; + + // check what we have.. :) + if(c == '['){ // got section! + // Got Section! + // Search for ] + char *start = (p+1); + + while(1){ + ++p; + c = *p; + + if(c == '\0'){ + ShowError("Syntax Error: unterminated Section name in %s:%u (expected ']')\n", fileName, linecnt); + fclose(fp); + return false; + }else if(c == ']'){ // closing backet (section name termination) + if( (p - start + 1) > (sizeof(currentSection) ) ){ + ShowError("Syntax Error: Section name in %s:%u is too large (max Supported length: %u chars)\n", fileName, linecnt, sizeof(currentSection)-1); + fclose(fp); + return false; + } + + // Set section! + *p = '\0'; // add termination here. + memcpy(currentSection, start, (p-start)+1 ); // we'll copy \0, too! (we replaced the ] backet with \0.) + currentSection_len = (p-start); + + break; + + }else if( (c >= '0' && c <= '9') || (c == '-') || (c == ' ') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ + // skip .. (allowed char / specifier) + continue; + }else{ + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Section name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse section name + + + }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ + // Got variable! + // Search for '=' or ':' wich termiantes the name + char *start = p; + char *valuestart = NULL; + size_t start_len; + + while(1){ + ++p; + c = *p; + + if(c == '\0'){ + ShowError("Syntax Error: unterminated Variable name in %s:%u\n", fileName, linecnt); + fclose(fp); + return false; + }else if( (c == '=') || (c == ':') ){ + // got name termination + + *p = '\0'; // Terminate it so (start) will hold the pointer to the name. + + break; + + }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ + // skip .. allowed char + continue; + }else{ + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Variable name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse var name + + start_len = (p-start); + if(start_len >= VARNAME_LEN){ + ShowError("%s:%u Variable length exceeds limit of %u Characters.\n", fileName, linecnt, VARNAME_LEN-1); + fclose(fp); + return false; + }else if(start_len == 0){ + ShowError("%s:%u Empty Variable name is not allowed.\n", fileName, linecnt); + fclose(fp); + return false; + } + + + valuestart = (p+1); + + + // Skip whitespace from begin of value (tab and space) + _skip_value_begin_whities: + c = *valuestart; + if(c == ' ' || c == '\t'){ + valuestart++; + goto _skip_value_begin_whities; + } + + // Scan for value termination, + // wich can be \0 or comment start (// or ; (INI) ) + // + p = valuestart; + while(1){ + c = *p; + if(c == '\0'){ + // Terminated by line end. + break; + }else if(c == '/' && p[1] == '/'){ + // terminated by c++ style comment. + *p = '\0'; + break; + }else if(c == ';'){ + // terminated by ini style comment. + *p = '\0'; + break; + } + + p++; + }//endwhile: search var value end. + + + // Strip whitespaces from end of value. + if(valuestart != p){ // not empty! + p--; + _strip_value_end_whities: + c = *p; + if(c == ' ' || c == '\t'){ + *p = '\0'; + p--; + goto _strip_value_end_whities; + } + p++; + } + + + // Buildin Hook: + if( stricmp(start, "import") == 0){ + if( configParse(inst, valuestart) != true){ + ShowError("%s:%u - Import of '%s' failed!\n", fileName, linecnt, valuestart); + } + }else{ + // put it to db. + struct conf_value *v, *o; + char key[ (SECTION_LEN+VARNAME_LEN+1+1) ]; //+1 for delimiter, +1 for termination. + size_t section_len; + + if(*currentSection == '\0'){ // empty / none + strncpy(key, "",9); + section_len = 9; + }else{ + strncpy(key, currentSection, currentSection_len); + section_len = currentSection_len; + } + + key[section_len] = '.'; // Delim + + strncpy(&key[section_len+1], start, start_len); + + key[section_len + start_len + 1] = '\0'; + + + v = makeValue(key, valuestart, (p-valuestart) ); + + // Try to get the old one before + o = strdb_get(inst->db, key); + if(o != NULL){ + strdb_remove(inst->db, key); + aFree(o); // + } + + strdb_put( inst->db, key, v); + } + + + }else{ + ShowError("Syntax Error: unexpected Character '%c' in %s:%u (offset %u)\n", c, fileName, linecnt, (p-line) ); + fclose(fp); + return false; + } + + + + } + + + + fclose(fp); + return true; }//end: configParse() #define MAKEKEY(dest, section, key) { size_t section_len, key_len; \ - if(section == NULL || *section == '\0'){ \ - strncpy(dest, "", 9); \ - section_len = 9; \ - }else{ \ - section_len = strlen(section); \ - strncpy(dest, section, section_len); \ - } \ - \ - dest[section_len] = '.'; \ - \ - key_len = strlen(key); \ - strncpy(&dest[section_len+1], key, key_len); \ - dest[section_len + key_len + 1] = '\0'; \ - } - - -raconf raconf_parse(const char *file_name) -{ - struct raconf *rc; - - rc = aCalloc(1, sizeof(struct raconf)); - if (rc == NULL) { - ShowFatalError("raconf_parse: failed to allocate memory for new handle\n"); - return NULL; - } - - rc->db = strdb_alloc(DB_OPT_BASE | DB_OPT_DUP_KEY, 98); - // - - if (configParse(rc, file_name) != true) { - ShowError("Failed to Parse Configuration file '%s'\n", file_name); - } - - return rc; + if(section == NULL || *section == '\0'){ \ + strncpy(dest, "", 9); \ + section_len = 9; \ + }else{ \ + section_len = strlen(section); \ + strncpy(dest, section, section_len); \ + } \ + \ + dest[section_len] = '.'; \ + \ + key_len = strlen(key); \ + strncpy(&dest[section_len+1], key, key_len); \ + dest[section_len + key_len + 1] = '\0'; \ + } + + +raconf raconf_parse(const char *file_name){ + struct raconf *rc; + + rc = aCalloc(1, sizeof(struct raconf) ); + if(rc == NULL){ + ShowFatalError("raconf_parse: failed to allocate memory for new handle\n"); + return NULL; + } + + rc->db = strdb_alloc(DB_OPT_BASE | DB_OPT_DUP_KEY, 98); + // + + if(configParse(rc, file_name) != true){ + ShowError("Failed to Parse Configuration file '%s'\n", file_name); + } + + return rc; }//end: raconf_parse() -void raconf_destroy(raconf rc) -{ - DBIterator *iter; - struct conf_value *v; - - // Clear all entrys in db. - iter = db_iterator(rc->db); - for (v = (struct conf_value *)dbi_first(iter); dbi_exists(iter); v = (struct conf_value *)dbi_next(iter)) { - aFree(v); - } - dbi_destroy(iter); - - db_destroy(rc->db); - - aFree(rc); - +void raconf_destroy(raconf rc){ + DBIterator *iter; + struct conf_value *v; + + // Clear all entrys in db. + iter = db_iterator(rc->db); + for( v = (struct conf_value*)dbi_first(iter); dbi_exists(iter); v = (struct conf_value*)dbi_next(iter) ){ + aFree(v); + } + dbi_destroy(iter); + + db_destroy(rc->db); + + aFree(rc); + }//end: raconf_destroy() -bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - - v = strdb_get(rc->db, keystr); - if (v == NULL) - return _default; - else - return v->bval; +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return v->bval; }//end: raconf_getbool() -float raconf_getfloat(raconf rc,const char *section, const char *key, float _default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) - return _default; - else - return (float)v->floatval; + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return (float)v->floatval; }//end: raconf_getfloat() -int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - - v = strdb_get(rc->db, keystr); - if (v == NULL) - return _default; - else - return v->intval; +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return v->intval; }//end: raconf_getint() -const char *raconf_getstr(raconf rc, const char *section, const char *key, const char *_default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; +const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; - MAKEKEY(keystr, section, key); + MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) - return _default; - else - return v->strval; + v = strdb_get(rc->db, keystr); + if(v == NULL) + return _default; + else + return v->strval; }//end: raconf_getstr() -bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - return _default; - } else { - return v->bval; - } - - } else { - return v->bval; - } +bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return v->bval; + } + + }else{ + return v->bval; + } }//end: raconf_getboolEx() -float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - return _default; - } else { - return (float)v->floatval; - } - - } else { - return (float)v->floatval; - } - +float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return (float)v->floatval; + } + + }else{ + return (float)v->floatval; + } + }//end: raconf_getfloatEx() -int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - return _default; - } else { - return v->intval; - } - - } else { - return v->intval; - } +int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return v->intval; + } + + }else{ + return v->intval; + } }//end: raconf_getintEx() -const char *raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default) -{ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if (v == NULL) { - return _default; - } else { - return v->strval; - } - - } else { - return v->strval; - } +const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default){ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if(v == NULL){ + return _default; + }else{ + return v->strval; + } + + }else{ + return v->strval; + } }//end: raconf_getstrEx() diff --git a/src/common/raconf.h b/src/common/raconf.h index 242c585bb..68a2b51b2 100644 --- a/src/common/raconf.h +++ b/src/common/raconf.h @@ -7,52 +7,52 @@ #include "../common/cbasetypes.h" // rAthena generic configuration file parser +// +// Config file Syntax is athena style +// extended with ini style support (including sections) // -// Config file Syntax is athena style -// extended with ini style support (including sections) -// -// Comments are started with // or ; (ini style) +// Comments are started with // or ; (ini style) // typedef struct raconf *raconf; -/** +/** * Parses a rAthna Configuration file - * + * * @param file_name path to the file to parse * * @returns not NULL incase of success */ -raconf raconf_parse(const char *file_name); +raconf raconf_parse(const char *file_name); -/** +/** * Frees a Handle received from raconf_parse * * @param rc - the handle to free */ -void raconf_destroy(raconf rc); +void raconf_destroy(raconf rc); -/** - * Gets the value for Section / Key pair, if key not exists returns _default! +/** + * Gets the value for Section / Key pair, if key not exists returns _default! * */ -bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default); -float raconf_getfloat(raconf rc,const char *section, const char *key, float _default); -int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default); -const char *raconf_getstr(raconf rc, const char *section, const char *key, const char *_default); +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default); +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default); +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default); +const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default); /** - * Gets the value for Section / Key pair, but has fallback section option if not found in section, + * Gets the value for Section / Key pair, but has fallback section option if not found in section, * if not found in both - default gets returned. * */ bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default); float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default); int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default); -const char *raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default); +const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default); diff --git a/src/common/random.c b/src/common/random.c index ab9b0052f..5c048c7eb 100644 --- a/src/common/random.c +++ b/src/common/random.c @@ -5,10 +5,10 @@ #include "../common/timer.h" // gettick #include "random.h" #if defined(WIN32) -#include "../common/winapi.h" + #include "../common/winapi.h" #elif defined(HAVE_GETPID) || defined(HAVE_GETTID) -#include -#include + #include + #include #endif #include // time #include // init_genrand, genrand_int32, genrand_res53 @@ -17,34 +17,34 @@ /// Initializes the random number generator with an appropriate seed. void rnd_init(void) { - uint32 seed = gettick(); - seed += (uint32)time(NULL); + uint32 seed = gettick(); + seed += (uint32)time(NULL); #if defined(WIN32) - seed += GetCurrentProcessId(); - seed += GetCurrentThreadId(); + seed += GetCurrentProcessId(); + seed += GetCurrentThreadId(); #else #if defined(HAVE_GETPID) - seed += (uint32)getpid(); + seed += (uint32)getpid(); #endif // HAVE_GETPID #if defined(HAVE_GETTID) - seed += (uint32)gettid(); + seed += (uint32)gettid(); #endif // HAVE_GETTID #endif - init_genrand(seed); + init_genrand(seed); } /// Initializes the random number generator. void rnd_seed(uint32 seed) { - init_genrand(seed); + init_genrand(seed); } /// Generates a random number in the interval [0, SINT32_MAX] int32 rnd(void) { - return (int32)genrand_int31(); + return (int32)genrand_int31(); } @@ -52,7 +52,7 @@ int32 rnd(void) /// NOTE: interval is open ended, so dice_faces is excluded (unless it's 0) uint32 rnd_roll(uint32 dice_faces) { - return (uint32)(rnd_uniform()*dice_faces); + return (uint32)(rnd_uniform()*dice_faces); } @@ -60,9 +60,9 @@ uint32 rnd_roll(uint32 dice_faces) /// Returns min if range is invalid. int32 rnd_value(int32 min, int32 max) { - if (min >= max) - return min; - return min + (int32)(rnd_uniform()*(max-min+1)); + if( min >= max ) + return min; + return min + (int32)(rnd_uniform()*(max-min+1)); } @@ -70,7 +70,7 @@ int32 rnd_value(int32 min, int32 max) /// NOTE: interval is open ended, so 1.0 is excluded double rnd_uniform(void) { - return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32 + return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32 } @@ -79,5 +79,5 @@ double rnd_uniform(void) /// NOTE: 53 bits is the maximum precision of a double double rnd_uniform53(void) { - return genrand_res53(); + return genrand_res53(); } diff --git a/src/common/showmsg.c b/src/common/showmsg.c index cfa1587e5..609ae3c50 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -15,33 +15,33 @@ #include "libconfig.h" #ifdef WIN32 -#include "../common/winapi.h" - -#ifdef DEBUGLOGMAP -#define DEBUGLOGPATH "log\\map-server.log" -#else -#ifdef DEBUGLOGCHAR -#define DEBUGLOGPATH "log\\char-server.log" -#else -#ifdef DEBUGLOGLOGIN -#define DEBUGLOGPATH "log\\login-server.log" -#endif -#endif -#endif + #include "../common/winapi.h" + + #ifdef DEBUGLOGMAP + #define DEBUGLOGPATH "log\\map-server.log" + #else + #ifdef DEBUGLOGCHAR + #define DEBUGLOGPATH "log\\char-server.log" + #else + #ifdef DEBUGLOGLOGIN + #define DEBUGLOGPATH "log\\login-server.log" + #endif + #endif + #endif #else -#include - -#ifdef DEBUGLOGMAP -#define DEBUGLOGPATH "log/map-server.log" -#else -#ifdef DEBUGLOGCHAR -#define DEBUGLOGPATH "log/char-server.log" -#else -#ifdef DEBUGLOGLOGIN -#define DEBUGLOGPATH "log/login-server.log" -#endif -#endif -#endif + #include + + #ifdef DEBUGLOGMAP + #define DEBUGLOGPATH "log/map-server.log" + #else + #ifdef DEBUGLOGCHAR + #define DEBUGLOGPATH "log/char-server.log" + #else + #ifdef DEBUGLOGLOGIN + #define DEBUGLOGPATH "log/login-server.log" + #endif + #endif + #endif #endif /////////////////////////////////////////////////////////////////////////////// @@ -60,41 +60,41 @@ int console_msg_log = 0;//[Ind] msg error logging #define SBUF_SIZE 2054 // never put less that what's required for the debug message -#define NEWBUF(buf) \ - struct { \ - char s_[SBUF_SIZE]; \ - StringBuf *d_; \ - char *v_; \ - int l_; \ - } buf ={"",NULL,NULL,0}; \ - //define NEWBUF - -#define BUFVPRINTF(buf,fmt,args) \ - buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \ - if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \ - {/* static buffer */ \ - buf.v_ = buf.s_; \ - } \ - else \ - {/* dynamic buffer */ \ - buf.d_ = StringBuf_Malloc(); \ - buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ - buf.v_ = StringBuf_Value(buf.d_); \ - ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ - } \ - //define BUFVPRINTF +#define NEWBUF(buf) \ + struct { \ + char s_[SBUF_SIZE]; \ + StringBuf *d_; \ + char *v_; \ + int l_; \ + } buf ={"",NULL,NULL,0}; \ +//define NEWBUF + +#define BUFVPRINTF(buf,fmt,args) \ + buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \ + if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \ + {/* static buffer */ \ + buf.v_ = buf.s_; \ + } \ + else \ + {/* dynamic buffer */ \ + buf.d_ = StringBuf_Malloc(); \ + buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ + buf.v_ = StringBuf_Value(buf.d_); \ + ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ + } \ +//define BUFVPRINTF #define BUFVAL(buf) buf.v_ #define BUFLEN(buf) buf.l_ -#define FREEBUF(buf) \ - if( buf.d_ ) \ - { \ - StringBuf_Free(buf.d_); \ - buf.d_ = NULL; \ - } \ - buf.v_ = NULL; \ - //define FREEBUF +#define FREEBUF(buf) \ + if( buf.d_ ) \ + { \ + StringBuf_Free(buf.d_); \ + buf.d_ = NULL; \ + } \ + buf.v_ = NULL; \ +//define FREEBUF /////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 @@ -104,38 +104,38 @@ int console_msg_log = 0;//[Ind] msg error logging // ansi compatible printf with control sequence parser for windows // fast hack, handle with care, not everything implemented // -// \033[#;...;#m - Set Graphics Rendition (SGR) +// \033[#;...;#m - Set Graphics Rendition (SGR) // -// printf("\x1b[1;31;40m"); // Bright red on black -// printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) -// printf("\x1b[1;30;47m"); // Bright black (grey) on dim white +// printf("\x1b[1;31;40m"); // Bright red on black +// printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) +// printf("\x1b[1;30;47m"); // Bright black (grey) on dim white // // Style Foreground Background -// 1st Digit 2nd Digit 3rd Digit RGB -// 0 - Reset 30 - Black 40 - Black 000 -// 1 - FG Bright 31 - Red 41 - Red 100 -// 2 - Unknown 32 - Green 42 - Green 010 -// 3 - Blink 33 - Yellow 43 - Yellow 110 -// 4 - Underline 34 - Blue 44 - Blue 001 -// 5 - BG Bright 35 - Magenta 45 - Magenta 101 -// 6 - Unknown 36 - Cyan 46 - Cyan 011 -// 7 - Reverse 37 - White 47 - White 111 +// 1st Digit 2nd Digit 3rd Digit RGB +// 0 - Reset 30 - Black 40 - Black 000 +// 1 - FG Bright 31 - Red 41 - Red 100 +// 2 - Unknown 32 - Green 42 - Green 010 +// 3 - Blink 33 - Yellow 43 - Yellow 110 +// 4 - Underline 34 - Blue 44 - Blue 001 +// 5 - BG Bright 35 - Magenta 45 - Magenta 101 +// 6 - Unknown 36 - Cyan 46 - Cyan 011 +// 7 - Reverse 37 - White 47 - White 111 // 8 - Concealed (invisible) // // \033[#A - Cursor Up (CUU) -// Moves the cursor up by the specified number of lines without changing columns. +// Moves the cursor up by the specified number of lines without changing columns. // If the cursor is already on the top line, this sequence is ignored. \e[A is equivalent to \e[1A. // // \033[#B - Cursor Down (CUD) -// Moves the cursor down by the specified number of lines without changing columns. +// Moves the cursor down by the specified number of lines without changing columns. // If the cursor is already on the bottom line, this sequence is ignored. \e[B is equivalent to \e[1B. // // \033[#C - Cursor Forward (CUF) -// Moves the cursor forward by the specified number of columns without changing lines. +// Moves the cursor forward by the specified number of columns without changing lines. // If the cursor is already in the rightmost column, this sequence is ignored. \e[C is equivalent to \e[1C. // // \033[#D - Cursor Backward (CUB) -// Moves the cursor back by the specified number of columns without changing lines. +// Moves the cursor back by the specified number of columns without changing lines. // If the cursor is already in the leftmost column, this sequence is ignored. \e[D is equivalent to \e[1D. // // \033[#E - Cursor Next Line (CNL) @@ -148,15 +148,15 @@ int console_msg_log = 0;//[Ind] msg error logging // Moves the cursor to indicated column in current row. \e[G is equivalent to \e[1G. // // \033[#;#H - Cursor Position (CUP) -// Moves the cursor to the specified position. The first # specifies the line number, -// the second # specifies the column. If you do not specify a position, the cursor moves to the home position: +// Moves the cursor to the specified position. The first # specifies the line number, +// the second # specifies the column. If you do not specify a position, the cursor moves to the home position: // the upper-left corner of the screen (line 1, column 1). // // \033[#;#f - Horizontal & Vertical Position // (same as \033[#;#H) // // \033[s - Save Cursor Position (SCP) -// The current cursor position is saved. +// The current cursor position is saved. // // \033[u - Restore cursor position (RCP) // Restores the cursor position saved with the (SCP) sequence \033[s. @@ -194,295 +194,331 @@ Escape sequences for Select Character Set #define is_console(handle) (FILE_TYPE_CHAR==GetFileType(handle)) /////////////////////////////////////////////////////////////////////////////// -int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) +int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) { - ///////////////////////////////////////////////////////////////// - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - static COORD saveposition = {0,0}; - */ - - ///////////////////////////////////////////////////////////////// - DWORD written; - char *p, *q; - NEWBUF(tempbuf); // temporary buffer - - if (!fmt || !*fmt) - return 0; - - // Print everything to the buffer - BUFVPRINTF(tempbuf,fmt,argptr); - - if (!is_console(handle) && stdout_with_ansisequence) { - WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); - return 0; - } - - // start with processing - p = BUFVAL(tempbuf); - while ((q = strchr(p, 0x1b)) != NULL) { - // find the escape character - if (0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0)) // write up to the escape - WriteFile(handle, p, (DWORD)(q-p), &written, 0); - - if (q[1]!='[') { - // write the escape char (whatever purpose it has) - if (0==WriteConsole(handle, q, 1, &written, 0)) - WriteFile(handle,q, 1, &written, 0); - p=q+1; //and start searching again - } else { - // from here, we will skip the '\033[' - // we break at the first unprocessible position - // assuming regular text is starting there - uint8 numbers[16], numpoint=0; - CONSOLE_SCREEN_BUFFER_INFO info; - - // initialize - GetConsoleScreenBufferInfo(handle, &info); - memset(numbers,0,sizeof(numbers)); - - // skip escape and bracket - q=q+2; - for (;;) { - if (ISDIGIT(*q)) { - // add number to number array, only accept 2digits, shift out the rest - // so // \033[123456789m will become \033[89m - numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); - ++q; - // and next character - continue; - } else if (*q == ';') { - // delimiter - if (numpoint7) num=7; // set white for 37, 38 and 39 - info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); - if ((num & 0x01)>0) // lowest bit set = red - info.wAttributes |= FOREGROUND_RED; - if ((num & 0x02)>0) // second bit set = green - info.wAttributes |= FOREGROUND_GREEN; - if ((num & 0x04)>0) // third bit set = blue - info.wAttributes |= FOREGROUND_BLUE; - } else if (0x40 == (0xF0 & numbers[i])) { - // background - uint8 num = numbers[i]&0x0F; - if (num==9) info.wAttributes |= BACKGROUND_INTENSITY; - if (num>7) num=7; // set white for 47, 48 and 49 - info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); - if ((num & 0x01)>0) // lowest bit set = red - info.wAttributes |= BACKGROUND_RED; - if ((num & 0x02)>0) // second bit set = green - info.wAttributes |= BACKGROUND_GREEN; - if ((num & 0x04)>0) // third bit set = blue - info.wAttributes |= BACKGROUND_BLUE; - } - } - // set the attributes - SetConsoleTextAttribute(handle, info.wAttributes); - } else if (*q=='J') { - // \033[#J - Erase Display (ED) - // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. - // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. - // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). - uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); - int cnt; - DWORD tmp; - COORD origin = {0,0}; - if (num==1) { - // chars from start up to and including cursor - cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; - } else if (num==2) { - // Number of chars on screen. - cnt = info.dwSize.X * info.dwSize.Y; - SetConsoleCursorPosition(handle, origin); - } else { // 0 and default - // number of chars from cursor to end - origin = info.dwCursorPosition; - cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; - } - FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); - FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); - } else if (*q=='K') { - // \033[K : clear line from actual position to end of the line - // \033[0K - Clears all characters from the cursor position to the end of the line. - // \033[1K - Clears all characters from start of line to the cursor position. - // \033[2K - Clears all characters of the whole line. - - uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); - COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 - SHORT cnt; - DWORD tmp; - if (num==1) { - cnt = info.dwCursorPosition.X + 1; - } else if (num==2) { - cnt = info.dwSize.X; - } else { // 0 and default - origin = info.dwCursorPosition; - cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full - } - FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); - FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); - } else if (*q == 'H' || *q == 'f') { - // \033[#;#H - Cursor Position (CUP) - // \033[#;#f - Horizontal & Vertical Position - // The first # specifies the line number, the second # specifies the column. - // The default for both is 1 - info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; - info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; - - if (info.dwCursorPosition.X >= info.dwSize.X) info.dwCursorPosition.Y = info.dwSize.X-1; - if (info.dwCursorPosition.Y >= info.dwSize.Y) info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q=='s') { - // \033[s - Save Cursor Position (SCP) - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(handle, &info); - saveposition = info.dwCursorPosition; - */ - } else if (*q=='u') { - // \033[u - Restore cursor position (RCP) - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - SetConsoleCursorPosition(handle, saveposition); - */ - } else if (*q == 'A') { - // \033[#A - Cursor Up (CUU) - // Moves the cursor UP # number of lines - info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if (info.dwCursorPosition.Y < 0) - info.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q == 'B') { - // \033[#B - Cursor Down (CUD) - // Moves the cursor DOWN # number of lines - info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if (info.dwCursorPosition.Y >= info.dwSize.Y) - info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q == 'C') { - // \033[#C - Cursor Forward (CUF) - // Moves the cursor RIGHT # number of columns - info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if (info.dwCursorPosition.X >= info.dwSize.X) - info.dwCursorPosition.X = info.dwSize.X-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q == 'D') { - // \033[#D - Cursor Backward (CUB) - // Moves the cursor LEFT # number of columns - info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if (info.dwCursorPosition.X < 0) - info.dwCursorPosition.X = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q == 'E') { - // \033[#E - Cursor Next Line (CNL) - // Moves the cursor down the indicated # of rows, to column 1 - info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - info.dwCursorPosition.X = 0; - - if (info.dwCursorPosition.Y >= info.dwSize.Y) - info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q == 'F') { - // \033[#F - Cursor Preceding Line (CPL) - // Moves the cursor up the indicated # of rows, to column 1. - info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - info.dwCursorPosition.X = 0; - - if (info.dwCursorPosition.Y < 0) - info.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q == 'G') { - // \033[#G - Cursor Horizontal Absolute (CHA) - // Moves the cursor to indicated column in current row. - info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; - - if (info.dwCursorPosition.X >= info.dwSize.X) - info.dwCursorPosition.X = info.dwSize.X-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { - // not implemented, just skip - } else { - // no number nor valid sequencer - // something is fishy, we break and give the current char free - --q; - } - // skip the sequencer and search again - p = q+1; - break; - }// end while - } - } - if (*p) // write the rest of the buffer - if (0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0)) - WriteFile(handle, p, (DWORD)strlen(p), &written, 0); - FREEBUF(tempbuf); - return 0; + ///////////////////////////////////////////////////////////////// + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + static COORD saveposition = {0,0}; + */ + + ///////////////////////////////////////////////////////////////// + DWORD written; + char *p, *q; + NEWBUF(tempbuf); // temporary buffer + + if(!fmt || !*fmt) + return 0; + + // Print everything to the buffer + BUFVPRINTF(tempbuf,fmt,argptr); + + if( !is_console(handle) && stdout_with_ansisequence ) + { + WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); + return 0; + } + + // start with processing + p = BUFVAL(tempbuf); + while ((q = strchr(p, 0x1b)) != NULL) + { // find the escape character + if( 0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0) ) // write up to the escape + WriteFile(handle, p, (DWORD)(q-p), &written, 0); + + if( q[1]!='[' ) + { // write the escape char (whatever purpose it has) + if(0==WriteConsole(handle, q, 1, &written, 0) ) + WriteFile(handle,q, 1, &written, 0); + p=q+1; //and start searching again + } + else + { // from here, we will skip the '\033[' + // we break at the first unprocessible position + // assuming regular text is starting there + uint8 numbers[16], numpoint=0; + CONSOLE_SCREEN_BUFFER_INFO info; + + // initialize + GetConsoleScreenBufferInfo(handle, &info); + memset(numbers,0,sizeof(numbers)); + + // skip escape and bracket + q=q+2; + for(;;) + { + if( ISDIGIT(*q) ) + { // add number to number array, only accept 2digits, shift out the rest + // so // \033[123456789m will become \033[89m + numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); + ++q; + // and next character + continue; + } + else if( *q == ';' ) + { // delimiter + if(numpoint7) num=7; // set white for 37, 38 and 39 + info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); + if( (num & 0x01)>0 ) // lowest bit set = red + info.wAttributes |= FOREGROUND_RED; + if( (num & 0x02)>0 ) // second bit set = green + info.wAttributes |= FOREGROUND_GREEN; + if( (num & 0x04)>0 ) // third bit set = blue + info.wAttributes |= FOREGROUND_BLUE; + } + else if( 0x40 == (0xF0 & numbers[i]) ) + { // background + uint8 num = numbers[i]&0x0F; + if(num==9) info.wAttributes |= BACKGROUND_INTENSITY; + if(num>7) num=7; // set white for 47, 48 and 49 + info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); + if( (num & 0x01)>0 ) // lowest bit set = red + info.wAttributes |= BACKGROUND_RED; + if( (num & 0x02)>0 ) // second bit set = green + info.wAttributes |= BACKGROUND_GREEN; + if( (num & 0x04)>0 ) // third bit set = blue + info.wAttributes |= BACKGROUND_BLUE; + } + } + // set the attributes + SetConsoleTextAttribute(handle, info.wAttributes); + } + else if( *q=='J' ) + { // \033[#J - Erase Display (ED) + // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. + // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. + // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). + uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); + int cnt; + DWORD tmp; + COORD origin = {0,0}; + if(num==1) + { // chars from start up to and including cursor + cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; + } + else if(num==2) + { // Number of chars on screen. + cnt = info.dwSize.X * info.dwSize.Y; + SetConsoleCursorPosition(handle, origin); + } + else// 0 and default + { // number of chars from cursor to end + origin = info.dwCursorPosition; + cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; + } + FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); + FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); + } + else if( *q=='K' ) + { // \033[K : clear line from actual position to end of the line + // \033[0K - Clears all characters from the cursor position to the end of the line. + // \033[1K - Clears all characters from start of line to the cursor position. + // \033[2K - Clears all characters of the whole line. + + uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); + COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 + SHORT cnt; + DWORD tmp; + if(num==1) + { + cnt = info.dwCursorPosition.X + 1; + } + else if(num==2) + { + cnt = info.dwSize.X; + } + else// 0 and default + { + origin = info.dwCursorPosition; + cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full + } + FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); + FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); + } + else if( *q == 'H' || *q == 'f' ) + { // \033[#;#H - Cursor Position (CUP) + // \033[#;#f - Horizontal & Vertical Position + // The first # specifies the line number, the second # specifies the column. + // The default for both is 1 + info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; + info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; + + if( info.dwCursorPosition.X >= info.dwSize.X ) info.dwCursorPosition.Y = info.dwSize.X-1; + if( info.dwCursorPosition.Y >= info.dwSize.Y ) info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q=='s' ) + { // \033[s - Save Cursor Position (SCP) + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(handle, &info); + saveposition = info.dwCursorPosition; + */ + } + else if( *q=='u' ) + { // \033[u - Restore cursor position (RCP) + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + SetConsoleCursorPosition(handle, saveposition); + */ + } + else if( *q == 'A' ) + { // \033[#A - Cursor Up (CUU) + // Moves the cursor UP # number of lines + info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if( info.dwCursorPosition.Y < 0 ) + info.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q == 'B' ) + { // \033[#B - Cursor Down (CUD) + // Moves the cursor DOWN # number of lines + info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if( info.dwCursorPosition.Y >= info.dwSize.Y ) + info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q == 'C' ) + { // \033[#C - Cursor Forward (CUF) + // Moves the cursor RIGHT # number of columns + info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if( info.dwCursorPosition.X >= info.dwSize.X ) + info.dwCursorPosition.X = info.dwSize.X-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q == 'D' ) + { // \033[#D - Cursor Backward (CUB) + // Moves the cursor LEFT # number of columns + info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if( info.dwCursorPosition.X < 0 ) + info.dwCursorPosition.X = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q == 'E' ) + { // \033[#E - Cursor Next Line (CNL) + // Moves the cursor down the indicated # of rows, to column 1 + info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + info.dwCursorPosition.X = 0; + + if( info.dwCursorPosition.Y >= info.dwSize.Y ) + info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q == 'F' ) + { // \033[#F - Cursor Preceding Line (CPL) + // Moves the cursor up the indicated # of rows, to column 1. + info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + info.dwCursorPosition.X = 0; + + if( info.dwCursorPosition.Y < 0 ) + info.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q == 'G' ) + { // \033[#G - Cursor Horizontal Absolute (CHA) + // Moves the cursor to indicated column in current row. + info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; + + if( info.dwCursorPosition.X >= info.dwSize.X ) + info.dwCursorPosition.X = info.dwSize.X-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } + else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') + { // not implemented, just skip + } + else + { // no number nor valid sequencer + // something is fishy, we break and give the current char free + --q; + } + // skip the sequencer and search again + p = q+1; + break; + }// end while + } + } + if (*p) // write the rest of the buffer + if( 0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0) ) + WriteFile(handle, p, (DWORD)strlen(p), &written, 0); + FREEBUF(tempbuf); + return 0; } -int FPRINTF(HANDLE handle, const char *fmt, ...) +int FPRINTF(HANDLE handle, const char *fmt, ...) { - int ret; - va_list argptr; - va_start(argptr, fmt); - ret = VFPRINTF(handle,fmt,argptr); - va_end(argptr); - return ret; + int ret; + va_list argptr; + va_start(argptr, fmt); + ret = VFPRINTF(handle,fmt,argptr); + va_end(argptr); + return ret; } #define FFLUSH(handle) @@ -496,109 +532,129 @@ int FPRINTF(HANDLE handle, const char *fmt, ...) #define is_console(file) (0!=isatty(fileno(file))) //vprintf_without_ansiformats -int VFPRINTF(FILE *file, const char *fmt, va_list argptr) +int VFPRINTF(FILE *file, const char *fmt, va_list argptr) { - char *p, *q; - NEWBUF(tempbuf); // temporary buffer - - if (!fmt || !*fmt) - return 0; - - if (is_console(file) || stdout_with_ansisequence) { - vfprintf(file, fmt, argptr); - return 0; - } - - // Print everything to the buffer - BUFVPRINTF(tempbuf,fmt,argptr); - - // start with processing - p = BUFVAL(tempbuf); - while ((q = strchr(p, 0x1b)) != NULL) { - // find the escape character - fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape - if (q[1]!='[') { - // write the escape char (whatever purpose it has) - fprintf(file, "%.*s", 1, q); - p=q+1; //and start searching again - } else { - // from here, we will skip the '\033[' - // we break at the first unprocessible position - // assuming regular text is starting there - - // skip escape and bracket - q=q+2; - while (1) { - if (ISDIGIT(*q)) { - ++q; - // and next character - continue; - } else if (*q == ';') { - // delimiter - ++q; - // and next number - continue; - } else if (*q == 'm') { - // \033[#;...;#m - Set Graphics Rendition (SGR) - // set the attributes - } else if (*q=='J') { - // \033[#J - Erase Display (ED) - } else if (*q=='K') { - // \033[K : clear line from actual position to end of the line - } else if (*q == 'H' || *q == 'f') { - // \033[#;#H - Cursor Position (CUP) - // \033[#;#f - Horizontal & Vertical Position - } else if (*q=='s') { - // \033[s - Save Cursor Position (SCP) - } else if (*q=='u') { - // \033[u - Restore cursor position (RCP) - } else if (*q == 'A') { - // \033[#A - Cursor Up (CUU) - // Moves the cursor UP # number of lines - } else if (*q == 'B') { - // \033[#B - Cursor Down (CUD) - // Moves the cursor DOWN # number of lines - } else if (*q == 'C') { - // \033[#C - Cursor Forward (CUF) - // Moves the cursor RIGHT # number of columns - } else if (*q == 'D') { - // \033[#D - Cursor Backward (CUB) - // Moves the cursor LEFT # number of columns - } else if (*q == 'E') { - // \033[#E - Cursor Next Line (CNL) - // Moves the cursor down the indicated # of rows, to column 1 - } else if (*q == 'F') { - // \033[#F - Cursor Preceding Line (CPL) - // Moves the cursor up the indicated # of rows, to column 1. - } else if (*q == 'G') { - // \033[#G - Cursor Horizontal Absolute (CHA) - // Moves the cursor to indicated column in current row. - } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { - // not implemented, just skip - } else { - // no number nor valid sequencer - // something is fishy, we break and give the current char free - --q; - } - // skip the sequencer and search again - p = q+1; - break; - }// end while - } - } - if (*p) // write the rest of the buffer - fprintf(file, "%s", p); - FREEBUF(tempbuf); - return 0; + char *p, *q; + NEWBUF(tempbuf); // temporary buffer + + if(!fmt || !*fmt) + return 0; + + if( is_console(file) || stdout_with_ansisequence ) + { + vfprintf(file, fmt, argptr); + return 0; + } + + // Print everything to the buffer + BUFVPRINTF(tempbuf,fmt,argptr); + + // start with processing + p = BUFVAL(tempbuf); + while ((q = strchr(p, 0x1b)) != NULL) + { // find the escape character + fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape + if( q[1]!='[' ) + { // write the escape char (whatever purpose it has) + fprintf(file, "%.*s", 1, q); + p=q+1; //and start searching again + } + else + { // from here, we will skip the '\033[' + // we break at the first unprocessible position + // assuming regular text is starting there + + // skip escape and bracket + q=q+2; + while(1) + { + if( ISDIGIT(*q) ) + { + ++q; + // and next character + continue; + } + else if( *q == ';' ) + { // delimiter + ++q; + // and next number + continue; + } + else if( *q == 'm' ) + { // \033[#;...;#m - Set Graphics Rendition (SGR) + // set the attributes + } + else if( *q=='J' ) + { // \033[#J - Erase Display (ED) + } + else if( *q=='K' ) + { // \033[K : clear line from actual position to end of the line + } + else if( *q == 'H' || *q == 'f' ) + { // \033[#;#H - Cursor Position (CUP) + // \033[#;#f - Horizontal & Vertical Position + } + else if( *q=='s' ) + { // \033[s - Save Cursor Position (SCP) + } + else if( *q=='u' ) + { // \033[u - Restore cursor position (RCP) + } + else if( *q == 'A' ) + { // \033[#A - Cursor Up (CUU) + // Moves the cursor UP # number of lines + } + else if( *q == 'B' ) + { // \033[#B - Cursor Down (CUD) + // Moves the cursor DOWN # number of lines + } + else if( *q == 'C' ) + { // \033[#C - Cursor Forward (CUF) + // Moves the cursor RIGHT # number of columns + } + else if( *q == 'D' ) + { // \033[#D - Cursor Backward (CUB) + // Moves the cursor LEFT # number of columns + } + else if( *q == 'E' ) + { // \033[#E - Cursor Next Line (CNL) + // Moves the cursor down the indicated # of rows, to column 1 + } + else if( *q == 'F' ) + { // \033[#F - Cursor Preceding Line (CPL) + // Moves the cursor up the indicated # of rows, to column 1. + } + else if( *q == 'G' ) + { // \033[#G - Cursor Horizontal Absolute (CHA) + // Moves the cursor to indicated column in current row. + } + else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') + { // not implemented, just skip + } + else + { // no number nor valid sequencer + // something is fishy, we break and give the current char free + --q; + } + // skip the sequencer and search again + p = q+1; + break; + }// end while + } + } + if (*p) // write the rest of the buffer + fprintf(file, "%s", p); + FREEBUF(tempbuf); + return 0; } -int FPRINTF(FILE *file, const char *fmt, ...) +int FPRINTF(FILE *file, const char *fmt, ...) { - int ret; - va_list argptr; - va_start(argptr, fmt); - ret = VFPRINTF(file,fmt,argptr); - va_end(argptr); - return ret; + int ret; + va_list argptr; + va_start(argptr, fmt); + ret = VFPRINTF(file,fmt,argptr); + va_end(argptr); + return ret; } #define FFLUSH fflush @@ -621,225 +677,216 @@ char timestamp_format[20] = ""; //For displaying Timestamps int _vShowMessage(enum msg_type flag, const char *string, va_list ap) { - va_list apcopy; - char prefix[100]; + va_list apcopy; + char prefix[100]; #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) - FILE *fp; + FILE *fp; #endif - - if (!string || *string == '\0') { - ShowError("Empty string passed to _vShowMessage().\n"); - return 1; - } - /** - * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. - **/ + + if (!string || *string == '\0') { + ShowError("Empty string passed to _vShowMessage().\n"); + return 1; + } + /** + * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. + **/ #if defined(BUILDBOT) - if (flag == MSG_WARNING || - flag == MSG_ERROR || - flag == MSG_SQL) { - buildbotflag = 1; - } + if( flag == MSG_WARNING || + flag == MSG_ERROR || + flag == MSG_SQL ) { + buildbotflag = 1; + } #endif - if ( - (flag == MSG_WARNING && console_msg_log&1) || - ((flag == MSG_ERROR || flag == MSG_SQL) && console_msg_log&2) || - (flag == MSG_DEBUG && console_msg_log&4)) { //[Ind] - FILE *log = NULL; - if ((log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+"))) { - char timestring[255]; - time_t curtime; - time(&curtime); - strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); - fprintf(log,"(%s) [ %s ] : ", - timestring, - flag == MSG_WARNING ? "Warning" : - flag == MSG_ERROR ? "Error" : - flag == MSG_SQL ? "SQL Error" : - flag == MSG_DEBUG ? "Debug" : - "Unknown"); - va_copy(apcopy, ap); - vfprintf(log,string,apcopy); - va_end(apcopy); - fclose(log); - } - } - if ( - (flag == MSG_INFORMATION && msg_silent&1) || - (flag == MSG_STATUS && msg_silent&2) || - (flag == MSG_NOTICE && msg_silent&4) || - (flag == MSG_WARNING && msg_silent&8) || - (flag == MSG_ERROR && msg_silent&16) || - (flag == MSG_SQL && msg_silent&16) || - (flag == MSG_DEBUG && msg_silent&32) - ) - return 0; //Do not print it. - - if (timestamp_format[0] && flag != MSG_NONE) { - //Display time format. [Skotlex] - time_t t = time(NULL); - strftime(prefix, 80, timestamp_format, localtime(&t)); - } else prefix[0]='\0'; - - switch (flag) { - case MSG_NONE: // direct printf replacement - break; - case MSG_STATUS: //Bright Green (To inform about good things) - strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); - break; - case MSG_SQL: //Bright Violet (For dumping out anything related with SQL) <- Actually, this is mostly used for SQL errors with the database, as successes can as well just be anything else... [Skotlex] - strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); - break; - case MSG_INFORMATION: //Bright White (Variable information) - strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); - break; - case MSG_NOTICE: //Bright White (Less than a warning) - strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); - break; - case MSG_WARNING: //Bright Yellow - strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); - break; - case MSG_DEBUG: //Bright Cyan, important stuff! - strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); - break; - case MSG_ERROR: //Bright Red (Regular errors) - strcat(prefix,CL_RED"[Error]"CL_RESET":"); - break; - case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) - strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); - break; - default: - ShowError("In function _vShowMessage() -> Invalid flag passed.\n"); - return 1; - } - - if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) { - //Send Errors to StdErr [Skotlex] - FPRINTF(STDERR, "%s ", prefix); - va_copy(apcopy, ap); - VFPRINTF(STDERR, string, apcopy); - va_end(apcopy); - FFLUSH(STDERR); - } else { - if (flag != MSG_NONE) - FPRINTF(STDOUT, "%s ", prefix); - va_copy(apcopy, ap); - VFPRINTF(STDOUT, string, apcopy); - va_end(apcopy); - FFLUSH(STDOUT); - } + if( + ( flag == MSG_WARNING && console_msg_log&1 ) || + ( ( flag == MSG_ERROR || flag == MSG_SQL ) && console_msg_log&2 ) || + ( flag == MSG_DEBUG && console_msg_log&4 ) ) {//[Ind] + FILE *log = NULL; + if( (log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { + char timestring[255]; + time_t curtime; + time(&curtime); + strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); + fprintf(log,"(%s) [ %s ] : ", + timestring, + flag == MSG_WARNING ? "Warning" : + flag == MSG_ERROR ? "Error" : + flag == MSG_SQL ? "SQL Error" : + flag == MSG_DEBUG ? "Debug" : + "Unknown"); + va_copy(apcopy, ap); + vfprintf(log,string,apcopy); + va_end(apcopy); + fclose(log); + } + } + if( + (flag == MSG_INFORMATION && msg_silent&1) || + (flag == MSG_STATUS && msg_silent&2) || + (flag == MSG_NOTICE && msg_silent&4) || + (flag == MSG_WARNING && msg_silent&8) || + (flag == MSG_ERROR && msg_silent&16) || + (flag == MSG_SQL && msg_silent&16) || + (flag == MSG_DEBUG && msg_silent&32) + ) + return 0; //Do not print it. + + if (timestamp_format[0] && flag != MSG_NONE) + { //Display time format. [Skotlex] + time_t t = time(NULL); + strftime(prefix, 80, timestamp_format, localtime(&t)); + } else prefix[0]='\0'; + + switch (flag) { + case MSG_NONE: // direct printf replacement + break; + case MSG_STATUS: //Bright Green (To inform about good things) + strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); + break; + case MSG_SQL: //Bright Violet (For dumping out anything related with SQL) <- Actually, this is mostly used for SQL errors with the database, as successes can as well just be anything else... [Skotlex] + strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); + break; + case MSG_INFORMATION: //Bright White (Variable information) + strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); + break; + case MSG_NOTICE: //Bright White (Less than a warning) + strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); + break; + case MSG_WARNING: //Bright Yellow + strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); + break; + case MSG_DEBUG: //Bright Cyan, important stuff! + strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); + break; + case MSG_ERROR: //Bright Red (Regular errors) + strcat(prefix,CL_RED"[Error]"CL_RESET":"); + break; + case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) + strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); + break; + default: + ShowError("In function _vShowMessage() -> Invalid flag passed.\n"); + return 1; + } + + if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) + { //Send Errors to StdErr [Skotlex] + FPRINTF(STDERR, "%s ", prefix); + va_copy(apcopy, ap); + VFPRINTF(STDERR, string, apcopy); + va_end(apcopy); + FFLUSH(STDERR); + } else { + if (flag != MSG_NONE) + FPRINTF(STDOUT, "%s ", prefix); + va_copy(apcopy, ap); + VFPRINTF(STDOUT, string, apcopy); + va_end(apcopy); + FFLUSH(STDOUT); + } #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) - if (strlen(DEBUGLOGPATH) > 0) { - fp=fopen(DEBUGLOGPATH,"a"); - if (fp == NULL) { - FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); - FFLUSH(STDERR); - } else { - fprintf(fp,"%s ", prefix); - va_copy(apcopy, ap); - vfprintf(fp,string,apcopy); - va_end(apcopy); - fclose(fp); - } - } else { - FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); - FFLUSH(STDERR); - } + if(strlen(DEBUGLOGPATH) > 0) { + fp=fopen(DEBUGLOGPATH,"a"); + if (fp == NULL) { + FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); + FFLUSH(STDERR); + } else { + fprintf(fp,"%s ", prefix); + va_copy(apcopy, ap); + vfprintf(fp,string,apcopy); + va_end(apcopy); + fclose(fp); + } + } else { + FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); + FFLUSH(STDERR); + } #endif - return 0; + return 0; } void ClearScreen(void) { #ifndef _WIN32 - ShowMessage(CL_CLS); // to prevent empty string passed messages + ShowMessage(CL_CLS); // to prevent empty string passed messages #endif } int _ShowMessage(enum msg_type flag, const char *string, ...) { - int ret; - va_list ap; - va_start(ap, string); - ret = _vShowMessage(flag, string, ap); - va_end(ap); - return ret; + int ret; + va_list ap; + va_start(ap, string); + ret = _vShowMessage(flag, string, ap); + va_end(ap); + return ret; } // direct printf replacement -void ShowMessage(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_NONE, string, ap); - va_end(ap); +void ShowMessage(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_NONE, string, ap); + va_end(ap); } -void ShowStatus(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_STATUS, string, ap); - va_end(ap); +void ShowStatus(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_STATUS, string, ap); + va_end(ap); } -void ShowSQL(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_SQL, string, ap); - va_end(ap); +void ShowSQL(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_SQL, string, ap); + va_end(ap); } -void ShowInfo(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_INFORMATION, string, ap); - va_end(ap); +void ShowInfo(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_INFORMATION, string, ap); + va_end(ap); } -void ShowNotice(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_NOTICE, string, ap); - va_end(ap); +void ShowNotice(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_NOTICE, string, ap); + va_end(ap); } -void ShowWarning(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_WARNING, string, ap); - va_end(ap); +void ShowWarning(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_WARNING, string, ap); + va_end(ap); } void ShowConfigWarning(config_setting_t *config, const char *string, ...) { - StringBuf buf; - va_list ap; - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, string); - StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); - va_start(ap, string); - _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap); - va_end(ap); - StringBuf_Destroy(&buf); + StringBuf buf; + va_list ap; + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, string); + StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); + va_start(ap, string); + _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap); + va_end(ap); + StringBuf_Destroy(&buf); } -void ShowDebug(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_DEBUG, string, ap); - va_end(ap); +void ShowDebug(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_DEBUG, string, ap); + va_end(ap); } -void ShowError(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_ERROR, string, ap); - va_end(ap); +void ShowError(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_ERROR, string, ap); + va_end(ap); } -void ShowFatalError(const char *string, ...) -{ - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_FATALERROR, string, ap); - va_end(ap); +void ShowFatalError(const char *string, ...) { + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_FATALERROR, string, ap); + va_end(ap); } diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 8c2b5bd42..0d6cb5c9f 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -14,58 +14,58 @@ // \033[0m : reset color parameter // \033[1m : use bold for font -#define CL_RESET "\033[0m" -#define CL_CLS "\033[2J" -#define CL_CLL "\033[K" +#define CL_RESET "\033[0m" +#define CL_CLS "\033[2J" +#define CL_CLL "\033[K" // font settings -#define CL_BOLD "\033[1m" -#define CL_NORM CL_RESET -#define CL_NORMAL CL_RESET -#define CL_NONE CL_RESET +#define CL_BOLD "\033[1m" +#define CL_NORM CL_RESET +#define CL_NORMAL CL_RESET +#define CL_NONE CL_RESET // foreground color and bold font (bright color on windows) -#define CL_WHITE "\033[1;37m" -#define CL_GRAY "\033[1;30m" -#define CL_RED "\033[1;31m" -#define CL_GREEN "\033[1;32m" -#define CL_YELLOW "\033[1;33m" -#define CL_BLUE "\033[1;34m" -#define CL_MAGENTA "\033[1;35m" -#define CL_CYAN "\033[1;36m" +#define CL_WHITE "\033[1;37m" +#define CL_GRAY "\033[1;30m" +#define CL_RED "\033[1;31m" +#define CL_GREEN "\033[1;32m" +#define CL_YELLOW "\033[1;33m" +#define CL_BLUE "\033[1;34m" +#define CL_MAGENTA "\033[1;35m" +#define CL_CYAN "\033[1;36m" // background color -#define CL_BG_BLACK "\033[40m" -#define CL_BG_RED "\033[41m" -#define CL_BG_GREEN "\033[42m" -#define CL_BG_YELLOW "\033[43m" -#define CL_BG_BLUE "\033[44m" -#define CL_BG_MAGENTA "\033[45m" -#define CL_BG_CYAN "\033[46m" -#define CL_BG_WHITE "\033[47m" +#define CL_BG_BLACK "\033[40m" +#define CL_BG_RED "\033[41m" +#define CL_BG_GREEN "\033[42m" +#define CL_BG_YELLOW "\033[43m" +#define CL_BG_BLUE "\033[44m" +#define CL_BG_MAGENTA "\033[45m" +#define CL_BG_CYAN "\033[46m" +#define CL_BG_WHITE "\033[47m" // foreground color and normal font (normal color on windows) -#define CL_LT_BLACK "\033[0;30m" -#define CL_LT_RED "\033[0;31m" -#define CL_LT_GREEN "\033[0;32m" -#define CL_LT_YELLOW "\033[0;33m" -#define CL_LT_BLUE "\033[0;34m" -#define CL_LT_MAGENTA "\033[0;35m" -#define CL_LT_CYAN "\033[0;36m" -#define CL_LT_WHITE "\033[0;37m" +#define CL_LT_BLACK "\033[0;30m" +#define CL_LT_RED "\033[0;31m" +#define CL_LT_GREEN "\033[0;32m" +#define CL_LT_YELLOW "\033[0;33m" +#define CL_LT_BLUE "\033[0;34m" +#define CL_LT_MAGENTA "\033[0;35m" +#define CL_LT_CYAN "\033[0;36m" +#define CL_LT_WHITE "\033[0;37m" // foreground color and bold font (bright color on windows) -#define CL_BT_BLACK "\033[1;30m" -#define CL_BT_RED "\033[1;31m" -#define CL_BT_GREEN "\033[1;32m" -#define CL_BT_YELLOW "\033[1;33m" -#define CL_BT_BLUE "\033[1;34m" -#define CL_BT_MAGENTA "\033[1;35m" -#define CL_BT_CYAN "\033[1;36m" -#define CL_BT_WHITE "\033[1;37m" +#define CL_BT_BLACK "\033[1;30m" +#define CL_BT_RED "\033[1;31m" +#define CL_BT_GREEN "\033[1;32m" +#define CL_BT_YELLOW "\033[1;33m" +#define CL_BT_BLUE "\033[1;34m" +#define CL_BT_MAGENTA "\033[1;35m" +#define CL_BT_CYAN "\033[1;36m" +#define CL_BT_WHITE "\033[1;37m" -#define CL_WTBL "\033[37;44m" // white on blue -#define CL_XXBL "\033[0;44m" // default on blue -#define CL_PASS "\033[0;32;42m" // green on green +#define CL_WTBL "\033[37;44m" // white on blue +#define CL_XXBL "\033[0;44m" // default on blue +#define CL_PASS "\033[0;32;42m" // green on green -#define CL_SPACE " " // space aquivalent of the print messages +#define CL_SPACE " " // space aquivalent of the print messages extern int stdout_with_ansisequence; //If the color ansi sequences are to be used. [flaviojs] extern int msg_silent; //Specifies how silent the console is. [Skotlex] @@ -73,15 +73,15 @@ extern int console_msg_log; //Specifies what error messages to log. [Ind] extern char timestamp_format[20]; //For displaying Timestamps [Skotlex] enum msg_type { - MSG_NONE, - MSG_STATUS, - MSG_SQL, - MSG_INFORMATION, - MSG_NOTICE, - MSG_WARNING, - MSG_DEBUG, - MSG_ERROR, - MSG_FATALERROR + MSG_NONE, + MSG_STATUS, + MSG_SQL, + MSG_INFORMATION, + MSG_NOTICE, + MSG_WARNING, + MSG_DEBUG, + MSG_ERROR, + MSG_FATALERROR }; extern void ClearScreen(void); diff --git a/src/common/socket.c b/src/common/socket.c index 4a6e01459..d24a9c1d8 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -15,35 +15,35 @@ #include #ifdef WIN32 -#include "../common/winapi.h" + #include "../common/winapi.h" #else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef SIOCGIFCONF -#include // SIOCGIFCONF on Solaris, maybe others? [Shinomori] -#endif -#ifndef FIONBIO -#include // FIONBIO on Solaris [FlavioJS] -#endif - -#ifdef HAVE_SETRLIMIT -#include -#endif + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #ifndef SIOCGIFCONF + #include // SIOCGIFCONF on Solaris, maybe others? [Shinomori] + #endif + #ifndef FIONBIO + #include // FIONBIO on Solaris [FlavioJS] + #endif + + #ifdef HAVE_SETRLIMIT + #include + #endif #endif ///////////////////////////////////////////////////////////////////// #if defined(WIN32) ///////////////////////////////////////////////////////////////////// -// windows portability layer +// windows portability layer typedef int socklen_t; @@ -75,21 +75,21 @@ static int sock_arr_len = 0; /// @return Fd or -1 int sock2fd(SOCKET s) { - int fd; - - // search for the socket - for (fd = 1; fd < sock_arr_len; ++fd) - if (sock_arr[fd] == s) - break;// found the socket - if (fd == sock_arr_len) - return -1;// not found - return fd; + int fd; + + // search for the socket + for( fd = 1; fd < sock_arr_len; ++fd ) + if( sock_arr[fd] == s ) + break;// found the socket + if( fd == sock_arr_len ) + return -1;// not found + return fd; } /// Inserts the socket into the global array of sockets. /// Returns a new fd associated with the socket. -/// If there are too many sockets it closes the socket, sets an error and +/// If there are too many sockets it closes the socket, sets an error and // returns -1 instead. /// Since fd 0 is reserved, it returns values in the range [1,FD_SETSIZE[. /// @@ -97,61 +97,61 @@ int sock2fd(SOCKET s) /// @return New fd or -1 int sock2newfd(SOCKET s) { - int fd; - - // find an empty position - for (fd = 1; fd < sock_arr_len; ++fd) - if (sock_arr[fd] == INVALID_SOCKET) - break;// empty position - if (fd == ARRAYLENGTH(sock_arr)) { - // too many sockets - closesocket(s); - WSASetLastError(WSAEMFILE); - return -1; - } - sock_arr[fd] = s; - if (sock_arr_len <= fd) - sock_arr_len = fd+1; - return fd; + int fd; + + // find an empty position + for( fd = 1; fd < sock_arr_len; ++fd ) + if( sock_arr[fd] == INVALID_SOCKET ) + break;// empty position + if( fd == ARRAYLENGTH(sock_arr) ) + {// too many sockets + closesocket(s); + WSASetLastError(WSAEMFILE); + return -1; + } + sock_arr[fd] = s; + if( sock_arr_len <= fd ) + sock_arr_len = fd+1; + return fd; } -int sAccept(int fd, struct sockaddr *addr, int *addrlen) +int sAccept(int fd, struct sockaddr* addr, int* addrlen) { - SOCKET s; + SOCKET s; - // accept connection - s = accept(fd2sock(fd), addr, addrlen); - if (s == INVALID_SOCKET) - return -1;// error - return sock2newfd(s); + // accept connection + s = accept(fd2sock(fd), addr, addrlen); + if( s == INVALID_SOCKET ) + return -1;// error + return sock2newfd(s); } int sClose(int fd) { - int ret = closesocket(fd2sock(fd)); - fd2sock(fd) = INVALID_SOCKET; - return ret; + int ret = closesocket(fd2sock(fd)); + fd2sock(fd) = INVALID_SOCKET; + return ret; } int sSocket(int af, int type, int protocol) { - SOCKET s; + SOCKET s; - // create socket - s = socket(af,type,protocol); - if (s == INVALID_SOCKET) - return -1;// error - return sock2newfd(s); + // create socket + s = socket(af,type,protocol); + if( s == INVALID_SOCKET ) + return -1;// error + return sock2newfd(s); } -char *sErr(int code) +char* sErr(int code) { - static char sbuf[512]; - // strerror does not handle socket codes - if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, - code, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&sbuf, sizeof(sbuf), NULL) == 0) - snprintf(sbuf, sizeof(sbuf), "unknown error"); - return sbuf; + static char sbuf[512]; + // strerror does not handle socket codes + if( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + code, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&sbuf, sizeof(sbuf), NULL) == 0 ) + snprintf(sbuf, sizeof(sbuf), "unknown error"); + return sbuf; } #define sBind(fd,name,namelen) bind(fd2sock(fd),name,namelen) @@ -205,7 +205,7 @@ char *sErr(int code) ///////////////////////////////////////////////////////////////////// #ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 + #define MSG_NOSIGNAL 0 #endif fd_set readfds; @@ -230,7 +230,7 @@ static size_t socket_max_client_packet = 24576; // The connection is closed if it goes over the limit. #define WFIFO_MAX (1*1024*1024) -struct socket_data *session[FD_SETSIZE]; +struct socket_data* session[FD_SETSIZE]; #ifdef SEND_SHORTLIST int send_shortlist_array[FD_SETSIZE];// we only support FD_SETSIZE sockets, limit the array to that @@ -241,390 +241,387 @@ uint32 send_shortlist_set[(FD_SETSIZE+31)/32];// to know if specific fd's are al static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); #ifndef MINICORE -int ip_rules = 1; -static int connect_check(uint32 ip); + int ip_rules = 1; + static int connect_check(uint32 ip); #endif -const char *error_msg(void) +const char* error_msg(void) { - static char buf[512]; - int code = sErrno; - snprintf(buf, sizeof(buf), "error %d: %s", code, sErr(code)); - return buf; + static char buf[512]; + int code = sErrno; + snprintf(buf, sizeof(buf), "error %d: %s", code, sErr(code)); + return buf; } /*====================================== - * CORE : Default processing functions + * CORE : Default processing functions *--------------------------------------*/ -int null_recv(int fd) -{ - return 0; -} -int null_send(int fd) -{ - return 0; -} -int null_parse(int fd) -{ - return 0; -} +int null_recv(int fd) { return 0; } +int null_send(int fd) { return 0; } +int null_parse(int fd) { return 0; } ParseFunc default_func_parse = null_parse; void set_defaultparse(ParseFunc defaultparse) { - default_func_parse = defaultparse; + default_func_parse = defaultparse; } /*====================================== - * CORE : Socket options + * CORE : Socket options *--------------------------------------*/ void set_nonblocking(int fd, unsigned long yes) { - // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s. - // The argp parameter is zero if nonblocking is to be disabled. - if (sIoctl(fd, FIONBIO, &yes) != 0) - ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg()); + // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s. + // The argp parameter is zero if nonblocking is to be disabled. + if( sIoctl(fd, FIONBIO, &yes) != 0 ) + ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg()); } void setsocketopts(int fd) { - int yes = 1; // reuse fix + int yes = 1; // reuse fix #if !defined(WIN32) - // set SO_REAUSEADDR to true, unix only. on windows this option causes - // the previous owner of the socket to give up, which is not desirable - // in most cases, neither compatible with unix. - sSetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof(yes)); + // set SO_REAUSEADDR to true, unix only. on windows this option causes + // the previous owner of the socket to give up, which is not desirable + // in most cases, neither compatible with unix. + sSetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof(yes)); #ifdef SO_REUSEPORT - sSetsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes)); + sSetsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes)); #endif #endif - // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag. - // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. - sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); - - // force the socket into no-wait, graceful-close mode (should be the default, but better make sure) - //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp) - { - struct linger opt; - opt.l_onoff = 0; // SO_DONTLINGER - opt.l_linger = 0; // Do not care - if (sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&opt, sizeof(opt))) - ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd); - } + // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag. + // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. + sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); + + // force the socket into no-wait, graceful-close mode (should be the default, but better make sure) + //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp) + { + struct linger opt; + opt.l_onoff = 0; // SO_DONTLINGER + opt.l_linger = 0; // Do not care + if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof(opt)) ) + ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd); + } } /*====================================== - * CORE : Socket Sub Function + * CORE : Socket Sub Function *--------------------------------------*/ void set_eof(int fd) { - if (session_isActive(fd)) { + if( session_isActive(fd) ) + { #ifdef SEND_SHORTLIST - // Add this socket to the shortlist for eof handling. - send_shortlist_add_fd(fd); + // Add this socket to the shortlist for eof handling. + send_shortlist_add_fd(fd); #endif - session[fd]->flag.eof = 1; - } + session[fd]->flag.eof = 1; + } } int recv_to_fifo(int fd) { - int len; - - if (!session_isActive(fd)) - return -1; - - len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); - - if (len == SOCKET_ERROR) { - //An exception has occured - if (sErrno != S_EWOULDBLOCK) { - //ShowDebug("recv_to_fifo: %s, closing connection #%d\n", error_msg(), fd); - set_eof(fd); - } - return 0; - } - - if (len == 0) { - //Normal connection end. - set_eof(fd); - return 0; - } - - session[fd]->rdata_size += len; - session[fd]->rdata_tick = last_tick; - return 0; + int len; + + if( !session_isActive(fd) ) + return -1; + + len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); + + if( len == SOCKET_ERROR ) + {//An exception has occured + if( sErrno != S_EWOULDBLOCK ) { + //ShowDebug("recv_to_fifo: %s, closing connection #%d\n", error_msg(), fd); + set_eof(fd); + } + return 0; + } + + if( len == 0 ) + {//Normal connection end. + set_eof(fd); + return 0; + } + + session[fd]->rdata_size += len; + session[fd]->rdata_tick = last_tick; + return 0; } int send_from_fifo(int fd) { - int len; + int len; - if (!session_isValid(fd)) - return -1; + if( !session_isValid(fd) ) + return -1; - if (session[fd]->wdata_size == 0) - return 0; // nothing to send + if( session[fd]->wdata_size == 0 ) + return 0; // nothing to send - len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, MSG_NOSIGNAL); + len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, MSG_NOSIGNAL); - if (len == SOCKET_ERROR) { - //An exception has occured - if (sErrno != S_EWOULDBLOCK) { - //ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd); - session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] - set_eof(fd); - } - return 0; - } + if( len == SOCKET_ERROR ) + {//An exception has occured + if( sErrno != S_EWOULDBLOCK ) { + //ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd); + session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] + set_eof(fd); + } + return 0; + } - if (len > 0) { - // some data could not be transferred? - // shift unsent data to the beginning of the queue - if ((size_t)len < session[fd]->wdata_size) - memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); + if( len > 0 ) + { + // some data could not be transferred? + // shift unsent data to the beginning of the queue + if( (size_t)len < session[fd]->wdata_size ) + memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); - session[fd]->wdata_size -= len; - } + session[fd]->wdata_size -= len; + } - return 0; + return 0; } /// Best effort - there's no warranty that the data will be sent. void flush_fifo(int fd) { - if (session[fd] != NULL) - session[fd]->func_send(fd); + if(session[fd] != NULL) + session[fd]->func_send(fd); } void flush_fifos(void) { - int i; - for (i = 1; i < fd_max; i++) - flush_fifo(i); + int i; + for(i = 1; i < fd_max; i++) + flush_fifo(i); } /*====================================== - * CORE : Connection functions + * CORE : Connection functions *--------------------------------------*/ int connect_client(int listen_fd) { - int fd; - struct sockaddr_in client_address; - socklen_t len; - - len = sizeof(client_address); - - fd = sAccept(listen_fd, (struct sockaddr *)&client_address, &len); - if (fd == -1) { - ShowError("connect_client: accept failed (%s)!\n", error_msg()); - return -1; - } - if (fd == 0) { - // reserved - ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if (fd >= FD_SETSIZE) { - // socket number too big - ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - set_nonblocking(fd, 1); + int fd; + struct sockaddr_in client_address; + socklen_t len; + + len = sizeof(client_address); + + fd = sAccept(listen_fd, (struct sockaddr*)&client_address, &len); + if ( fd == -1 ) { + ShowError("connect_client: accept failed (%s)!\n", error_msg()); + return -1; + } + if( fd == 0 ) + {// reserved + ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if( fd >= FD_SETSIZE ) + {// socket number too big + ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + set_nonblocking(fd, 1); #ifndef MINICORE - if (ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr))) { - do_close(fd); - return -1; - } + if( ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr)) ) { + do_close(fd); + return -1; + } #endif - if (fd_max <= fd) fd_max = fd + 1; - sFD_SET(fd,&readfds); + if( fd_max <= fd ) fd_max = fd + 1; + sFD_SET(fd,&readfds); - create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); - session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); + create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); + session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); - return fd; + return fd; } int make_listen_bind(uint32 ip, uint16 port) { - struct sockaddr_in server_address; - int fd; - int result; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - if (fd == -1) { - ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg()); - exit(EXIT_FAILURE); - } - if (fd == 0) { - // reserved - ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if (fd >= FD_SETSIZE) { - // socket number too big - ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - set_nonblocking(fd, 1); - - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = htonl(ip); - server_address.sin_port = htons(port); - - result = sBind(fd, (struct sockaddr *)&server_address, sizeof(server_address)); - if (result == SOCKET_ERROR) { - ShowError("make_listen_bind: bind failed (socket #%d, %s)!\n", fd, error_msg()); - exit(EXIT_FAILURE); - } - result = sListen(fd,5); - if (result == SOCKET_ERROR) { - ShowError("make_listen_bind: listen failed (socket #%d, %s)!\n", fd, error_msg()); - exit(EXIT_FAILURE); - } - - if (fd_max <= fd) fd_max = fd + 1; - sFD_SET(fd, &readfds); - - create_session(fd, connect_client, null_send, null_parse); - session[fd]->client_addr = 0; // just listens - session[fd]->rdata_tick = 0; // disable timeouts on this socket - - return fd; + struct sockaddr_in server_address; + int fd; + int result; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + if( fd == -1 ) + { + ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg()); + exit(EXIT_FAILURE); + } + if( fd == 0 ) + {// reserved + ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if( fd >= FD_SETSIZE ) + {// socket number too big + ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + set_nonblocking(fd, 1); + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl(ip); + server_address.sin_port = htons(port); + + result = sBind(fd, (struct sockaddr*)&server_address, sizeof(server_address)); + if( result == SOCKET_ERROR ) { + ShowError("make_listen_bind: bind failed (socket #%d, %s)!\n", fd, error_msg()); + exit(EXIT_FAILURE); + } + result = sListen(fd,5); + if( result == SOCKET_ERROR ) { + ShowError("make_listen_bind: listen failed (socket #%d, %s)!\n", fd, error_msg()); + exit(EXIT_FAILURE); + } + + if(fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd, &readfds); + + create_session(fd, connect_client, null_send, null_parse); + session[fd]->client_addr = 0; // just listens + session[fd]->rdata_tick = 0; // disable timeouts on this socket + + return fd; } -int make_connection(uint32 ip, uint16 port, bool silent) -{ - struct sockaddr_in remote_address; - int fd; - int result; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - if (fd == -1) { - ShowError("make_connection: socket creation failed (%s)!\n", error_msg()); - return -1; - } - if (fd == 0) { - // reserved - ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if (fd >= FD_SETSIZE) { - // socket number too big - ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - - remote_address.sin_family = AF_INET; - remote_address.sin_addr.s_addr = htonl(ip); - remote_address.sin_port = htons(port); - - if (!silent) - ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port); - - result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in)); - if (result == SOCKET_ERROR) { - if (!silent) - ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg()); - do_close(fd); - return -1; - } - //Now the socket can be made non-blocking. [Skotlex] - set_nonblocking(fd, 1); - - if (fd_max <= fd) fd_max = fd + 1; - sFD_SET(fd,&readfds); - - create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); - session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr); - - return fd; +int make_connection(uint32 ip, uint16 port, bool silent) { + struct sockaddr_in remote_address; + int fd; + int result; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + if (fd == -1) { + ShowError("make_connection: socket creation failed (%s)!\n", error_msg()); + return -1; + } + if( fd == 0 ) + {// reserved + ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if( fd >= FD_SETSIZE ) + {// socket number too big + ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + + remote_address.sin_family = AF_INET; + remote_address.sin_addr.s_addr = htonl(ip); + remote_address.sin_port = htons(port); + + if( !silent ) + ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port); + + result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in)); + if( result == SOCKET_ERROR ) { + if( !silent ) + ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg()); + do_close(fd); + return -1; + } + //Now the socket can be made non-blocking. [Skotlex] + set_nonblocking(fd, 1); + + if (fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd,&readfds); + + create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); + session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr); + + return fd; } static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse) { - CREATE(session[fd], struct socket_data, 1); - CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE); - CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE); - session[fd]->max_rdata = RFIFO_SIZE; - session[fd]->max_wdata = WFIFO_SIZE; - session[fd]->func_recv = func_recv; - session[fd]->func_send = func_send; - session[fd]->func_parse = func_parse; - session[fd]->rdata_tick = last_tick; - return 0; + CREATE(session[fd], struct socket_data, 1); + CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE); + CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE); + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; + session[fd]->func_recv = func_recv; + session[fd]->func_send = func_send; + session[fd]->func_parse = func_parse; + session[fd]->rdata_tick = last_tick; + return 0; } static void delete_session(int fd) { - if (session_isValid(fd)) { - aFree(session[fd]->rdata); - aFree(session[fd]->wdata); - aFree(session[fd]->session_data); - aFree(session[fd]); - session[fd] = NULL; - } + if( session_isValid(fd) ) + { + aFree(session[fd]->rdata); + aFree(session[fd]->wdata); + aFree(session[fd]->session_data); + aFree(session[fd]); + session[fd] = NULL; + } } int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size) { - if (!session_isValid(fd)) - return 0; - - if (session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) { - RECREATE(session[fd]->rdata, unsigned char, rfifo_size); - session[fd]->max_rdata = rfifo_size; - } - - if (session[fd]->max_wdata != wfifo_size && session[fd]->wdata_size < wfifo_size) { - RECREATE(session[fd]->wdata, unsigned char, wfifo_size); - session[fd]->max_wdata = wfifo_size; - } - return 0; + if( !session_isValid(fd) ) + return 0; + + if( session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) { + RECREATE(session[fd]->rdata, unsigned char, rfifo_size); + session[fd]->max_rdata = rfifo_size; + } + + if( session[fd]->max_wdata != wfifo_size && session[fd]->wdata_size < wfifo_size) { + RECREATE(session[fd]->wdata, unsigned char, wfifo_size); + session[fd]->max_wdata = wfifo_size; + } + return 0; } int realloc_writefifo(int fd, size_t addition) { - size_t newsize; - - if (!session_isValid(fd)) // might not happen - return 0; - - if (session[fd]->wdata_size + addition > session[fd]->max_wdata) { - // grow rule; grow in multiples of WFIFO_SIZE - newsize = WFIFO_SIZE; - while (session[fd]->wdata_size + addition > newsize) newsize += WFIFO_SIZE; - } else if (session[fd]->max_wdata >= (size_t)2*(session[fd]->flag.server?FIFOSIZE_SERVERLINK:WFIFO_SIZE) - && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata) { - // shrink rule, shrink by 2 when only a quarter of the fifo is used, don't shrink below nominal size. - newsize = session[fd]->max_wdata / 2; - } else // no change - return 0; - - RECREATE(session[fd]->wdata, unsigned char, newsize); - session[fd]->max_wdata = newsize; - - return 0; + size_t newsize; + + if( !session_isValid(fd) ) // might not happen + return 0; + + if( session[fd]->wdata_size + addition > session[fd]->max_wdata ) + { // grow rule; grow in multiples of WFIFO_SIZE + newsize = WFIFO_SIZE; + while( session[fd]->wdata_size + addition > newsize ) newsize += WFIFO_SIZE; + } + else + if( session[fd]->max_wdata >= (size_t)2*(session[fd]->flag.server?FIFOSIZE_SERVERLINK:WFIFO_SIZE) + && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata ) + { // shrink rule, shrink by 2 when only a quarter of the fifo is used, don't shrink below nominal size. + newsize = session[fd]->max_wdata / 2; + } + else // no change + return 0; + + RECREATE(session[fd]->wdata, unsigned char, newsize); + session[fd]->max_wdata = newsize; + + return 0; } /// advance the RFIFO cursor (marking 'len' bytes as processed) @@ -632,186 +629,197 @@ int RFIFOSKIP(int fd, size_t len) { struct socket_data *s; - if (!session_isActive(fd)) - return 0; + if ( !session_isActive(fd) ) + return 0; - s = session[fd]; + s = session[fd]; - if (s->rdata_size < s->rdata_pos + len) { - ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd); - len = RFIFOREST(fd); - } + if ( s->rdata_size < s->rdata_pos + len ) { + ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd); + len = RFIFOREST(fd); + } - s->rdata_pos = s->rdata_pos + len; - return 0; + s->rdata_pos = s->rdata_pos + len; + return 0; } /// advance the WFIFO cursor (marking 'len' bytes for sending) int WFIFOSET(int fd, size_t len) { - size_t newreserve; - struct socket_data *s = session[fd]; - - if (!session_isValid(fd) || s->wdata == NULL) - return 0; - - // we have written len bytes to the buffer already before calling WFIFOSET - if (s->wdata_size+len > s->max_wdata) { - // actually there was a buffer overflow already - uint32 ip = s->client_addr; - ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata); - ShowDebug("Likely command that caused it: 0x%x\n", (*(uint16 *)(s->wdata + s->wdata_size))); - // no other chance, make a better fifo model - exit(EXIT_FAILURE); - } - - if (len > 0xFFFF) { - // dynamic packets allow up to UINT16_MAX bytes (.W .W ...) - // all known fixed-size packets are within this limit, so use the same limit - ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16 *)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF); - exit(EXIT_FAILURE); - } else if (len == 0) { - // abuses the fact, that the code that did WFIFOHEAD(fd,0), already wrote - // the packet type into memory, even if it could have overwritten vital data - // this can happen when a new packet was added on map-server, but packet len table was not updated - ShowWarning("WFIFOSET: Attempted to send zero-length packet, most likely 0x%04x (please report this).\n", WFIFOW(fd,0)); - return 0; - } - - if (!s->flag.server) { - - if (len > socket_max_client_packet) { // see declaration of socket_max_client_packet for details - ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet); - return 0; - } - - if (s->wdata_size+len > WFIFO_MAX) { // reached maximum write fifo size - ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr)); - set_eof(fd); - return 0; - } - - } - s->wdata_size += len; - //If the interserver has 200% of its normal size full, flush the data. - if (s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK) - flush_fifo(fd); - - // always keep a WFIFO_SIZE reserve in the buffer - // For inter-server connections, let the reserve be 1/4th of the link size. - newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; - - // readjust the buffer to include the chosen reserve - realloc_writefifo(fd, newreserve); + size_t newreserve; + struct socket_data* s = session[fd]; + + if( !session_isValid(fd) || s->wdata == NULL ) + return 0; + + // we have written len bytes to the buffer already before calling WFIFOSET + if(s->wdata_size+len > s->max_wdata) + { // actually there was a buffer overflow already + uint32 ip = s->client_addr; + ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata); + ShowDebug("Likely command that caused it: 0x%x\n", (*(uint16*)(s->wdata + s->wdata_size))); + // no other chance, make a better fifo model + exit(EXIT_FAILURE); + } + + if( len > 0xFFFF ) + { + // dynamic packets allow up to UINT16_MAX bytes (.W .W ...) + // all known fixed-size packets are within this limit, so use the same limit + ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16*)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF); + exit(EXIT_FAILURE); + } + else if( len == 0 ) + { + // abuses the fact, that the code that did WFIFOHEAD(fd,0), already wrote + // the packet type into memory, even if it could have overwritten vital data + // this can happen when a new packet was added on map-server, but packet len table was not updated + ShowWarning("WFIFOSET: Attempted to send zero-length packet, most likely 0x%04x (please report this).\n", WFIFOW(fd,0)); + return 0; + } + + if( !s->flag.server ) { + + if( len > socket_max_client_packet ) {// see declaration of socket_max_client_packet for details + ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet); + return 0; + } + + if( s->wdata_size+len > WFIFO_MAX ) {// reached maximum write fifo size + ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr)); + set_eof(fd); + return 0; + } + + } + s->wdata_size += len; + //If the interserver has 200% of its normal size full, flush the data. + if( s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK ) + flush_fifo(fd); + + // always keep a WFIFO_SIZE reserve in the buffer + // For inter-server connections, let the reserve be 1/4th of the link size. + newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; + + // readjust the buffer to include the chosen reserve + realloc_writefifo(fd, newreserve); #ifdef SEND_SHORTLIST - send_shortlist_add_fd(fd); + send_shortlist_add_fd(fd); #endif - return 0; + return 0; } int do_sockets(int next) { - fd_set rfd; - struct timeval timeout; - int ret,i; + fd_set rfd; + struct timeval timeout; + int ret,i; - // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof. - // Send remaining data and process client-side disconnects here. + // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof. + // Send remaining data and process client-side disconnects here. #ifdef SEND_SHORTLIST - send_shortlist_do_sends(); + send_shortlist_do_sends(); #else - for (i = 1; i < fd_max; i++) { - if (!session[i]) - continue; - - if (session[i]->wdata_size) - session[i]->func_send(i); - } + for (i = 1; i < fd_max; i++) + { + if(!session[i]) + continue; + + if(session[i]->wdata_size) + session[i]->func_send(i); + } #endif - // can timeout until the next tick - timeout.tv_sec = next/1000; - timeout.tv_usec = next%1000*1000; + // can timeout until the next tick + timeout.tv_sec = next/1000; + timeout.tv_usec = next%1000*1000; - memcpy(&rfd, &readfds, sizeof(rfd)); - ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout); + memcpy(&rfd, &readfds, sizeof(rfd)); + ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout); - if (ret == SOCKET_ERROR) { - if (sErrno != S_EINTR) { - ShowFatalError("do_sockets: select() failed, %s!\n", error_msg()); - exit(EXIT_FAILURE); - } - return 0; // interrupted by a signal, just loop and try again - } + if( ret == SOCKET_ERROR ) + { + if( sErrno != S_EINTR ) + { + ShowFatalError("do_sockets: select() failed, %s!\n", error_msg()); + exit(EXIT_FAILURE); + } + return 0; // interrupted by a signal, just loop and try again + } - last_tick = time(NULL); + last_tick = time(NULL); #if defined(WIN32) - // on windows, enumerating all members of the fd_set is way faster if we access the internals - for (i = 0; i < (int)rfd.fd_count; ++i) { - int fd = sock2fd(rfd.fd_array[i]); - if (session[fd]) - session[fd]->func_recv(fd); - } + // on windows, enumerating all members of the fd_set is way faster if we access the internals + for( i = 0; i < (int)rfd.fd_count; ++i ) + { + int fd = sock2fd(rfd.fd_array[i]); + if( session[fd] ) + session[fd]->func_recv(fd); + } #else - // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way - for (i = 1; ret && i < fd_max; ++i) { - if (sFD_ISSET(i,&rfd) && session[i]) { - session[i]->func_recv(i); - --ret; - } - } + // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way + for( i = 1; ret && i < fd_max; ++i ) + { + if(sFD_ISSET(i,&rfd) && session[i]) + { + session[i]->func_recv(i); + --ret; + } + } #endif - // POSTSEND Send remaining data and handle eof sessions. + // POSTSEND Send remaining data and handle eof sessions. #ifdef SEND_SHORTLIST - send_shortlist_do_sends(); + send_shortlist_do_sends(); #else - for (i = 1; i < fd_max; i++) { - if (!session[i]) - continue; - - if (session[i]->wdata_size) - session[i]->func_send(i); - - if (session[i]->flag.eof) { //func_send can't free a session, this is safe. - //Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex] - session[i]->func_parse(i); //This should close the session immediately. - } - } + for (i = 1; i < fd_max; i++) + { + if(!session[i]) + continue; + + if(session[i]->wdata_size) + session[i]->func_send(i); + + if(session[i]->flag.eof) //func_send can't free a session, this is safe. + { //Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex] + session[i]->func_parse(i); //This should close the session immediately. + } + } #endif - // parse input data on each socket - for (i = 1; i < fd_max; i++) { - if (!session[i]) - continue; - - if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { - if (session[i]->flag.server) { /* server is special */ - if (session[i]->flag.ping != 2) /* only update if necessary otherwise it'd resend the ping unnecessarily */ - session[i]->flag.ping = 1; - } else { - ShowInfo("Session #%d timed out\n", i); - set_eof(i); - } - } - - session[i]->func_parse(i); - - if (!session[i]) - continue; - - // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) - if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { - set_eof(i); - continue; - } - RFIFOFLUSH(i); - } - - return 0; + // parse input data on each socket + for(i = 1; i < fd_max; i++) + { + if(!session[i]) + continue; + + if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { + if( session[i]->flag.server ) {/* server is special */ + if( session[i]->flag.ping != 2 )/* only update if necessary otherwise it'd resend the ping unnecessarily */ + session[i]->flag.ping = 1; + } else { + ShowInfo("Session #%d timed out\n", i); + set_eof(i); + } + } + + session[i]->func_parse(i); + + if(!session[i]) + continue; + + // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) + if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { + set_eof(i); + continue; + } + RFIFOFLUSH(i); + } + + return 0; } ////////////////////////////// @@ -820,26 +828,26 @@ int do_sockets(int next) // IP rules and DDoS protection typedef struct _connect_history { - struct _connect_history *next; - uint32 ip; - uint32 tick; - int count; - unsigned ddos : 1; + struct _connect_history* next; + uint32 ip; + uint32 tick; + int count; + unsigned ddos : 1; } ConnectHistory; typedef struct _access_control { - uint32 ip; - uint32 mask; + uint32 ip; + uint32 mask; } AccessControl; enum _aco { - ACO_DENY_ALLOW, - ACO_ALLOW_DENY, - ACO_MUTUAL_FAILURE + ACO_DENY_ALLOW, + ACO_ALLOW_DENY, + ACO_MUTUAL_FAILURE }; -static AccessControl *access_allow = NULL; -static AccessControl *access_deny = NULL; +static AccessControl* access_allow = NULL; +static AccessControl* access_deny = NULL; static int access_order = ACO_DENY_ALLOW; static int access_allownum = 0; static int access_denynum = 0; @@ -849,7 +857,7 @@ static int ddos_interval = 3*1000; static int ddos_autoreset = 10*60*1000; /// Connection history, an array of linked lists. /// The array's index for any ip is ip&0xFFFF -static ConnectHistory *connect_history[0x10000]; +static ConnectHistory* connect_history[0x10000]; static int connect_check_(uint32 ip); @@ -857,11 +865,11 @@ static int connect_check_(uint32 ip); /// @see connect_check_() static int connect_check(uint32 ip) { - int result = connect_check_(ip); - if (access_debug) { - ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!"); - } - return result; + int result = connect_check_(ip); + if( access_debug ) { + ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!"); + } + return result; } /// Verifies if the IP can connect. @@ -869,494 +877,504 @@ static int connect_check(uint32 ip) /// 1 or 2 : Connection Accepted static int connect_check_(uint32 ip) { - ConnectHistory *hist = connect_history[ip&0xFFFF]; - int i; - int is_allowip = 0; - int is_denyip = 0; - int connect_ok = 0; - - // Search the allow list - for (i=0; i < access_allownum; ++i) { - if ((ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask)) { - if (access_debug) { - ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", - CONVIP(ip), - CONVIP(access_allow[i].ip), - CONVIP(access_allow[i].mask)); - } - is_allowip = 1; - break; - } - } - // Search the deny list - for (i=0; i < access_denynum; ++i) { - if ((ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask)) { - if (access_debug) { - ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", - CONVIP(ip), - CONVIP(access_deny[i].ip), - CONVIP(access_deny[i].mask)); - } - is_denyip = 1; - break; - } - } - // Decide connection status - // 0 : Reject - // 1 : Accept - // 2 : Unconditional Accept (accepts even if flagged as DDoS) - switch (access_order) { - case ACO_DENY_ALLOW: - default: - if (is_denyip) - connect_ok = 0; // Reject - else if (is_allowip) - connect_ok = 2; // Unconditional Accept - else - connect_ok = 1; // Accept - break; - case ACO_ALLOW_DENY: - if (is_allowip) - connect_ok = 2; // Unconditional Accept - else if (is_denyip) - connect_ok = 0; // Reject - else - connect_ok = 1; // Accept - break; - case ACO_MUTUAL_FAILURE: - if (is_allowip && !is_denyip) - connect_ok = 2; // Unconditional Accept - else - connect_ok = 0; // Reject - break; - } - - // Inspect connection history - while (hist) { - if (ip == hist->ip) { - // IP found - if (hist->ddos) { - // flagged as DDoS - return (connect_ok == 2 ? 1 : 0); - } else if (DIFF_TICK(gettick(),hist->tick) < ddos_interval) { - // connection within ddos_interval - hist->tick = gettick(); - if (hist->count++ >= ddos_count) { - // DDoS attack detected - hist->ddos = 1; - ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip)); - return (connect_ok == 2 ? 1 : 0); - } - return connect_ok; - } else { - // not within ddos_interval, clear data - hist->tick = gettick(); - hist->count = 0; - return connect_ok; - } - } - hist = hist->next; - } - // IP not found, add to history - CREATE(hist, ConnectHistory, 1); - memset(hist, 0, sizeof(ConnectHistory)); - hist->ip = ip; - hist->tick = gettick(); - hist->next = connect_history[ip&0xFFFF]; - connect_history[ip&0xFFFF] = hist; - return connect_ok; + ConnectHistory* hist = connect_history[ip&0xFFFF]; + int i; + int is_allowip = 0; + int is_denyip = 0; + int connect_ok = 0; + + // Search the allow list + for( i=0; i < access_allownum; ++i ){ + if( (ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask) ){ + if( access_debug ){ + ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", + CONVIP(ip), + CONVIP(access_allow[i].ip), + CONVIP(access_allow[i].mask)); + } + is_allowip = 1; + break; + } + } + // Search the deny list + for( i=0; i < access_denynum; ++i ){ + if( (ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask) ){ + if( access_debug ){ + ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", + CONVIP(ip), + CONVIP(access_deny[i].ip), + CONVIP(access_deny[i].mask)); + } + is_denyip = 1; + break; + } + } + // Decide connection status + // 0 : Reject + // 1 : Accept + // 2 : Unconditional Accept (accepts even if flagged as DDoS) + switch(access_order) { + case ACO_DENY_ALLOW: + default: + if( is_denyip ) + connect_ok = 0; // Reject + else if( is_allowip ) + connect_ok = 2; // Unconditional Accept + else + connect_ok = 1; // Accept + break; + case ACO_ALLOW_DENY: + if( is_allowip ) + connect_ok = 2; // Unconditional Accept + else if( is_denyip ) + connect_ok = 0; // Reject + else + connect_ok = 1; // Accept + break; + case ACO_MUTUAL_FAILURE: + if( is_allowip && !is_denyip ) + connect_ok = 2; // Unconditional Accept + else + connect_ok = 0; // Reject + break; + } + + // Inspect connection history + while( hist ) { + if( ip == hist->ip ) + {// IP found + if( hist->ddos ) + {// flagged as DDoS + return (connect_ok == 2 ? 1 : 0); + } else if( DIFF_TICK(gettick(),hist->tick) < ddos_interval ) + {// connection within ddos_interval + hist->tick = gettick(); + if( hist->count++ >= ddos_count ) + {// DDoS attack detected + hist->ddos = 1; + ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip)); + return (connect_ok == 2 ? 1 : 0); + } + return connect_ok; + } else + {// not within ddos_interval, clear data + hist->tick = gettick(); + hist->count = 0; + return connect_ok; + } + } + hist = hist->next; + } + // IP not found, add to history + CREATE(hist, ConnectHistory, 1); + memset(hist, 0, sizeof(ConnectHistory)); + hist->ip = ip; + hist->tick = gettick(); + hist->next = connect_history[ip&0xFFFF]; + connect_history[ip&0xFFFF] = hist; + return connect_ok; } /// Timer function. /// Deletes old connection history records. static int connect_check_clear(int tid, unsigned int tick, int id, intptr_t data) { - int i; - int clear = 0; - int list = 0; - ConnectHistory root; - ConnectHistory *prev_hist; - ConnectHistory *hist; - - for (i=0; i < 0x10000 ; ++i) { - prev_hist = &root; - root.next = hist = connect_history[i]; - while (hist) { - if ((!hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_interval*3) || - (hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_autoreset)) { - // Remove connection history - prev_hist->next = hist->next; - aFree(hist); - hist = prev_hist->next; - clear++; - } else { - prev_hist = hist; - hist = hist->next; - } - list++; - } - connect_history[i] = root.next; - } - if (access_debug) { - ShowInfo("connect_check_clear: Cleared %d of %d from IP list.\n", clear, list); - } - return list; + int i; + int clear = 0; + int list = 0; + ConnectHistory root; + ConnectHistory* prev_hist; + ConnectHistory* hist; + + for( i=0; i < 0x10000 ; ++i ){ + prev_hist = &root; + root.next = hist = connect_history[i]; + while( hist ){ + if( (!hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_interval*3) || + (hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_autoreset) ) + {// Remove connection history + prev_hist->next = hist->next; + aFree(hist); + hist = prev_hist->next; + clear++; + } else { + prev_hist = hist; + hist = hist->next; + } + list++; + } + connect_history[i] = root.next; + } + if( access_debug ){ + ShowInfo("connect_check_clear: Cleared %d of %d from IP list.\n", clear, list); + } + return list; } /// Parses the ip address and mask and puts it into acc. /// Returns 1 is successful, 0 otherwise. -int access_ipmask(const char *str, AccessControl *acc) +int access_ipmask(const char* str, AccessControl* acc) { - uint32 ip; - uint32 mask; - unsigned int a[4]; - unsigned int m[4]; - int n; - - if (strcmp(str,"all") == 0) { - ip = 0; - mask = 0; - } else { - if (((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask - (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask - (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4) || // not an ip - a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 || // invalid ip - (n == 8 && (m[0] > 255 || m[1] > 255 || m[2] > 255 || m[3] > 255)) || // invalid standard mask - (n == 5 && m[0] > 32)) { // invalid bit mask - return 0; - } - ip = MAKEIP(a[0],a[1],a[2],a[3]); - if (n == 8) { - // standard mask - mask = MAKEIP(m[0],m[1],m[2],m[3]); - } else if (n == 5) { - // bit mask - mask = 0; - while (m[0]) { - mask = (mask >> 1) | 0x80000000; - --m[0]; - } - } else { - // just this ip - mask = 0xFFFFFFFF; - } - } - if (access_debug) { - ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask)); - } - acc->ip = ip; - acc->mask = mask; - return 1; + uint32 ip; + uint32 mask; + unsigned int a[4]; + unsigned int m[4]; + int n; + + if( strcmp(str,"all") == 0 ) { + ip = 0; + mask = 0; + } else { + if( ((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask + (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask + (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4 ) || // not an ip + a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 || // invalid ip + (n == 8 && (m[0] > 255 || m[1] > 255 || m[2] > 255 || m[3] > 255)) || // invalid standard mask + (n == 5 && m[0] > 32) ){ // invalid bit mask + return 0; + } + ip = MAKEIP(a[0],a[1],a[2],a[3]); + if( n == 8 ) + {// standard mask + mask = MAKEIP(m[0],m[1],m[2],m[3]); + } else if( n == 5 ) + {// bit mask + mask = 0; + while( m[0] ){ + mask = (mask >> 1) | 0x80000000; + --m[0]; + } + } else + {// just this ip + mask = 0xFFFFFFFF; + } + } + if( access_debug ){ + ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask)); + } + acc->ip = ip; + acc->mask = mask; + return 1; } ////////////////////////////// #endif ////////////////////////////// -int socket_config_read(const char *cfgName) +int socket_config_read(const char* cfgName) { - char line[1024],w1[1024],w2[1024]; - FILE *fp; - - fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("File not found: %s\n", cfgName); - return 1; - } - - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (!strcmpi(w1, "stall_time")) { - stall_time = atoi(w2); - if (stall_time < 3) - stall_time = 3;/* a minimum is required to refrain it from killing itself */ - } + char line[1024],w1[1024],w2[1024]; + FILE *fp; + + fp = fopen(cfgName, "r"); + if(fp == NULL) { + ShowError("File not found: %s\n", cfgName); + return 1; + } + + while(fgets(line, sizeof(line), fp)) + { + if(line[0] == '/' && line[1] == '/') + continue; + if(sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (!strcmpi(w1, "stall_time")) { + stall_time = atoi(w2); + if( stall_time < 3 ) + stall_time = 3;/* a minimum is required to refrain it from killing itself */ + } #ifndef MINICORE - else if (!strcmpi(w1, "enable_ip_rules")) { - ip_rules = config_switch(w2); - } else if (!strcmpi(w1, "order")) { - if (!strcmpi(w2, "deny,allow")) - access_order = ACO_DENY_ALLOW; - else if (!strcmpi(w2, "allow,deny")) - access_order = ACO_ALLOW_DENY; - else if (!strcmpi(w2, "mutual-failure")) - access_order = ACO_MUTUAL_FAILURE; - } else if (!strcmpi(w1, "allow")) { - RECREATE(access_allow, AccessControl, access_allownum+1); - if (access_ipmask(w2, &access_allow[access_allownum])) - ++access_allownum; - else - ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); - } else if (!strcmpi(w1, "deny")) { - RECREATE(access_deny, AccessControl, access_denynum+1); - if (access_ipmask(w2, &access_deny[access_denynum])) - ++access_denynum; - else - ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); - } else if (!strcmpi(w1,"ddos_interval")) - ddos_interval = atoi(w2); - else if (!strcmpi(w1,"ddos_count")) - ddos_count = atoi(w2); - else if (!strcmpi(w1,"ddos_autoreset")) - ddos_autoreset = atoi(w2); - else if (!strcmpi(w1,"debug")) - access_debug = config_switch(w2); - else if (!strcmpi(w1,"socket_max_client_packet")) - socket_max_client_packet = strtoul(w2, NULL, 0); + else if (!strcmpi(w1, "enable_ip_rules")) { + ip_rules = config_switch(w2); + } else if (!strcmpi(w1, "order")) { + if (!strcmpi(w2, "deny,allow")) + access_order = ACO_DENY_ALLOW; + else if (!strcmpi(w2, "allow,deny")) + access_order = ACO_ALLOW_DENY; + else if (!strcmpi(w2, "mutual-failure")) + access_order = ACO_MUTUAL_FAILURE; + } else if (!strcmpi(w1, "allow")) { + RECREATE(access_allow, AccessControl, access_allownum+1); + if (access_ipmask(w2, &access_allow[access_allownum])) + ++access_allownum; + else + ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); + } else if (!strcmpi(w1, "deny")) { + RECREATE(access_deny, AccessControl, access_denynum+1); + if (access_ipmask(w2, &access_deny[access_denynum])) + ++access_denynum; + else + ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); + } + else if (!strcmpi(w1,"ddos_interval")) + ddos_interval = atoi(w2); + else if (!strcmpi(w1,"ddos_count")) + ddos_count = atoi(w2); + else if (!strcmpi(w1,"ddos_autoreset")) + ddos_autoreset = atoi(w2); + else if (!strcmpi(w1,"debug")) + access_debug = config_switch(w2); + else if (!strcmpi(w1,"socket_max_client_packet")) + socket_max_client_packet = strtoul(w2, NULL, 0); #endif - else if (!strcmpi(w1, "import")) - socket_config_read(w2); - else - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); - } - - fclose(fp); - return 0; + else if (!strcmpi(w1, "import")) + socket_config_read(w2); + else + ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + } + + fclose(fp); + return 0; } void socket_final(void) { - int i; + int i; #ifndef MINICORE - ConnectHistory *hist; - ConnectHistory *next_hist; - - for (i=0; i < 0x10000; ++i) { - hist = connect_history[i]; - while (hist) { - next_hist = hist->next; - aFree(hist); - hist = next_hist; - } - } - if (access_allow) - aFree(access_allow); - if (access_deny) - aFree(access_deny); + ConnectHistory* hist; + ConnectHistory* next_hist; + + for( i=0; i < 0x10000; ++i ){ + hist = connect_history[i]; + while( hist ){ + next_hist = hist->next; + aFree(hist); + hist = next_hist; + } + } + if( access_allow ) + aFree(access_allow); + if( access_deny ) + aFree(access_deny); #endif - for (i = 1; i < fd_max; i++) - if (session[i]) - do_close(i); + for( i = 1; i < fd_max; i++ ) + if(session[i]) + do_close(i); - // session[0] のダミーデータを削除 - aFree(session[0]->rdata); - aFree(session[0]->wdata); - aFree(session[0]); + // session[0] のダミーデータを削除 + aFree(session[0]->rdata); + aFree(session[0]->wdata); + aFree(session[0]); } /// Closes a socket. void do_close(int fd) { - if (fd <= 0 ||fd >= FD_SETSIZE) - return;// invalid - - flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket) - sFD_CLR(fd, &readfds);// this needs to be done before closing the socket - sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes - sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket. - if (session[fd]) delete_session(fd); + if( fd <= 0 ||fd >= FD_SETSIZE ) + return;// invalid + + flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket) + sFD_CLR(fd, &readfds);// this needs to be done before closing the socket + sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes + sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket. + if (session[fd]) delete_session(fd); } /// Retrieve local ips in host byte order. /// Uses loopback is no address is found. -int socket_getips(uint32 *ips, int max) +int socket_getips(uint32* ips, int max) { - int num = 0; + int num = 0; - if (ips == NULL || max <= 0) - return 0; + if( ips == NULL || max <= 0 ) + return 0; #ifdef WIN32 - { - char fullhost[255]; - u_long **a; - struct hostent *hent; - - // XXX This should look up the local IP addresses in the registry - // instead of calling gethostbyname. However, the way IP addresses - // are stored in the registry is annoyingly complex, so I'll leave - // this as T.B.D. [Meruru] - if (gethostname(fullhost, sizeof(fullhost)) == SOCKET_ERROR) { - ShowError("socket_getips: No hostname defined!\n"); - return 0; - } else { - hent = gethostbyname(fullhost); - if (hent == NULL) { - ShowError("socket_getips: Cannot resolve our own hostname to an IP address\n"); - return 0; - } - a = (u_long **)hent->h_addr_list; - for (; a[num] != NULL && num < max; ++num) - ips[num] = (uint32)ntohl(*a[num]); - } - } + { + char fullhost[255]; + u_long** a; + struct hostent* hent; + + // XXX This should look up the local IP addresses in the registry + // instead of calling gethostbyname. However, the way IP addresses + // are stored in the registry is annoyingly complex, so I'll leave + // this as T.B.D. [Meruru] + if( gethostname(fullhost, sizeof(fullhost)) == SOCKET_ERROR ) + { + ShowError("socket_getips: No hostname defined!\n"); + return 0; + } + else + { + hent = gethostbyname(fullhost); + if( hent == NULL ){ + ShowError("socket_getips: Cannot resolve our own hostname to an IP address\n"); + return 0; + } + a = (u_long**)hent->h_addr_list; + for( ; a[num] != NULL && num < max; ++num) + ips[num] = (uint32)ntohl(*a[num]); + } + } #else // not WIN32 - { - int pos; - int fd; - char buf[2*16*sizeof(struct ifreq)]; - struct ifconf ic; - struct ifreq *ir; - struct sockaddr_in *a; - u_long ad; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - memset(buf, 0x00, sizeof(buf)); - - // The ioctl call will fail with Invalid Argument if there are more - // interfaces than will fit in the buffer - ic.ifc_len = sizeof(buf); - ic.ifc_buf = buf; - if (sIoctl(fd, SIOCGIFCONF, &ic) == -1) { - ShowError("socket_getips: SIOCGIFCONF failed!\n"); - return 0; - } else { - for (pos=0; pos < ic.ifc_len && num < max;) { - ir = (struct ifreq *)(buf+pos); - a = (struct sockaddr_in *) &(ir->ifr_addr); - if (a->sin_family == AF_INET) { - ad = ntohl(a->sin_addr.s_addr); - if (ad != INADDR_LOOPBACK && ad != INADDR_ANY) - ips[num++] = (uint32)ad; - } -#if (defined(BSD) && BSD >= 199103) || defined(_AIX) || defined(__APPLE__) - pos += ir->ifr_addr.sa_len + sizeof(ir->ifr_name); -#else// not AIX or APPLE - pos += sizeof(struct ifreq); -#endif//not AIX or APPLE - } - } - sClose(fd); - } + { + int pos; + int fd; + char buf[2*16*sizeof(struct ifreq)]; + struct ifconf ic; + struct ifreq* ir; + struct sockaddr_in* a; + u_long ad; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + memset(buf, 0x00, sizeof(buf)); + + // The ioctl call will fail with Invalid Argument if there are more + // interfaces than will fit in the buffer + ic.ifc_len = sizeof(buf); + ic.ifc_buf = buf; + if( sIoctl(fd, SIOCGIFCONF, &ic) == -1 ) + { + ShowError("socket_getips: SIOCGIFCONF failed!\n"); + return 0; + } + else + { + for( pos=0; pos < ic.ifc_len && num < max; ) + { + ir = (struct ifreq*)(buf+pos); + a = (struct sockaddr_in*) &(ir->ifr_addr); + if( a->sin_family == AF_INET ){ + ad = ntohl(a->sin_addr.s_addr); + if( ad != INADDR_LOOPBACK && ad != INADDR_ANY ) + ips[num++] = (uint32)ad; + } + #if (defined(BSD) && BSD >= 199103) || defined(_AIX) || defined(__APPLE__) + pos += ir->ifr_addr.sa_len + sizeof(ir->ifr_name); + #else// not AIX or APPLE + pos += sizeof(struct ifreq); + #endif//not AIX or APPLE + } + } + sClose(fd); + } #endif // not W32 - // Use loopback if no ips are found - if (num == 0) - ips[num++] = (uint32)INADDR_LOOPBACK; + // Use loopback if no ips are found + if( num == 0 ) + ips[num++] = (uint32)INADDR_LOOPBACK; - return num; + return num; } void socket_init(void) { - char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf"; - unsigned int rlim_cur = FD_SETSIZE; + char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf"; + unsigned int rlim_cur = FD_SETSIZE; #ifdef WIN32 - { - // Start up windows networking - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD(2, 0); - if (WSAStartup(wVersionRequested, &wsaData) != 0) { - ShowError("socket_init: WinSock not available!\n"); - return; - } - if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { - ShowError("socket_init: WinSock version mismatch (2.0 or compatible required)!\n"); - return; - } - } + {// Start up windows networking + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + if( WSAStartup(wVersionRequested, &wsaData) != 0 ) + { + ShowError("socket_init: WinSock not available!\n"); + return; + } + if( LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0 ) + { + ShowError("socket_init: WinSock version mismatch (2.0 or compatible required)!\n"); + return; + } + } #elif defined(HAVE_SETRLIMIT) && !defined(CYGWIN) - // NOTE: getrlimit and setrlimit have bogus behaviour in cygwin. - // "Number of fds is virtually unlimited in cygwin" (sys/param.h) - { - // set socket limit to FD_SETSIZE - struct rlimit rlp; - if (0 == getrlimit(RLIMIT_NOFILE, &rlp)) { - rlp.rlim_cur = FD_SETSIZE; - if (0 != setrlimit(RLIMIT_NOFILE, &rlp)) { - // failed, try setting the maximum too (permission to change system limits is required) - rlp.rlim_max = FD_SETSIZE; - if (0 != setrlimit(RLIMIT_NOFILE, &rlp)) { - // failed - const char *errmsg = error_msg(); - int rlim_ori; - // set to maximum allowed - getrlimit(RLIMIT_NOFILE, &rlp); - rlim_ori = (int)rlp.rlim_cur; - rlp.rlim_cur = rlp.rlim_max; - setrlimit(RLIMIT_NOFILE, &rlp); - // report limit - getrlimit(RLIMIT_NOFILE, &rlp); - rlim_cur = rlp.rlim_cur; - ShowWarning("socket_init: failed to set socket limit to %d, setting to maximum allowed (original limit=%d, current limit=%d, maximum allowed=%d, %s).\n", FD_SETSIZE, rlim_ori, (int)rlp.rlim_cur, (int)rlp.rlim_max, errmsg); - } - } - } - } + // NOTE: getrlimit and setrlimit have bogus behaviour in cygwin. + // "Number of fds is virtually unlimited in cygwin" (sys/param.h) + {// set socket limit to FD_SETSIZE + struct rlimit rlp; + if( 0 == getrlimit(RLIMIT_NOFILE, &rlp) ) + { + rlp.rlim_cur = FD_SETSIZE; + if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) ) + {// failed, try setting the maximum too (permission to change system limits is required) + rlp.rlim_max = FD_SETSIZE; + if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) ) + {// failed + const char *errmsg = error_msg(); + int rlim_ori; + // set to maximum allowed + getrlimit(RLIMIT_NOFILE, &rlp); + rlim_ori = (int)rlp.rlim_cur; + rlp.rlim_cur = rlp.rlim_max; + setrlimit(RLIMIT_NOFILE, &rlp); + // report limit + getrlimit(RLIMIT_NOFILE, &rlp); + rlim_cur = rlp.rlim_cur; + ShowWarning("socket_init: failed to set socket limit to %d, setting to maximum allowed (original limit=%d, current limit=%d, maximum allowed=%d, %s).\n", FD_SETSIZE, rlim_ori, (int)rlp.rlim_cur, (int)rlp.rlim_max, errmsg); + } + } + } + } #endif - // Get initial local ips - naddr_ = socket_getips(addr_,16); + // Get initial local ips + naddr_ = socket_getips(addr_,16); - sFD_ZERO(&readfds); + sFD_ZERO(&readfds); #if defined(SEND_SHORTLIST) - memset(send_shortlist_set, 0, sizeof(send_shortlist_set)); + memset(send_shortlist_set, 0, sizeof(send_shortlist_set)); #endif - socket_config_read(SOCKET_CONF_FILENAME); + socket_config_read(SOCKET_CONF_FILENAME); - // initialise last send-receive tick - last_tick = time(NULL); + // initialise last send-receive tick + last_tick = time(NULL); - // session[0] is now currently used for disconnected sessions of the map server, and as such, - // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex] - create_session(0, null_recv, null_send, null_parse); + // session[0] is now currently used for disconnected sessions of the map server, and as such, + // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex] + create_session(0, null_recv, null_send, null_parse); #ifndef MINICORE - // Delete old connection history every 5 minutes - memset(connect_history, 0, sizeof(connect_history)); - add_timer_func_list(connect_check_clear, "connect_check_clear"); - add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); + // Delete old connection history every 5 minutes + memset(connect_history, 0, sizeof(connect_history)); + add_timer_func_list(connect_check_clear, "connect_check_clear"); + add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); #endif - ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); + ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); } bool session_isValid(int fd) { - return (fd > 0 && fd < FD_SETSIZE && session[fd] != NULL); + return ( fd > 0 && fd < FD_SETSIZE && session[fd] != NULL ); } bool session_isActive(int fd) { - return (session_isValid(fd) && !session[fd]->flag.eof); + return ( session_isValid(fd) && !session[fd]->flag.eof ); } // Resolves hostname into a numeric ip. -uint32 host2ip(const char *hostname) +uint32 host2ip(const char* hostname) { - struct hostent *h = gethostbyname(hostname); - return (h != NULL) ? ntohl(*(uint32 *)h->h_addr) : 0; + struct hostent* h = gethostbyname(hostname); + return (h != NULL) ? ntohl(*(uint32*)h->h_addr) : 0; } // Converts a numeric ip into a dot-formatted string. // Result is placed either into a user-provided buffer or a static system buffer. -const char *ip2str(uint32 ip, char ip_str[16]) +const char* ip2str(uint32 ip, char ip_str[16]) { - struct in_addr addr; - addr.s_addr = htonl(ip); - return (ip_str == NULL) ? inet_ntoa(addr) : strncpy(ip_str, inet_ntoa(addr), 16); + struct in_addr addr; + addr.s_addr = htonl(ip); + return (ip_str == NULL) ? inet_ntoa(addr) : strncpy(ip_str, inet_ntoa(addr), 16); } // Converts a dot-formatted ip string into a numeric ip. -uint32 str2ip(const char *ip_str) +uint32 str2ip(const char* ip_str) { - return ntohl(inet_addr(ip_str)); + return ntohl(inet_addr(ip_str)); } // Reorders bytes from network to little endian (Windows). // Neccessary for sending port numbers to the RO client until Gravity notices that they forgot ntohs() calls. uint16 ntows(uint16 netshort) { - return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8); + return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8); } #ifdef SEND_SHORTLIST @@ -1364,70 +1382,75 @@ uint16 ntows(uint16 netshort) // sending or eof handling. void send_shortlist_add_fd(int fd) { - int i; - int bit; + int i; + int bit; - if (!session_isValid(fd)) - return;// out of range + if( !session_isValid(fd) ) + return;// out of range - i = fd/32; - bit = fd%32; + i = fd/32; + bit = fd%32; - if ((send_shortlist_set[i]>>bit)&1) - return;// already in the list + if( (send_shortlist_set[i]>>bit)&1 ) + return;// already in the list - if (send_shortlist_count >= ARRAYLENGTH(send_shortlist_array)) { - ShowDebug("send_shortlist_add_fd: shortlist is full, ignoring... (fd=%d shortlist.count=%d shortlist.length=%d)\n", fd, send_shortlist_count, ARRAYLENGTH(send_shortlist_array)); - return; - } + if( send_shortlist_count >= ARRAYLENGTH(send_shortlist_array) ) + { + ShowDebug("send_shortlist_add_fd: shortlist is full, ignoring... (fd=%d shortlist.count=%d shortlist.length=%d)\n", fd, send_shortlist_count, ARRAYLENGTH(send_shortlist_array)); + return; + } - // set the bit - send_shortlist_set[i] |= 1<= 0; --i) { - int fd = send_shortlist_array[i]; - int idx = fd/32; - int bit = fd%32; - - // Remove fd from shortlist, move the last fd to the current position - --send_shortlist_count; - send_shortlist_array[i] = send_shortlist_array[send_shortlist_count]; - send_shortlist_array[send_shortlist_count] = 0; - - if (fd <= 0 || fd >= FD_SETSIZE) { - ShowDebug("send_shortlist_do_sends: fd is out of range, corrupted memory? (fd=%d)\n", fd); - continue; - } - if (((send_shortlist_set[idx]>>bit)&1) == 0) { - ShowDebug("send_shortlist_do_sends: fd is not set, why is it in the shortlist? (fd=%d)\n", fd); - continue; - } - send_shortlist_set[idx]&=~(1<wdata_size) - session[fd]->func_send(fd); - - // If it's been marked as eof, call the parse func on it so that - // the socket will be immediately closed. - if (session[fd]->flag.eof) - session[fd]->func_parse(fd); - - // If the session still exists, is not eof and has things left to - // be sent from it we'll re-add it to the shortlist. - if (session[fd] && !session[fd]->flag.eof && session[fd]->wdata_size) - send_shortlist_add_fd(fd); - } - } + int i; + + for( i = send_shortlist_count-1; i >= 0; --i ) + { + int fd = send_shortlist_array[i]; + int idx = fd/32; + int bit = fd%32; + + // Remove fd from shortlist, move the last fd to the current position + --send_shortlist_count; + send_shortlist_array[i] = send_shortlist_array[send_shortlist_count]; + send_shortlist_array[send_shortlist_count] = 0; + + if( fd <= 0 || fd >= FD_SETSIZE ) + { + ShowDebug("send_shortlist_do_sends: fd is out of range, corrupted memory? (fd=%d)\n", fd); + continue; + } + if( ((send_shortlist_set[idx]>>bit)&1) == 0 ) + { + ShowDebug("send_shortlist_do_sends: fd is not set, why is it in the shortlist? (fd=%d)\n", fd); + continue; + } + send_shortlist_set[idx]&=~(1<wdata_size ) + session[fd]->func_send(fd); + + // If it's been marked as eof, call the parse func on it so that + // the socket will be immediately closed. + if( session[fd]->flag.eof ) + session[fd]->func_parse(fd); + + // If the session still exists, is not eof and has things left to + // be sent from it we'll re-add it to the shortlist. + if( session[fd] && !session[fd]->flag.eof && session[fd]->wdata_size ) + send_shortlist_add_fd(fd); + } + } } #endif diff --git a/src/common/socket.h b/src/common/socket.h index 5c4008d62..7c0e02f5d 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -1,18 +1,18 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _SOCKET_H_ +#ifndef _SOCKET_H_ #define _SOCKET_H_ #include "../common/cbasetypes.h" #ifdef WIN32 -#include "../common/winapi.h" -typedef long in_addr_t; + #include "../common/winapi.h" + typedef long in_addr_t; #else -#include -#include -#include + #include + #include + #include #endif #include @@ -38,15 +38,15 @@ typedef long in_addr_t; #define RFIFOREST(fd) (session[fd]->flag.eof ? 0 : session[fd]->rdata_size - session[fd]->rdata_pos) #define RFIFOFLUSH(fd) \ - do { \ - if(session[fd]->rdata_size == session[fd]->rdata_pos){ \ - session[fd]->rdata_size = session[fd]->rdata_pos = 0; \ - } else { \ - session[fd]->rdata_size -= session[fd]->rdata_pos; \ - memmove(session[fd]->rdata, session[fd]->rdata+session[fd]->rdata_pos, session[fd]->rdata_size); \ - session[fd]->rdata_pos = 0; \ - } \ - } while(0) + do { \ + if(session[fd]->rdata_size == session[fd]->rdata_pos){ \ + session[fd]->rdata_size = session[fd]->rdata_pos = 0; \ + } else { \ + session[fd]->rdata_size -= session[fd]->rdata_pos; \ + memmove(session[fd]->rdata, session[fd]->rdata+session[fd]->rdata_pos, session[fd]->rdata_size); \ + session[fd]->rdata_pos = 0; \ + } \ + } while(0) // buffer I/O macros #define RBUFP(p,pos) (((uint8*)(p)) + (pos)) @@ -71,32 +71,33 @@ typedef int (*RecvFunc)(int fd); typedef int (*SendFunc)(int fd); typedef int (*ParseFunc)(int fd); -struct socket_data { - struct { - unsigned char eof : 1; - unsigned char server : 1; - unsigned char ping : 2; - } flag; +struct socket_data +{ + struct { + unsigned char eof : 1; + unsigned char server : 1; + unsigned char ping : 2; + } flag; - uint32 client_addr; // remote client address + uint32 client_addr; // remote client address - uint8 *rdata, *wdata; - size_t max_rdata, max_wdata; - size_t rdata_size, wdata_size; - size_t rdata_pos; - time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled + uint8 *rdata, *wdata; + size_t max_rdata, max_wdata; + size_t rdata_size, wdata_size; + size_t rdata_pos; + time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled - RecvFunc func_recv; - SendFunc func_send; - ParseFunc func_parse; + RecvFunc func_recv; + SendFunc func_send; + ParseFunc func_parse; - void *session_data; // stores application-specific data related to the session + void* session_data; // stores application-specific data related to the session }; // Data prototype declaration -extern struct socket_data *session[FD_SETSIZE]; +extern struct socket_data* session[FD_SETSIZE]; extern int fd_max; @@ -130,21 +131,21 @@ extern void set_nonblocking(int fd, unsigned long yes); void set_defaultparse(ParseFunc defaultparse); // hostname/ip conversion functions -uint32 host2ip(const char *hostname); -const char *ip2str(uint32 ip, char ip_str[16]); -uint32 str2ip(const char *ip_str); +uint32 host2ip(const char* hostname); +const char* ip2str(uint32 ip, char ip_str[16]); +uint32 str2ip(const char* ip_str); #define CONVIP(ip) ((ip)>>24)&0xFF,((ip)>>16)&0xFF,((ip)>>8)&0xFF,((ip)>>0)&0xFF #define MAKEIP(a,b,c,d) (uint32)( ( ( (a)&0xFF ) << 24 ) | ( ( (b)&0xFF ) << 16 ) | ( ( (c)&0xFF ) << 8 ) | ( ( (d)&0xFF ) << 0 ) ) uint16 ntows(uint16 netshort); -int socket_getips(uint32 *ips, int max); +int socket_getips(uint32* ips, int max); extern uint32 addr_[16]; // ip addresses of local host (host byte order) extern int naddr_; // # of ip addresses void set_eof(int fd); -/// Use a shortlist of sockets instead of iterating all sessions for sockets +/// Use a shortlist of sockets instead of iterating all sessions for sockets /// that have data to send or need eof handling. /// Adapted to use a static array instead of a linked list. /// diff --git a/src/common/spinlock.h b/src/common/spinlock.h index 8d1624b33..3419bfdd5 100644 --- a/src/common/spinlock.h +++ b/src/common/spinlock.h @@ -14,7 +14,7 @@ // For more information, see LICENCE in the main folder // // - + #ifdef WIN32 #include "../common/winapi.h" #endif @@ -25,81 +25,77 @@ #ifdef WIN32 -typedef struct __declspec(align(64)) SPIN_LOCK { - volatile LONG lock; - volatile LONG nest; - volatile LONG sync_lock; +typedef struct __declspec( align(64) ) SPIN_LOCK{ + volatile LONG lock; + volatile LONG nest; + volatile LONG sync_lock; } SPIN_LOCK, *PSPIN_LOCK; #else -typedef struct SPIN_LOCK { - volatile int32 lock; - volatile int32 nest; // nesting level. - - volatile int32 sync_lock; +typedef struct SPIN_LOCK{ + volatile int32 lock; + volatile int32 nest; // nesting level. + + volatile int32 sync_lock; } __attribute__((aligned(64))) SPIN_LOCK, *PSPIN_LOCK; #endif -static forceinline void InitializeSpinLock(PSPIN_LOCK lck) -{ - lck->lock = 0; - lck->nest = 0; - lck->sync_lock = 0; +static forceinline void InitializeSpinLock(PSPIN_LOCK lck){ + lck->lock = 0; + lck->nest = 0; + lck->sync_lock = 0; } -static forceinline void FinalizeSpinLock(PSPIN_LOCK lck) -{ - return; +static forceinline void FinalizeSpinLock(PSPIN_LOCK lck){ + return; } #define getsynclock(l) { while(1){ if(InterlockedCompareExchange(l, 1, 0) == 0) break; rathread_yield(); } } #define dropsynclock(l) { InterlockedExchange(l, 0); } -static forceinline void EnterSpinLock(PSPIN_LOCK lck) -{ - int tid = rathread_get_tid(); - - // Get Sync Lock && Check if the requester thread already owns the lock. - // if it owns, increase nesting level - getsynclock(&lck->sync_lock); - if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { - InterlockedIncrement(&lck->nest); - dropsynclock(&lck->sync_lock); - return; // Got Lock - } - // drop sync lock - dropsynclock(&lck->sync_lock); - - - // Spin until we've got it ! - while (1) { - - if (InterlockedCompareExchange(&lck->lock, tid, 0) == 0) { - - InterlockedIncrement(&lck->nest); - return; // Got Lock - } - - rathread_yield(); // Force ctxswitch to another thread. - } +static forceinline void EnterSpinLock(PSPIN_LOCK lck){ + int tid = rathread_get_tid(); + + // Get Sync Lock && Check if the requester thread already owns the lock. + // if it owns, increase nesting level + getsynclock(&lck->sync_lock); + if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ + InterlockedIncrement(&lck->nest); + dropsynclock(&lck->sync_lock); + return; // Got Lock + } + // drop sync lock + dropsynclock(&lck->sync_lock); + + + // Spin until we've got it ! + while(1){ + + if(InterlockedCompareExchange(&lck->lock, tid, 0) == 0){ + + InterlockedIncrement(&lck->nest); + return; // Got Lock + } + + rathread_yield(); // Force ctxswitch to another thread. + } } -static forceinline void LeaveSpinLock(PSPIN_LOCK lck) -{ - int tid = rathread_get_tid(); - - getsynclock(&lck->sync_lock); - - if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { // this thread owns the lock. - if (InterlockedDecrement(&lck->nest) == 0) - InterlockedExchange(&lck->lock, 0); // Unlock! - } +static forceinline void LeaveSpinLock(PSPIN_LOCK lck){ + int tid = rathread_get_tid(); - dropsynclock(&lck->sync_lock); + getsynclock(&lck->sync_lock); + + if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ // this thread owns the lock. + if(InterlockedDecrement(&lck->nest) == 0) + InterlockedExchange(&lck->lock, 0); // Unlock! + } + + dropsynclock(&lck->sync_lock); } diff --git a/src/common/sql.c b/src/common/sql.c index 740da476d..800aa89b0 100644 --- a/src/common/sql.c +++ b/src/common/sql.c @@ -18,38 +18,41 @@ /// Sql handle -struct Sql { - StringBuf buf; - MYSQL handle; - MYSQL_RES *result; - MYSQL_ROW row; - unsigned long *lengths; - int keepalive; +struct Sql +{ + StringBuf buf; + MYSQL handle; + MYSQL_RES* result; + MYSQL_ROW row; + unsigned long* lengths; + int keepalive; }; // Column length receiver. // Takes care of the possible size missmatch between uint32 and unsigned long. -struct s_column_length { - uint32 *out_length; - unsigned long length; +struct s_column_length +{ + uint32* out_length; + unsigned long length; }; typedef struct s_column_length s_column_length; /// Sql statement -struct SqlStmt { - StringBuf buf; - MYSQL_STMT *stmt; - MYSQL_BIND *params; - MYSQL_BIND *columns; - s_column_length *column_lengths; - size_t max_params; - size_t max_columns; - bool bind_params; - bool bind_columns; +struct SqlStmt +{ + StringBuf buf; + MYSQL_STMT* stmt; + MYSQL_BIND* params; + MYSQL_BIND* columns; + s_column_length* column_lengths; + size_t max_params; + size_t max_columns; + bool bind_params; + bool bind_columns; }; @@ -61,111 +64,117 @@ struct SqlStmt { /// Allocates and initializes a new Sql handle. -Sql *Sql_Malloc(void) +Sql* Sql_Malloc(void) { - Sql *self; + Sql* self; - CREATE(self, Sql, 1); - mysql_init(&self->handle); - StringBuf_Init(&self->buf); - self->lengths = NULL; - self->result = NULL; - self->keepalive = INVALID_TIMER; + CREATE(self, Sql, 1); + mysql_init(&self->handle); + StringBuf_Init(&self->buf); + self->lengths = NULL; + self->result = NULL; + self->keepalive = INVALID_TIMER; - return self; + return self; } -static int Sql_P_Keepalive(Sql *self); +static int Sql_P_Keepalive(Sql* self); /// Establishes a connection. -int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db) +int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - StringBuf_Clear(&self->buf); - if (!mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/)) { - ShowSQL("%s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } + StringBuf_Clear(&self->buf); + if( !mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/) ) + { + ShowSQL("%s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } - self->keepalive = Sql_P_Keepalive(self); - if (self->keepalive == INVALID_TIMER) { - ShowSQL("Failed to establish keepalive for DB connection!\n"); - return SQL_ERROR; - } + self->keepalive = Sql_P_Keepalive(self); + if( self->keepalive == INVALID_TIMER ) + { + ShowSQL("Failed to establish keepalive for DB connection!\n"); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Retrieves the timeout of the connection. -int Sql_GetTimeout(Sql *self, uint32 *out_timeout) +int Sql_GetTimeout(Sql* self, uint32* out_timeout) { - if (self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'")) { - char *data; - size_t len; - if (SQL_SUCCESS == Sql_NextRow(self) && - SQL_SUCCESS == Sql_GetData(self, 1, &data, &len)) { - *out_timeout = (uint32)strtoul(data, NULL, 10); - Sql_FreeResult(self); - return SQL_SUCCESS; - } - Sql_FreeResult(self); - } - return SQL_ERROR; + if( self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) + { + char* data; + size_t len; + if( SQL_SUCCESS == Sql_NextRow(self) && + SQL_SUCCESS == Sql_GetData(self, 1, &data, &len) ) + { + *out_timeout = (uint32)strtoul(data, NULL, 10); + Sql_FreeResult(self); + return SQL_SUCCESS; + } + Sql_FreeResult(self); + } + return SQL_ERROR; } /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. -int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_len, char sep) +int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep) { - char *data; - size_t len; - size_t off = 0; + char* data; + size_t len; + size_t off = 0; - if (self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table)) - return SQL_ERROR; + if( self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table) ) + return SQL_ERROR; - out_buf[off] = '\0'; - while (SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len)) { - len = strnlen(data, len); - if (off + len + 2 > buf_len) { - ShowDebug("Sql_GetColumns: output buffer is too small\n"); - *out_buf = '\0'; - return SQL_ERROR; - } - memcpy(out_buf+off, data, len); - off += len; - out_buf[off++] = sep; - } - out_buf[off] = '\0'; - Sql_FreeResult(self); - return SQL_SUCCESS; + out_buf[off] = '\0'; + while( SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len) ) + { + len = strnlen(data, len); + if( off + len + 2 > buf_len ) + { + ShowDebug("Sql_GetColumns: output buffer is too small\n"); + *out_buf = '\0'; + return SQL_ERROR; + } + memcpy(out_buf+off, data, len); + off += len; + out_buf[off++] = sep; + } + out_buf[off] = '\0'; + Sql_FreeResult(self); + return SQL_SUCCESS; } /// Changes the encoding of the connection. -int Sql_SetEncoding(Sql *self, const char *encoding) +int Sql_SetEncoding(Sql* self, const char* encoding) { - if (self && mysql_set_character_set(&self->handle, encoding) == 0) - return SQL_SUCCESS; - return SQL_ERROR; + if( self && mysql_set_character_set(&self->handle, encoding) == 0 ) + return SQL_SUCCESS; + return SQL_ERROR; } /// Pings the connection. -int Sql_Ping(Sql *self) +int Sql_Ping(Sql* self) { - if (self && mysql_ping(&self->handle) == 0) - return SQL_SUCCESS; - return SQL_ERROR; + if( self && mysql_ping(&self->handle) == 0 ) + return SQL_SUCCESS; + return SQL_ERROR; } @@ -175,10 +184,10 @@ int Sql_Ping(Sql *self) /// @private static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t data) { - Sql *self = (Sql *)data; - ShowInfo("Pinging SQL server to keep connection alive...\n"); - Sql_Ping(self); - return 0; + Sql* self = (Sql*)data; + ShowInfo("Pinging SQL server to keep connection alive...\n"); + Sql_Ping(self); + return 0; } @@ -187,213 +196,224 @@ static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t dat /// /// @return the keepalive timer id, or INVALID_TIMER /// @private -static int Sql_P_Keepalive(Sql *self) +static int Sql_P_Keepalive(Sql* self) { - uint32 timeout, ping_interval; + uint32 timeout, ping_interval; - // set a default value first - timeout = 28800; // 8 hours + // set a default value first + timeout = 28800; // 8 hours - // request the timeout value from the mysql server - Sql_GetTimeout(self, &timeout); + // request the timeout value from the mysql server + Sql_GetTimeout(self, &timeout); - if (timeout < 60) - timeout = 60; + if( timeout < 60 ) + timeout = 60; - // establish keepalive - ping_interval = timeout - 30; // 30-second reserve - //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); - return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); + // establish keepalive + ping_interval = timeout - 30; // 30-second reserve + //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); + return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); } /// Escapes a string. -size_t Sql_EscapeString(Sql *self, char *out_to, const char *from) +size_t Sql_EscapeString(Sql* self, char *out_to, const char *from) { - if (self) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); + if( self ) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); } /// Escapes a string. -size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t from_len) +size_t Sql_EscapeStringLen(Sql* self, char *out_to, const char *from, size_t from_len) { - if (self) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); + if( self ) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); } /// Executes a query. -int Sql_Query(Sql *self, const char *query, ...) +int Sql_Query(Sql* self, const char* query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = Sql_QueryV(self, query, args); - va_end(args); + va_start(args, query); + res = Sql_QueryV(self, query, args); + va_end(args); - return res; + return res; } /// Executes a query. -int Sql_QueryV(Sql *self, const char *query, va_list args) +int Sql_QueryV(Sql* self, const char* query, va_list args) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if (mysql_errno(&self->handle) != 0) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if( mysql_errno(&self->handle) != 0 ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Executes a query. -int Sql_QueryStr(Sql *self, const char *query) +int Sql_QueryStr(Sql* self, const char* query) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if (mysql_errno(&self->handle) != 0) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if( mysql_errno(&self->handle) != 0 ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. -uint64 Sql_LastInsertId(Sql *self) +uint64 Sql_LastInsertId(Sql* self) { - if (self) - return (uint64)mysql_insert_id(&self->handle); - else - return 0; + if( self ) + return (uint64)mysql_insert_id(&self->handle); + else + return 0; } /// Returns the number of columns in each row of the result. -uint32 Sql_NumColumns(Sql *self) +uint32 Sql_NumColumns(Sql* self) { - if (self && self->result) - return (uint32)mysql_num_fields(self->result); - return 0; + if( self && self->result ) + return (uint32)mysql_num_fields(self->result); + return 0; } /// Returns the number of rows in the result. -uint64 Sql_NumRows(Sql *self) +uint64 Sql_NumRows(Sql* self) { - if (self && self->result) - return (uint64)mysql_num_rows(self->result); - return 0; + if( self && self->result ) + return (uint64)mysql_num_rows(self->result); + return 0; } /// Fetches the next row. -int Sql_NextRow(Sql *self) +int Sql_NextRow(Sql* self) { - if (self && self->result) { - self->row = mysql_fetch_row(self->result); - if (self->row) { - self->lengths = mysql_fetch_lengths(self->result); - return SQL_SUCCESS; - } - self->lengths = NULL; - if (mysql_errno(&self->handle) == 0) - return SQL_NO_DATA; - } - return SQL_ERROR; + if( self && self->result ) + { + self->row = mysql_fetch_row(self->result); + if( self->row ) + { + self->lengths = mysql_fetch_lengths(self->result); + return SQL_SUCCESS; + } + self->lengths = NULL; + if( mysql_errno(&self->handle) == 0 ) + return SQL_NO_DATA; + } + return SQL_ERROR; } /// Gets the data of a column. -int Sql_GetData(Sql *self, size_t col, char **out_buf, size_t *out_len) +int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len) { - if (self && self->row) { - if (col < Sql_NumColumns(self)) { - if (out_buf) *out_buf = self->row[col]; - if (out_len) *out_len = (size_t)self->lengths[col]; - } else { - // out of range - ignore - if (out_buf) *out_buf = NULL; - if (out_len) *out_len = 0; - } - return SQL_SUCCESS; - } - return SQL_ERROR; + if( self && self->row ) + { + if( col < Sql_NumColumns(self) ) + { + if( out_buf ) *out_buf = self->row[col]; + if( out_len ) *out_len = (size_t)self->lengths[col]; + } + else + {// out of range - ignore + if( out_buf ) *out_buf = NULL; + if( out_len ) *out_len = 0; + } + return SQL_SUCCESS; + } + return SQL_ERROR; } /// Frees the result of the query. -void Sql_FreeResult(Sql *self) +void Sql_FreeResult(Sql* self) { - if (self && self->result) { - mysql_free_result(self->result); - self->result = NULL; - self->row = NULL; - self->lengths = NULL; - } + if( self && self->result ) + { + mysql_free_result(self->result); + self->result = NULL; + self->row = NULL; + self->lengths = NULL; + } } /// Shows debug information (last query). -void Sql_ShowDebug_(Sql *self, const char *debug_file, const unsigned long debug_line) +void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line) { - if (self == NULL) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if (StringBuf_Length(&self->buf) > 0) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if( self == NULL ) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if( StringBuf_Length(&self->buf) > 0 ) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql *self) +void Sql_Free(Sql* self) { - if (self) { - Sql_FreeResult(self); - StringBuf_Destroy(&self->buf); - if (self->keepalive != INVALID_TIMER) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); - aFree(self); - } + if( self ) + { + Sql_FreeResult(self); + StringBuf_Destroy(&self->buf); + if( self->keepalive != INVALID_TIMER ) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); + aFree(self); + } } @@ -409,19 +429,16 @@ void Sql_Free(Sql *self) /// @private static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) { - switch (sz) { - case 1: - return MYSQL_TYPE_TINY; - case 2: - return MYSQL_TYPE_SHORT; - case 4: - return MYSQL_TYPE_LONG; - case 8: - return MYSQL_TYPE_LONGLONG; - default: - ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); - return MYSQL_TYPE_NULL; - } + switch( sz ) + { + case 1: return MYSQL_TYPE_TINY; + case 2: return MYSQL_TYPE_SHORT; + case 4: return MYSQL_TYPE_LONG; + case 8: return MYSQL_TYPE_LONGLONG; + default: + ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); + return MYSQL_TYPE_NULL; + } } @@ -429,96 +446,74 @@ static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) /// Binds a parameter/result. /// /// @private -static int Sql_P_BindSqlDataType(MYSQL_BIND *bind, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, unsigned long *out_length, int8 *out_is_null) -{ - memset(bind, 0, sizeof(MYSQL_BIND)); - switch (buffer_type) { - case SQLDT_NULL: - bind->buffer_type = MYSQL_TYPE_NULL; - buffer_len = 0;// FIXME length = ? [FlavioJS] - break; - // fixed size - case SQLDT_UINT8: - bind->is_unsigned = 1; - case SQLDT_INT8: - bind->buffer_type = MYSQL_TYPE_TINY; - buffer_len = 1; - break; - case SQLDT_UINT16: - bind->is_unsigned = 1; - case SQLDT_INT16: - bind->buffer_type = MYSQL_TYPE_SHORT; - buffer_len = 2; - break; - case SQLDT_UINT32: - bind->is_unsigned = 1; - case SQLDT_INT32: - bind->buffer_type = MYSQL_TYPE_LONG; - buffer_len = 4; - break; - case SQLDT_UINT64: - bind->is_unsigned = 1; - case SQLDT_INT64: - bind->buffer_type = MYSQL_TYPE_LONGLONG; - buffer_len = 8; - break; - // platform dependent size - case SQLDT_UCHAR: - bind->is_unsigned = 1; - case SQLDT_CHAR: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); - buffer_len = sizeof(char); - break; - case SQLDT_USHORT: - bind->is_unsigned = 1; - case SQLDT_SHORT: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); - buffer_len = sizeof(short); - break; - case SQLDT_UINT: - bind->is_unsigned = 1; - case SQLDT_INT: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); - buffer_len = sizeof(int); - break; - case SQLDT_ULONG: - bind->is_unsigned = 1; - case SQLDT_LONG: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); - buffer_len = sizeof(long); - break; - case SQLDT_ULONGLONG: - bind->is_unsigned = 1; - case SQLDT_LONGLONG: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); - buffer_len = sizeof(int64); - break; - // floating point - case SQLDT_FLOAT: - bind->buffer_type = MYSQL_TYPE_FLOAT; - buffer_len = 4; - break; - case SQLDT_DOUBLE: - bind->buffer_type = MYSQL_TYPE_DOUBLE; - buffer_len = 8; - break; - // other - case SQLDT_STRING: - case SQLDT_ENUM: - bind->buffer_type = MYSQL_TYPE_STRING; - break; - case SQLDT_BLOB: - bind->buffer_type = MYSQL_TYPE_BLOB; - break; - default: - ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); - return SQL_ERROR; - } - bind->buffer = buffer; - bind->buffer_length = (unsigned long)buffer_len; - bind->length = out_length; - bind->is_null = (my_bool *)out_is_null; - return SQL_SUCCESS; +static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, unsigned long* out_length, int8* out_is_null) +{ + memset(bind, 0, sizeof(MYSQL_BIND)); + switch( buffer_type ) + { + case SQLDT_NULL: bind->buffer_type = MYSQL_TYPE_NULL; + buffer_len = 0;// FIXME length = ? [FlavioJS] + break; + // fixed size + case SQLDT_UINT8: bind->is_unsigned = 1; + case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY; + buffer_len = 1; + break; + case SQLDT_UINT16: bind->is_unsigned = 1; + case SQLDT_INT16: bind->buffer_type = MYSQL_TYPE_SHORT; + buffer_len = 2; + break; + case SQLDT_UINT32: bind->is_unsigned = 1; + case SQLDT_INT32: bind->buffer_type = MYSQL_TYPE_LONG; + buffer_len = 4; + break; + case SQLDT_UINT64: bind->is_unsigned = 1; + case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG; + buffer_len = 8; + break; + // platform dependent size + case SQLDT_UCHAR: bind->is_unsigned = 1; + case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); + buffer_len = sizeof(char); + break; + case SQLDT_USHORT: bind->is_unsigned = 1; + case SQLDT_SHORT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); + buffer_len = sizeof(short); + break; + case SQLDT_UINT: bind->is_unsigned = 1; + case SQLDT_INT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); + buffer_len = sizeof(int); + break; + case SQLDT_ULONG: bind->is_unsigned = 1; + case SQLDT_LONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); + buffer_len = sizeof(long); + break; + case SQLDT_ULONGLONG: bind->is_unsigned = 1; + case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); + buffer_len = sizeof(int64); + break; + // floating point + case SQLDT_FLOAT: bind->buffer_type = MYSQL_TYPE_FLOAT; + buffer_len = 4; + break; + case SQLDT_DOUBLE: bind->buffer_type = MYSQL_TYPE_DOUBLE; + buffer_len = 8; + break; + // other + case SQLDT_STRING: + case SQLDT_ENUM: bind->buffer_type = MYSQL_TYPE_STRING; + break; + case SQLDT_BLOB: bind->buffer_type = MYSQL_TYPE_BLOB; + break; + default: + ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); + return SQL_ERROR; + } + bind->buffer = buffer; + bind->buffer_length = (unsigned long)buffer_len; + bind->length = out_length; + bind->is_null = (my_bool*)out_is_null; + return SQL_SUCCESS; } @@ -526,37 +521,38 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND *bind, enum SqlDataType buffer_type, /// Prints debug information about a field (type and length). /// /// @private -static void Sql_P_ShowDebugMysqlFieldInfo(const char *prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char *length_postfix) -{ - const char *sign = (is_unsigned ? "UNSIGNED " : ""); - const char *type_string; - switch (type) { - default: - ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); - return; +static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char* length_postfix) +{ + const char* sign = (is_unsigned ? "UNSIGNED " : ""); + const char* type_string; + switch( type ) + { + default: + ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); + return; #define SHOW_DEBUG_OF(x) case x: type_string = #x; break - SHOW_DEBUG_OF(MYSQL_TYPE_TINY); - SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); - SHOW_DEBUG_OF(MYSQL_TYPE_LONG); - SHOW_DEBUG_OF(MYSQL_TYPE_INT24); - SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); - SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); - SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); - SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); - SHOW_DEBUG_OF(MYSQL_TYPE_DATE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIME); - SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); - SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); - SHOW_DEBUG_OF(MYSQL_TYPE_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); - SHOW_DEBUG_OF(MYSQL_TYPE_SET); - SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); - SHOW_DEBUG_OF(MYSQL_TYPE_NULL); + SHOW_DEBUG_OF(MYSQL_TYPE_TINY); + SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); + SHOW_DEBUG_OF(MYSQL_TYPE_LONG); + SHOW_DEBUG_OF(MYSQL_TYPE_INT24); + SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); + SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); + SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); + SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); + SHOW_DEBUG_OF(MYSQL_TYPE_DATE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIME); + SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); + SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); + SHOW_DEBUG_OF(MYSQL_TYPE_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); + SHOW_DEBUG_OF(MYSQL_TYPE_SET); + SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); + SHOW_DEBUG_OF(MYSQL_TYPE_NULL); #undef SHOW_DEBUG_TYPE_OF - } - ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); + } + ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); } @@ -564,369 +560,389 @@ static void Sql_P_ShowDebugMysqlFieldInfo(const char *prefix, enum enum_field_ty /// Reports debug information about a truncated column. /// /// @private -static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt *self, size_t i) +static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i) { - MYSQL_RES *meta; - MYSQL_FIELD *field; - MYSQL_BIND *column; + MYSQL_RES* meta; + MYSQL_FIELD* field; + MYSQL_BIND* column; - meta = mysql_stmt_result_metadata(self->stmt); - field = mysql_fetch_field_direct(meta, (unsigned int)i); - ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); - ShowDebug("column - %lu\n", (unsigned long)i); - Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); - column = &self->columns[i]; - if (column->buffer_type == MYSQL_TYPE_STRING) - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); - else - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); - mysql_free_result(meta); + meta = mysql_stmt_result_metadata(self->stmt); + field = mysql_fetch_field_direct(meta, (unsigned int)i); + ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); + ShowDebug("column - %lu\n", (unsigned long)i); + Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); + column = &self->columns[i]; + if( column->buffer_type == MYSQL_TYPE_STRING ) + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); + else + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); + mysql_free_result(meta); } /// Allocates and initializes a new SqlStmt handle. -SqlStmt *SqlStmt_Malloc(Sql *sql) +SqlStmt* SqlStmt_Malloc(Sql* sql) { - SqlStmt *self; - MYSQL_STMT *stmt; + SqlStmt* self; + MYSQL_STMT* stmt; - if (sql == NULL) - return NULL; + if( sql == NULL ) + return NULL; - stmt = mysql_stmt_init(&sql->handle); - if (stmt == NULL) { - ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); - return NULL; - } - CREATE(self, SqlStmt, 1); - StringBuf_Init(&self->buf); - self->stmt = stmt; - self->params = NULL; - self->columns = NULL; - self->column_lengths = NULL; - self->max_params = 0; - self->max_columns = 0; - self->bind_params = false; - self->bind_columns = false; + stmt = mysql_stmt_init(&sql->handle); + if( stmt == NULL ) + { + ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); + return NULL; + } + CREATE(self, SqlStmt, 1); + StringBuf_Init(&self->buf); + self->stmt = stmt; + self->params = NULL; + self->columns = NULL; + self->column_lengths = NULL; + self->max_params = 0; + self->max_columns = 0; + self->bind_params = false; + self->bind_columns = false; - return self; + return self; } /// Prepares the statement. -int SqlStmt_Prepare(SqlStmt *self, const char *query, ...) +int SqlStmt_Prepare(SqlStmt* self, const char* query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = SqlStmt_PrepareV(self, query, args); - va_end(args); + va_start(args, query); + res = SqlStmt_PrepareV(self, query, args); + va_end(args); - return res; + return res; } /// Prepares the statement. -int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args) +int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Prepares the statement. -int SqlStmt_PrepareStr(SqlStmt *self, const char *query) +int SqlStmt_PrepareStr(SqlStmt* self, const char* query) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of parameters in the prepared statement. -size_t SqlStmt_NumParams(SqlStmt *self) +size_t SqlStmt_NumParams(SqlStmt* self) { - if (self) - return (size_t)mysql_stmt_param_count(self->stmt); - else - return 0; + if( self ) + return (size_t)mysql_stmt_param_count(self->stmt); + else + return 0; } /// Binds a parameter to a buffer. -int SqlStmt_BindParam(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len) +int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - if (!self->bind_params) { - // initialize the bindings - size_t i; - size_t count; + if( !self->bind_params ) + {// initialize the bindings + size_t i; + size_t count; - count = SqlStmt_NumParams(self); - if (self->max_params < count) { - self->max_params = count; - RECREATE(self->params, MYSQL_BIND, count); - } - memset(self->params, 0, count*sizeof(MYSQL_BIND)); - for (i = 0; i < count; ++i) - self->params[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_params = true; - } - if (idx < self->max_params) - return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); - else - return SQL_SUCCESS;// out of range - ignore + count = SqlStmt_NumParams(self); + if( self->max_params < count ) + { + self->max_params = count; + RECREATE(self->params, MYSQL_BIND, count); + } + memset(self->params, 0, count*sizeof(MYSQL_BIND)); + for( i = 0; i < count; ++i ) + self->params[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_params = true; + } + if( idx < self->max_params ) + return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); + else + return SQL_SUCCESS;// out of range - ignore } /// Executes the prepared statement. -int SqlStmt_Execute(SqlStmt *self) +int SqlStmt_Execute(SqlStmt* self) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - SqlStmt_FreeResult(self); - if ((self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || - mysql_stmt_execute(self->stmt)) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_columns = false; - if (mysql_stmt_store_result(self->stmt)) { // store all the data - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } + SqlStmt_FreeResult(self); + if( (self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || + mysql_stmt_execute(self->stmt) ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_columns = false; + if( mysql_stmt_store_result(self->stmt) )// store all the data + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. -uint64 SqlStmt_LastInsertId(SqlStmt *self) +uint64 SqlStmt_LastInsertId(SqlStmt* self) { - if (self) - return (uint64)mysql_stmt_insert_id(self->stmt); - else - return 0; + if( self ) + return (uint64)mysql_stmt_insert_id(self->stmt); + else + return 0; } /// Returns the number of columns in each row of the result. -size_t SqlStmt_NumColumns(SqlStmt *self) +size_t SqlStmt_NumColumns(SqlStmt* self) { - if (self) - return (size_t)mysql_stmt_field_count(self->stmt); - else - return 0; + if( self ) + return (size_t)mysql_stmt_field_count(self->stmt); + else + return 0; } /// Binds the result of a column to a buffer. -int SqlStmt_BindColumn(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null) -{ - if (self == NULL) - return SQL_ERROR; - - if (buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM) { - if (buffer_len < 1) { - ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); - return SQL_ERROR; - } - --buffer_len;// nul-terminator - } - if (!self->bind_columns) { - // initialize the bindings - size_t i; - size_t cols; - - cols = SqlStmt_NumColumns(self); - if (self->max_columns < cols) { - self->max_columns = cols; - RECREATE(self->columns, MYSQL_BIND, cols); - RECREATE(self->column_lengths, s_column_length, cols); - } - memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); - memset(self->column_lengths, 0, cols*sizeof(s_column_length)); - for (i = 0; i < cols; ++i) - self->columns[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_columns = true; - } - if (idx < self->max_columns) { - self->column_lengths[idx].out_length = out_length; - return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); - } else { - return SQL_SUCCESS;// out of range - ignore - } +int SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null) +{ + if( self == NULL ) + return SQL_ERROR; + + if( buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM ) + { + if( buffer_len < 1 ) + { + ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); + return SQL_ERROR; + } + --buffer_len;// nul-terminator + } + if( !self->bind_columns ) + {// initialize the bindings + size_t i; + size_t cols; + + cols = SqlStmt_NumColumns(self); + if( self->max_columns < cols ) + { + self->max_columns = cols; + RECREATE(self->columns, MYSQL_BIND, cols); + RECREATE(self->column_lengths, s_column_length, cols); + } + memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); + memset(self->column_lengths, 0, cols*sizeof(s_column_length)); + for( i = 0; i < cols; ++i ) + self->columns[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_columns = true; + } + if( idx < self->max_columns ) + { + self->column_lengths[idx].out_length = out_length; + return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); + } + else + { + return SQL_SUCCESS;// out of range - ignore + } } /// Returns the number of rows in the result. -uint64 SqlStmt_NumRows(SqlStmt *self) +uint64 SqlStmt_NumRows(SqlStmt* self) { - if (self) - return (uint64)mysql_stmt_num_rows(self->stmt); - else - return 0; + if( self ) + return (uint64)mysql_stmt_num_rows(self->stmt); + else + return 0; } /// Fetches the next row. -int SqlStmt_NextRow(SqlStmt *self) -{ - int err; - size_t i; - size_t cols; - MYSQL_BIND *column; - unsigned long length; - - if (self == NULL) - return SQL_ERROR; - - // bind columns - if (self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns)) - err = 1;// error binding columns - else - err = mysql_stmt_fetch(self->stmt);// fetch row - - // check for errors - if (err == MYSQL_NO_DATA) - return SQL_NO_DATA; +int SqlStmt_NextRow(SqlStmt* self) +{ + int err; + size_t i; + size_t cols; + MYSQL_BIND* column; + unsigned long length; + + if( self == NULL ) + return SQL_ERROR; + + // bind columns + if( self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns) ) + err = 1;// error binding columns + else + err = mysql_stmt_fetch(self->stmt);// fetch row + + // check for errors + if( err == MYSQL_NO_DATA ) + return SQL_NO_DATA; #if defined(MYSQL_DATA_TRUNCATED) - // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] - if (err == MYSQL_DATA_TRUNCATED) { - my_bool truncated; - - if (!self->bind_columns) { - ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); - return SQL_ERROR; - } - - // find truncated column - cols = SqlStmt_NumColumns(self); - for (i = 0; i < cols; ++i) { - column = &self->columns[i]; - column->error = &truncated; - mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); - column->error = NULL; - if (truncated) { - // report truncated column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - } - ShowSQL("DB error - data truncated (unknown source)\n"); - return SQL_ERROR; - } + // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] + if( err == MYSQL_DATA_TRUNCATED ) + { + my_bool truncated; + + if( !self->bind_columns ) + { + ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); + return SQL_ERROR; + } + + // find truncated column + cols = SqlStmt_NumColumns(self); + for( i = 0; i < cols; ++i ) + { + column = &self->columns[i]; + column->error = &truncated; + mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); + column->error = NULL; + if( truncated ) + {// report truncated column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + } + ShowSQL("DB error - data truncated (unknown source)\n"); + return SQL_ERROR; + } #endif - if (err) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - - // propagate column lengths and clear unused parts of string/enum/blob buffers - cols = SqlStmt_NumColumns(self); - for (i = 0; i < cols; ++i) { - length = self->column_lengths[i].length; - column = &self->columns[i]; + if( err ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + + // propagate column lengths and clear unused parts of string/enum/blob buffers + cols = SqlStmt_NumColumns(self); + for( i = 0; i < cols; ++i ) + { + length = self->column_lengths[i].length; + column = &self->columns[i]; #if !defined(MYSQL_DATA_TRUNCATED) - // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] - if (column->buffer_length < length) { - // report truncated column - if (column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB) { - // string/enum/blob column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - // FIXME numeric types and null [FlavioJS] - } + // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] + if( column->buffer_length < length ) + {// report truncated column + if( column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB ) + {// string/enum/blob column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + // FIXME numeric types and null [FlavioJS] + } #endif - if (self->column_lengths[i].out_length) - *self->column_lengths[i].out_length = (uint32)length; - if (column->buffer_type == MYSQL_TYPE_STRING) { - // clear unused part of the string/enum buffer (and nul-terminate) - memset((char *)column->buffer + length, 0, column->buffer_length - length + 1); - } else if (column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length) { - // clear unused part of the blob buffer - memset((char *)column->buffer + length, 0, column->buffer_length - length); - } - } + if( self->column_lengths[i].out_length ) + *self->column_lengths[i].out_length = (uint32)length; + if( column->buffer_type == MYSQL_TYPE_STRING ) + {// clear unused part of the string/enum buffer (and nul-terminate) + memset((char*)column->buffer + length, 0, column->buffer_length - length + 1); + } + else if( column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length ) + {// clear unused part of the blob buffer + memset((char*)column->buffer + length, 0, column->buffer_length - length); + } + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt *self) +void SqlStmt_FreeResult(SqlStmt* self) { - if (self) - mysql_stmt_free_result(self->stmt); + if( self ) + mysql_stmt_free_result(self->stmt); } /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt *self, const char *debug_file, const unsigned long debug_line) +void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line) { - if (self == NULL) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if (StringBuf_Length(&self->buf) > 0) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if( self == NULL ) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if( StringBuf_Length(&self->buf) > 0 ) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt *self) -{ - if (self) { - SqlStmt_FreeResult(self); - StringBuf_Destroy(&self->buf); - mysql_stmt_close(self->stmt); - if (self->params) - aFree(self->params); - if (self->columns) { - aFree(self->columns); - aFree(self->column_lengths); - } - aFree(self); - } +void SqlStmt_Free(SqlStmt* self) +{ + if( self ) + { + SqlStmt_FreeResult(self); + StringBuf_Destroy(&self->buf); + mysql_stmt_close(self->stmt); + if( self->params ) + aFree(self->params); + if( self->columns ) + { + aFree(self->columns); + aFree(self->column_lengths); + } + aFree(self); + } } diff --git a/src/common/sql.h b/src/common/sql.h index 4534061e0..898e2c778 100644 --- a/src/common/sql.h +++ b/src/common/sql.h @@ -21,38 +21,39 @@ /// Data type identifier. /// String, enum and blob data types need the buffer length specified. -enum SqlDataType { - SQLDT_NULL, - // fixed size - SQLDT_INT8, - SQLDT_INT16, - SQLDT_INT32, - SQLDT_INT64, - SQLDT_UINT8, - SQLDT_UINT16, - SQLDT_UINT32, - SQLDT_UINT64, - // platform dependent size - SQLDT_CHAR, - SQLDT_SHORT, - SQLDT_INT, - SQLDT_LONG, - SQLDT_LONGLONG, - SQLDT_UCHAR, - SQLDT_USHORT, - SQLDT_UINT, - SQLDT_ULONG, - SQLDT_ULONGLONG, - // floating point - SQLDT_FLOAT, - SQLDT_DOUBLE, - // other - SQLDT_STRING, - SQLDT_ENUM, - // Note: An ENUM is a string with restricted values. When an invalid value - // is inserted, it is saved as an empty string (numerical value 0). - SQLDT_BLOB, - SQLDT_LASTID +enum SqlDataType +{ + SQLDT_NULL, + // fixed size + SQLDT_INT8, + SQLDT_INT16, + SQLDT_INT32, + SQLDT_INT64, + SQLDT_UINT8, + SQLDT_UINT16, + SQLDT_UINT32, + SQLDT_UINT64, + // platform dependent size + SQLDT_CHAR, + SQLDT_SHORT, + SQLDT_INT, + SQLDT_LONG, + SQLDT_LONGLONG, + SQLDT_UCHAR, + SQLDT_USHORT, + SQLDT_UINT, + SQLDT_ULONG, + SQLDT_ULONGLONG, + // floating point + SQLDT_FLOAT, + SQLDT_DOUBLE, + // other + SQLDT_STRING, + SQLDT_ENUM, + // Note: An ENUM is a string with restricted values. When an invalid value + // is inserted, it is saved as an empty string (numerical value 0). + SQLDT_BLOB, + SQLDT_LASTID }; struct Sql;// Sql handle (private access) @@ -64,14 +65,14 @@ typedef struct SqlStmt SqlStmt; /// Allocates and initializes a new Sql handle. -struct Sql *Sql_Malloc(void); +struct Sql* Sql_Malloc(void); /// Establishes a connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db); +int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db); @@ -79,7 +80,7 @@ int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *hos /// Retrieves the timeout of the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetTimeout(Sql *self, uint32 *out_timeout); +int Sql_GetTimeout(Sql* self, uint32* out_timeout); @@ -87,7 +88,7 @@ int Sql_GetTimeout(Sql *self, uint32 *out_timeout); /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_len, char sep); +int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep); @@ -95,14 +96,14 @@ int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_l /// Changes the encoding of the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_SetEncoding(Sql *self, const char *encoding); +int Sql_SetEncoding(Sql* self, const char* encoding); /// Pings the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Ping(Sql *self); +int Sql_Ping(Sql* self); @@ -110,7 +111,7 @@ int Sql_Ping(Sql *self); /// The output buffer must be at least strlen(from)*2+1 in size. /// /// @return The size of the escaped string -size_t Sql_EscapeString(Sql *self, char *out_to, const char *from); +size_t Sql_EscapeString(Sql* self, char* out_to, const char* from); @@ -118,7 +119,7 @@ size_t Sql_EscapeString(Sql *self, char *out_to, const char *from); /// The output buffer must be at least from_len*2+1 in size. /// /// @return The size of the escaped string -size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t from_len); +size_t Sql_EscapeStringLen(Sql* self, char* out_to, const char* from, size_t from_len); @@ -127,7 +128,7 @@ size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t fro /// The query is constructed as if it was sprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Query(Sql *self, const char *query, ...); +int Sql_Query(Sql* self, const char* query, ...); @@ -136,7 +137,7 @@ int Sql_Query(Sql *self, const char *query, ...); /// The query is constructed as if it was svprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_QueryV(Sql *self, const char *query, va_list args); +int Sql_QueryV(Sql* self, const char* query, va_list args); @@ -145,28 +146,28 @@ int Sql_QueryV(Sql *self, const char *query, va_list args); /// The query is used directly. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_QueryStr(Sql *self, const char *query); +int Sql_QueryStr(Sql* self, const char* query); /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. /// /// @return Value of the auto-increment column -uint64 Sql_LastInsertId(Sql *self); +uint64 Sql_LastInsertId(Sql* self); /// Returns the number of columns in each row of the result. /// /// @return Number of columns -uint32 Sql_NumColumns(Sql *self); +uint32 Sql_NumColumns(Sql* self); /// Returns the number of rows in the result. /// /// @return Number of rows -uint64 Sql_NumRows(Sql *self); +uint64 Sql_NumRows(Sql* self); @@ -174,7 +175,7 @@ uint64 Sql_NumRows(Sql *self); /// The data of the previous row is no longer valid. /// /// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA -int Sql_NextRow(Sql *self); +int Sql_NextRow(Sql* self); @@ -182,12 +183,12 @@ int Sql_NextRow(Sql *self); /// The data remains valid until the next row is fetched or the result is freed. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetData(Sql *self, size_t col, char **out_buf, size_t *out_len); +int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len); /// Frees the result of the query. -void Sql_FreeResult(Sql *self); +void Sql_FreeResult(Sql* self); @@ -197,22 +198,22 @@ void Sql_FreeResult(Sql *self); #define Sql_ShowDebug(self) Sql_ShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (last query). -void Sql_ShowDebug_(Sql *self, const char *debug_file, const unsigned long debug_line); +void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line); /// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql *self); +void Sql_Free(Sql* self); /////////////////////////////////////////////////////////////////////////////// // Prepared Statements /////////////////////////////////////////////////////////////////////////////// -// Parameters are placed in the statement by embedding question mark ('?') +// Parameters are placed in the statement by embedding question mark ('?') // characters into the query at the appropriate positions. // The markers are legal only in places where they represent data. -// The markers cannot be inside quotes. Quotes will be added automatically +// The markers cannot be inside quotes. Quotes will be added automatically // when they are required. // // example queries with parameters: @@ -226,7 +227,7 @@ void Sql_Free(Sql *self); /// Queries in Sql and SqlStmt are independent and don't affect each other. /// /// @return SqlStmt handle or NULL if an error occured -struct SqlStmt *SqlStmt_Malloc(Sql *sql); +struct SqlStmt* SqlStmt_Malloc(Sql* sql); @@ -235,7 +236,7 @@ struct SqlStmt *SqlStmt_Malloc(Sql *sql); /// The query is constructed as if it was sprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Prepare(SqlStmt *self, const char *query, ...); +int SqlStmt_Prepare(SqlStmt* self, const char* query, ...); @@ -244,7 +245,7 @@ int SqlStmt_Prepare(SqlStmt *self, const char *query, ...); /// The query is constructed as if it was svprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args); +int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args); @@ -253,14 +254,14 @@ int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args); /// The query is used directly. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareStr(SqlStmt *self, const char *query); +int SqlStmt_PrepareStr(SqlStmt* self, const char* query); /// Returns the number of parameters in the prepared statement. /// /// @return Number or paramenters -size_t SqlStmt_NumParams(SqlStmt *self); +size_t SqlStmt_NumParams(SqlStmt* self); @@ -269,7 +270,7 @@ size_t SqlStmt_NumParams(SqlStmt *self); /// All parameters should have bindings. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindParam(SqlStmt *self, size_t idx, SqlDataType buffer_type, void *buffer, size_t buffer_len); +int SqlStmt_BindParam(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len); @@ -277,38 +278,38 @@ int SqlStmt_BindParam(SqlStmt *self, size_t idx, SqlDataType buffer_type, void * /// Any previous result is freed and all column bindings are removed. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Execute(SqlStmt *self); +int SqlStmt_Execute(SqlStmt* self); /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. /// /// @return Value of the auto-increment column -uint64 SqlStmt_LastInsertId(SqlStmt *self); +uint64 SqlStmt_LastInsertId(SqlStmt* self); /// Returns the number of columns in each row of the result. /// /// @return Number of columns -size_t SqlStmt_NumColumns(SqlStmt *self); +size_t SqlStmt_NumColumns(SqlStmt* self); /// Binds the result of a column to a buffer. /// The buffer will be filled with data when the next row is fetched. -/// For string/enum buffer types there has to be enough space for the data +/// For string/enum buffer types there has to be enough space for the data /// and the nul-terminator (an extra byte). /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindColumn(SqlStmt *self, size_t idx, SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null); +int SqlStmt_BindColumn(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null); /// Returns the number of rows in the result. /// /// @return Number of rows -uint64 SqlStmt_NumRows(SqlStmt *self); +uint64 SqlStmt_NumRows(SqlStmt* self); @@ -316,12 +317,12 @@ uint64 SqlStmt_NumRows(SqlStmt *self); /// All column bindings will be filled with data. /// /// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA -int SqlStmt_NextRow(SqlStmt *self); +int SqlStmt_NextRow(SqlStmt* self); /// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt *self); +void SqlStmt_FreeResult(SqlStmt* self); @@ -331,12 +332,12 @@ void SqlStmt_FreeResult(SqlStmt *self); #define SqlStmt_ShowDebug(self) SqlStmt_ShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt *self, const char *debug_file, const unsigned long debug_line); +void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line); /// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt *self); +void SqlStmt_Free(SqlStmt* self); diff --git a/src/common/strlib.c b/src/common/strlib.c index 89aac3b40..dfacbf136 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -14,348 +14,360 @@ #define J_MAX_MALLOC_SIZE 65535 // escapes a string in-place (' -> \' , \ -> \\ , % -> _) -char *jstrescape(char *pt) +char* jstrescape (char* pt) { - //copy from here - char *ptr; - int i = 0, j = 0; - - //copy string to temporary - CREATE(ptr, char, J_MAX_MALLOC_SIZE); - strcpy(ptr,pt); - - while (ptr[i] != '\0') { - switch (ptr[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '%': - pt[j++] = '_'; - i++; - break; - default: - pt[j++] = ptr[i++]; - } - } - pt[j++] = '\0'; - aFree(ptr); - return pt; + //copy from here + char *ptr; + int i = 0, j = 0; + + //copy string to temporary + CREATE(ptr, char, J_MAX_MALLOC_SIZE); + strcpy(ptr,pt); + + while (ptr[i] != '\0') { + switch (ptr[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '%': + pt[j++] = '_'; i++; + break; + default: + pt[j++] = ptr[i++]; + } + } + pt[j++] = '\0'; + aFree(ptr); + return pt; } // escapes a string into a provided buffer -char *jstrescapecpy(char *pt, const char *spt) +char* jstrescapecpy (char* pt, const char* spt) { - //copy from here - //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time - //a escape character is found, the target's final length increases! [Skotlex] - int i =0, j=0; - - if (!spt) { //Return an empty string [Skotlex] - pt[0] = '\0'; - return &pt[0]; - } - - while (spt[i] != '\0') { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; - i++; - break; - default: - pt[j++] = spt[i++]; - } - } - pt[j++] = '\0'; - return &pt[0]; + //copy from here + //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time + //a escape character is found, the target's final length increases! [Skotlex] + int i =0, j=0; + + if (!spt) { //Return an empty string [Skotlex] + pt[0] = '\0'; + return &pt[0]; + } + + while (spt[i] != '\0') { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; i++; + break; + default: + pt[j++] = spt[i++]; + } + } + pt[j++] = '\0'; + return &pt[0]; } // escapes exactly 'size' bytes of a string into a provided buffer -int jmemescapecpy(char *pt, const char *spt, int size) +int jmemescapecpy (char* pt, const char* spt, int size) { - //copy from here - int i =0, j=0; - - while (i < size) { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; - i++; - break; - default: - pt[j++] = spt[i++]; - } - } - // copy size is 0 ~ (j-1) - return j; + //copy from here + int i =0, j=0; + + while (i < size) { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; i++; + break; + default: + pt[j++] = spt[i++]; + } + } + // copy size is 0 ~ (j-1) + return j; } // Function to suppress control characters in a string. -int remove_control_chars(char *str) +int remove_control_chars(char* str) { - int i; - int change = 0; + int i; + int change = 0; - for (i = 0; str[i]; i++) { - if (ISCNTRL(str[i])) { - str[i] = '_'; - change = 1; - } - } + for(i = 0; str[i]; i++) { + if (ISCNTRL(str[i])) { + str[i] = '_'; + change = 1; + } + } - return change; + return change; } // Removes characters identified by ISSPACE from the start and end of the string // NOTE: make sure the string is not const!! -char *trim(char *str) +char* trim(char* str) { - size_t start; - size_t end; - - if (str == NULL) - return str; - - // get start position - for (start = 0; str[start] && ISSPACE(str[start]); ++start) - ; - // get end position - for (end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end) - ; - // trim - if (start == end) - *str = '\0';// empty string - else { - // move string with nul terminator - str[end] = '\0'; - memmove(str,str+start,end-start+1); - } - return str; + size_t start; + size_t end; + + if( str == NULL ) + return str; + + // get start position + for( start = 0; str[start] && ISSPACE(str[start]); ++start ) + ; + // get end position + for( end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end ) + ; + // trim + if( start == end ) + *str = '\0';// empty string + else + {// move string with nul terminator + str[end] = '\0'; + memmove(str,str+start,end-start+1); + } + return str; } // Converts one or more consecutive occurences of the delimiters into a single space // and removes such occurences from the beginning and end of string // NOTE: make sure the string is not const!! -char *normalize_name(char *str,const char *delims) +char* normalize_name(char* str,const char* delims) { - char *in = str; - char *out = str; - int put_space = 0; - - if (str == NULL || delims == NULL) - return str; - - // trim start of string - while (*in && strchr(delims,*in)) - ++in; - while (*in) { - if (put_space) { - // replace trim characters with a single space - *out = ' '; - ++out; - } - // copy non trim characters - while (*in && !strchr(delims,*in)) { - *out = *in; - ++out; - ++in; - } - // skip trim characters - while (*in && strchr(delims,*in)) - ++in; - put_space = 1; - } - *out = '\0'; - return str; + char* in = str; + char* out = str; + int put_space = 0; + + if( str == NULL || delims == NULL ) + return str; + + // trim start of string + while( *in && strchr(delims,*in) ) + ++in; + while( *in ) + { + if( put_space ) + {// replace trim characters with a single space + *out = ' '; + ++out; + } + // copy non trim characters + while( *in && !strchr(delims,*in) ) + { + *out = *in; + ++out; + ++in; + } + // skip trim characters + while( *in && strchr(delims,*in) ) + ++in; + put_space = 1; + } + *out = '\0'; + return str; } -//stristr: Case insensitive version of strstr, code taken from +//stristr: Case insensitive version of strstr, code taken from //http://www.daniweb.com/code/snippet313.html, Dave Sinkula // -const char *stristr(const char *haystack, const char *needle) +const char* stristr(const char* haystack, const char* needle) { - if (!*needle) { - return haystack; - } - for (; *haystack; ++haystack) { - if (TOUPPER(*haystack) == TOUPPER(*needle)) { - // matched starting char -- loop through remaining chars - const char *h, *n; - for (h = haystack, n = needle; *h && *n; ++h, ++n) { - if (TOUPPER(*h) != TOUPPER(*n)) { - break; - } - } - if (!*n) { // matched all of 'needle' to null termination - return haystack; // return the start of the match - } - } - } - return 0; + if ( !*needle ) + { + return haystack; + } + for ( ; *haystack; ++haystack ) + { + if ( TOUPPER(*haystack) == TOUPPER(*needle) ) + { + // matched starting char -- loop through remaining chars + const char *h, *n; + for ( h = haystack, n = needle; *h && *n; ++h, ++n ) + { + if ( TOUPPER(*h) != TOUPPER(*n) ) + { + break; + } + } + if ( !*n ) // matched all of 'needle' to null termination + { + return haystack; // return the start of the match + } + } + } + return 0; } #ifdef __WIN32 -char *_strtok_r(char *s1, const char *s2, char **lasts) +char* _strtok_r(char *s1, const char *s2, char **lasts) { - char *ret; - - if (s1 == NULL) - s1 = *lasts; - while (*s1 && strchr(s2, *s1)) - ++s1; - if (*s1 == '\0') - return NULL; - ret = s1; - while (*s1 && !strchr(s2, *s1)) - ++s1; - if (*s1) - *s1++ = '\0'; - *lasts = s1; - return ret; + char *ret; + + if (s1 == NULL) + s1 = *lasts; + while(*s1 && strchr(s2, *s1)) + ++s1; + if(*s1 == '\0') + return NULL; + ret = s1; + while(*s1 && !strchr(s2, *s1)) + ++s1; + if(*s1) + *s1++ = '\0'; + *lasts = s1; + return ret; } #endif #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) /* Find the length of STRING, but scan at most MAXLEN characters. If no '\0' terminator is found in that many characters, return MAXLEN. */ -size_t strnlen(const char *string, size_t maxlen) +size_t strnlen (const char* string, size_t maxlen) { - const char *end = (const char *)memchr(string, '\0', maxlen); - return end ? (size_t)(end - string) : maxlen; + const char* end = (const char*)memchr(string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; } #endif #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char *str, char **endptr, int base) +uint64 strtoull(const char* str, char** endptr, int base) { - uint64 result; - int count; - int n; - - if (base == 0) { - if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) - base = 16; - else if (str[0] == '0') - base = 8; - else - base = 10; - } - - if (base == 8) - count = sscanf(str, "%I64o%n", &result, &n); - else if (base == 10) - count = sscanf(str, "%I64u%n", &result, &n); - else if (base == 16) - count = sscanf(str, "%I64x%n", &result, &n); - else - count = 0; // fail - - if (count < 1) { - errno = EINVAL; - result = 0; - n = 0; - } - - if (endptr) - *endptr = (char *)str + n; - - return result; + uint64 result; + int count; + int n; + + if( base == 0 ) + { + if( str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + base = 16; + else + if( str[0] == '0' ) + base = 8; + else + base = 10; + } + + if( base == 8 ) + count = sscanf(str, "%I64o%n", &result, &n); + else + if( base == 10 ) + count = sscanf(str, "%I64u%n", &result, &n); + else + if( base == 16 ) + count = sscanf(str, "%I64x%n", &result, &n); + else + count = 0; // fail + + if( count < 1 ) + { + errno = EINVAL; + result = 0; + n = 0; + } + + if( endptr ) + *endptr = (char*)str + n; + + return result; } #endif //---------------------------------------------------- // E-mail check: return 0 (not correct) or 1 (valid). //---------------------------------------------------- -int e_mail_check(char *email) +int e_mail_check(char* email) { - char ch; - char *last_arobas; - size_t len = strlen(email); + char ch; + char* last_arobas; + size_t len = strlen(email); - // athena limits - if (len < 3 || len > 39) - return 0; + // athena limits + if (len < 3 || len > 39) + return 0; - // part of RFC limits (official reference of e-mail description) - if (strchr(email, '@') == NULL || email[len-1] == '@') - return 0; + // part of RFC limits (official reference of e-mail description) + if (strchr(email, '@') == NULL || email[len-1] == '@') + return 0; - if (email[len-1] == '.') - return 0; + if (email[len-1] == '.') + return 0; - last_arobas = strrchr(email, '@'); + last_arobas = strrchr(email, '@'); - if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) - return 0; + if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) + return 0; - for (ch = 1; ch < 32; ch++) - if (strchr(last_arobas, ch) != NULL) - return 0; + for(ch = 1; ch < 32; ch++) + if (strchr(last_arobas, ch) != NULL) + return 0; - if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) - return 0; + if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) + return 0; - // all correct - return 1; + // all correct + return 1; } //-------------------------------------------------- // Return numerical value of a switch configuration // on/off, english, fran軋is, deutsch, espaol //-------------------------------------------------- -int config_switch(const char *str) +int config_switch(const char* str) { - if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) - return 1; - if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) - return 0; + if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) + return 1; + if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) + return 0; - return (int)strtol(str, NULL, 0); + return (int)strtol(str, NULL, 0); } /// strncpy that always nul-terminates the string -char *safestrncpy(char *dst, const char *src, size_t n) +char* safestrncpy(char* dst, const char* src, size_t n) { - if (n > 0) { - char *d = dst; - const char *s = src; - d[--n] = '\0';/* nul-terminate string */ - for (; n > 0; --n) { - if ((*d++ = *s++) == '\0') { - /* nul-pad remaining bytes */ - while (--n > 0) - *d++ = '\0'; - break; - } - } - } - return dst; + if( n > 0 ) + { + char* d = dst; + const char* s = src; + d[--n] = '\0';/* nul-terminate string */ + for( ; n > 0; --n ) + { + if( (*d++ = *s++) == '\0' ) + {/* nul-pad remaining bytes */ + while( --n > 0 ) + *d++ = '\0'; + break; + } + } + } + return dst; } /// doesn't crash on null pointer -size_t safestrnlen(const char *string, size_t maxlen) +size_t safestrnlen(const char* string, size_t maxlen) { - return (string != NULL) ? strnlen(string, maxlen) : 0; + return ( string != NULL ) ? strnlen(string, maxlen) : 0; } /// Works like snprintf, but always nul-terminates the buffer. @@ -367,40 +379,41 @@ size_t safestrnlen(const char *string, size_t maxlen) /// @param fmt Format string /// @param ... Format arguments /// @return The size of the string or -1 if the buffer is too small -int safesnprintf(char *buf, size_t sz, const char *fmt, ...) +int safesnprintf(char* buf, size_t sz, const char* fmt, ...) { - va_list ap; - int ret; - - va_start(ap,fmt); - ret = vsnprintf(buf, sz, fmt, ap); - va_end(ap); - if (ret < 0 || (size_t)ret >= sz) { - // overflow - buf[sz-1] = '\0';// always nul-terminate - return -1; - } - return ret; + va_list ap; + int ret; + + va_start(ap,fmt); + ret = vsnprintf(buf, sz, fmt, ap); + va_end(ap); + if( ret < 0 || (size_t)ret >= sz ) + {// overflow + buf[sz-1] = '\0';// always nul-terminate + return -1; + } + return ret; } /// Returns the line of the target position in the string. /// Lines start at 1. -int strline(const char *str, size_t pos) +int strline(const char* str, size_t pos) { - const char *target; - int line; - - if (str == NULL || pos == 0) - return 1; - - target = str+pos; - for (line = 1; ; ++line) { - str = strchr(str, '\n'); - if (str == NULL || target <= str) - break;// found target line - ++str;// skip newline - } - return line; + const char* target; + int line; + + if( str == NULL || pos == 0 ) + return 1; + + target = str+pos; + for( line = 1; ; ++line ) + { + str = strchr(str, '\n'); + if( str == NULL || target <= str ) + break;// found target line + ++str;// skip newline + } + return line; } /// Produces the hexadecimal representation of the given input. @@ -410,18 +423,19 @@ int strline(const char *str, size_t pos) /// @param output Output string /// @param input Binary input buffer /// @param count Number of bytes to convert -bool bin2hex(char *output, unsigned char *input, size_t count) +bool bin2hex(char* output, unsigned char* input, size_t count) { - char toHex[] = "0123456789abcdef"; - size_t i; - - for (i = 0; i < count; ++i) { - *output++ = toHex[(*input & 0xF0) >> 4]; - *output++ = toHex[(*input & 0x0F) >> 0]; - ++input; - } - *output = '\0'; - return true; + char toHex[] = "0123456789abcdef"; + size_t i; + + for( i = 0; i < count; ++i ) + { + *output++ = toHex[(*input & 0xF0) >> 4]; + *output++ = toHex[(*input & 0x0F) >> 0]; + ++input; + } + *output = '\0'; + return true; } @@ -432,134 +446,146 @@ bool bin2hex(char *output, unsigned char *input, size_t count) /// /// @param sv Parse state /// @return 1 if a field was parsed, 0 if already done, -1 on error. -int sv_parse_next(struct s_svstate *sv) +int sv_parse_next(struct s_svstate* sv) { - enum { - START_OF_FIELD, - PARSING_FIELD, - PARSING_C_ESCAPE, - END_OF_FIELD, - TERMINATE, - END - } state; - const char *str; - int len; - enum e_svopt opt; - char delim; - int i; - - if (sv == NULL) - return -1;// error - - str = sv->str; - len = sv->len; - opt = sv->opt; - delim = sv->delim; - - // check opt - if (delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF))) { - ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - if (delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR))) { - ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - - if (sv->done || str == NULL) { - sv->done = true; - return 0;// nothing to parse - } + enum { + START_OF_FIELD, + PARSING_FIELD, + PARSING_C_ESCAPE, + END_OF_FIELD, + TERMINATE, + END + } state; + const char* str; + int len; + enum e_svopt opt; + char delim; + int i; + + if( sv == NULL ) + return -1;// error + + str = sv->str; + len = sv->len; + opt = sv->opt; + delim = sv->delim; + + // check opt + if( delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF)) ) + { + ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + if( delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR)) ) + { + ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + + if( sv->done || str == NULL ) + { + sv->done = true; + return 0;// nothing to parse + } #define IS_END() ( i >= len ) #define IS_DELIM() ( str[i] == delim ) #define IS_TERMINATOR() ( \ - ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ - ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ - ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) + ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ + ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ + ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) #define IS_C_ESCAPE() ( (opt&SV_ESCAPE_C) && str[i] == '\\' ) #define SET_FIELD_START() sv->start = i #define SET_FIELD_END() sv->end = i - i = sv->off; - state = START_OF_FIELD; - while (state != END) { - switch (state) { - case START_OF_FIELD:// record start of field and start parsing it - SET_FIELD_START(); - state = PARSING_FIELD; - break; - - case PARSING_FIELD:// skip field character - if (IS_END() || IS_DELIM() || IS_TERMINATOR()) - state = END_OF_FIELD; - else if (IS_C_ESCAPE()) - state = PARSING_C_ESCAPE; - else - ++i;// normal character - break; - - case PARSING_C_ESCAPE: { // skip escape sequence (validates it too) - ++i;// '\\' - if (IS_END()) { - ShowError("sv_parse_next: empty escape sequence\n"); - return -1; - } - if (str[i] == 'x') { - // hex escape - ++i;// 'x' - if (IS_END() || !ISXDIGIT(str[i])) { - ShowError("sv_parse_next: \\x with no following hex digits\n"); - return -1; - } - do { - ++i;// hex digit - } while (!IS_END() && ISXDIGIT(str[i])); - } else if (str[i] == '0' || str[i] == '1' || str[i] == '2') { - // octal escape - ++i;// octal digit - if (!IS_END() && str[i] >= '0' && str[i] <= '7') - ++i;// octal digit - if (!IS_END() && str[i] >= '0' && str[i] <= '7') - ++i;// octal digit - } else if (strchr(SV_ESCAPE_C_SUPPORTED, str[i])) { - // supported escape character - ++i; - } else { - ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); - return -1; - } - state = PARSING_FIELD; - break; - } - - case END_OF_FIELD:// record end of field and stop - SET_FIELD_END(); - state = END; - if (IS_END()) - ;// nothing else - else if (IS_DELIM()) - ++i;// delim - else if (IS_TERMINATOR()) - state = TERMINATE; - break; - - case TERMINATE: + i = sv->off; + state = START_OF_FIELD; + while( state != END ) + { + switch( state ) + { + case START_OF_FIELD:// record start of field and start parsing it + SET_FIELD_START(); + state = PARSING_FIELD; + break; + + case PARSING_FIELD:// skip field character + if( IS_END() || IS_DELIM() || IS_TERMINATOR() ) + state = END_OF_FIELD; + else if( IS_C_ESCAPE() ) + state = PARSING_C_ESCAPE; + else + ++i;// normal character + break; + + case PARSING_C_ESCAPE:// skip escape sequence (validates it too) + { + ++i;// '\\' + if( IS_END() ) + { + ShowError("sv_parse_next: empty escape sequence\n"); + return -1; + } + if( str[i] == 'x' ) + {// hex escape + ++i;// 'x' + if( IS_END() || !ISXDIGIT(str[i]) ) + { + ShowError("sv_parse_next: \\x with no following hex digits\n"); + return -1; + } + do{ + ++i;// hex digit + }while( !IS_END() && ISXDIGIT(str[i])); + } + else if( str[i] == '0' || str[i] == '1' || str[i] == '2' ) + {// octal escape + ++i;// octal digit + if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) + ++i;// octal digit + if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) + ++i;// octal digit + } + else if( strchr(SV_ESCAPE_C_SUPPORTED, str[i]) ) + {// supported escape character + ++i; + } + else + { + ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); + return -1; + } + state = PARSING_FIELD; + break; + } + + case END_OF_FIELD:// record end of field and stop + SET_FIELD_END(); + state = END; + if( IS_END() ) + ;// nothing else + else if( IS_DELIM() ) + ++i;// delim + else if( IS_TERMINATOR() ) + state = TERMINATE; + break; + + case TERMINATE: #if 0 - // skip line terminator - if ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') - i += 2;// CRLF - else - ++i;// CR or LF + // skip line terminator + if( (opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n' ) + i += 2;// CRLF + else + ++i;// CR or LF #endif - sv->done = true; - state = END; - break; - } - } - if (IS_END()) - sv->done = true; - sv->off = i; + sv->done = true; + state = END; + break; + } + } + if( IS_END() ) + sv->done = true; + sv->off = i; #undef IS_END #undef IS_DELIM @@ -568,7 +594,7 @@ int sv_parse_next(struct s_svstate *sv) #undef SET_FIELD_START #undef SET_FIELD_END - return 1; + return 1; } @@ -577,13 +603,13 @@ int sv_parse_next(struct s_svstate *sv) /// out_pos[0] and out_pos[1] are the start and end of line. /// Other position pairs are the start and end of fields. /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_pos can be NULL. /// If a line terminator is found, the end position is placed there. -/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] +/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] /// for the seconds field and so on. /// Unfilled positions are set to -1. -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -592,34 +618,35 @@ int sv_parse_next(struct s_svstate *sv) /// @param npos Size of the pos array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, int npos, enum e_svopt opt) +int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt) { - struct s_svstate sv; - int count; - - // initialize - if (out_pos == NULL) npos = 0; - for (count = 0; count < npos; ++count) - out_pos[count] = -1; - sv.str = str; - sv.len = len; - sv.off = startoff; - sv.opt = opt; - sv.delim = delim; - sv.done = false; - - // parse - count = 0; - if (npos > 0) out_pos[0] = startoff; - while (!sv.done) { - ++count; - if (sv_parse_next(&sv) <= 0) - return -1;// error - if (npos > count*2) out_pos[count*2] = sv.start; - if (npos > count*2+1) out_pos[count*2+1] = sv.end; - } - if (npos > 1) out_pos[1] = sv.off; - return count; + struct s_svstate sv; + int count; + + // initialize + if( out_pos == NULL ) npos = 0; + for( count = 0; count < npos; ++count ) + out_pos[count] = -1; + sv.str = str; + sv.len = len; + sv.off = startoff; + sv.opt = opt; + sv.delim = delim; + sv.done = false; + + // parse + count = 0; + if( npos > 0 ) out_pos[0] = startoff; + while( !sv.done ) + { + ++count; + if( sv_parse_next(&sv) <= 0 ) + return -1;// error + if( npos > count*2 ) out_pos[count*2] = sv.start; + if( npos > count*2+1 ) out_pos[count*2+1] = sv.end; + } + if( npos > 1 ) out_pos[1] = sv.off; + return count; } /// Splits a delim-separated string. @@ -628,11 +655,11 @@ int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, i /// out_fields[0] is the start of the next line. /// Other entries are the start of fields (nul-teminated). /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_fields can be NULL. /// Fields that don't fit in out_fields are not nul-terminated. /// Extra entries in out_fields are filled with the end of the last field (empty string). -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -641,64 +668,75 @@ int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, i /// @param nfields Size of the field array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_split(char *str, int len, int startoff, char delim, char **out_fields, int nfields, enum e_svopt opt) +int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt) { - int pos[1024]; - int i; - int done; - char *end; - int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); - - if (ret == -1 || out_fields == NULL || nfields <= 0) - return ret; // nothing to do - - // next line - end = str + pos[1]; - if (end[0] == '\0') { - *out_fields = end; - } else if ((opt&SV_TERMINATE_LF) && end[0] == '\n') { - if (!(opt&SV_KEEP_TERMINATOR)) - end[0] = '\0'; - *out_fields = end + 1; - } else if ((opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n') { - if (!(opt&SV_KEEP_TERMINATOR)) - end[0] = end[1] = '\0'; - *out_fields = end + 2; - } else if ((opt&SV_TERMINATE_CR) && end[0] == '\r') { - if (!(opt&SV_KEEP_TERMINATOR)) - end[0] = '\0'; - *out_fields = end + 1; - } else { - ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); - return -1;// error - } - ++out_fields; - --nfields; - - // fields - i = 2; - done = 0; - while (done < ret && nfields > 0) { - if (i < ARRAYLENGTH(pos)) { - // split field - *out_fields = str + pos[i]; - end = str + pos[i+1]; - *end = '\0'; - // next field - i += 2; - ++done; - ++out_fields; - --nfields; - } else { - // get more fields - sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); - i = 2; - } - } - // remaining fields - for (i = 0; i < nfields; ++i) - out_fields[i] = end; - return ret; + int pos[1024]; + int i; + int done; + char* end; + int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); + + if( ret == -1 || out_fields == NULL || nfields <= 0 ) + return ret; // nothing to do + + // next line + end = str + pos[1]; + if( end[0] == '\0' ) + { + *out_fields = end; + } + else if( (opt&SV_TERMINATE_LF) && end[0] == '\n' ) + { + if( !(opt&SV_KEEP_TERMINATOR) ) + end[0] = '\0'; + *out_fields = end + 1; + } + else if( (opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n' ) + { + if( !(opt&SV_KEEP_TERMINATOR) ) + end[0] = end[1] = '\0'; + *out_fields = end + 2; + } + else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' ) + { + if( !(opt&SV_KEEP_TERMINATOR) ) + end[0] = '\0'; + *out_fields = end + 1; + } + else + { + ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); + return -1;// error + } + ++out_fields; + --nfields; + + // fields + i = 2; + done = 0; + while( done < ret && nfields > 0 ) + { + if( i < ARRAYLENGTH(pos) ) + {// split field + *out_fields = str + pos[i]; + end = str + pos[i+1]; + *end = '\0'; + // next field + i += 2; + ++done; + ++out_fields; + --nfields; + } + else + {// get more fields + sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); + i = 2; + } + } + // remaining fields + for( i = 0; i < nfields; ++i ) + out_fields[i] = end; + return ret; } /// Escapes src to out_dest according to the format of the C compiler. @@ -710,77 +748,69 @@ int sv_split(char *str, int len, int startoff, char delim, char **out_fields, in /// @param len Length of the source string /// @param escapes Extra characters to be escaped /// @return Length of the escaped string -size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *escapes) +size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes) { - size_t i; - size_t j; - - if (out_dest == NULL) - return 0;// nothing to do - if (src == NULL) { - // nothing to escape - *out_dest = 0; - return 0; - } - if (escapes == NULL) - escapes = ""; - - for (i = 0, j = 0; i < len; ++i) { - switch (src[i]) { - case '\0':// octal 0 - out_dest[j++] = '\\'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - break; - case '\r':// carriage return - out_dest[j++] = '\\'; - out_dest[j++] = 'r'; - break; - case '\n':// line feed - out_dest[j++] = '\\'; - out_dest[j++] = 'n'; - break; - case '\\':// escape character - out_dest[j++] = '\\'; - out_dest[j++] = '\\'; - break; - default: - if (strchr(escapes,src[i])) { - // escape - out_dest[j++] = '\\'; - switch (src[i]) { - case '\a': - out_dest[j++] = 'a'; - break; - case '\b': - out_dest[j++] = 'b'; - break; - case '\t': - out_dest[j++] = 't'; - break; - case '\v': - out_dest[j++] = 'v'; - break; - case '\f': - out_dest[j++] = 'f'; - break; - case '\?': - out_dest[j++] = '?'; - break; - default:// to octal - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007))); - break; - } - } else - out_dest[j++] = src[i]; - break; - } - } - out_dest[j] = 0; - return j; + size_t i; + size_t j; + + if( out_dest == NULL ) + return 0;// nothing to do + if( src == NULL ) + {// nothing to escape + *out_dest = 0; + return 0; + } + if( escapes == NULL ) + escapes = ""; + + for( i = 0, j = 0; i < len; ++i ) + { + switch( src[i] ) + { + case '\0':// octal 0 + out_dest[j++] = '\\'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + break; + case '\r':// carriage return + out_dest[j++] = '\\'; + out_dest[j++] = 'r'; + break; + case '\n':// line feed + out_dest[j++] = '\\'; + out_dest[j++] = 'n'; + break; + case '\\':// escape character + out_dest[j++] = '\\'; + out_dest[j++] = '\\'; + break; + default: + if( strchr(escapes,src[i]) ) + {// escape + out_dest[j++] = '\\'; + switch( src[i] ) + { + case '\a': out_dest[j++] = 'a'; break; + case '\b': out_dest[j++] = 'b'; break; + case '\t': out_dest[j++] = 't'; break; + case '\v': out_dest[j++] = 'v'; break; + case '\f': out_dest[j++] = 'f'; break; + case '\?': out_dest[j++] = '?'; break; + default:// to octal + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007) )); + break; + } + } + else + out_dest[j++] = src[i]; + break; + } + } + out_dest[j] = 0; + return j; } /// Unescapes src to out_dest according to the format of the C compiler. @@ -791,135 +821,129 @@ size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *esca /// @param src Source string /// @param len Length of the source string /// @return Length of the escaped string -size_t sv_unescape_c(char *out_dest, const char *src, size_t len) +size_t sv_unescape_c(char* out_dest, const char* src, size_t len) { - static unsigned char low2hex[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? - }; - size_t i; - size_t j; - - for (i = 0, j = 0; i < len;) { - if (src[i] == '\\') { - ++i;// '\\' - if (i >= len) - ShowWarning("sv_unescape_c: empty escape sequence\n"); - else if (src[i] == 'x') { - // hex escape sequence - unsigned char c = 0; - unsigned char inrange = 1; - - ++i;// 'x' - if (i >= len || !ISXDIGIT(src[i])) { - ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); - continue; - } - do { - if (c > 0x0F && inrange) { - ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); - inrange = 0; - } - c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit - ++i; - } while (i < len && ISXDIGIT(src[i])); - out_dest[j++] = (char)c; - } else if (src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3') { - // octal escape sequence (255=0377) - unsigned char c = src[i]-'0'; - ++i;// '0', '1', '2' or '3' - if (i < len && src[i] >= '0' && src[i] <= '7') { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - if (i < len && src[i] >= '0' && src[i] <= '7') { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - out_dest[j++] = (char)c; - } else { - // other escape sequence - if (strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL) - ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); - switch (src[i]) { - case 'a': - out_dest[j++] = '\a'; - break; - case 'b': - out_dest[j++] = '\b'; - break; - case 't': - out_dest[j++] = '\t'; - break; - case 'n': - out_dest[j++] = '\n'; - break; - case 'v': - out_dest[j++] = '\v'; - break; - case 'f': - out_dest[j++] = '\f'; - break; - case 'r': - out_dest[j++] = '\r'; - break; - case '?': - out_dest[j++] = '\?'; - break; - default: - out_dest[j++] = src[i]; - break; - } - ++i;// escaped character - } - } else - out_dest[j++] = src[i++];// normal character - } - out_dest[j] = 0; - return j; + static unsigned char low2hex[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? + }; + size_t i; + size_t j; + + for( i = 0, j = 0; i < len; ) + { + if( src[i] == '\\' ) + { + ++i;// '\\' + if( i >= len ) + ShowWarning("sv_unescape_c: empty escape sequence\n"); + else if( src[i] == 'x' ) + {// hex escape sequence + unsigned char c = 0; + unsigned char inrange = 1; + + ++i;// 'x' + if( i >= len || !ISXDIGIT(src[i]) ) + { + ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); + continue; + } + do{ + if( c > 0x0F && inrange ) + { + ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); + inrange = 0; + } + c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit + ++i; + }while( i < len && ISXDIGIT(src[i]) ); + out_dest[j++] = (char)c; + } + else if( src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3' ) + {// octal escape sequence (255=0377) + unsigned char c = src[i]-'0'; + ++i;// '0', '1', '2' or '3' + if( i < len && src[i] >= '0' && src[i] <= '7' ) + { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + if( i < len && src[i] >= '0' && src[i] <= '7' ) + { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + out_dest[j++] = (char)c; + } + else + {// other escape sequence + if( strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL ) + ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); + switch( src[i] ) + { + case 'a': out_dest[j++] = '\a'; break; + case 'b': out_dest[j++] = '\b'; break; + case 't': out_dest[j++] = '\t'; break; + case 'n': out_dest[j++] = '\n'; break; + case 'v': out_dest[j++] = '\v'; break; + case 'f': out_dest[j++] = '\f'; break; + case 'r': out_dest[j++] = '\r'; break; + case '?': out_dest[j++] = '\?'; break; + default: out_dest[j++] = src[i]; break; + } + ++i;// escaped character + } + } + else + out_dest[j++] = src[i++];// normal character + } + out_dest[j] = 0; + return j; } /// Skips a C escape sequence (starting with '\\'). -const char *skip_escaped_c(const char *p) +const char* skip_escaped_c(const char* p) { - if (p && *p == '\\') { - ++p; - switch (*p) { - case 'x':// hexadecimal - ++p; - while (ISXDIGIT(*p)) - ++p; - break; - case '0': - case '1': - case '2': - case '3':// octal - ++p; - if (*p >= '0' && *p <= '7') - ++p; - if (*p >= '0' && *p <= '7') - ++p; - break; - default: - if (*p && strchr(SV_ESCAPE_C_SUPPORTED, *p)) - ++p; - } - } - return p; + if( p && *p == '\\' ) + { + ++p; + switch( *p ) + { + case 'x':// hexadecimal + ++p; + while( ISXDIGIT(*p) ) + ++p; + break; + case '0': + case '1': + case '2': + case '3':// octal + ++p; + if( *p >= '0' && *p <= '7' ) + ++p; + if( *p >= '0' && *p <= '7' ) + ++p; + break; + default: + if( *p && strchr(SV_ESCAPE_C_SUPPORTED, *p) ) + ++p; + } + } + return p; } @@ -934,72 +958,78 @@ const char *skip_escaped_c(const char *p) /// @param maxcols Maximum number of columns of a valid row /// @param parseproc User-supplied row processing function /// @return true on success, false if file could not be opened -bool sv_readdb(const char *directory, const char *filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char *fields[], int columns, int current)) +bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)) { - FILE *fp; - int lines = 0; - int entries = 0; - char **fields; // buffer for fields ([0] is reserved) - int columns, fields_length; - char path[1024], line[1024]; - char *match; - - snprintf(path, sizeof(path), "%s/%s", directory, filename); - - // open file - fp = fopen(path, "r"); - if (fp == NULL) { - ShowError("sv_readdb: can't read %s\n", path); - return false; - } - - // allocate enough memory for the maximum requested amount of columns plus the reserved one - fields_length = maxcols+1; - fields = (char **)aMalloc(fields_length*sizeof(char *)); - - // process rows one by one - while (fgets(line, sizeof(line), fp)) { - lines++; - - if ((match = strstr(line, "//")) != NULL) { - // strip comments - match[0] = 0; - } - - //TODO: strip trailing whitespace - if (line[0] == '\0' || line[0] == '\n' || line[0] == '\r') - continue; - - columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); - - if (columns < mincols) { - ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols); - continue; // not enough columns - } - if (columns > maxcols) { - ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols); - continue; // too many columns - } - if (entries == maxrows) { - ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path); - break; - } - - // parse this row - if (!parseproc(fields+1, columns, entries)) { - ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path); - continue; // invalid row contents - } - - // success! - entries++; - } - - aFree(fields); - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); - - return true; + FILE* fp; + int lines = 0; + int entries = 0; + char** fields; // buffer for fields ([0] is reserved) + int columns, fields_length; + char path[1024], line[1024]; + char* match; + + snprintf(path, sizeof(path), "%s/%s", directory, filename); + + // open file + fp = fopen(path, "r"); + if( fp == NULL ) + { + ShowError("sv_readdb: can't read %s\n", path); + return false; + } + + // allocate enough memory for the maximum requested amount of columns plus the reserved one + fields_length = maxcols+1; + fields = (char**)aMalloc(fields_length*sizeof(char*)); + + // process rows one by one + while( fgets(line, sizeof(line), fp) ) + { + lines++; + + if( ( match = strstr(line, "//") ) != NULL ) + {// strip comments + match[0] = 0; + } + + //TODO: strip trailing whitespace + if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r') + continue; + + columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); + + if( columns < mincols ) + { + ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols); + continue; // not enough columns + } + if( columns > maxcols ) + { + ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols ); + continue; // too many columns + } + if( entries == maxrows ) + { + ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path); + break; + } + + // parse this row + if( !parseproc(fields+1, columns, entries) ) + { + ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path); + continue; // invalid row contents + } + + // success! + entries++; + } + + aFree(fields); + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); + + return true; } @@ -1009,126 +1039,129 @@ bool sv_readdb(const char *directory, const char *filename, char delim, int minc // @author MouseJstr (original) /// Allocates a StringBuf -StringBuf *StringBuf_Malloc() +StringBuf* StringBuf_Malloc() { - StringBuf *self; - CREATE(self, StringBuf, 1); - StringBuf_Init(self); - return self; + StringBuf* self; + CREATE(self, StringBuf, 1); + StringBuf_Init(self); + return self; } /// Initializes a previously allocated StringBuf -void StringBuf_Init(StringBuf *self) +void StringBuf_Init(StringBuf* self) { - self->max_ = 1024; - self->ptr_ = self->buf_ = (char *)aMalloc(self->max_ + 1); + self->max_ = 1024; + self->ptr_ = self->buf_ = (char*)aMalloc(self->max_ + 1); } /// Appends the result of printf to the StringBuf -int StringBuf_Printf(StringBuf *self, const char *fmt, ...) +int StringBuf_Printf(StringBuf* self, const char* fmt, ...) { - int len; - va_list ap; + int len; + va_list ap; - va_start(ap, fmt); - len = StringBuf_Vprintf(self, fmt, ap); - va_end(ap); + va_start(ap, fmt); + len = StringBuf_Vprintf(self, fmt, ap); + va_end(ap); - return len; + return len; } /// Appends the result of vprintf to the StringBuf -int StringBuf_Vprintf(StringBuf *self, const char *fmt, va_list ap) +int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) { - int n, size, off; - - for (;;) { - va_list apcopy; - /* Try to print in the allocated space. */ - size = self->max_ - (self->ptr_ - self->buf_); - va_copy(apcopy, ap); - n = vsnprintf(self->ptr_, size, fmt, apcopy); - va_end(apcopy); - /* If that worked, return the length. */ - if (n > -1 && n < size) { - self->ptr_ += n; - return (int)(self->ptr_ - self->buf_); - } - /* Else try again with more space. */ - self->max_ *= 2; // twice the old size - off = (int)(self->ptr_ - self->buf_); - self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } + int n, size, off; + + for(;;) + { + va_list apcopy; + /* Try to print in the allocated space. */ + size = self->max_ - (self->ptr_ - self->buf_); + va_copy(apcopy, ap); + n = vsnprintf(self->ptr_, size, fmt, apcopy); + va_end(apcopy); + /* If that worked, return the length. */ + if( n > -1 && n < size ) + { + self->ptr_ += n; + return (int)(self->ptr_ - self->buf_); + } + /* Else try again with more space. */ + self->max_ *= 2; // twice the old size + off = (int)(self->ptr_ - self->buf_); + self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } } /// Appends the contents of another StringBuf to the StringBuf -int StringBuf_Append(StringBuf *self, const StringBuf *sbuf) +int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)(sbuf->ptr_ - sbuf->buf_); - - if (needed >= available) { - int off = (int)(self->ptr_ - self->buf_); - self->max_ += needed; - self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, sbuf->buf_, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)(sbuf->ptr_ - sbuf->buf_); + + if( needed >= available ) + { + int off = (int)(self->ptr_ - self->buf_); + self->max_ += needed; + self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, sbuf->buf_, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Appends str to the StringBuf -int StringBuf_AppendStr(StringBuf *self, const char *str) +int StringBuf_AppendStr(StringBuf* self, const char* str) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)strlen(str); - - if (needed >= available) { - // not enough space, expand the buffer (minimum expansion = 1024) - int off = (int)(self->ptr_ - self->buf_); - self->max_ += max(needed, 1024); - self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, str, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)strlen(str); + + if( needed >= available ) + {// not enough space, expand the buffer (minimum expansion = 1024) + int off = (int)(self->ptr_ - self->buf_); + self->max_ += max(needed, 1024); + self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, str, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Returns the length of the data in the Stringbuf -int StringBuf_Length(StringBuf *self) +int StringBuf_Length(StringBuf* self) { - return (int)(self->ptr_ - self->buf_); + return (int)(self->ptr_ - self->buf_); } /// Returns the data in the StringBuf -char *StringBuf_Value(StringBuf *self) +char* StringBuf_Value(StringBuf* self) { - *self->ptr_ = '\0'; - return self->buf_; + *self->ptr_ = '\0'; + return self->buf_; } /// Clears the contents of the StringBuf -void StringBuf_Clear(StringBuf *self) +void StringBuf_Clear(StringBuf* self) { - self->ptr_ = self->buf_; + self->ptr_ = self->buf_; } /// Destroys the StringBuf -void StringBuf_Destroy(StringBuf *self) +void StringBuf_Destroy(StringBuf* self) { - aFree(self->buf_); - self->ptr_ = self->buf_ = 0; - self->max_ = 0; + aFree(self->buf_); + self->ptr_ = self->buf_ = 0; + self->max_ = 0; } // Frees a StringBuf returned by StringBuf_Malloc -void StringBuf_Free(StringBuf *self) +void StringBuf_Free(StringBuf* self) { - StringBuf_Destroy(self); - aFree(self); + StringBuf_Destroy(self); + aFree(self); } diff --git a/src/common/strlib.h b/src/common/strlib.h index ae4f688c2..bbc2c6105 100644 --- a/src/common/strlib.h +++ b/src/common/strlib.h @@ -11,65 +11,66 @@ #include #undef __USE_GNU -char *jstrescape(char *pt); -char *jstrescapecpy(char *pt, const char *spt); -int jmemescapecpy(char *pt, const char *spt, int size); +char* jstrescape (char* pt); +char* jstrescapecpy (char* pt, const char* spt); +int jmemescapecpy (char* pt, const char* spt, int size); -int remove_control_chars(char *str); -char *trim(char *str); -char *normalize_name(char *str,const char *delims); +int remove_control_chars(char* str); +char* trim(char* str); +char* normalize_name(char* str,const char* delims); const char *stristr(const char *haystack, const char *needle); #ifdef WIN32 #define HAVE_STRTOK_R #define strtok_r(s,delim,save_ptr) _strtok_r((s),(delim),(save_ptr)) -char *_strtok_r(char *s1, const char *s2, char **lasts); +char* _strtok_r(char* s1, const char* s2, char** lasts); #endif #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) -size_t strnlen(const char *string, size_t maxlen); +size_t strnlen (const char* string, size_t maxlen); #endif #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char *str, char **endptr, int base); +uint64 strtoull(const char* str, char** endptr, int base); #endif -int e_mail_check(char *email); -int config_switch(const char *str); +int e_mail_check(char* email); +int config_switch(const char* str); /// strncpy that always nul-terminates the string -char *safestrncpy(char *dst, const char *src, size_t n); +char* safestrncpy(char* dst, const char* src, size_t n); /// doesn't crash on null pointer -size_t safestrnlen(const char *string, size_t maxlen); +size_t safestrnlen(const char* string, size_t maxlen); /// Works like snprintf, but always nul-terminates the buffer. /// Returns the size of the string (without nul-terminator) /// or -1 if the buffer is too small. -int safesnprintf(char *buf, size_t sz, const char *fmt, ...); +int safesnprintf(char* buf, size_t sz, const char* fmt, ...); /// Returns the line of the target position in the string. /// Lines start at 1. -int strline(const char *str, size_t pos); +int strline(const char* str, size_t pos); /// Produces the hexadecimal representation of the given input. /// The output buffer must be at least count*2+1 in size. /// Returns true on success, false on failure. -bool bin2hex(char *output, unsigned char *input, size_t count); +bool bin2hex(char* output, unsigned char* input, size_t count); /// Bitfield determining the behaviour of sv_parse and sv_split. -typedef enum e_svopt { - // default: no escapes and no line terminator - SV_NOESCAPE_NOTERMINATE = 0, - // Escapes according to the C compiler. - SV_ESCAPE_C = 1, - // Line terminators - SV_TERMINATE_LF = 2, - SV_TERMINATE_CRLF = 4, - SV_TERMINATE_CR = 8, - // If sv_split keeps the end of line terminator, instead of replacing with '\0' - SV_KEEP_TERMINATOR = 16 +typedef enum e_svopt +{ + // default: no escapes and no line terminator + SV_NOESCAPE_NOTERMINATE = 0, + // Escapes according to the C compiler. + SV_ESCAPE_C = 1, + // Line terminators + SV_TERMINATE_LF = 2, + SV_TERMINATE_CRLF = 4, + SV_TERMINATE_CR = 8, + // If sv_split keeps the end of line terminator, instead of replacing with '\0' + SV_KEEP_TERMINATOR = 16 } e_svopt; /// Other escape sequences supported by the C compiler. @@ -77,15 +78,16 @@ typedef enum e_svopt { /// Parse state. /// The field is [start,end[ -struct s_svstate { - const char *str; //< string to parse - int len; //< string length - int off; //< current offset in the string - int start; //< where the field starts - int end; //< where the field ends - enum e_svopt opt; //< parse options - char delim; //< field delimiter - bool done; //< if all the text has been parsed +struct s_svstate +{ + const char* str; //< string to parse + int len; //< string length + int off; //< current offset in the string + int start; //< where the field starts + int end; //< where the field ends + enum e_svopt opt; //< parse options + char delim; //< field delimiter + bool done; //< if all the text has been parsed }; /// Parses a single field in a delim-separated string. @@ -93,14 +95,14 @@ struct s_svstate { /// /// @param sv Parse state /// @return 1 if a field was parsed, 0 if done, -1 on error. -int sv_parse_next(struct s_svstate *sv); +int sv_parse_next(struct s_svstate* sv); /// Parses a delim-separated string. /// Starts parsing at startoff and fills the pos array with position pairs. /// out_pos[0] and out_pos[1] are the start and end of line. /// Other position pairs are the start and end of fields. /// Returns the number of fields found or -1 if an error occurs. -int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, int npos, enum e_svopt opt); +int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt); /// Splits a delim-separated string. /// WARNING: this function modifies the input string @@ -108,45 +110,46 @@ int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, i /// out_fields[0] is the start of the next line. /// Other entries are the start of fields (nul-teminated). /// Returns the number of fields found or -1 if an error occurs. -int sv_split(char *str, int len, int startoff, char delim, char **out_fields, int nfields, enum e_svopt opt); +int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt); /// Escapes src to out_dest according to the format of the C compiler. /// Returns the length of the escaped string. /// out_dest should be len*4+1 in size. -size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *escapes); +size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes); /// Unescapes src to out_dest according to the format of the C compiler. /// Returns the length of the unescaped string. /// out_dest should be len+1 in size and can be the same buffer as src. -size_t sv_unescape_c(char *out_dest, const char *src, size_t len); +size_t sv_unescape_c(char* out_dest, const char* src, size_t len); /// Skips a C escape sequence (starting with '\\'). -const char *skip_escaped_c(const char *p); +const char* skip_escaped_c(const char* p); /// Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row. /// Tracks the progress of the operation (current line number, number of successfully processed rows). /// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read. -bool sv_readdb(const char *directory, const char *filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char *fields[], int columns, int current)); +bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current)); /// StringBuf - dynamic string -struct StringBuf { - char *buf_; - char *ptr_; - unsigned int max_; +struct StringBuf +{ + char *buf_; + char *ptr_; + unsigned int max_; }; typedef struct StringBuf StringBuf; -StringBuf *StringBuf_Malloc(void); -void StringBuf_Init(StringBuf *self); -int StringBuf_Printf(StringBuf *self, const char *fmt, ...); -int StringBuf_Vprintf(StringBuf *self, const char *fmt, va_list args); -int StringBuf_Append(StringBuf *self, const StringBuf *sbuf); -int StringBuf_AppendStr(StringBuf *self, const char *str); -int StringBuf_Length(StringBuf *self); -char *StringBuf_Value(StringBuf *self); -void StringBuf_Clear(StringBuf *self); -void StringBuf_Destroy(StringBuf *self); -void StringBuf_Free(StringBuf *self); +StringBuf* StringBuf_Malloc(void); +void StringBuf_Init(StringBuf* self); +int StringBuf_Printf(StringBuf* self, const char* fmt, ...); +int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list args); +int StringBuf_Append(StringBuf* self, const StringBuf *sbuf); +int StringBuf_AppendStr(StringBuf* self, const char* str); +int StringBuf_Length(StringBuf* self); +char* StringBuf_Value(StringBuf* self); +void StringBuf_Clear(StringBuf* self); +void StringBuf_Destroy(StringBuf* self); +void StringBuf_Free(StringBuf* self); #endif /* _STRLIB_H_ */ diff --git a/src/common/thread.c b/src/common/thread.c index 610ee394c..315b310b2 100644 --- a/src/common/thread.c +++ b/src/common/thread.c @@ -9,7 +9,7 @@ #ifdef WIN32 #include "../common/winapi.h" #define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.) -#define __thread __declspec( thread ) +#define __thread __declspec( thread ) #else #include #include @@ -25,25 +25,25 @@ #include "thread.h" // When Compiling using MSC (on win32..) we know we have support in any case! -#ifdef _MSC_VER -#define HAS_TLS +#ifdef _MSC_VER +#define HAS_TLS #endif #define RA_THREADS_MAX 64 struct rAthread { - unsigned int myID; - - RATHREAD_PRIO prio; - rAthreadProc proc; - void *param; - -#ifdef WIN32 - HANDLE hThread; -#else - pthread_t hThread; -#endif + unsigned int myID; + + RATHREAD_PRIO prio; + rAthreadProc proc; + void *param; + + #ifdef WIN32 + HANDLE hThread; + #else + pthread_t hThread; + #endif }; @@ -57,100 +57,95 @@ __thread int g_rathread_ID = -1; /// static struct rAthread l_threads[RA_THREADS_MAX]; -void rathread_init() -{ - register unsigned int i; - memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread)); - - for (i = 0; i < RA_THREADS_MAX; i++) { - l_threads[i].myID = i; - } +void rathread_init(){ + register unsigned int i; + memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) ); + + for(i = 0; i < RA_THREADS_MAX; i++){ + l_threads[i].myID = i; + } - // now lets init thread id 0, which represnts the main thread + // now lets init thread id 0, which represnts the main thread #ifdef HAS_TLS - g_rathread_ID = 0; + g_rathread_ID = 0; #endif - l_threads[0].prio = RAT_PRIO_NORMAL; - l_threads[0].proc = (rAthreadProc)0xDEADCAFE; + l_threads[0].prio = RAT_PRIO_NORMAL; + l_threads[0].proc = (rAthreadProc)0xDEADCAFE; }//end: rathread_init() -void rathread_final() -{ - register unsigned int i; - - // Unterminated Threads Left? - // Should'nt happen .. - // Kill 'em all! - // - for (i = 1; i < RA_THREADS_MAX; i++) { - if (l_threads[i].proc != NULL) { - ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); - rathread_destroy(&l_threads[i]); - } - } - - +void rathread_final(){ + register unsigned int i; + + // Unterminated Threads Left? + // Should'nt happen .. + // Kill 'em all! + // + for(i = 1; i < RA_THREADS_MAX; i++){ + if(l_threads[i].proc != NULL){ + ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); + rathread_destroy(&l_threads[i]); + } + } + + }//end: rathread_final() // gets called whenever a thread terminated .. -static void rat_thread_terminated(rAthread handle) -{ +static void rat_thread_terminated( rAthread handle ){ - int id_backup = handle->myID; + int id_backup = handle->myID; - // Simply set all members to 0 (except the id) - memset(handle, 0x00, sizeof(struct rAthread)); - - handle->myID = id_backup; // done ;) + // Simply set all members to 0 (except the id) + memset(handle, 0x00, sizeof(struct rAthread)); + + handle->myID = id_backup; // done ;) }//end: rat_thread_terminated() #ifdef WIN32 -DWORD WINAPI _raThreadMainRedirector(LPVOID p) -{ +DWORD WINAPI _raThreadMainRedirector(LPVOID p){ #else -static void *_raThreadMainRedirector(void *p) -{ - sigset_t set; // on Posix Thread platforms +static void *_raThreadMainRedirector( void *p ){ + sigset_t set; // on Posix Thread platforms #endif - void *ret; - - // Update myID @ TLS to right id. + void *ret; + + // Update myID @ TLS to right id. #ifdef HAS_TLS - g_rathread_ID = ((rAthread)p)->myID; + g_rathread_ID = ((rAthread)p)->myID; #endif #ifndef WIN32 - // When using posix threads - // the threads inherits the Signal mask from the thread which's spawned - // this thread - // so we've to block everything we dont care about. - sigemptyset(&set); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGTERM); - sigaddset(&set, SIGPIPE); - - pthread_sigmask(SIG_BLOCK, &set, NULL); - + // When using posix threads + // the threads inherits the Signal mask from the thread which's spawned + // this thread + // so we've to block everything we dont care about. + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGPIPE); + + pthread_sigmask(SIG_BLOCK, &set, NULL); + #endif - ret = ((rAthread)p)->proc(((rAthread)p)->param) ; + ret = ((rAthread)p)->proc( ((rAthread)p)->param ) ; -#ifdef WIN32 - CloseHandle(((rAthread)p)->hThread); +#ifdef WIN32 + CloseHandle( ((rAthread)p)->hThread ); #endif - rat_thread_terminated((rAthread)p); + rat_thread_terminated( (rAthread)p ); #ifdef WIN32 - return (DWORD)ret; + return (DWORD)ret; #else - return ret; + return ret; #endif }//end: _raThreadMainRedirector() @@ -160,172 +155,163 @@ static void *_raThreadMainRedirector(void *p) /// /// API Level -/// -rAthread rathread_create(rAthreadProc entryPoint, void *param) -{ - return rathread_createEx(entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL); +/// +rAthread rathread_create( rAthreadProc entryPoint, void *param ){ + return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL ); }//end: rathread_create() -rAthread rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio) -{ +rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ){ #ifndef WIN32 - pthread_attr_t attr; + pthread_attr_t attr; #endif - size_t tmp; - unsigned int i; - rAthread handle = NULL; - - - // given stacksize aligned to systems pagesize? - tmp = szStack % getpagesize(); - if (tmp != 0) - szStack += tmp; - - - // Get a free Thread Slot. - for (i = 0; i < RA_THREADS_MAX; i++) { - if (l_threads[i].proc == NULL) { - handle = &l_threads[i]; - break; - } - } - - if (handle == NULL) { - ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); - return NULL; - } - - - - handle->proc = entryPoint; - handle->param = param; + size_t tmp; + unsigned int i; + rAthread handle = NULL; + + + // given stacksize aligned to systems pagesize? + tmp = szStack % getpagesize(); + if(tmp != 0) + szStack += tmp; + + + // Get a free Thread Slot. + for(i = 0; i < RA_THREADS_MAX; i++){ + if(l_threads[i].proc == NULL){ + handle = &l_threads[i]; + break; + } + } + + if(handle == NULL){ + ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); + return NULL; + } + + + + handle->proc = entryPoint; + handle->param = param; #ifdef WIN32 - handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void *)handle, 0, NULL); + handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void*)handle, 0, NULL); #else - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, szStack); - - if (pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void *)handle) != 0) { - handle->proc = NULL; - handle->param = NULL; - return NULL; - } - pthread_attr_destroy(&attr); + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, szStack); + + if(pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void*)handle) != 0){ + handle->proc = NULL; + handle->param = NULL; + return NULL; + } + pthread_attr_destroy(&attr); #endif - rathread_prio_set(handle, prio); - - return handle; + rathread_prio_set( handle, prio ); + + return handle; }//end: rathread_createEx -void rathread_destroy(rAthread handle) -{ +void rathread_destroy ( rAthread handle ){ #ifdef WIN32 - if (TerminateThread(handle->hThread, 0) != FALSE) { - CloseHandle(handle->hThread); - rat_thread_terminated(handle); - } + if( TerminateThread(handle->hThread, 0) != FALSE){ + CloseHandle(handle->hThread); + rat_thread_terminated(handle); + } #else - if (pthread_cancel(handle->hThread) == 0) { - - // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. - // - pthread_join(handle->hThread, NULL); - - // Tell our manager to release ressources ;) - rat_thread_terminated(handle); - } + if( pthread_cancel( handle->hThread ) == 0){ + + // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. + // + pthread_join( handle->hThread, NULL ); + + // Tell our manager to release ressources ;) + rat_thread_terminated(handle); + } #endif }//end: rathread_destroy() -rAthread rathread_self() -{ +rAthread rathread_self( ){ #ifdef HAS_TLS - rAthread handle = &l_threads[g_rathread_ID]; - - if (handle->proc != NULL) // entry point set, so its used! - return handle; + rAthread handle = &l_threads[g_rathread_ID]; + + if(handle->proc != NULL) // entry point set, so its used! + return handle; #else - // .. so no tls means we have to search the thread by its api-handle .. - int i; - -#ifdef WIN32 - HANDLE hSelf; - hSelf = GetCurrent = GetCurrentThread(); -#else - pthread_t hSelf; - hSelf = pthread_self(); -#endif - - for (i = 0; i < RA_THREADS_MAX; i++) { - if (l_threads[i].hThread == hSelf && l_threads[i].proc != NULL) - return &l_threads[i]; - } - + // .. so no tls means we have to search the thread by its api-handle .. + int i; + + #ifdef WIN32 + HANDLE hSelf; + hSelf = GetCurrent = GetCurrentThread(); + #else + pthread_t hSelf; + hSelf = pthread_self(); + #endif + + for(i = 0; i < RA_THREADS_MAX; i++){ + if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL) + return &l_threads[i]; + } + #endif - - return NULL; + + return NULL; }//end: rathread_self() -int rathread_get_tid() -{ +int rathread_get_tid(){ -#ifdef HAS_TLS - return g_rathread_ID; +#ifdef HAS_TLS + return g_rathread_ID; #else - // todo -#ifdef WIN32 - return (int)GetCurrentThreadId(); -#else - return (intptr_t)pthread_self(); -#endif - + // todo + #ifdef WIN32 + return (int)GetCurrentThreadId(); + #else + return (intptr_t)pthread_self(); + #endif + #endif - + }//end: rathread_get_tid() -bool rathread_wait(rAthread handle, void* *out_exitCode) -{ - - // Hint: - // no thread data cleanup routine call here! - // its managed by the callProxy itself.. - // +bool rathread_wait( rAthread handle, void* *out_exitCode ){ + + // Hint: + // no thread data cleanup routine call here! + // its managed by the callProxy itself.. + // #ifdef WIN32 - WaitForSingleObject(handle->hThread, INFINITE); - return true; + WaitForSingleObject(handle->hThread, INFINITE); + return true; #else - if (pthread_join(handle->hThread, out_exitCode) == 0) - return true; - return false; + if(pthread_join(handle->hThread, out_exitCode) == 0) + return true; + return false; #endif }//end: rathread_wait() -void rathread_prio_set(rAthread handle, RATHREAD_PRIO prio) -{ - handle->prio = RAT_PRIO_NORMAL; - //@TODO +void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ){ + handle->prio = RAT_PRIO_NORMAL; + //@TODO }//end: rathread_prio_set() -RATHREAD_PRIO rathread_prio_get(rAthread handle) -{ - return handle->prio; +RATHREAD_PRIO rathread_prio_get( rAthread handle){ + return handle->prio; }//end: rathread_prio_get() -void rathread_yield() -{ -#ifdef WIN32 - SwitchToThread(); +void rathread_yield(){ +#ifdef WIN32 + SwitchToThread(); #else - sched_yield(); -#endif + sched_yield(); +#endif }//end: rathread_yield() diff --git a/src/common/thread.h b/src/common/thread.h index cfbfe689f..a5a66e954 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -1,19 +1,19 @@ // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#pragma once +#pragma once #ifndef _rA_THREAD_H_ #define _rA_THREAD_H_ #include "../common/cbasetypes.h" typedef struct rAthread *rAthread; -typedef void *(*rAthreadProc)(void *); +typedef void* (*rAthreadProc)(void*); typedef enum RATHREAD_PRIO { - RAT_PRIO_LOW = 0, - RAT_PRIO_NORMAL, - RAT_PRIO_HIGH + RAT_PRIO_LOW = 0, + RAT_PRIO_NORMAL, + RAT_PRIO_HIGH } RATHREAD_PRIO; @@ -22,51 +22,51 @@ typedef enum RATHREAD_PRIO { * * @param entyPoint - entryProc, * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint. - * + * * @return not NULL if success */ -rAthread rathread_create(rAthreadProc entryPoint, void *param); +rAthread rathread_create( rAthreadProc entryPoint, void *param ); -/** +/** * Creates a new Thread (with more creation options) * * @param entyPoint - entryProc, * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint - * @param szStack - stack Size in bytes + * @param szStack - stack Size in bytes * @param prio - Priority of the Thread @ OS Scheduler.. * * @return not NULL if success */ -rAthread rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio); +rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ); /** * Destroys the given Thread immediatly * - * @note The Handle gets invalid after call! dont use it afterwards. + * @note The Handle gets invalid after call! dont use it afterwards. * * @param handle - thread to destroy. */ -void rathread_destroy(rAthread handle); +void rathread_destroy ( rAthread handle ); -/** +/** * Returns the thread handle of the thread calling this function - * + * * @note this wont work @ programms main thread - * @note the underlying implementation might not perform very well, cache the value received! - * + * @note the underlying implementation might not perform very well, cache the value received! + * * @return not NULL if success */ -rAthread rathread_self(); +rAthread rathread_self( ); /** - * Returns own thrad id (TID) + * Returns own thrad id (TID) * - * @note this is an unique identifier for the calling thread, and - * depends on platfrom / compiler, and may not be the systems Thread ID! + * @note this is an unique identifier for the calling thread, and + * depends on platfrom / compiler, and may not be the systems Thread ID! * * @return -1 when fails, otherwise >= 0 */ @@ -74,39 +74,39 @@ int rathread_get_tid(); /** - * Waits for the given thread to terminate + * Waits for the given thread to terminate * * @param handle - thread to wait (join) for * @param out_Exitcode - [OPTIONAL] - if given => Exitcode (value) of the given thread - if it's terminated - * + * * @return true - if the given thread has been terminated. */ -bool rathread_wait(rAthread handle, void* *out_exitCode); +bool rathread_wait( rAthread handle, void* *out_exitCode ); -/** +/** * Sets the given PRIORITY @ OS Task Scheduler - * + * * @param handle - thread to set prio for * @param rio - the priority (RAT_PRIO_LOW ... ) */ -void rathread_prio_set(rAthread handle, RATHREAD_PRIO prio); +void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ); -/** +/** * Gets the current Prio of the given trhead * * @param handle - the thread to get the prio for. */ -RATHREAD_PRIO rathread_prio_get(rAthread handle); +RATHREAD_PRIO rathread_prio_get( rAthread handle); /** * Tells the OS scheduler to yield the execution of the calling thread - * + * * @note: this will not "pause" the thread, - * it just allows the OS to spent the remaining time - * of the slice to another thread. + * it just allows the OS to spent the remaining time + * of the slice to another thread. */ void rathread_yield(); diff --git a/src/common/timer.c b/src/common/timer.c index bb2458233..c239a9d70 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -26,12 +26,12 @@ #define TIMER_MAX_INTERVAL 1000 // timers (array) -static struct TimerData *timer_data = NULL; +static struct TimerData* timer_data = NULL; static int timer_data_max = 0; static int timer_data_num = 0; // free timers (array) -static int *free_timer_list = NULL; +static int* free_timer_list = NULL; static int free_timer_list_max = 0; static int free_timer_list_pos = 0; @@ -53,87 +53,85 @@ time_t start_time; /*---------------------------- - * Timer debugging + * Timer debugging *----------------------------*/ struct timer_func_list { - struct timer_func_list *next; - TimerFunc func; - char *name; + struct timer_func_list* next; + TimerFunc func; + char* name; } *tfl_root = NULL; /// Sets the name of a timer function. -int add_timer_func_list(TimerFunc func, char *name) +int add_timer_func_list(TimerFunc func, char* name) { - struct timer_func_list *tfl; - - if (name) { - for (tfl=tfl_root; tfl != NULL; tfl=tfl->next) { - // check suspicious cases - if (func == tfl->func) - ShowWarning("add_timer_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); - else if (strcmp(name,tfl->name) == 0) - ShowWarning("add_timer_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); - } - CREATE(tfl,struct timer_func_list,1); - tfl->next = tfl_root; - tfl->func = func; - tfl->name = aStrdup(name); - tfl_root = tfl; - } - return 0; + struct timer_func_list* tfl; + + if (name) { + for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) + {// check suspicious cases + if( func == tfl->func ) + ShowWarning("add_timer_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); + else if( strcmp(name,tfl->name) == 0 ) + ShowWarning("add_timer_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); + } + CREATE(tfl,struct timer_func_list,1); + tfl->next = tfl_root; + tfl->func = func; + tfl->name = aStrdup(name); + tfl_root = tfl; + } + return 0; } /// Returns the name of the timer function. -char *search_timer_func_list(TimerFunc func) +char* search_timer_func_list(TimerFunc func) { - struct timer_func_list *tfl; + struct timer_func_list* tfl; - for (tfl=tfl_root; tfl != NULL; tfl=tfl->next) - if (func == tfl->func) - return tfl->name; + for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) + if (func == tfl->func) + return tfl->name; - return "unknown timer function"; + return "unknown timer function"; } /*---------------------------- - * Get tick time + * Get tick time *----------------------------*/ #if defined(ENABLE_RDTSC) static uint64 RDTSC_BEGINTICK = 0, RDTSC_CLOCK = 0; -static __inline uint64 _rdtsc() -{ - register union { - uint64 qw; - uint32 dw[2]; - } t; - - asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1])); +static __inline uint64 _rdtsc(){ + register union{ + uint64 qw; + uint32 dw[2]; + } t; - return t.qw; + asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1]) ); + + return t.qw; } -static void rdtsc_calibrate() -{ - uint64 t1, t2; - int32 i; - - ShowStatus("Calibrating Timer Source, please wait... "); - - RDTSC_CLOCK = 0; - - for (i = 0; i < 5; i++) { - t1 = _rdtsc(); - usleep(1000000); //1000 MS - t2 = _rdtsc(); - RDTSC_CLOCK += (t2 - t1) / 1000; - } - RDTSC_CLOCK /= 5; - - RDTSC_BEGINTICK = _rdtsc(); - - ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000)); +static void rdtsc_calibrate(){ + uint64 t1, t2; + int32 i; + + ShowStatus("Calibrating Timer Source, please wait... "); + + RDTSC_CLOCK = 0; + + for(i = 0; i < 5; i++){ + t1 = _rdtsc(); + usleep(1000000); //1000 MS + t2 = _rdtsc(); + RDTSC_CLOCK += (t2 - t1) / 1000; + } + RDTSC_CLOCK /= 5; + + RDTSC_BEGINTICK = _rdtsc(); + + ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000) ); } #endif @@ -142,19 +140,19 @@ static void rdtsc_calibrate() static unsigned int tick(void) { #if defined(WIN32) - return GetTickCount(); + return GetTickCount(); #elif defined(ENABLE_RDTSC) - // - return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK); - // + // + return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK); + // #elif defined(HAVE_MONOTONIC_CLOCK) - struct timespec tval; - clock_gettime(CLOCK_MONOTONIC, &tval); - return tval.tv_sec * 1000 + tval.tv_nsec / 1000000; + struct timespec tval; + clock_gettime(CLOCK_MONOTONIC, &tval); + return tval.tv_sec * 1000 + tval.tv_nsec / 1000000; #else - struct timeval tval; - gettimeofday(&tval, NULL); - return tval.tv_sec * 1000 + tval.tv_usec / 1000; + struct timeval tval; + gettimeofday(&tval, NULL); + return tval.tv_sec * 1000 + tval.tv_usec / 1000; #endif } @@ -167,14 +165,14 @@ static int gettick_count = 1; unsigned int gettick_nocache(void) { - gettick_count = TICK_CACHE; - gettick_cache = tick(); - return gettick_cache; + gettick_count = TICK_CACHE; + gettick_cache = tick(); + return gettick_cache; } unsigned int gettick(void) { - return (--gettick_count == 0) ? gettick_nocache() : gettick_cache; + return ( --gettick_count == 0 ) ? gettick_nocache() : gettick_cache; } ////////////////////////////// #else @@ -182,108 +180,110 @@ unsigned int gettick(void) // tick doesn't get cached unsigned int gettick_nocache(void) { - return tick(); + return tick(); } unsigned int gettick(void) { - return tick(); + return tick(); } ////////////////////////////////////////////////////////////////////////// #endif ////////////////////////////////////////////////////////////////////////// /*====================================== - * CORE : Timer Heap + * CORE : Timer Heap *--------------------------------------*/ /// Adds a timer to the timer_heap static void push_timer_heap(int tid) { - BHEAP_ENSURE(timer_heap, 1, 256); - BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); + BHEAP_ENSURE(timer_heap, 1, 256); + BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); } /*========================== - * Timer Management + * Timer Management *--------------------------*/ /// Returns a free timer id. static int acquire_timer(void) { - int tid; - - // select a free timer - if (free_timer_list_pos) { - do { - tid = free_timer_list[--free_timer_list_pos]; - } while (tid >= timer_data_num && free_timer_list_pos > 0); - } else - tid = timer_data_num; - - // check available space - if (tid >= timer_data_num) - for (tid = timer_data_num; tid < timer_data_max && timer_data[tid].type; tid++); - if (tid >= timer_data_num && tid >= timer_data_max) { - // expand timer array - timer_data_max += 256; - if (timer_data) - RECREATE(timer_data, struct TimerData, timer_data_max); - else - CREATE(timer_data, struct TimerData, timer_data_max); - memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData)*256); - } - - if (tid >= timer_data_num) - timer_data_num = tid + 1; - - return tid; + int tid; + + // select a free timer + if (free_timer_list_pos) { + do { + tid = free_timer_list[--free_timer_list_pos]; + } while(tid >= timer_data_num && free_timer_list_pos > 0); + } else + tid = timer_data_num; + + // check available space + if( tid >= timer_data_num ) + for (tid = timer_data_num; tid < timer_data_max && timer_data[tid].type; tid++); + if (tid >= timer_data_num && tid >= timer_data_max) + {// expand timer array + timer_data_max += 256; + if( timer_data ) + RECREATE(timer_data, struct TimerData, timer_data_max); + else + CREATE(timer_data, struct TimerData, timer_data_max); + memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData)*256); + } + + if( tid >= timer_data_num ) + timer_data_num = tid + 1; + + return tid; } /// Starts a new timer that is deleted once it expires (single-use). /// Returns the timer's id. int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data) { - int tid; - - tid = acquire_timer(); - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_ONCE_AUTODEL; - timer_data[tid].interval = 1000; - push_timer_heap(tid); - - return tid; + int tid; + + tid = acquire_timer(); + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_ONCE_AUTODEL; + timer_data[tid].interval = 1000; + push_timer_heap(tid); + + return tid; } /// Starts a new timer that automatically restarts itself (infinite loop until manually removed). /// Returns the timer's id, or INVALID_TIMER if it fails. int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval) { - int tid; - - if (interval < 1) { - ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); - return INVALID_TIMER; - } - - tid = acquire_timer(); - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_INTERVAL; - timer_data[tid].interval = interval; - push_timer_heap(tid); - - return tid; + int tid; + + if( interval < 1 ) + { + ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); + return INVALID_TIMER; + } + + tid = acquire_timer(); + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_INTERVAL; + timer_data[tid].interval = interval; + push_timer_heap(tid); + + return tid; } /// Retrieves internal timer data -const struct TimerData *get_timer(int tid) { - return (tid >= 0 && tid < timer_data_num) ? &timer_data[tid] : NULL; +const struct TimerData* get_timer(int tid) +{ + return ( tid >= 0 && tid < timer_data_num ) ? &timer_data[tid] : NULL; } /// Marks a timer specified by 'id' for immediate deletion once it expires. @@ -291,135 +291,142 @@ const struct TimerData *get_timer(int tid) { /// Returns 0 on success, < 0 on failure. int delete_timer(int tid, TimerFunc func) { - if (tid < 0 || tid >= timer_data_num) { - ShowError("delete_timer error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); - return -1; - } - if (timer_data[tid].func != func) { - ShowError("delete_timer error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); - return -2; - } - - timer_data[tid].func = NULL; - timer_data[tid].type = TIMER_ONCE_AUTODEL; - - return 0; + if( tid < 0 || tid >= timer_data_num ) + { + ShowError("delete_timer error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); + return -1; + } + if( timer_data[tid].func != func ) + { + ShowError("delete_timer error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); + return -2; + } + + timer_data[tid].func = NULL; + timer_data[tid].type = TIMER_ONCE_AUTODEL; + + return 0; } /// Adjusts a timer's expiration time. /// Returns the new tick value, or -1 if it fails. int addtick_timer(int tid, unsigned int tick) { - return settick_timer(tid, timer_data[tid].tick+tick); + return settick_timer(tid, timer_data[tid].tick+tick); } /// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). /// Returns the new tick value, or -1 if it fails. int settick_timer(int tid, unsigned int tick) { - size_t i; - - // search timer position - ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); - if (i == BHEAP_LENGTH(timer_heap)) { - ShowError("settick_timer: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); - return -1; - } - - if ((int)tick == -1) - tick = 0;// add 1ms to avoid the error value -1 - - if (timer_data[tid].tick == tick) - return (int)tick;// nothing to do, already in propper position - - // pop and push adjusted timer - BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP); - timer_data[tid].tick = tick; - BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); - return (int)tick; + size_t i; + + // search timer position + ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); + if( i == BHEAP_LENGTH(timer_heap) ) + { + ShowError("settick_timer: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + return -1; + } + + if( (int)tick == -1 ) + tick = 0;// add 1ms to avoid the error value -1 + + if( timer_data[tid].tick == tick ) + return (int)tick;// nothing to do, already in propper position + + // pop and push adjusted timer + BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP); + timer_data[tid].tick = tick; + BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); + return (int)tick; } /// Executes all expired timers. /// Returns the value of the smallest non-expired timer (or 1 second if there aren't any). int do_timer(unsigned int tick) { - int diff = TIMER_MAX_INTERVAL; // return value - - // process all timers one by one - while (BHEAP_LENGTH(timer_heap)) { - int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) - - diff = DIFF_TICK(timer_data[tid].tick, tick); - if (diff > 0) - break; // no more expired timers to process - - // remove timer - BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP); - timer_data[tid].type |= TIMER_REMOVE_HEAP; - - if (timer_data[tid].func) { - if (diff < -1000) - // timer was delayed for more than 1 second, use current tick instead - timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data); - else - timer_data[tid].func(tid, timer_data[tid].tick, timer_data[tid].id, timer_data[tid].data); - } - - // in the case the function didn't change anything... - if (timer_data[tid].type & TIMER_REMOVE_HEAP) { - timer_data[tid].type &= ~TIMER_REMOVE_HEAP; - - switch (timer_data[tid].type) { - default: - case TIMER_ONCE_AUTODEL: - timer_data[tid].type = 0; - if (free_timer_list_pos >= free_timer_list_max) { - free_timer_list_max += 256; - RECREATE(free_timer_list,int,free_timer_list_max); - memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); - } - free_timer_list[free_timer_list_pos++] = tid; - break; - case TIMER_INTERVAL: - if (DIFF_TICK(timer_data[tid].tick, tick) < -1000) - timer_data[tid].tick = tick + timer_data[tid].interval; - else - timer_data[tid].tick += timer_data[tid].interval; - push_timer_heap(tid); - break; - } - } - } - - return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL); + int diff = TIMER_MAX_INTERVAL; // return value + + // process all timers one by one + while( BHEAP_LENGTH(timer_heap) ) + { + int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) + + diff = DIFF_TICK(timer_data[tid].tick, tick); + if( diff > 0 ) + break; // no more expired timers to process + + // remove timer + BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP); + timer_data[tid].type |= TIMER_REMOVE_HEAP; + + if( timer_data[tid].func ) + { + if( diff < -1000 ) + // timer was delayed for more than 1 second, use current tick instead + timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data); + else + timer_data[tid].func(tid, timer_data[tid].tick, timer_data[tid].id, timer_data[tid].data); + } + + // in the case the function didn't change anything... + if( timer_data[tid].type & TIMER_REMOVE_HEAP ) + { + timer_data[tid].type &= ~TIMER_REMOVE_HEAP; + + switch( timer_data[tid].type ) + { + default: + case TIMER_ONCE_AUTODEL: + timer_data[tid].type = 0; + if (free_timer_list_pos >= free_timer_list_max) { + free_timer_list_max += 256; + RECREATE(free_timer_list,int,free_timer_list_max); + memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); + } + free_timer_list[free_timer_list_pos++] = tid; + break; + case TIMER_INTERVAL: + if( DIFF_TICK(timer_data[tid].tick, tick) < -1000 ) + timer_data[tid].tick = tick + timer_data[tid].interval; + else + timer_data[tid].tick += timer_data[tid].interval; + push_timer_heap(tid); + break; + } + } + } + + return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL); } unsigned long get_uptime(void) { - return (unsigned long)difftime(time(NULL), start_time); + return (unsigned long)difftime(time(NULL), start_time); } void timer_init(void) { #if defined(ENABLE_RDTSC) - rdtsc_calibrate(); + rdtsc_calibrate(); #endif - time(&start_time); + time(&start_time); } void timer_final(void) { - struct timer_func_list *tfl; - struct timer_func_list *next; - - for (tfl=tfl_root; tfl != NULL; tfl = next) { - next = tfl->next; // copy next pointer - aFree(tfl->name); // free structures - aFree(tfl); - } - - if (timer_data) aFree(timer_data); - BHEAP_CLEAR(timer_heap); - if (free_timer_list) aFree(free_timer_list); + struct timer_func_list *tfl; + struct timer_func_list *next; + + for( tfl=tfl_root; tfl != NULL; tfl = next ) { + next = tfl->next; // copy next pointer + aFree(tfl->name); // free structures + aFree(tfl); + } + + if (timer_data) aFree(timer_data); + BHEAP_CLEAR(timer_heap); + if (free_timer_list) aFree(free_timer_list); } diff --git a/src/common/timer.h b/src/common/timer.h index 9b46927d8..d45c73d12 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _TIMER_H_ -#define _TIMER_H_ +#ifndef _TIMER_H_ +#define _TIMER_H_ #include "../common/cbasetypes.h" @@ -12,9 +12,9 @@ // timer flags enum { - TIMER_ONCE_AUTODEL = 0x01, - TIMER_INTERVAL = 0x02, - TIMER_REMOVE_HEAP = 0x10, + TIMER_ONCE_AUTODEL = 0x01, + TIMER_INTERVAL = 0x02, + TIMER_REMOVE_HEAP = 0x10, }; // Struct declaration @@ -22,15 +22,15 @@ enum { typedef int (*TimerFunc)(int tid, unsigned int tick, int id, intptr_t data); struct TimerData { - unsigned int tick; - TimerFunc func; - int type; - int interval; - int heap_pos; - - // general-purpose storage - int id; - intptr_t data; + unsigned int tick; + TimerFunc func; + int type; + int interval; + int heap_pos; + + // general-purpose storage + int id; + intptr_t data; }; // Function prototype declaration @@ -40,13 +40,13 @@ unsigned int gettick_nocache(void); int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data); int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval); -const struct TimerData *get_timer(int tid); +const struct TimerData* get_timer(int tid); int delete_timer(int tid, TimerFunc func); int addtick_timer(int tid, unsigned int tick); int settick_timer(int tid, unsigned int tick); -int add_timer_func_list(TimerFunc func, char *name); +int add_timer_func_list(TimerFunc func, char* name); unsigned long get_uptime(void); diff --git a/src/common/utils.c b/src/common/utils.c index 9d090f594..296df7e70 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -15,262 +15,269 @@ #include // floor() #ifdef WIN32 -#include "../common/winapi.h" -#ifndef F_OK -#define F_OK 0x0 -#endif /* F_OK */ + #include "../common/winapi.h" + #ifndef F_OK + #define F_OK 0x0 + #endif /* F_OK */ #else -#include -#include -#include + #include + #include + #include #endif /// Dumps given buffer into file pointed to by a handle. -void WriteDump(FILE *fp, const void *buffer, size_t length) +void WriteDump(FILE* fp, const void* buffer, size_t length) { - size_t i; - char hex[48+1], ascii[16+1]; - - fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); - ascii[16] = 0; - - for (i = 0; i < length; i++) { - char c = RBUFB(buffer,i); - - ascii[i%16] = ISCNTRL(c) ? '.' : c; - sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); - - if ((i%16) == 15) { - fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii); - } - } - - if ((i%16) != 0) { - ascii[i%16] = 0; - fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii); - } + size_t i; + char hex[48+1], ascii[16+1]; + + fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); + ascii[16] = 0; + + for( i = 0; i < length; i++ ) + { + char c = RBUFB(buffer,i); + + ascii[i%16] = ISCNTRL(c) ? '.' : c; + sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); + + if( (i%16) == 15 ) + { + fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii); + } + } + + if( (i%16) != 0 ) + { + ascii[i%16] = 0; + fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii); + } } /// Dumps given buffer on the console. -void ShowDump(const void *buffer, size_t length) +void ShowDump(const void* buffer, size_t length) { - size_t i; - char hex[48+1], ascii[16+1]; - - ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); - ascii[16] = 0; - - for (i = 0; i < length; i++) { - char c = RBUFB(buffer,i); - - ascii[i%16] = ISCNTRL(c) ? '.' : c; - sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); - - if ((i%16) == 15) { - ShowDebug("%03X %s %s\n", i/16, hex, ascii); - } - } - - if ((i%16) != 0) { - ascii[i%16] = 0; - ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii); - } + size_t i; + char hex[48+1], ascii[16+1]; + + ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); + ascii[16] = 0; + + for( i = 0; i < length; i++ ) + { + char c = RBUFB(buffer,i); + + ascii[i%16] = ISCNTRL(c) ? '.' : c; + sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); + + if( (i%16) == 15 ) + { + ShowDebug("%03X %s %s\n", i/16, hex, ascii); + } + } + + if( (i%16) != 0 ) + { + ascii[i%16] = 0; + ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii); + } } #ifdef WIN32 -static char *checkpath(char *path, const char *srcpath) -{ - // just make sure the char*path is not const - char *p=path; - if (NULL!=path && NULL!=srcpath) - while (*srcpath) { - if (*srcpath=='/') { - *p++ = '\\'; - srcpath++; - } else - *p++ = *srcpath++; - } - *p = *srcpath; //EOS - return path; +static char* checkpath(char *path, const char *srcpath) +{ // just make sure the char*path is not const + char *p=path; + if(NULL!=path && NULL!=srcpath) + while(*srcpath) { + if (*srcpath=='/') { + *p++ = '\\'; + srcpath++; + } + else + *p++ = *srcpath++; + } + *p = *srcpath; //EOS + return path; } -void findfile(const char *p, const char *pat, void (func)(const char *)) +void findfile(const char *p, const char *pat, void (func)(const char*)) { - WIN32_FIND_DATAA FindFileData; - HANDLE hFind; - char tmppath[MAX_PATH+1]; - - const char *path = (p ==NULL)? "." : p; - const char *pattern = (pat==NULL)? "" : pat; - - checkpath(tmppath,path); - if (PATHSEP != tmppath[strlen(tmppath)-1]) - strcat(tmppath, "\\*"); - else - strcat(tmppath, "*"); - - hFind = FindFirstFileA(tmppath, &FindFileData); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (strcmp(FindFileData.cFileName, ".") == 0) - continue; - if (strcmp(FindFileData.cFileName, "..") == 0) - continue; - - sprintf(tmppath,"%s%c%s",path,PATHSEP,FindFileData.cFileName); - - if (FindFileData.cFileName && strstr(FindFileData.cFileName, pattern)) { - func(tmppath); - } - - - if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - findfile(tmppath, pat, func); - } - } while (FindNextFileA(hFind, &FindFileData) != 0); - FindClose(hFind); - } - return; + WIN32_FIND_DATAA FindFileData; + HANDLE hFind; + char tmppath[MAX_PATH+1]; + + const char *path = (p ==NULL)? "." : p; + const char *pattern = (pat==NULL)? "" : pat; + + checkpath(tmppath,path); + if( PATHSEP != tmppath[strlen(tmppath)-1]) + strcat(tmppath, "\\*"); + else + strcat(tmppath, "*"); + + hFind = FindFirstFileA(tmppath, &FindFileData); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + if (strcmp(FindFileData.cFileName, ".") == 0) + continue; + if (strcmp(FindFileData.cFileName, "..") == 0) + continue; + + sprintf(tmppath,"%s%c%s",path,PATHSEP,FindFileData.cFileName); + + if (FindFileData.cFileName && strstr(FindFileData.cFileName, pattern)) { + func( tmppath ); + } + + + if( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + findfile(tmppath, pat, func); + } + }while (FindNextFileA(hFind, &FindFileData) != 0); + FindClose(hFind); + } + return; } #else #define MAX_DIR_PATH 2048 -static char *checkpath(char *path, const char *srcpath) -{ - // just make sure the char*path is not const - char *p=path; - if (NULL!=path && NULL!=srcpath) - while (*srcpath) { - if (*srcpath=='\\') { - *p++ = '/'; - srcpath++; - } else - *p++ = *srcpath++; - } - *p = *srcpath; //EOS - return path; +static char* checkpath(char *path, const char*srcpath) +{ // just make sure the char*path is not const + char *p=path; + if(NULL!=path && NULL!=srcpath) + while(*srcpath) { + if (*srcpath=='\\') { + *p++ = '/'; + srcpath++; + } + else + *p++ = *srcpath++; + } + *p = *srcpath; //EOS + return path; } -void findfile(const char *p, const char *pat, void (func)(const char *)) +void findfile(const char *p, const char *pat, void (func)(const char*)) { - DIR *dir; // pointer to the scanned directory. - struct dirent *entry; // pointer to one directory entry. - struct stat dir_stat; // used by stat(). - char tmppath[MAX_DIR_PATH+1]; - char path[MAX_DIR_PATH+1]= "."; - const char *pattern = (pat==NULL)? "" : pat; - if (p!=NULL) strcpy(path,p); - - // open the directory for reading - dir = opendir(checkpath(path, path)); - if (!dir) { - ShowError("Cannot read directory '%s'\n", path); - return; - } - - // scan the directory, traversing each sub-directory - // matching the pattern for each file name. - while ((entry = readdir(dir))) { - // skip the "." and ".." entries. - if (strcmp(entry->d_name, ".") == 0) - continue; - if (strcmp(entry->d_name, "..") == 0) - continue; - - sprintf(tmppath,"%s%c%s",path, PATHSEP, entry->d_name); - - // check if the pattern matchs. - if (entry->d_name && strstr(entry->d_name, pattern)) { - func(tmppath); - } - // check if it is a directory. - if (stat(tmppath, &dir_stat) == -1) { - ShowError("stat error %s\n': ", tmppath); - continue; - } - // is this a directory? - if (S_ISDIR(dir_stat.st_mode)) { - // decent recursivly - findfile(tmppath, pat, func); - } - }//end while - - closedir(dir); + DIR* dir; // pointer to the scanned directory. + struct dirent* entry; // pointer to one directory entry. + struct stat dir_stat; // used by stat(). + char tmppath[MAX_DIR_PATH+1]; + char path[MAX_DIR_PATH+1]= "."; + const char *pattern = (pat==NULL)? "" : pat; + if(p!=NULL) strcpy(path,p); + + // open the directory for reading + dir = opendir( checkpath(path, path) ); + if (!dir) { + ShowError("Cannot read directory '%s'\n", path); + return; + } + + // scan the directory, traversing each sub-directory + // matching the pattern for each file name. + while ((entry = readdir(dir))) { + // skip the "." and ".." entries. + if (strcmp(entry->d_name, ".") == 0) + continue; + if (strcmp(entry->d_name, "..") == 0) + continue; + + sprintf(tmppath,"%s%c%s",path, PATHSEP, entry->d_name); + + // check if the pattern matchs. + if (entry->d_name && strstr(entry->d_name, pattern)) { + func( tmppath ); + } + // check if it is a directory. + if (stat(tmppath, &dir_stat) == -1) { + ShowError("stat error %s\n': ", tmppath); + continue; + } + // is this a directory? + if (S_ISDIR(dir_stat.st_mode)) { + // decent recursivly + findfile(tmppath, pat, func); + } + }//end while + + closedir(dir); } #endif -bool exists(const char *filename) +bool exists(const char* filename) { - return !access(filename, F_OK); + return !access(filename, F_OK); } uint8 GetByte(uint32 val, int idx) { - switch (idx) { - case 0: - return (uint8)((val & 0x000000FF)); - case 1: - return (uint8)((val & 0x0000FF00) >> 0x08); - case 2: - return (uint8)((val & 0x00FF0000) >> 0x10); - case 3: - return (uint8)((val & 0xFF000000) >> 0x18); - default: + switch( idx ) + { + case 0: return (uint8)( (val & 0x000000FF) ); + case 1: return (uint8)( (val & 0x0000FF00) >> 0x08 ); + case 2: return (uint8)( (val & 0x00FF0000) >> 0x10 ); + case 3: return (uint8)( (val & 0xFF000000) >> 0x18 ); + default: #if defined(DEBUG) - ShowDebug("GetByte: invalid index (idx=%d)\n", idx); + ShowDebug("GetByte: invalid index (idx=%d)\n", idx); #endif - return 0; - } + return 0; + } } uint16 GetWord(uint32 val, int idx) { - switch (idx) { - case 0: - return (uint16)((val & 0x0000FFFF)); - case 1: - return (uint16)((val & 0xFFFF0000) >> 0x10); - default: + switch( idx ) + { + case 0: return (uint16)( (val & 0x0000FFFF) ); + case 1: return (uint16)( (val & 0xFFFF0000) >> 0x10 ); + default: #if defined(DEBUG) - ShowDebug("GetWord: invalid index (idx=%d)\n", idx); + ShowDebug("GetWord: invalid index (idx=%d)\n", idx); #endif - return 0; - } + return 0; + } } uint16 MakeWord(uint8 byte0, uint8 byte1) { - return byte0 | (byte1 << 0x08); + return byte0 | (byte1 << 0x08); } uint32 MakeDWord(uint16 word0, uint16 word1) { - return - ((uint32)(word0))| - ((uint32)(word1 << 0x10)); + return + ( (uint32)(word0 ) )| + ( (uint32)(word1 << 0x10) ); } /// calculates the value of A / B, in percent (rounded down) unsigned int get_percentage(const unsigned int A, const unsigned int B) { - double result; + double result; - if (B == 0) { - ShowError("get_percentage(): divison by zero! (A=%u,B=%u)\n", A, B); - return ~0U; - } + if( B == 0 ) + { + ShowError("get_percentage(): divison by zero! (A=%u,B=%u)\n", A, B); + return ~0U; + } - result = 100 * ((double)A / (double)B); + result = 100 * ((double)A / (double)B); - if (result > UINT_MAX) { - ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result); - return UINT_MAX; - } + if( result > UINT_MAX ) + { + ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result); + return UINT_MAX; + } - return (unsigned int)floor(result); + return (unsigned int)floor(result); } diff --git a/src/common/utils.h b/src/common/utils.h index 7f68e484e..8e39f2655 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -8,11 +8,11 @@ #include // FILE* // generate a hex dump of the first 'length' bytes of 'buffer' -void WriteDump(FILE *fp, const void *buffer, size_t length); -void ShowDump(const void *buffer, size_t length); +void WriteDump(FILE* fp, const void* buffer, size_t length); +void ShowDump(const void* buffer, size_t length); -void findfile(const char *p, const char *pat, void (func)(const char *)); -bool exists(const char *filename); +void findfile(const char *p, const char *pat, void (func)(const char*)); +bool exists(const char* filename); //Caps values to min/max #define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a) diff --git a/src/common/winapi.h b/src/common/winapi.h index dfb7d4588..7ce555049 100644 --- a/src/common/winapi.h +++ b/src/common/winapi.h @@ -2,12 +2,12 @@ #define STRICT -#define NTDDI_VERSION NTDDI_WIN2K +#define NTDDI_VERSION NTDDI_WIN2K #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 -#define _WIN32_IE 0x0600 +#define _WIN32_IE 0x0600 #define WIN32_LEAN_AND_MEAN -#define NOCOMM +#define NOCOMM #define NOKANJI #define NOHELP #define NOMCX diff --git a/src/config/const.h b/src/config/const.h index 11477e75f..5fb74e22e 100644 --- a/src/config/const.h +++ b/src/config/const.h @@ -13,85 +13,85 @@ */ /** - * "Sane Checks" to save you from compiling with cool bugs + * "Sane Checks" to save you from compiling with cool bugs **/ #if SECURE_NPCTIMEOUT_INTERVAL <= 0 -#error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s) + #error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s) #endif #if SECURE_NPCTIMEOUT < 0 -#error SECURE_NPCTIMEOUT cannot be lower than 0 + #error SECURE_NPCTIMEOUT cannot be lower than 0 #endif /** * Path within the /db folder to (non-)renewal specific db files **/ #ifdef RENEWAL -#define DBPATH "re/" + #define DBPATH "re/" #else -#define DBPATH "pre-re/" + #define DBPATH "pre-re/" #endif /** * DefType **/ #ifdef RENEWAL -typedef short defType; -#define DEFTYPE_MIN SHRT_MIN -#define DEFTYPE_MAX SHRT_MAX + typedef short defType; + #define DEFTYPE_MIN SHRT_MIN + #define DEFTYPE_MAX SHRT_MAX #else -typedef signed char defType; -#define DEFTYPE_MIN CHAR_MIN -#define DEFTYPE_MAX CHAR_MAX + typedef signed char defType; + #define DEFTYPE_MIN CHAR_MIN + #define DEFTYPE_MAX CHAR_MAX #endif /* pointer size fix which fixes several gcc warnings */ #ifdef __64BIT__ -#define __64BPRTSIZE(y) (intptr)y + #define __64BPRTSIZE(y) (intptr)y #else -#define __64BPRTSIZE(y) y + #define __64BPRTSIZE(y) y #endif /* ATCMD_FUNC(mobinfo) HIT and FLEE calculations */ #ifdef RENEWAL -#define MOB_FLEE(mob) ( mob->lv + mob->status.agi + mob->status.luk/5 + 100 ) -#define MOB_HIT(mob) ( mob->lv + mob->status.dex + mob->status.luk/3 + 175 ) + #define MOB_FLEE(mob) ( mob->lv + mob->status.agi + mob->status.luk/5 + 100 ) + #define MOB_HIT(mob) ( mob->lv + mob->status.dex + mob->status.luk/3 + 175 ) #else -#define MOB_FLEE(mob) ( mob->lv + mob->status.agi ) -#define MOB_HIT(mob) ( mob->lv + mob->status.dex ) + #define MOB_FLEE(mob) ( mob->lv + mob->status.agi ) + #define MOB_HIT(mob) ( mob->lv + mob->status.dex ) #endif /* Renewal's dmg level modifier, used as a macro for a easy way to turn off. */ #ifdef RENEWAL_LVDMG -#define RE_LVL_DMOD(val) \ - if( status_get_lv(src) > 100 && val > 0 ) \ - skillratio = skillratio * status_get_lv(src) / val; -#define RE_LVL_MDMOD(val) \ - if( status_get_lv(src) > 100 && val > 0) \ - md.damage = md.damage * status_get_lv(src) / val; -/* ranger traps special */ -#define RE_LVL_TMDMOD() \ - if( status_get_lv(src) > 100 ) \ - md.damage = md.damage * 150 / 100 + md.damage * status_get_lv(src) / 100; + #define RE_LVL_DMOD(val) \ + if( status_get_lv(src) > 100 && val > 0 ) \ + skillratio = skillratio * status_get_lv(src) / val; + #define RE_LVL_MDMOD(val) \ + if( status_get_lv(src) > 100 && val > 0) \ + md.damage = md.damage * status_get_lv(src) / val; + /* ranger traps special */ + #define RE_LVL_TMDMOD() \ + if( status_get_lv(src) > 100 ) \ + md.damage = md.damage * 150 / 100 + md.damage * status_get_lv(src) / 100; #else -#define RE_LVL_DMOD(val) -#define RE_LVL_MDMOD(val) -#define RE_LVL_TMDMOD() + #define RE_LVL_DMOD(val) + #define RE_LVL_MDMOD(val) + #define RE_LVL_TMDMOD() #endif /* Feb 1st 2012 */ #if PACKETVER >= 20120201 -#define NEW_CARTS -#define MAX_CARTS 9 + #define NEW_CARTS + #define MAX_CARTS 9 #else -#define MAX_CARTS 5 + #define MAX_CARTS 5 #endif // Renewal variable cast time reduction #ifdef RENEWAL_CAST -#define VARCAST_REDUCTION(val){ \ - if( (varcast_r += val) != 0 && varcast_r >= 0 ) \ - time = time * (1 - (float)min(val, 100) / 100); \ - } + #define VARCAST_REDUCTION(val){ \ + if( (varcast_r += val) != 0 && varcast_r >= 0 ) \ + time = time * (1 - (float)min(val, 100) / 100); \ + } #endif /** * End of File diff --git a/src/login/account.h b/src/login/account.h index 22e31d799..1b567be70 100644 --- a/src/login/account.h +++ b/src/login/account.h @@ -12,141 +12,144 @@ typedef struct AccountDBIterator AccountDBIterator; // standard engines -AccountDB *account_db_sql(void); +AccountDB* account_db_sql(void); // extra engines (will probably use the other txt functions) #define ACCOUNTDB_CONSTRUCTOR_(engine) account_db_##engine #define ACCOUNTDB_CONSTRUCTOR(engine) ACCOUNTDB_CONSTRUCTOR_(engine) #ifdef ACCOUNTDB_ENGINE_0 -AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0)(void); +AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0)(void); #endif #ifdef ACCOUNTDB_ENGINE_1 -AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1)(void); +AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1)(void); #endif #ifdef ACCOUNTDB_ENGINE_2 -AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2)(void); +AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2)(void); #endif #ifdef ACCOUNTDB_ENGINE_3 -AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3)(void); +AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3)(void); #endif #ifdef ACCOUNTDB_ENGINE_4 -AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4)(void); +AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4)(void); #endif -struct mmo_account { - int account_id; - char userid[NAME_LENGTH]; - char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords - char sex; // gender (M/F/S) - char email[40]; // e-mail (by default: a@a.com) - int group_id; // player group id - unsigned int state; // packet 0x006a value + 1 (0: compte OK) - time_t unban_time; // (timestamp): ban time limit of the account (0 = no ban) - time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited) - unsigned int logincount;// number of successful auth attempts - char lastlogin[24]; // date+time of last successful login - char last_ip[16]; // save of last IP of connection - char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD, default: 0000-00-00) - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) +struct mmo_account +{ + int account_id; + char userid[NAME_LENGTH]; + char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords + char sex; // gender (M/F/S) + char email[40]; // e-mail (by default: a@a.com) + int group_id; // player group id + unsigned int state; // packet 0x006a value + 1 (0: compte OK) + time_t unban_time; // (timestamp): ban time limit of the account (0 = no ban) + time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited) + unsigned int logincount;// number of successful auth attempts + char lastlogin[24]; // date+time of last successful login + char last_ip[16]; // save of last IP of connection + char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD, default: 0000-00-00) + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) }; -struct AccountDBIterator { - /// Destroys this iterator, releasing all allocated memory (including itself). - /// - /// @param self Iterator - void (*destroy)(AccountDBIterator *self); +struct AccountDBIterator +{ + /// Destroys this iterator, releasing all allocated memory (including itself). + /// + /// @param self Iterator + void (*destroy)(AccountDBIterator* self); - /// Fetches the next account in the database. - /// Fills acc with the account data. - /// @param self Iterator - /// @param acc Account data - /// @return true if successful - bool (*next)(AccountDBIterator *self, struct mmo_account *acc); + /// Fetches the next account in the database. + /// Fills acc with the account data. + /// @param self Iterator + /// @param acc Account data + /// @return true if successful + bool (*next)(AccountDBIterator* self, struct mmo_account* acc); }; -struct AccountDB { - /// Initializes this database, making it ready for use. - /// Call this after setting the properties. - /// - /// @param self Database - /// @return true if successful - bool (*init)(AccountDB *self); - - /// Destroys this database, releasing all allocated memory (including itself). - /// - /// @param self Database - void (*destroy)(AccountDB *self); - - /// Gets a property from this database. - /// These read-only properties must be implemented: - /// "engine.name" -> "txt", "sql", ... - /// "engine.version" -> internal version - /// "engine.comment" -> anything (suggestion: description or specs of the engine) - /// - /// @param self Database - /// @param key Property name - /// @param buf Buffer for the value - /// @param buflen Buffer length - /// @return true if successful - bool (*get_property)(AccountDB *self, const char *key, char *buf, size_t buflen); - - /// Sets a property in this database. - /// - /// @param self Database - /// @param key Property name - /// @param value Property value - /// @return true if successful - bool (*set_property)(AccountDB *self, const char *key, const char *value); - - /// Creates a new account in this database. - /// If acc->account_id is not -1, the provided value will be used. - /// Otherwise the account_id will be auto-generated and written to acc->account_id. - /// - /// @param self Database - /// @param acc Account data - /// @return true if successful - bool (*create)(AccountDB *self, struct mmo_account *acc); - - /// Removes an account from this database. - /// - /// @param self Database - /// @param account_id Account id - /// @return true if successful - bool (*remove)(AccountDB *self, const int account_id); - - /// Modifies the data of an existing account. - /// Uses acc->account_id to identify the account. - /// - /// @param self Database - /// @param acc Account data - /// @return true if successful - bool (*save)(AccountDB *self, const struct mmo_account *acc); - - /// Finds an account with account_id and copies it to acc. - /// - /// @param self Database - /// @param acc Pointer that receives the account data - /// @param account_id Target account id - /// @return true if successful - bool (*load_num)(AccountDB *self, struct mmo_account *acc, const int account_id); - - /// Finds an account with userid and copies it to acc. - /// - /// @param self Database - /// @param acc Pointer that receives the account data - /// @param userid Target username - /// @return true if successful - bool (*load_str)(AccountDB *self, struct mmo_account *acc, const char *userid); - - /// Returns a new forward iterator. - /// - /// @param self Database - /// @return Iterator - AccountDBIterator *(*iterator)(AccountDB *self); +struct AccountDB +{ + /// Initializes this database, making it ready for use. + /// Call this after setting the properties. + /// + /// @param self Database + /// @return true if successful + bool (*init)(AccountDB* self); + + /// Destroys this database, releasing all allocated memory (including itself). + /// + /// @param self Database + void (*destroy)(AccountDB* self); + + /// Gets a property from this database. + /// These read-only properties must be implemented: + /// "engine.name" -> "txt", "sql", ... + /// "engine.version" -> internal version + /// "engine.comment" -> anything (suggestion: description or specs of the engine) + /// + /// @param self Database + /// @param key Property name + /// @param buf Buffer for the value + /// @param buflen Buffer length + /// @return true if successful + bool (*get_property)(AccountDB* self, const char* key, char* buf, size_t buflen); + + /// Sets a property in this database. + /// + /// @param self Database + /// @param key Property name + /// @param value Property value + /// @return true if successful + bool (*set_property)(AccountDB* self, const char* key, const char* value); + + /// Creates a new account in this database. + /// If acc->account_id is not -1, the provided value will be used. + /// Otherwise the account_id will be auto-generated and written to acc->account_id. + /// + /// @param self Database + /// @param acc Account data + /// @return true if successful + bool (*create)(AccountDB* self, struct mmo_account* acc); + + /// Removes an account from this database. + /// + /// @param self Database + /// @param account_id Account id + /// @return true if successful + bool (*remove)(AccountDB* self, const int account_id); + + /// Modifies the data of an existing account. + /// Uses acc->account_id to identify the account. + /// + /// @param self Database + /// @param acc Account data + /// @return true if successful + bool (*save)(AccountDB* self, const struct mmo_account* acc); + + /// Finds an account with account_id and copies it to acc. + /// + /// @param self Database + /// @param acc Pointer that receives the account data + /// @param account_id Target account id + /// @return true if successful + bool (*load_num)(AccountDB* self, struct mmo_account* acc, const int account_id); + + /// Finds an account with userid and copies it to acc. + /// + /// @param self Database + /// @param acc Pointer that receives the account data + /// @param userid Target username + /// @return true if successful + bool (*load_str)(AccountDB* self, struct mmo_account* acc, const char* userid); + + /// Returns a new forward iterator. + /// + /// @param self Database + /// @return Iterator + AccountDBIterator* (*iterator)(AccountDB* self); }; diff --git a/src/login/account_sql.c b/src/login/account_sql.c index 6e56d4688..5073941e2 100644 --- a/src/login/account_sql.c +++ b/src/login/account_sql.c @@ -15,96 +15,98 @@ #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]; +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 +typedef struct AccountDBIterator_SQL +{ + AccountDBIterator vtable; // public interface - AccountDB_SQL *db; - int last_account_id; + 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); +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* 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; + 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; } @@ -112,532 +114,567 @@ AccountDB *account_db_sql(void) /// establishes database connection -static bool account_db_sql_init(AccountDB *self) +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; + 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) +static void account_db_sql_destroy(AccountDB* self) { - AccountDB_SQL *db = (AccountDB_SQL *)self; + AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql_Free(db->accounts); - db->accounts = NULL; - aFree(db); + 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) +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 + 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) +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 + 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) +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); + 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) +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; + 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; + 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")); + result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") ); - return result; + 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) +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); + 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) +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); + 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) +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); + 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) +static AccountDBIterator* account_db_sql_iterator(AccountDB* self) { - AccountDB_SQL *db = (AccountDB_SQL *)self; - AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)aCalloc(1, sizeof(AccountDBIterator_SQL)); + 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; + // 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; + // fill data + iter->db = db; + iter->last_account_id = -1; - return &iter->vtable; + return &iter->vtable; } /// Destroys this iterator, releasing all allocated memory (including itself). -static void account_db_sql_iter_destroy(AccountDBIterator *self) +static void account_db_sql_iter_destroy(AccountDBIterator* self) { - AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)self; - aFree(iter); + 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) +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; - int account_id; - 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 - 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; + AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self; + AccountDB_SQL* db = (AccountDB_SQL*)iter->db; + Sql* sql_handle = db->accounts; + int account_id; + 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 + 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) +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, - "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d", - 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_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; + Sql* sql_handle = db->accounts; + char* data; + int i = 0; + + // retrieve login entry for the specified account + if( SQL_ERROR == Sql_Query(sql_handle, + "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d", + 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_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) +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, - "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - 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_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } else { - // update account table - if (SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", 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_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; + 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, + "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + 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_Execute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + break; + } + } + else + {// update account table + if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", 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_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; } diff --git a/src/login/ipban.h b/src/login/ipban.h index 6adc40483..b2a1a7d9e 100644 --- a/src/login/ipban.h +++ b/src/login/ipban.h @@ -19,7 +19,7 @@ bool ipban_check(uint32 ip); void ipban_log(uint32 ip); // parses configuration option -bool ipban_config_read(const char *key, const char *value); +bool ipban_config_read(const char* key, const char* value); #endif // __IPBAN_H_INCLUDED__ diff --git a/src/login/ipban_sql.c b/src/login/ipban_sql.c index eec9a98be..c75a1f956 100644 --- a/src/login/ipban_sql.c +++ b/src/login/ipban_sql.c @@ -31,7 +31,7 @@ static char ipban_codepage[32] = ""; static char ipban_table[32] = "ipbanlist"; // globals -static Sql *sql_handle = NULL; +static Sql* sql_handle = NULL; static int cleanup_timer_id = INVALID_TIMER; static bool ipban_inited = false; @@ -41,196 +41,218 @@ int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data); // initialize void ipban_init(void) { - const char *username; - const char *password; - const char *hostname; - uint16 port; - const char *database; - const char *codepage; - - ipban_inited = true; - - if (!login_config.ipban) - return;// ipban disabled - - if (ipban_db_hostname[0] != '\0') { - // local settings - username = ipban_db_username; - password = ipban_db_password; - hostname = ipban_db_hostname; - port = ipban_db_port; - database = ipban_db_database; - codepage = ipban_codepage; - } else { - // global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - // establish connections - sql_handle = Sql_Malloc(); - if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) - Sql_ShowDebug(sql_handle); - - if (login_config.ipban_cleanup_interval > 0) { - // set up periodic cleanup of connection history and active bans - add_timer_func_list(ipban_cleanup, "ipban_cleanup"); - cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000); - } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups - ipban_cleanup(0,0,0,0); + const char* username; + const char* password; + const char* hostname; + uint16 port; + const char* database; + const char* codepage; + + ipban_inited = true; + + if( !login_config.ipban ) + return;// ipban disabled + + if( ipban_db_hostname[0] != '\0' ) + {// local settings + username = ipban_db_username; + password = ipban_db_password; + hostname = ipban_db_hostname; + port = ipban_db_port; + database = ipban_db_database; + codepage = ipban_codepage; + } + else + {// global settings + username = global_db_username; + password = global_db_password; + hostname = global_db_hostname; + port = global_db_port; + database = global_db_database; + codepage = global_codepage; + } + + // establish connections + sql_handle = Sql_Malloc(); + if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) + { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) + Sql_ShowDebug(sql_handle); + + if( login_config.ipban_cleanup_interval > 0 ) + { // set up periodic cleanup of connection history and active bans + add_timer_func_list(ipban_cleanup, "ipban_cleanup"); + cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000); + } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups + ipban_cleanup(0,0,0,0); } // finalize void ipban_final(void) { - if (!login_config.ipban) - return;// ipban disabled - - if (login_config.ipban_cleanup_interval > 0) - // release data - delete_timer(cleanup_timer_id, ipban_cleanup); - - ipban_cleanup(0,0,0,0); // always clean up on login-server stop - - // close connections - Sql_Free(sql_handle); - sql_handle = NULL; + if( !login_config.ipban ) + return;// ipban disabled + + if( login_config.ipban_cleanup_interval > 0 ) + // release data + delete_timer(cleanup_timer_id, ipban_cleanup); + + ipban_cleanup(0,0,0,0); // always clean up on login-server stop + + // close connections + Sql_Free(sql_handle); + sql_handle = NULL; } // load configuration options -bool ipban_config_read(const char *key, const char *value) +bool ipban_config_read(const char* key, const char* value) { - const char *signature; - - if (ipban_inited) - return false;// settings can only be changed before init - - signature = "sql."; - if (strncmpi(key, signature, strlen(signature)) == 0) { - key += strlen(signature); - if (strcmpi(key, "db_hostname") == 0) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else if (strcmpi(key, "db_port") == 0) - global_db_port = (uint16)strtoul(value, NULL, 10); - else if (strcmpi(key, "db_username") == 0) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else if (strcmpi(key, "db_password") == 0) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else if (strcmpi(key, "db_database") == 0) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else if (strcmpi(key, "codepage") == 0) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - signature = "ipban.sql."; - if (strncmpi(key, signature, strlen(signature)) == 0) { - key += strlen(signature); - if (strcmpi(key, "db_hostname") == 0) - safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname)); - else if (strcmpi(key, "db_port") == 0) - ipban_db_port = (uint16)strtoul(value, NULL, 10); - else if (strcmpi(key, "db_username") == 0) - safestrncpy(ipban_db_username, value, sizeof(ipban_db_username)); - else if (strcmpi(key, "db_password") == 0) - safestrncpy(ipban_db_password, value, sizeof(ipban_db_password)); - else if (strcmpi(key, "db_database") == 0) - safestrncpy(ipban_db_database, value, sizeof(ipban_db_database)); - else if (strcmpi(key, "codepage") == 0) - safestrncpy(ipban_codepage, value, sizeof(ipban_codepage)); - else if (strcmpi(key, "ipban_table") == 0) - safestrncpy(ipban_table, value, sizeof(ipban_table)); - else - return false;// not found - return true; - } - - signature = "ipban."; - if (strncmpi(key, signature, strlen(signature)) == 0) { - key += strlen(signature); - if (strcmpi(key, "enable") == 0) - login_config.ipban = (bool)config_switch(value); - else if (strcmpi(key, "dynamic_pass_failure_ban") == 0) - login_config.dynamic_pass_failure_ban = (bool)config_switch(value); - else if (strcmpi(key, "dynamic_pass_failure_ban_interval") == 0) - login_config.dynamic_pass_failure_ban_interval = atoi(value); - else if (strcmpi(key, "dynamic_pass_failure_ban_limit") == 0) - login_config.dynamic_pass_failure_ban_limit = atoi(value); - else if (strcmpi(key, "dynamic_pass_failure_ban_duration") == 0) - login_config.dynamic_pass_failure_ban_duration = atoi(value); - else - return false;// not found - return true; - } - - return false;// not found + const char* signature; + + if( ipban_inited ) + return false;// settings can only be changed before init + + signature = "sql."; + if( strncmpi(key, signature, strlen(signature)) == 0 ) + { + key += strlen(signature); + if( strcmpi(key, "db_hostname") == 0 ) + safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); + else + if( strcmpi(key, "db_port") == 0 ) + global_db_port = (uint16)strtoul(value, NULL, 10); + else + if( strcmpi(key, "db_username") == 0 ) + safestrncpy(global_db_username, value, sizeof(global_db_username)); + else + if( strcmpi(key, "db_password") == 0 ) + safestrncpy(global_db_password, value, sizeof(global_db_password)); + else + if( strcmpi(key, "db_database") == 0 ) + safestrncpy(global_db_database, value, sizeof(global_db_database)); + else + if( strcmpi(key, "codepage") == 0 ) + safestrncpy(global_codepage, value, sizeof(global_codepage)); + else + return false;// not found + return true; + } + + signature = "ipban.sql."; + if( strncmpi(key, signature, strlen(signature)) == 0 ) + { + key += strlen(signature); + if( strcmpi(key, "db_hostname") == 0 ) + safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname)); + else + if( strcmpi(key, "db_port") == 0 ) + ipban_db_port = (uint16)strtoul(value, NULL, 10); + else + if( strcmpi(key, "db_username") == 0 ) + safestrncpy(ipban_db_username, value, sizeof(ipban_db_username)); + else + if( strcmpi(key, "db_password") == 0 ) + safestrncpy(ipban_db_password, value, sizeof(ipban_db_password)); + else + if( strcmpi(key, "db_database") == 0 ) + safestrncpy(ipban_db_database, value, sizeof(ipban_db_database)); + else + if( strcmpi(key, "codepage") == 0 ) + safestrncpy(ipban_codepage, value, sizeof(ipban_codepage)); + else + if( strcmpi(key, "ipban_table") == 0 ) + safestrncpy(ipban_table, value, sizeof(ipban_table)); + else + return false;// not found + return true; + } + + signature = "ipban."; + if( strncmpi(key, signature, strlen(signature)) == 0 ) + { + key += strlen(signature); + if( strcmpi(key, "enable") == 0 ) + login_config.ipban = (bool)config_switch(value); + else + if( strcmpi(key, "dynamic_pass_failure_ban") == 0 ) + login_config.dynamic_pass_failure_ban = (bool)config_switch(value); + else + if( strcmpi(key, "dynamic_pass_failure_ban_interval") == 0 ) + login_config.dynamic_pass_failure_ban_interval = atoi(value); + else + if( strcmpi(key, "dynamic_pass_failure_ban_limit") == 0 ) + login_config.dynamic_pass_failure_ban_limit = atoi(value); + else + if( strcmpi(key, "dynamic_pass_failure_ban_duration") == 0 ) + login_config.dynamic_pass_failure_ban_duration = atoi(value); + else + return false;// not found + return true; + } + + return false;// not found } // check ip against active bans list bool ipban_check(uint32 ip) { - uint8 *p = (uint8 *)&ip; - char *data = NULL; - int matches; + uint8* p = (uint8*)&ip; + char* data = NULL; + int matches; - if (!login_config.ipban) - return false;// ipban disabled + if( !login_config.ipban ) + return false;// ipban disabled - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')", - ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0])) { - Sql_ShowDebug(sql_handle); - // close connection because we can't verify their connectivity. - return true; - } + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')", + ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]) ) + { + Sql_ShowDebug(sql_handle); + // close connection because we can't verify their connectivity. + return true; + } - if (SQL_ERROR == Sql_NextRow(sql_handle)) - return true;// Shouldn't happen, but just in case... + if( SQL_ERROR == Sql_NextRow(sql_handle) ) + return true;// Shouldn't happen, but just in case... - Sql_GetData(sql_handle, 0, &data, NULL); - matches = atoi(data); - Sql_FreeResult(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); + matches = atoi(data); + Sql_FreeResult(sql_handle); - return(matches > 0); + return( matches > 0 ); } // log failed attempt void ipban_log(uint32 ip) { - unsigned long failures; + unsigned long failures; - if (!login_config.ipban) - return;// ipban disabled + if( !login_config.ipban ) + return;// ipban disabled - failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip. + failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip. - // if over the limit, add a temporary ban entry - if (failures >= login_config.dynamic_pass_failure_ban_limit) { - uint8 *p = (uint8 *)&ip; - if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban')", - ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration)) - Sql_ShowDebug(sql_handle); - } + // if over the limit, add a temporary ban entry + if( failures >= login_config.dynamic_pass_failure_ban_limit ) + { + uint8* p = (uint8*)&ip; + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban')", + ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration) ) + Sql_ShowDebug(sql_handle); + } } // remove expired bans int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - if (!login_config.ipban) - return 0;// ipban disabled + if( !login_config.ipban ) + return 0;// ipban disabled - if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()")) - Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()") ) + Sql_ShowDebug(sql_handle); - return 0; + return 0; } diff --git a/src/login/login.c b/src/login/login.c index 1f63463d5..e079dbaf2 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -25,31 +25,31 @@ int login_fd; // login server socket struct mmo_char_server server[MAX_SERVERS]; // char server data // Account engines available -static struct { - AccountDB *(*constructor)(void); - AccountDB *db; +static struct{ + AccountDB* (*constructor)(void); + AccountDB* db; } account_engines[] = { - {account_db_sql, NULL}, + {account_db_sql, NULL}, #ifdef ACCOUNTDB_ENGINE_0 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_1 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_2 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_3 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_4 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4), NULL}, #endif - // end of structure - {NULL, NULL} + // end of structure + {NULL, NULL} }; // account database -AccountDB *accounts = NULL; +AccountDB* accounts = NULL; //Account registration flood protection [Kevin] int allowed_regs = 1; @@ -57,14 +57,14 @@ int time_allowed = 10; //in seconds // Advanced subnet check [LuzZza] struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; + uint32 mask; + uint32 char_ip; + uint32 map_ip; } subnet[16]; int subnet_count = 0; -int mmo_auth_new(const char *userid, const char *pass, const char sex, const char *last_ip); +int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip); //----------------------------------------------------- // Auth database @@ -73,16 +73,16 @@ int mmo_auth_new(const char *userid, const char *pass, const char sex, const cha struct auth_node { - int account_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - char sex; - uint32 version; - uint8 clienttype; + int account_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + char sex; + uint32 version; + uint8 clienttype; }; -static DBMap *auth_db; // int account_id -> struct auth_node* +static DBMap* auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- @@ -90,12 +90,12 @@ static DBMap *auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- struct online_login_data { - int account_id; - int waiting_disconnect; - int char_server; + int account_id; + int waiting_disconnect; + int char_server; }; -static DBMap *online_db; // int account_id -> struct online_login_data* +static DBMap* online_db; // int account_id -> struct online_login_data* static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data); /** @@ -103,46 +103,49 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t */ static DBData create_online_user(DBKey key, va_list args) { - struct online_login_data *p; - CREATE(p, struct online_login_data, 1); - p->account_id = key.i; - p->char_server = -1; - p->waiting_disconnect = INVALID_TIMER; - return db_ptr2data(p); + struct online_login_data* p; + CREATE(p, struct online_login_data, 1); + p->account_id = key.i; + p->char_server = -1; + p->waiting_disconnect = INVALID_TIMER; + return db_ptr2data(p); } -struct online_login_data *add_online_user(int char_server, int account_id) { - struct online_login_data *p; - p = idb_ensure(online_db, account_id, create_online_user); - p->char_server = char_server; - if (p->waiting_disconnect != INVALID_TIMER) { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - return p; +struct online_login_data* add_online_user(int char_server, int account_id) +{ + struct online_login_data* p; + p = idb_ensure(online_db, account_id, create_online_user); + p->char_server = char_server; + if( p->waiting_disconnect != INVALID_TIMER ) + { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + return p; } void remove_online_user(int account_id) { - struct online_login_data *p; - p = (struct online_login_data *)idb_get(online_db, account_id); - if (p == NULL) - return; - if (p->waiting_disconnect != INVALID_TIMER) - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - - idb_remove(online_db, account_id); + struct online_login_data* p; + p = (struct online_login_data*)idb_get(online_db, account_id); + if( p == NULL ) + return; + if( p->waiting_disconnect != INVALID_TIMER ) + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + + idb_remove(online_db, account_id); } static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct online_login_data *p = (struct online_login_data *)idb_get(online_db, id); - if (p != NULL && p->waiting_disconnect == tid && p->account_id == id) { - p->waiting_disconnect = INVALID_TIMER; - remove_online_user(id); - idb_remove(auth_db, id); - } - return 0; + struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id); + if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ) + { + p->waiting_disconnect = INVALID_TIMER; + remove_online_user(id); + idb_remove(auth_db, id); + } + return 0; } /** @@ -150,17 +153,20 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t */ static int online_db_setoffline(DBKey key, DBData *data, va_list ap) { - struct online_login_data *p = db_data2ptr(data); - int server = va_arg(ap, int); - if (server == -1) { - p->char_server = -1; - if (p->waiting_disconnect != INVALID_TIMER) { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - } else if (p->char_server == server) - p->char_server = -2; //Char server disconnected. - return 0; + struct online_login_data* p = db_data2ptr(data); + int server = va_arg(ap, int); + if( server == -1 ) + { + p->char_server = -1; + if( p->waiting_disconnect != INVALID_TIMER ) + { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + } + else if( p->char_server == server ) + p->char_server = -2; //Char server disconnected. + return 0; } /** @@ -168,72 +174,75 @@ static int online_db_setoffline(DBKey key, DBData *data, va_list ap) */ static int online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) { - struct online_login_data *character= db_data2ptr(data); - if (character->char_server == -2) //Unknown server.. set them offline - remove_online_user(character->account_id); - return 0; + struct online_login_data *character= db_data2ptr(data); + if (character->char_server == -2) //Unknown server.. set them offline + remove_online_user(character->account_id); + return 0; } static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - online_db->foreach(online_db, online_data_cleanup_sub); - return 0; -} + online_db->foreach(online_db, online_data_cleanup_sub); + return 0; +} //-------------------------------------------------------------------- // Packet send to all char-servers, except one (wos: without our self) //-------------------------------------------------------------------- -int charif_sendallwos(int sfd, uint8 *buf, size_t len) +int charif_sendallwos(int sfd, uint8* buf, size_t len) { - int i, c; - - for (i = 0, c = 0; i < ARRAYLENGTH(server); ++i) { - int fd = server[i].fd; - if (session_isValid(fd) && fd != sfd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - ++c; - } - } - - return c; + int i, c; + + for( i = 0, c = 0; i < ARRAYLENGTH(server); ++i ) + { + int fd = server[i].fd; + if( session_isValid(fd) && fd != sfd ) + { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + ++c; + } + } + + return c; } /// Initializes a server structure. void chrif_server_init(int id) { - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; + memset(&server[id], 0, sizeof(server[id])); + server[id].fd = -1; } /// Destroys a server structure. void chrif_server_destroy(int id) { - if (server[id].fd != -1) { - do_close(server[id].fd); - server[id].fd = -1; - } + if( server[id].fd != -1 ) + { + do_close(server[id].fd); + server[id].fd = -1; + } } /// Resets all the data related to a server. void chrif_server_reset(int id) { - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. - chrif_server_destroy(id); - chrif_server_init(id); + online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. + chrif_server_destroy(id); + chrif_server_init(id); } /// Called when the connection to Char Server is disconnected. void chrif_on_disconnect(int id) { - ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); - chrif_server_reset(id); + ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); + chrif_server_reset(id); } @@ -242,49 +251,52 @@ void chrif_on_disconnect(int id) //----------------------------------------------------- static int sync_ip_addresses(int tid, unsigned int tick, int id, intptr_t data) { - uint8 buf[2]; - ShowInfo("IP Sync in progress...\n"); - WBUFW(buf,0) = 0x2735; - charif_sendallwos(-1, buf, 2); - return 0; + uint8 buf[2]; + ShowInfo("IP Sync in progress...\n"); + WBUFW(buf,0) = 0x2735; + charif_sendallwos(-1, buf, 2); + return 0; } //----------------------------------------------------- // encrypted/unencrypted password check (from eApp) //----------------------------------------------------- -bool check_encrypted(const char *str1, const char *str2, const char *passwd) +bool check_encrypted(const char* str1, const char* str2, const char* passwd) { - char tmpstr[64+1], md5str[32+1]; + char tmpstr[64+1], md5str[32+1]; - safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); - MD5_String(tmpstr, md5str); + safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); + MD5_String(tmpstr, md5str); - return (0==strcmp(passwd, md5str)); + return (0==strcmp(passwd, md5str)); } -bool check_password(const char *md5key, int passwdenc, const char *passwd, const char *refpass) +bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass) { - if (passwdenc == 0) { - return (0==strcmp(passwd, refpass)); - } else { - // password mode set to 1 -> md5(md5key, refpass) enable with - // password mode set to 2 -> md5(refpass, md5key) enable with - - return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || - ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); - } + if(passwdenc == 0) + { + return (0==strcmp(passwd, refpass)); + } + else + { + // password mode set to 1 -> md5(md5key, refpass) enable with + // password mode set to 2 -> md5(refpass, md5key) enable with + + return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || + ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); + } } //----------------------------------------------------- // custom timestamp formatting (from eApp) //----------------------------------------------------- -const char *timestamp2string(char *str, size_t size, time_t timestamp, const char *format) +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) { - size_t len = strftime(str, size, format, localtime(×tamp)); - memset(str + len, '\0', size - len); - return str; + size_t len = strftime(str, size, format, localtime(×tamp)); + memset(str + len, '\0', size - len); + return str; } @@ -293,9 +305,9 @@ const char *timestamp2string(char *str, size_t size, time_t timestamp, const cha //-------------------------------------------- int lan_subnetcheck(uint32 ip) { - int i; - ARR_FIND(0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask)); - return (i < subnet_count) ? subnet[i].char_ip : 0; + int i; + ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); + return ( i < subnet_count ) ? subnet[i].char_ip : 0; } //---------------------------------- @@ -303,89 +315,99 @@ int lan_subnetcheck(uint32 ip) //---------------------------------- int login_lan_config_read(const char *lancfgName) { - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if ((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - while (fgets(line, sizeof(line), fp)) { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if (sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - if (strcmpi(w1, "subnet") == 0) { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if ((subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask)) { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - if (subnet_count > 1) /* only useful if there is more than 1 available */ - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + while(fgets(line, sizeof(line), fp)) + { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) + { + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + if( strcmpi(w1, "subnet") == 0 ) + { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) + { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + if( subnet_count > 1 ) /* only useful if there is more than 1 available */ + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; } //----------------------- // Console Command Parser [Wizputer] //----------------------- -int parse_console(const char *command) +int parse_console(const char* command) { - ShowNotice("Console command: %s\n", command); - - if (strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0) - runflag = 0; - else if (strcmpi("alive", command) == 0 || strcmpi("status", command) == 0) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if (strcmpi("help", command) == 0) { - ShowInfo("To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo("To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - ShowInfo("To create a new account:\n"); - ShowInfo(" 'create'\n"); - } else { - // commands with parameters - char cmd[128], params[256]; - - if (sscanf(command, "%127s %255[^\r\n]", cmd, params) < 2) { - return 0; - } - - if (strcmpi(cmd, "create") == 0) { - char username[NAME_LENGTH], password[NAME_LENGTH], sex; - - if (sscanf(params, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1) { - ShowWarning("Console: Invalid parameters for '%s'. Usage: %s \n", cmd, cmd); - return 0; - } - - if (mmo_auth_new(username, password, TOUPPER(sex), "0.0.0.0") != -1) { - ShowError("Console: Account creation failed.\n"); - return 0; - } - ShowStatus("Console: Account '%s' created successfully.\n", username); - } - } - - return 0; + ShowNotice("Console command: %s\n", command); + + if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0 ) + runflag = 0; + else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 ) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if( strcmpi("help", command) == 0 ) + { + ShowInfo("To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|quit|end'\n"); + ShowInfo("To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + ShowInfo("To create a new account:\n"); + ShowInfo(" 'create'\n"); + } + else + {// commands with parameters + char cmd[128], params[256]; + + if( sscanf(command, "%127s %255[^\r\n]", cmd, params) < 2 ) + { + return 0; + } + + if( strcmpi(cmd, "create") == 0 ) + { + char username[NAME_LENGTH], password[NAME_LENGTH], sex; + + if( sscanf(params, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ) + { + ShowWarning("Console: Invalid parameters for '%s'. Usage: %s \n", cmd, cmd); + return 0; + } + + if( mmo_auth_new(username, password, TOUPPER(sex), "0.0.0.0") != -1 ) + { + ShowError("Console: Account creation failed.\n"); + return 0; + } + ShowStatus("Console: Account '%s' created successfully.\n", username); + } + } + + return 0; } @@ -394,898 +416,880 @@ int parse_console(const char *command) //-------------------------------- int parse_fromchar(int fd) { - int j, id; - uint32 ipl; - char ip[16]; - - ARR_FIND(0, ARRAYLENGTH(server), id, server[id].fd == fd); - if (id == ARRAYLENGTH(server)) { - // not a char server - ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd); - set_eof(fd); - do_close(fd); - return 0; - } - - if (session[fd]->flag.eof) { - do_close(fd); - server[id].fd = -1; - chrif_on_disconnect(id); - return 0; - } - - ipl = server[id].ip; - ip2str(ipl, ip); - - while (RFIFOREST(fd) >= 2) { - uint16 command = RFIFOW(fd,0); - - switch (command) { - - case 0x2712: // request from char-server to authenticate an account - if (RFIFOREST(fd) < 23) - return 0; - { - struct auth_node *node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint8 sex = RFIFOB(fd,14); - //uint32 ip_ = ntohl(RFIFOL(fd,15)); - int request_id = RFIFOL(fd,19); - RFIFOSKIP(fd,23); - - node = (struct auth_node *)idb_get(auth_db, account_id); - if (runflag == LOGINSERVER_ST_RUNNING && - node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 && - node->sex == sex_num2str(sex) /*&& - node->ip == ip_*/) { - // found - //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); - - // send ack - WFIFOHEAD(fd,25); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = sex; - WFIFOB(fd,15) = 0;// ok - WFIFOL(fd,16) = request_id; - WFIFOL(fd,20) = node->version; - WFIFOB(fd,24) = node->clienttype; - WFIFOSET(fd,25); - - // each auth entry can only be used once - idb_remove(auth_db, account_id); - } else { - // authentication not found - ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); - WFIFOHEAD(fd,25); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = sex; - WFIFOB(fd,15) = 1;// auth failed - WFIFOL(fd,16) = request_id; - WFIFOL(fd,20) = 0; - WFIFOB(fd,24) = 0; - WFIFOSET(fd,25); - } - } - break; - - case 0x2714: - if (RFIFOREST(fd) < 6) - return 0; - { - int users = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - // how many users on world? (update) - if (server[id].users != users) { - ShowStatus("set users %s : %d\n", server[id].name, users); - - server[id].users = users; - } - } - break; - - case 0x2715: // request from char server to change e-email from default "a@a.com" - if (RFIFOREST(fd) < 46) - return 0; - { - struct mmo_account acc; - char email[40]; - - int account_id = RFIFOL(fd,2); - safestrncpy(email, (char *)RFIFOP(fd,6), 40); - remove_control_chars(email); - RFIFOSKIP(fd,46); - - if (e_mail_check(email) == 0) - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else if (!accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "a@a.com") == 0 || acc.email[0] == '\0') - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else { - memcpy(acc.email, email, 40); - ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip); - // Save - accounts->save(accounts, &acc); - } - } - break; - - case 0x2716: // request account data - if (RFIFOREST(fd) < 6) - return 0; - { - struct mmo_account acc; - time_t expiration_time = 0; - char email[40] = ""; - int group_id = 0; - char birthdate[10+1] = ""; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if (!accounts->load_num(accounts, &acc, account_id)) - ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip); - else { - safestrncpy(email, acc.email, sizeof(email)); - expiration_time = acc.expiration_time; - group_id = acc.group_id; - safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); - } - - WFIFOHEAD(fd,62); - WFIFOW(fd,0) = 0x2717; - WFIFOL(fd,2) = account_id; - safestrncpy((char *)WFIFOP(fd,6), email, 40); - WFIFOL(fd,46) = (uint32)expiration_time; - WFIFOB(fd,50) = group_id; - safestrncpy((char *)WFIFOP(fd,51), birthdate, 10+1); - WFIFOSET(fd,62); - } - break; - - case 0x2719: // ping request from charserver - RFIFOSKIP(fd,2); - - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2718; - WFIFOSET(fd,2); - break; - - // Map server send information to change an email of an account via char-server - case 0x2722: // 0x2722 .L .40B .40B - if (RFIFOREST(fd) < 86) - return 0; - { - struct mmo_account acc; - char actual_email[40]; - char new_email[40]; - - int account_id = RFIFOL(fd,2); - safestrncpy(actual_email, (char *)RFIFOP(fd,6), 40); - safestrncpy(new_email, (char *)RFIFOP(fd,46), 40); - RFIFOSKIP(fd, 86); - - if (e_mail_check(actual_email) == 0) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else if (e_mail_check(new_email) == 0) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else if (strcmpi(new_email, "a@a.com") == 0) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else if (!accounts->load_num(accounts, &acc, account_id)) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else if (strcmpi(acc.email, actual_email) != 0) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip); - else { - safestrncpy(acc.email, new_email, 40); - ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip); - // Save - accounts->save(accounts, &acc); - } - } - break; - - case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) - if (RFIFOREST(fd) < 10) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - unsigned int state = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - if (!accounts->load_num(accounts, &acc, account_id)) - ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else if (acc.state == state) - ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else { - ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); - - acc.state = state; - // Save - accounts->save(accounts, &acc); - - // notify other servers - if (state != 0) { - uint8 buf[11]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = 0; // 0: change of state, 1: ban - WBUFL(buf,7) = state; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - } - } - break; - - case 0x2725: // Receiving of map-server via char-server a ban request - if (RFIFOREST(fd) < 18) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - int year = (short)RFIFOW(fd,6); - int month = (short)RFIFOW(fd,8); - int mday = (short)RFIFOW(fd,10); - int hour = (short)RFIFOW(fd,12); - int min = (short)RFIFOW(fd,14); - int sec = (short)RFIFOW(fd,16); - RFIFOSKIP(fd,18); - - if (!accounts->load_num(accounts, &acc, account_id)) - ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else { - time_t timestamp; - struct tm *tmtime; - if (acc.unban_time == 0 || acc.unban_time < time(NULL)) - timestamp = time(NULL); // new ban - else - timestamp = acc.unban_time; // add to existing ban - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + year; - tmtime->tm_mon = tmtime->tm_mon + month; - tmtime->tm_mday = tmtime->tm_mday + mday; - tmtime->tm_hour = tmtime->tm_hour + hour; - tmtime->tm_min = tmtime->tm_min + min; - tmtime->tm_sec = tmtime->tm_sec + sec; - timestamp = mktime(tmtime); - if (timestamp == -1) - ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); - else if (timestamp <= time(NULL) || timestamp == 0) - ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); - else { - uint8 buf[11]; - char tmpstr[24]; - timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); - ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); - - acc.unban_time = timestamp; - - // Save - accounts->save(accounts, &acc); - - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = 1; // 0: change of status, 1: ban - WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - } - } - break; - - case 0x2727: // Change of sex (sex is reversed) - if (RFIFOREST(fd) < 6) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if (!accounts->load_num(accounts, &acc, account_id)) - ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else if (acc.sex == 'S') - ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else { - unsigned char buf[7]; - char sex = (acc.sex == 'M') ? 'F' : 'M'; //Change gender - - ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); - - acc.sex = sex; - // Save - accounts->save(accounts, &acc); - - // announce to other servers - WBUFW(buf,0) = 0x2723; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = sex_str2num(sex); - charif_sendallwos(-1, buf, 7); - } - } - break; - - case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,4); - - if (!accounts->load_num(accounts, &acc, account_id)) - ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else { - int len; - int p; - ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip); - for (j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j) { - sscanf((char *)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len); - acc.account_reg2[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char *)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len); - acc.account_reg2[j].value[len]='\0'; - p +=len+1; - remove_control_chars(acc.account_reg2[j].str); - remove_control_chars(acc.account_reg2[j].value); - } - acc.account_reg2_num = j; - - // Save - accounts->save(accounts, &acc); - - // Sending information towards the other char-servers. - RFIFOW(fd,0) = 0x2729;// reusing read buffer - charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2)); - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x272a: // Receiving of map-server via char-server an unban request - if (RFIFOREST(fd) < 6) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if (!accounts->load_num(accounts, &acc, account_id)) - ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else if (acc.unban_time == 0) - ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip); - else { - ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip); - acc.unban_time = 0; - accounts->save(accounts, &acc); - } - } - break; - - case 0x272b: // Set account_id to online [Wizputer] - if (RFIFOREST(fd) < 6) - return 0; - add_online_user(id, RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - case 0x272c: // Set account_id to offline [Wizputer] - if (RFIFOREST(fd) < 6) - return 0; - remove_online_user(RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - case 0x272d: // Receive list of all online accounts. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - struct online_login_data *p; - int aid; - uint32 i, users; - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first - users = RFIFOW(fd,4); - for (i = 0; i < users; i++) { - aid = RFIFOL(fd,6+i*4); - p = idb_ensure(online_db, aid, create_online_user); - p->char_server = id; - if (p->waiting_disconnect != INVALID_TIMER) { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x272e: //Request account_reg2 for a character. - if (RFIFOREST(fd) < 10) - return 0; - { - struct mmo_account acc; - size_t off; - - int account_id = RFIFOL(fd,2); - int char_id = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg)); - WFIFOW(fd,0) = 0x2729; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 1; //Type 1 for Account2 registry - - off = 13; - if (accounts->load_num(accounts, &acc, account_id)) { - for (j = 0; j < acc.account_reg2_num; j++) { - if (acc.account_reg2[j].str[0] != '\0') { - off += sprintf((char *)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. - off += sprintf((char *)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1; - } - } - } - - WFIFOW(fd,2) = (uint16)off; - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2736: // WAN IP update from char-server - if (RFIFOREST(fd) < 6) - return 0; - server[id].ip = ntohl(RFIFOL(fd,2)); - ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - case 0x2737: //Request to set all offline. - ShowInfo("Setting accounts from char-server %d offline.\n", id); - online_db->foreach(online_db, online_db_setoffline, id); - RFIFOSKIP(fd,2); - break; - - default: - ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); - set_eof(fd); - return 0; - } // switch - } // while - - return 0; + int j, id; + uint32 ipl; + char ip[16]; + + ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd ); + if( id == ARRAYLENGTH(server) ) + {// not a char server + ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd); + set_eof(fd); + do_close(fd); + return 0; + } + + if( session[fd]->flag.eof ) + { + do_close(fd); + server[id].fd = -1; + chrif_on_disconnect(id); + return 0; + } + + ipl = server[id].ip; + ip2str(ipl, ip); + + while( RFIFOREST(fd) >= 2 ) + { + uint16 command = RFIFOW(fd,0); + + switch( command ) + { + + case 0x2712: // request from char-server to authenticate an account + if( RFIFOREST(fd) < 23 ) + return 0; + { + struct auth_node* node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint8 sex = RFIFOB(fd,14); + //uint32 ip_ = ntohl(RFIFOL(fd,15)); + int request_id = RFIFOL(fd,19); + RFIFOSKIP(fd,23); + + node = (struct auth_node*)idb_get(auth_db, account_id); + if( runflag == LOGINSERVER_ST_RUNNING && + node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 && + node->sex == sex_num2str(sex) /*&& + node->ip == ip_*/ ) + {// found + //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); + + // send ack + WFIFOHEAD(fd,25); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = sex; + WFIFOB(fd,15) = 0;// ok + WFIFOL(fd,16) = request_id; + WFIFOL(fd,20) = node->version; + WFIFOB(fd,24) = node->clienttype; + WFIFOSET(fd,25); + + // each auth entry can only be used once + idb_remove(auth_db, account_id); + } + else + {// authentication not found + ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); + WFIFOHEAD(fd,25); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = sex; + WFIFOB(fd,15) = 1;// auth failed + WFIFOL(fd,16) = request_id; + WFIFOL(fd,20) = 0; + WFIFOB(fd,24) = 0; + WFIFOSET(fd,25); + } + } + break; + + case 0x2714: + if( RFIFOREST(fd) < 6 ) + return 0; + { + int users = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + // how many users on world? (update) + if( server[id].users != users ) + { + ShowStatus("set users %s : %d\n", server[id].name, users); + + server[id].users = users; + } + } + break; + + case 0x2715: // request from char server to change e-email from default "a@a.com" + if (RFIFOREST(fd) < 46) + return 0; + { + struct mmo_account acc; + char email[40]; + + int account_id = RFIFOL(fd,2); + safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email); + RFIFOSKIP(fd,46); + + if( e_mail_check(email) == 0 ) + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else + if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "a@a.com") == 0 || acc.email[0] == '\0' ) + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else { + memcpy(acc.email, email, 40); + ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip); + // Save + accounts->save(accounts, &acc); + } + } + break; + + case 0x2716: // request account data + if( RFIFOREST(fd) < 6 ) + return 0; + { + struct mmo_account acc; + time_t expiration_time = 0; + char email[40] = ""; + int group_id = 0; + char birthdate[10+1] = ""; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip); + else + { + safestrncpy(email, acc.email, sizeof(email)); + expiration_time = acc.expiration_time; + group_id = acc.group_id; + safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); + } + + WFIFOHEAD(fd,62); + WFIFOW(fd,0) = 0x2717; + WFIFOL(fd,2) = account_id; + safestrncpy((char*)WFIFOP(fd,6), email, 40); + WFIFOL(fd,46) = (uint32)expiration_time; + WFIFOB(fd,50) = group_id; + safestrncpy((char*)WFIFOP(fd,51), birthdate, 10+1); + WFIFOSET(fd,62); + } + break; + + case 0x2719: // ping request from charserver + RFIFOSKIP(fd,2); + + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2718; + WFIFOSET(fd,2); + break; + + // Map server send information to change an email of an account via char-server + case 0x2722: // 0x2722 .L .40B .40B + if (RFIFOREST(fd) < 86) + return 0; + { + struct mmo_account acc; + char actual_email[40]; + char new_email[40]; + + int account_id = RFIFOL(fd,2); + safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40); + safestrncpy(new_email, (char*)RFIFOP(fd,46), 40); + RFIFOSKIP(fd, 86); + + if( e_mail_check(actual_email) == 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else + if( e_mail_check(new_email) == 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else + if( strcmpi(new_email, "a@a.com") == 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else + if( strcmpi(acc.email, actual_email) != 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip); + else { + safestrncpy(acc.email, new_email, 40); + ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip); + // Save + accounts->save(accounts, &acc); + } + } + break; + + case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) + if (RFIFOREST(fd) < 10) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + unsigned int state = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else + if( acc.state == state ) + ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else { + ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); + + acc.state = state; + // Save + accounts->save(accounts, &acc); + + // notify other servers + if (state != 0) { + uint8 buf[11]; + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 0; // 0: change of state, 1: ban + WBUFL(buf,7) = state; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + } + } + break; + + case 0x2725: // Receiving of map-server via char-server a ban request + if (RFIFOREST(fd) < 18) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + int year = (short)RFIFOW(fd,6); + int month = (short)RFIFOW(fd,8); + int mday = (short)RFIFOW(fd,10); + int hour = (short)RFIFOW(fd,12); + int min = (short)RFIFOW(fd,14); + int sec = (short)RFIFOW(fd,16); + RFIFOSKIP(fd,18); + + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else + { + time_t timestamp; + struct tm *tmtime; + if (acc.unban_time == 0 || acc.unban_time < time(NULL)) + timestamp = time(NULL); // new ban + else + timestamp = acc.unban_time; // add to existing ban + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + year; + tmtime->tm_mon = tmtime->tm_mon + month; + tmtime->tm_mday = tmtime->tm_mday + mday; + tmtime->tm_hour = tmtime->tm_hour + hour; + tmtime->tm_min = tmtime->tm_min + min; + tmtime->tm_sec = tmtime->tm_sec + sec; + timestamp = mktime(tmtime); + if (timestamp == -1) + ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); + else + if( timestamp <= time(NULL) || timestamp == 0 ) + ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); + else + { + uint8 buf[11]; + char tmpstr[24]; + timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); + ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); + + acc.unban_time = timestamp; + + // Save + accounts->save(accounts, &acc); + + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 1; // 0: change of status, 1: ban + WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + } + } + break; + + case 0x2727: // Change of sex (sex is reversed) + if( RFIFOREST(fd) < 6 ) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else + if( acc.sex == 'S' ) + ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else + { + unsigned char buf[7]; + char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender + + ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); + + acc.sex = sex; + // Save + accounts->save(accounts, &acc); + + // announce to other servers + WBUFW(buf,0) = 0x2723; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = sex_str2num(sex); + charif_sendallwos(-1, buf, 7); + } + } + break; + + case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. + if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) ) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,4); + + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else + { + int len; + int p; + ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip); + for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ) + { + sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len); + acc.account_reg2[j].str[len]='\0'; + p +=len+1; //+1 to skip the '\0' between strings. + sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len); + acc.account_reg2[j].value[len]='\0'; + p +=len+1; + remove_control_chars(acc.account_reg2[j].str); + remove_control_chars(acc.account_reg2[j].value); + } + acc.account_reg2_num = j; + + // Save + accounts->save(accounts, &acc); + + // Sending information towards the other char-servers. + RFIFOW(fd,0) = 0x2729;// reusing read buffer + charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2)); + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + } + break; + + case 0x272a: // Receiving of map-server via char-server an unban request + if( RFIFOREST(fd) < 6 ) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else + if( acc.unban_time == 0 ) + ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip); + else + { + ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip); + acc.unban_time = 0; + accounts->save(accounts, &acc); + } + } + break; + + case 0x272b: // Set account_id to online [Wizputer] + if( RFIFOREST(fd) < 6 ) + return 0; + add_online_user(id, RFIFOL(fd,2)); + RFIFOSKIP(fd,6); + break; + + case 0x272c: // Set account_id to offline [Wizputer] + if( RFIFOREST(fd) < 6 ) + return 0; + remove_online_user(RFIFOL(fd,2)); + RFIFOSKIP(fd,6); + break; + + case 0x272d: // Receive list of all online accounts. [Skotlex] + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + struct online_login_data *p; + int aid; + uint32 i, users; + online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first + users = RFIFOW(fd,4); + for (i = 0; i < users; i++) { + aid = RFIFOL(fd,6+i*4); + p = idb_ensure(online_db, aid, create_online_user); + p->char_server = id; + if (p->waiting_disconnect != INVALID_TIMER) + { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x272e: //Request account_reg2 for a character. + if (RFIFOREST(fd) < 10) + return 0; + { + struct mmo_account acc; + size_t off; + + int account_id = RFIFOL(fd,2); + int char_id = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg)); + WFIFOW(fd,0) = 0x2729; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = char_id; + WFIFOB(fd,12) = 1; //Type 1 for Account2 registry + + off = 13; + if( accounts->load_num(accounts, &acc, account_id) ) + { + for( j = 0; j < acc.account_reg2_num; j++ ) + { + if( acc.account_reg2[j].str[0] != '\0' ) + { + off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. + off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1; + } + } + } + + WFIFOW(fd,2) = (uint16)off; + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2736: // WAN IP update from char-server + if( RFIFOREST(fd) < 6 ) + return 0; + server[id].ip = ntohl(RFIFOL(fd,2)); + ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + case 0x2737: //Request to set all offline. + ShowInfo("Setting accounts from char-server %d offline.\n", id); + online_db->foreach(online_db, online_db_setoffline, id); + RFIFOSKIP(fd,2); + break; + + default: + ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); + set_eof(fd); + return 0; + } // switch + } // while + + return 0; } //------------------------------------- // Make new account //------------------------------------- -int mmo_auth_new(const char *userid, const char *pass, const char sex, const char *last_ip) -{ - static int num_regs = 0; // registration counter - static unsigned int new_reg_tick = 0; - unsigned int tick = gettick(); - struct mmo_account acc; - - //Account Registration Flood Protection by [Kevin] - if (new_reg_tick == 0) - new_reg_tick = gettick(); - if (DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs) { - ShowNotice("Account registration denied (registration limit exceeded)\n"); - return 3; - } - - if (login_config.new_acc_length_limit && (strlen(userid) < 4 || strlen(pass) < 4)) - return 1; - - // check for invalid inputs - if (sex != 'M' && sex != 'F') - return 0; // 0 = Unregistered ID - - // check if the account doesn't exist already - if (accounts->load_str(accounts, &acc, userid)) { - ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", userid, sex, acc.pass, pass); - return 1; // 1 = Incorrect Password - } - - memset(&acc, '\0', sizeof(acc)); - acc.account_id = -1; // assigned by account db - safestrncpy(acc.userid, userid, sizeof(acc.userid)); - safestrncpy(acc.pass, pass, sizeof(acc.pass)); - acc.sex = sex; - safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); - acc.expiration_time = (login_config.start_limited_time != -1) ? time(NULL) + login_config.start_limited_time : 0; - safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin)); - safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip)); - safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate)); - - if (!accounts->create(accounts, &acc)) - return 0; - - ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", acc.userid, acc.account_id, acc.pass, acc.sex); - - if (DIFF_TICK(tick, new_reg_tick) > 0) { // Update the registration check. - num_regs = 0; - new_reg_tick = tick + time_allowed*1000; - } - ++num_regs; - - return -1; +int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip) { + static int num_regs = 0; // registration counter + static unsigned int new_reg_tick = 0; + unsigned int tick = gettick(); + struct mmo_account acc; + + //Account Registration Flood Protection by [Kevin] + if( new_reg_tick == 0 ) + new_reg_tick = gettick(); + if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) { + ShowNotice("Account registration denied (registration limit exceeded)\n"); + return 3; + } + + if( login_config.new_acc_length_limit && ( strlen(userid) < 4 || strlen(pass) < 4 ) ) + return 1; + + // check for invalid inputs + if( sex != 'M' && sex != 'F' ) + return 0; // 0 = Unregistered ID + + // check if the account doesn't exist already + if( accounts->load_str(accounts, &acc, userid) ) { + ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", userid, sex, acc.pass, pass); + return 1; // 1 = Incorrect Password + } + + memset(&acc, '\0', sizeof(acc)); + acc.account_id = -1; // assigned by account db + safestrncpy(acc.userid, userid, sizeof(acc.userid)); + safestrncpy(acc.pass, pass, sizeof(acc.pass)); + acc.sex = sex; + safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); + acc.expiration_time = ( login_config.start_limited_time != -1 ) ? time(NULL) + login_config.start_limited_time : 0; + safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin)); + safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip)); + safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate)); + + if( !accounts->create(accounts, &acc) ) + return 0; + + ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", acc.userid, acc.account_id, acc.pass, acc.sex); + + if( DIFF_TICK(tick, new_reg_tick) > 0 ) {// Update the registration check. + num_regs = 0; + new_reg_tick = tick + time_allowed*1000; + } + ++num_regs; + + return -1; } //----------------------------------------------------- // Check/authentication of a connection //----------------------------------------------------- -int mmo_auth(struct login_session_data *sd, bool isServer) -{ - struct mmo_account acc; - int len; - - char ip[16]; - ip2str(session[sd->fd]->client_addr, ip); - - // DNS Blacklist check - if (login_config.use_dnsbl) { - char r_ip[16]; - char ip_dnsbl[256]; - char *dnsbl_serv; - uint8 *sin_addr = (uint8 *)&session[sd->fd]->client_addr; - - sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); - - for (dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",")) { - sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); - if (host2ip(ip_dnsbl)) { - ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); - return 3; - } - } - - } - - //Client Version check - if (login_config.check_client_version && sd->version != login_config.client_version_to_connect) - return 5; - - len = strnlen(sd->userid, NAME_LENGTH); - - // Account creation with _M/_F - if (login_config.new_account_flag) { - if (len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths - sd->passwdenc == 0 && // unencoded password - sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4)) { // _M/_F suffix - int result; - - // remove the _M/_F suffix - len -= 2; - sd->userid[len] = '\0'; - - result = mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip); - if (result != -1) - return result;// Failed to make account. [Skotlex]. - } - } - - if (!accounts->load_str(accounts, &acc, sd->userid)) { - ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); - return 0; // 0 = Unregistered ID - } - - if (!check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass)) { - ShowNotice("Invalid password (account: '%s', pass: '%s', received pass: '%s', ip: %s)\n", sd->userid, acc.pass, sd->passwd, ip); - return 1; // 1 = Incorrect Password - } - - if (acc.expiration_time != 0 && acc.expiration_time < time(NULL)) { - ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); - return 2; // 2 = This ID is expired - } - - if (acc.unban_time != 0 && acc.unban_time > time(NULL)) { - char tmpstr[24]; - timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format); - ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); - return 6; // 6 = Your are Prohibited to log in until %s - } - - if (acc.state != 0) { - ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); - return acc.state - 1; - } - - if (login_config.client_hash_check && !isServer) { - struct client_hash_node *node = login_config.client_hash_nodes; - bool match = false; - - if (!sd->has_client_hash) { - ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); - return 5; - } - - while (node) { - if (node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0) { - match = true; - break; - } - - node = node->next; - } - - if (!match) { - char smd5[33]; - int i; - - for (i = 0; i < 16; i++) - sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); - - ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip); - return 5; - } - } - - ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); - - // update session data - sd->account_id = acc.account_id; - sd->login_id1 = rnd(); - sd->login_id2 = rnd(); - safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin)); - sd->sex = acc.sex; - sd->group_id = acc.group_id; - - // update account data - timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S"); - safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip)); - acc.unban_time = 0; - acc.logincount++; - - accounts->save(accounts, &acc); - - if (sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM) - ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); - - return -1; // account OK +int mmo_auth(struct login_session_data* sd, bool isServer) { + struct mmo_account acc; + int len; + + char ip[16]; + ip2str(session[sd->fd]->client_addr, ip); + + // DNS Blacklist check + if( login_config.use_dnsbl ) { + char r_ip[16]; + char ip_dnsbl[256]; + char* dnsbl_serv; + uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr; + + sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); + + for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) { + sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); + if( host2ip(ip_dnsbl) ) { + ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); + return 3; + } + } + + } + + //Client Version check + if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ) + return 5; + + len = strnlen(sd->userid, NAME_LENGTH); + + // Account creation with _M/_F + if( login_config.new_account_flag ) { + if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths + sd->passwdenc == 0 && // unencoded password + sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) ) // _M/_F suffix + { + int result; + + // remove the _M/_F suffix + len -= 2; + sd->userid[len] = '\0'; + + result = mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip); + if( result != -1 ) + return result;// Failed to make account. [Skotlex]. + } + } + + if( !accounts->load_str(accounts, &acc, sd->userid) ) { + ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); + return 0; // 0 = Unregistered ID + } + + if( !check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass) ) { + ShowNotice("Invalid password (account: '%s', pass: '%s', received pass: '%s', ip: %s)\n", sd->userid, acc.pass, sd->passwd, ip); + return 1; // 1 = Incorrect Password + } + + if( acc.expiration_time != 0 && acc.expiration_time < time(NULL) ) { + ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); + return 2; // 2 = This ID is expired + } + + if( acc.unban_time != 0 && acc.unban_time > time(NULL) ) { + char tmpstr[24]; + timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format); + ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); + return 6; // 6 = Your are Prohibited to log in until %s + } + + if( acc.state != 0 ) { + ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + return acc.state - 1; + } + + if( login_config.client_hash_check && !isServer ) { + struct client_hash_node *node = login_config.client_hash_nodes; + bool match = false; + + if( !sd->has_client_hash ) { + ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + return 5; + } + + while( node ) { + if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) { + match = true; + break; + } + + node = node->next; + } + + if( !match ) { + char smd5[33]; + int i; + + for( i = 0; i < 16; i++ ) + sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); + + ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip); + return 5; + } + } + + ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); + + // update session data + sd->account_id = acc.account_id; + sd->login_id1 = rnd(); + sd->login_id2 = rnd(); + safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin)); + sd->sex = acc.sex; + sd->group_id = acc.group_id; + + // update account data + timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S"); + safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip)); + acc.unban_time = 0; + acc.logincount++; + + accounts->save(accounts, &acc); + + if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM ) + ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); + + return -1; // account OK } -void login_auth_ok(struct login_session_data *sd) +void login_auth_ok(struct login_session_data* sd) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - uint8 server_num, n; - uint32 subnet_char_ip; - struct auth_node *node; - int i; - - if (runflag != LOGINSERVER_ST_RUNNING) { - // players can only login while running - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1;// server closed - WFIFOSET(fd,3); - return; - } - - if (login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect) { - ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } else if (login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect) { - ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - server_num = 0; - for (i = 0; i < ARRAYLENGTH(server); ++i) - if (session_isActive(server[i].fd)) - server_num++; - - if (server_num == 0) { - // if no char-server, don't send void list of servers, just disconnect the player with proper message - ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - { - struct online_login_data *data = (struct online_login_data *)idb_get(online_db, sd->account_id); - if (data) { - // account is already marked as online! - if (data->char_server > -1) { - // Request char servers to kick this account out. [Skotlex] - uint8 buf[6]; - ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); - WBUFW(buf,0) = 0x2734; - WBUFL(buf,2) = sd->account_id; - charif_sendallwos(-1, buf, 6); - if (data->waiting_disconnect == INVALID_TIMER) - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login - WFIFOSET(fd,3); - return; - } else if (data->char_server == -1) { - // client has authed but did not access char-server yet - // wipe previous session - idb_remove(auth_db, sd->account_id); - remove_online_user(sd->account_id); - data = NULL; - } - } - } - - login_log(ip, sd->userid, 100, "login ok"); - ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); - - WFIFOHEAD(fd,47+32*server_num); - WFIFOW(fd,0) = 0x69; - WFIFOW(fd,2) = 47+32*server_num; - WFIFOL(fd,4) = sd->login_id1; - WFIFOL(fd,8) = sd->account_id; - WFIFOL(fd,12) = sd->login_id2; - WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) - //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) - memset(WFIFOP(fd,20), 0, 24); - WFIFOW(fd,44) = 0; // unknown - WFIFOB(fd,46) = sex_str2num(sd->sex); - for (i = 0, n = 0; i < ARRAYLENGTH(server); ++i) { - if (!session_isValid(server[i].fd)) - continue; - - subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] - WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); - WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); - WFIFOW(fd,47+n*32+26) = server[i].users; - WFIFOW(fd,47+n*32+28) = server[i].type; - WFIFOW(fd,47+n*32+30) = server[i].new_; - n++; - } - WFIFOSET(fd,47+32*server_num); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->ip = ip; - node->version = sd->version; - node->clienttype = sd->clienttype; - idb_put(auth_db, sd->account_id, node); - - { - struct online_login_data *data; - - // mark client as 'online' - data = add_online_user(-1, sd->account_id); - - // schedule deletion of this node - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - } + int fd = sd->fd; + uint32 ip = session[fd]->client_addr; + + uint8 server_num, n; + uint32 subnet_char_ip; + struct auth_node* node; + int i; + + if( runflag != LOGINSERVER_ST_RUNNING ) + { + // players can only login while running + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1;// server closed + WFIFOSET(fd,3); + return; + } + + if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect ) { + ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } else if( login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect ) { + ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + server_num = 0; + for( i = 0; i < ARRAYLENGTH(server); ++i ) + if( session_isActive(server[i].fd) ) + server_num++; + + if( server_num == 0 ) + {// if no char-server, don't send void list of servers, just disconnect the player with proper message + ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + { + struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); + if( data ) + {// account is already marked as online! + if( data->char_server > -1 ) + {// Request char servers to kick this account out. [Skotlex] + uint8 buf[6]; + ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); + WBUFW(buf,0) = 0x2734; + WBUFL(buf,2) = sd->account_id; + charif_sendallwos(-1, buf, 6); + if( data->waiting_disconnect == INVALID_TIMER ) + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login + WFIFOSET(fd,3); + return; + } + else + if( data->char_server == -1 ) + {// client has authed but did not access char-server yet + // wipe previous session + idb_remove(auth_db, sd->account_id); + remove_online_user(sd->account_id); + data = NULL; + } + } + } + + login_log(ip, sd->userid, 100, "login ok"); + ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); + + WFIFOHEAD(fd,47+32*server_num); + WFIFOW(fd,0) = 0x69; + WFIFOW(fd,2) = 47+32*server_num; + WFIFOL(fd,4) = sd->login_id1; + WFIFOL(fd,8) = sd->account_id; + WFIFOL(fd,12) = sd->login_id2; + WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) + //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) + memset(WFIFOP(fd,20), 0, 24); + WFIFOW(fd,44) = 0; // unknown + WFIFOB(fd,46) = sex_str2num(sd->sex); + for( i = 0, n = 0; i < ARRAYLENGTH(server); ++i ) + { + if( !session_isValid(server[i].fd) ) + continue; + + subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] + WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); + WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); + WFIFOW(fd,47+n*32+26) = server[i].users; + WFIFOW(fd,47+n*32+28) = server[i].type; + WFIFOW(fd,47+n*32+30) = server[i].new_; + n++; + } + WFIFOSET(fd,47+32*server_num); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->ip = ip; + node->version = sd->version; + node->clienttype = sd->clienttype; + idb_put(auth_db, sd->account_id, node); + + { + struct online_login_data* data; + + // mark client as 'online' + data = add_online_user(-1, sd->account_id); + + // schedule deletion of this node + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + } } -void login_auth_failed(struct login_session_data *sd, int result) +void login_auth_failed(struct login_session_data* sd, int result) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - if (login_config.log_login) { - const char *error; - switch (result) { - case 0: - error = "Unregistered ID."; - break; // 0 = Unregistered ID - case 1: - error = "Incorrect Password."; - break; // 1 = Incorrect Password - case 2: - error = "Account Expired."; - break; // 2 = This ID is expired - case 3: - error = "Rejected from server."; - break; // 3 = Rejected from Server - case 4: - error = "Blocked by GM."; - break; // 4 = You have been blocked by the GM Team - case 5: - error = "Not latest game EXE."; - break; // 5 = Your Game's EXE file is not the latest version - case 6: - error = "Banned."; - break; // 6 = Your are Prohibited to log in until %s - case 7: - error = "Server Over-population."; - break; // 7 = Server is jammed due to over populated - case 8: - error = "Account limit from company"; - break; // 8 = No more accounts may be connected from this company - case 9: - error = "Ban by DBA"; - break; // 9 = MSI_REFUSE_BAN_BY_DBA - case 10: - error = "Email not confirmed"; - break; // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED - case 11: - error = "Ban by GM"; - break; // 11 = MSI_REFUSE_BAN_BY_GM - case 12: - error = "Working in DB"; - break; // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK - case 13: - error = "Self Lock"; - break; // 13 = MSI_REFUSE_SELF_LOCK - case 14: - error = "Not Permitted Group"; - break; // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP - case 15: - error = "Not Permitted Group"; - break; // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP - case 99: - error = "Account gone."; - break; // 99 = This ID has been totally erased - case 100: - error = "Login info remains."; - break; // 100 = Login information remains at %s - case 101: - error = "Hacking investigation."; - break; // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information - case 102: - error = "Bug investigation."; - break; // 102 = This account has been temporarily prohibited from login due to a bug-related investigation - case 103: - error = "Deleting char."; - break; // 103 = This character is being deleted. Login is temporarily unavailable for the time being - case 104: - error = "Deleting spouse char."; - break; // 104 = This character is being deleted. Login is temporarily unavailable for the time being - default : - error = "Unknown Error."; - break; - } - - login_log(ip, sd->userid, result, error); - } - - if (result == 1 && login_config.dynamic_pass_failure_ban) - ipban_log(ip); // log failed password attempt - - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = (uint8)result; - if (result != 6) - memset(WFIFOP(fd,3), '\0', 20); - else { - // 6 = Your are Prohibited to log in until %s - struct mmo_account acc; - time_t unban_time = (accounts->load_str(accounts, &acc, sd->userid)) ? acc.unban_time : 0; - timestamp2string((char *)WFIFOP(fd,3), 20, unban_time, login_config.date_format); - } - WFIFOSET(fd,23); + int fd = sd->fd; + uint32 ip = session[fd]->client_addr; + + if (login_config.log_login) + { + const char* error; + switch( result ) { + case 0: error = "Unregistered ID."; break; // 0 = Unregistered ID + case 1: error = "Incorrect Password."; break; // 1 = Incorrect Password + case 2: error = "Account Expired."; break; // 2 = This ID is expired + case 3: error = "Rejected from server."; break; // 3 = Rejected from Server + case 4: error = "Blocked by GM."; break; // 4 = You have been blocked by the GM Team + case 5: error = "Not latest game EXE."; break; // 5 = Your Game's EXE file is not the latest version + case 6: error = "Banned."; break; // 6 = Your are Prohibited to log in until %s + case 7: error = "Server Over-population."; break; // 7 = Server is jammed due to over populated + case 8: error = "Account limit from company"; break; // 8 = No more accounts may be connected from this company + case 9: error = "Ban by DBA"; break; // 9 = MSI_REFUSE_BAN_BY_DBA + case 10: error = "Email not confirmed"; break; // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED + case 11: error = "Ban by GM"; break; // 11 = MSI_REFUSE_BAN_BY_GM + case 12: error = "Working in DB"; break; // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK + case 13: error = "Self Lock"; break; // 13 = MSI_REFUSE_SELF_LOCK + case 14: error = "Not Permitted Group"; break; // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP + case 15: error = "Not Permitted Group"; break; // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP + case 99: error = "Account gone."; break; // 99 = This ID has been totally erased + case 100: error = "Login info remains."; break; // 100 = Login information remains at %s + case 101: error = "Hacking investigation."; break; // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information + case 102: error = "Bug investigation."; break; // 102 = This account has been temporarily prohibited from login due to a bug-related investigation + case 103: error = "Deleting char."; break; // 103 = This character is being deleted. Login is temporarily unavailable for the time being + case 104: error = "Deleting spouse char."; break; // 104 = This character is being deleted. Login is temporarily unavailable for the time being + default : error = "Unknown Error."; break; + } + + login_log(ip, sd->userid, result, error); + } + + if( result == 1 && login_config.dynamic_pass_failure_ban ) + ipban_log(ip); // log failed password attempt + + WFIFOHEAD(fd,23); + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = (uint8)result; + if( result != 6 ) + memset(WFIFOP(fd,3), '\0', 20); + else + {// 6 = Your are Prohibited to log in until %s + struct mmo_account acc; + time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0; + timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format); + } + WFIFOSET(fd,23); } @@ -1294,400 +1298,428 @@ void login_auth_failed(struct login_session_data *sd, int result) //---------------------------------------------------------------------------------------- int parse_login(int fd) { - struct login_session_data *sd = (struct login_session_data *)session[fd]->session_data; - int result; - - char ip[16]; - uint32 ipl = session[fd]->client_addr; - ip2str(ipl, ip); - - if (session[fd]->flag.eof) { - ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); - do_close(fd); - return 0; - } - - if (sd == NULL) { - // Perform ip-ban check - if (login_config.ipban && ipban_check(ipl)) { - ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip); - login_log(ipl, "unknown", -3, "ip banned"); - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = 3; // 3 = Rejected from Server - WFIFOSET(fd,23); - set_eof(fd); - return 0; - } - - // create a session for this new connection - CREATE(session[fd]->session_data, struct login_session_data, 1); - sd = (struct login_session_data *)session[fd]->session_data; - sd->fd = fd; - } - - while (RFIFOREST(fd) >= 2) { - uint16 command = RFIFOW(fd,0); - - switch (command) { - - case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. - if (RFIFOREST(fd) < 26) - return 0; - RFIFOSKIP(fd,26); - break; - - // client md5 hash (binary) - case 0x0204: // S 0204 .16B (kRO 2004-05-31aSakexe langtype 0 and 6) - if (RFIFOREST(fd) < 18) - return 0; - - sd->has_client_hash = 1; - memcpy(sd->client_hash, RFIFOP(fd, 2), 16); - - RFIFOSKIP(fd,18); - break; - - // request client login (raw password) - case 0x0064: // S 0064 .L .24B .24B .B - case 0x0277: // S 0277 .L .24B .24B .B .16B .13B - case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B - // request client login (md5-hashed password) - case 0x01dd: // S 01dd .L .24B .16B .B - case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - case 0x027c: // S 027c .L .24B .16B .B .13B(junk) - case 0x0825: { // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B - size_t packet_len = RFIFOREST(fd); - - if ((command == 0x0064 && packet_len < 55) - || (command == 0x0277 && packet_len < 84) - || (command == 0x02b0 && packet_len < 85) - || (command == 0x01dd && packet_len < 47) - || (command == 0x01fa && packet_len < 48) - || (command == 0x027c && packet_len < 60) - || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2)))) - return 0; - } - { - uint32 version; - char username[NAME_LENGTH]; - char password[NAME_LENGTH]; - unsigned char passhash[16]; - uint8 clienttype; - bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); - - // Shinryo: For the time being, just use token as password. - if (command == 0x0825) { - char *accname = (char *)RFIFOP(fd, 9); - char *token = (char *)RFIFOP(fd, 0x5C); - size_t uAccLen = strlen(accname); - size_t uTokenLen = RFIFOREST(fd) - 0x5C; - - version = RFIFOL(fd,4); - - if (uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen <= 0) { - login_auth_failed(sd, 3); - return 0; - } - - safestrncpy(username, accname, uAccLen + 1); - safestrncpy(password, token, uTokenLen + 1); - clienttype = RFIFOB(fd, 8); - } else { - version = RFIFOL(fd,2); - safestrncpy(username, (const char *)RFIFOP(fd,6), NAME_LENGTH); - if (israwpass) { - safestrncpy(password, (const char *)RFIFOP(fd,30), NAME_LENGTH); - clienttype = RFIFOB(fd,54); - } else { - memcpy(passhash, RFIFOP(fd,30), 16); - clienttype = RFIFOB(fd,46); - } - } - RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent - - sd->clienttype = clienttype; - sd->version = version; - safestrncpy(sd->userid, username, NAME_LENGTH); - if (israwpass) { - ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); - safestrncpy(sd->passwd, password, NAME_LENGTH); - if (login_config.use_md5_passwds) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = 0; - } else { - ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s).\n", sd->userid, ip); - bin2hex(sd->passwd, passhash, 16); // raw binary data here! - sd->passwdenc = PASSWORDENC; - } - - if (sd->passwdenc != 0 && login_config.use_md5_passwds) { - login_auth_failed(sd, 3); // send "rejected from server" - return 0; - } - - result = mmo_auth(sd, false); - - if (result == -1) - login_auth_ok(sd); - else - login_auth_failed(sd, result); - } - break; - - case 0x01db: // Sending request of the coding key - RFIFOSKIP(fd,2); - { - memset(sd->md5key, '\0', sizeof(sd->md5key)); - sd->md5keylen = (uint16)(12 + rnd() % 4); - MD5_Salt(sd->md5keylen, sd->md5key); - - WFIFOHEAD(fd,4 + sd->md5keylen); - WFIFOW(fd,0) = 0x01dc; - WFIFOW(fd,2) = 4 + sd->md5keylen; - memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST(fd) < 86) - return 0; - { - char server_name[20]; - char message[256]; - uint32 server_ip; - uint16 server_port; - uint16 type; - uint16 new_; - - safestrncpy(sd->userid, (char *)RFIFOP(fd,2), NAME_LENGTH); - safestrncpy(sd->passwd, (char *)RFIFOP(fd,26), NAME_LENGTH); - if (login_config.use_md5_passwds) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = 0; - sd->version = login_config.client_version_to_connect; // hack to skip version check - server_ip = ntohl(RFIFOL(fd,54)); - server_port = ntohs(RFIFOW(fd,58)); - safestrncpy(server_name, (char *)RFIFOP(fd,60), 20); - type = RFIFOW(fd,82); - new_ = RFIFOW(fd,84); - RFIFOSKIP(fd,86); - - ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); - sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); - login_log(session[fd]->client_addr, sd->userid, 100, message); - - result = mmo_auth(sd, true); - if (runflag == LOGINSERVER_ST_RUNNING && - result == -1 && - sd->sex == 'S' && - sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) && - !session_isValid(server[sd->account_id].fd)) { - ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); - safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); - server[sd->account_id].fd = fd; - server[sd->account_id].ip = server_ip; - server[sd->account_id].port = server_port; - server[sd->account_id].users = 0; - server[sd->account_id].type = type; - server[sd->account_id].new_ = new_; - - session[fd]->func_parse = parse_fromchar; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - // send connection success - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } else { - ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } - } - return 0; // processing will continue elsewhere - - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); - set_eof(fd); - return 0; - } - } - - return 0; + struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data; + int result; + + char ip[16]; + uint32 ipl = session[fd]->client_addr; + ip2str(ipl, ip); + + if( session[fd]->flag.eof ) + { + ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); + do_close(fd); + return 0; + } + + if( sd == NULL ) + { + // Perform ip-ban check + if( login_config.ipban && ipban_check(ipl) ) + { + ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip); + login_log(ipl, "unknown", -3, "ip banned"); + WFIFOHEAD(fd,23); + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = 3; // 3 = Rejected from Server + WFIFOSET(fd,23); + set_eof(fd); + return 0; + } + + // create a session for this new connection + CREATE(session[fd]->session_data, struct login_session_data, 1); + sd = (struct login_session_data*)session[fd]->session_data; + sd->fd = fd; + } + + while( RFIFOREST(fd) >= 2 ) + { + uint16 command = RFIFOW(fd,0); + + switch( command ) + { + + case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. + if (RFIFOREST(fd) < 26) + return 0; + RFIFOSKIP(fd,26); + break; + + // client md5 hash (binary) + case 0x0204: // S 0204 .16B (kRO 2004-05-31aSakexe langtype 0 and 6) + if (RFIFOREST(fd) < 18) + return 0; + + sd->has_client_hash = 1; + memcpy(sd->client_hash, RFIFOP(fd, 2), 16); + + RFIFOSKIP(fd,18); + break; + + // request client login (raw password) + case 0x0064: // S 0064 .L .24B .24B .B + case 0x0277: // S 0277 .L .24B .24B .B .16B .13B + case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B + // request client login (md5-hashed password) + case 0x01dd: // S 01dd .L .24B .16B .B + case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) + case 0x027c: // S 027c .L .24B .16B .B .13B(junk) + case 0x0825: // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B + { + size_t packet_len = RFIFOREST(fd); + + if( (command == 0x0064 && packet_len < 55) + || (command == 0x0277 && packet_len < 84) + || (command == 0x02b0 && packet_len < 85) + || (command == 0x01dd && packet_len < 47) + || (command == 0x01fa && packet_len < 48) + || (command == 0x027c && packet_len < 60) + || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) ) + return 0; + } + { + uint32 version; + char username[NAME_LENGTH]; + char password[NAME_LENGTH]; + unsigned char passhash[16]; + uint8 clienttype; + bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); + + // Shinryo: For the time being, just use token as password. + if(command == 0x0825) + { + char *accname = (char *)RFIFOP(fd, 9); + char *token = (char *)RFIFOP(fd, 0x5C); + size_t uAccLen = strlen(accname); + size_t uTokenLen = RFIFOREST(fd) - 0x5C; + + version = RFIFOL(fd,4); + + if(uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen <= 0) + { + login_auth_failed(sd, 3); + return 0; + } + + safestrncpy(username, accname, uAccLen + 1); + safestrncpy(password, token, uTokenLen + 1); + clienttype = RFIFOB(fd, 8); + } + else + { + version = RFIFOL(fd,2); + safestrncpy(username, (const char*)RFIFOP(fd,6), NAME_LENGTH); + if( israwpass ) + { + safestrncpy(password, (const char*)RFIFOP(fd,30), NAME_LENGTH); + clienttype = RFIFOB(fd,54); + } + else + { + memcpy(passhash, RFIFOP(fd,30), 16); + clienttype = RFIFOB(fd,46); + } + } + RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent + + sd->clienttype = clienttype; + sd->version = version; + safestrncpy(sd->userid, username, NAME_LENGTH); + if( israwpass ) + { + ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); + safestrncpy(sd->passwd, password, NAME_LENGTH); + if( login_config.use_md5_passwds ) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = 0; + } + else + { + ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s).\n", sd->userid, ip); + bin2hex(sd->passwd, passhash, 16); // raw binary data here! + sd->passwdenc = PASSWORDENC; + } + + if( sd->passwdenc != 0 && login_config.use_md5_passwds ) + { + login_auth_failed(sd, 3); // send "rejected from server" + return 0; + } + + result = mmo_auth(sd, false); + + if( result == -1 ) + login_auth_ok(sd); + else + login_auth_failed(sd, result); + } + break; + + case 0x01db: // Sending request of the coding key + RFIFOSKIP(fd,2); + { + memset(sd->md5key, '\0', sizeof(sd->md5key)); + sd->md5keylen = (uint16)(12 + rnd() % 4); + MD5_Salt(sd->md5keylen, sd->md5key); + + WFIFOHEAD(fd,4 + sd->md5keylen); + WFIFOW(fd,0) = 0x01dc; + WFIFOW(fd,2) = 4 + sd->md5keylen; + memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2710: // Connection request of a char-server + if (RFIFOREST(fd) < 86) + return 0; + { + char server_name[20]; + char message[256]; + uint32 server_ip; + uint16 server_port; + uint16 type; + uint16 new_; + + safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH); + safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH); + if( login_config.use_md5_passwds ) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = 0; + sd->version = login_config.client_version_to_connect; // hack to skip version check + server_ip = ntohl(RFIFOL(fd,54)); + server_port = ntohs(RFIFOW(fd,58)); + safestrncpy(server_name, (char*)RFIFOP(fd,60), 20); + type = RFIFOW(fd,82); + new_ = RFIFOW(fd,84); + RFIFOSKIP(fd,86); + + ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); + sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); + login_log(session[fd]->client_addr, sd->userid, 100, message); + + result = mmo_auth(sd, true); + if( runflag == LOGINSERVER_ST_RUNNING && + result == -1 && + sd->sex == 'S' && + sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) && + !session_isValid(server[sd->account_id].fd) ) + { + ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); + safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); + server[sd->account_id].fd = fd; + server[sd->account_id].ip = server_ip; + server[sd->account_id].port = server_port; + server[sd->account_id].users = 0; + server[sd->account_id].type = type; + server[sd->account_id].new_ = new_; + + session[fd]->func_parse = parse_fromchar; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + // send connection success + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + } + else + { + ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } + } + return 0; // processing will continue elsewhere + + default: + ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); + set_eof(fd); + return 0; + } + } + + return 0; } void login_set_defaults() { - login_config.login_ip = INADDR_ANY; - login_config.login_port = 6900; - login_config.ipban_cleanup_interval = 60; - login_config.ip_sync_interval = 0; - login_config.log_login = true; - safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); - login_config.console = false; - login_config.new_account_flag = true; - login_config.new_acc_length_limit = true; - login_config.use_md5_passwds = false; - login_config.group_id_to_connect = -1; - login_config.min_group_id_to_connect = -1; - login_config.check_client_version = false; - login_config.client_version_to_connect = 20; - - login_config.ipban = true; - login_config.dynamic_pass_failure_ban = true; - login_config.dynamic_pass_failure_ban_interval = 5; - login_config.dynamic_pass_failure_ban_limit = 7; - login_config.dynamic_pass_failure_ban_duration = 5; - login_config.use_dnsbl = false; - safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); - safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); - - login_config.client_hash_check = 0; - login_config.client_hash_nodes = NULL; + login_config.login_ip = INADDR_ANY; + login_config.login_port = 6900; + login_config.ipban_cleanup_interval = 60; + login_config.ip_sync_interval = 0; + login_config.log_login = true; + safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); + login_config.console = false; + login_config.new_account_flag = true; + login_config.new_acc_length_limit = true; + login_config.use_md5_passwds = false; + login_config.group_id_to_connect = -1; + login_config.min_group_id_to_connect = -1; + login_config.check_client_version = false; + login_config.client_version_to_connect = 20; + + login_config.ipban = true; + login_config.dynamic_pass_failure_ban = true; + login_config.dynamic_pass_failure_ban_interval = 5; + login_config.dynamic_pass_failure_ban_limit = 7; + login_config.dynamic_pass_failure_ban_duration = 5; + login_config.use_dnsbl = false; + safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); + safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); + + login_config.client_hash_check = 0; + login_config.client_hash_nodes = NULL; } //----------------------------------- // Reading main configuration file //----------------------------------- -int login_config_read(const char *cfgName) +int login_config_read(const char* cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("Configuration file (%s) not found.\n", cfgName); - return 1; - } - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) - continue; - - if (!strcmpi(w1,"timestamp_format")) - strncpy(timestamp_format, w2, 20); - else if (!strcmpi(w1,"stdout_with_ansisequence")) - stdout_with_ansisequence = config_switch(w2); - else if (!strcmpi(w1,"console_silent")) { - msg_silent = atoi(w2); - if (msg_silent) /* only bother if we actually have this enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } else if (!strcmpi(w1, "bind_ip")) { - char ip_str[16]; - login_config.login_ip = host2ip(w2); - if (login_config.login_ip) - ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); - } else if (!strcmpi(w1, "login_port")) { - login_config.login_port = (uint16)atoi(w2); - } else if (!strcmpi(w1, "log_login")) - login_config.log_login = (bool)config_switch(w2); - - else if (!strcmpi(w1, "new_account")) - login_config.new_account_flag = (bool)config_switch(w2); - else if (!strcmpi(w1, "new_acc_length_limit")) - login_config.new_acc_length_limit = (bool)config_switch(w2); - else if (!strcmpi(w1, "start_limited_time")) - login_config.start_limited_time = atoi(w2); - else if (!strcmpi(w1, "check_client_version")) - login_config.check_client_version = (bool)config_switch(w2); - else if (!strcmpi(w1, "client_version_to_connect")) - login_config.client_version_to_connect = strtoul(w2, NULL, 10); - else if (!strcmpi(w1, "use_MD5_passwords")) - login_config.use_md5_passwds = (bool)config_switch(w2); - else if (!strcmpi(w1, "group_id_to_connect")) - login_config.group_id_to_connect = atoi(w2); - else if (!strcmpi(w1, "min_group_id_to_connect")) - login_config.min_group_id_to_connect = atoi(w2); - else if (!strcmpi(w1, "date_format")) - safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); - else if (!strcmpi(w1, "console")) - login_config.console = (bool)config_switch(w2); - else if (!strcmpi(w1, "allowed_regs")) //account flood protection system - allowed_regs = atoi(w2); - else if (!strcmpi(w1, "time_allowed")) - time_allowed = atoi(w2); - else if (!strcmpi(w1, "use_dnsbl")) - login_config.use_dnsbl = (bool)config_switch(w2); - else if (!strcmpi(w1, "dnsbl_servers")) - safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); - else if (!strcmpi(w1, "ipban_cleanup_interval")) - login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); - else if (!strcmpi(w1, "ip_sync_interval")) - login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. - else if (!strcmpi(w1, "client_hash_check")) - login_config.client_hash_check = config_switch(w2); - else if (!strcmpi(w1, "client_hash")) { - int group = 0; - char md5[33]; - int i; - - if (sscanf(w2, "%d, %32s", &group, md5) == 2) { - struct client_hash_node *nnode; - CREATE(nnode, struct client_hash_node, 1); - - for (i = 0; i < 32; i += 2) { - char buf[3]; - unsigned int byte; - - memcpy(buf, &md5[i], 2); - buf[2] = 0; - - sscanf(buf, "%x", &byte); - nnode->hash[i / 2] = (uint8)(byte & 0xFF); - } - - nnode->group_id = group; - nnode->next = login_config.client_hash_nodes; - - login_config.client_hash_nodes = nnode; - } - } else if (!strcmpi(w1, "import")) - login_config_read(w2); - else if (!strcmpi(w1, "account.engine")) - safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine)); - else { - // try the account engines - int i; - for (i = 0; account_engines[i].constructor; ++i) { - AccountDB *db = account_engines[i].db; - if (db && db->set_property(db, w1, w2)) - break; - } - // try others - ipban_config_read(w1, w2); - loginlog_config_read(w1, w2); - } - } - fclose(fp); - ShowInfo("Finished reading %s.\n", cfgName); - return 0; + char line[1024], w1[1024], w2[1024]; + FILE* fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("Configuration file (%s) not found.\n", cfgName); + return 1; + } + while(fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) + continue; + + if(!strcmpi(w1,"timestamp_format")) + strncpy(timestamp_format, w2, 20); + else if(!strcmpi(w1,"stdout_with_ansisequence")) + stdout_with_ansisequence = config_switch(w2); + else if(!strcmpi(w1,"console_silent")) { + msg_silent = atoi(w2); + if( msg_silent ) /* only bother if we actually have this enabled */ + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + } + else if( !strcmpi(w1, "bind_ip") ) { + char ip_str[16]; + login_config.login_ip = host2ip(w2); + if( login_config.login_ip ) + ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); + } + else if( !strcmpi(w1, "login_port") ) { + login_config.login_port = (uint16)atoi(w2); + } + else if(!strcmpi(w1, "log_login")) + login_config.log_login = (bool)config_switch(w2); + + else if(!strcmpi(w1, "new_account")) + login_config.new_account_flag = (bool)config_switch(w2); + else if(!strcmpi(w1, "new_acc_length_limit")) + login_config.new_acc_length_limit = (bool)config_switch(w2); + else if(!strcmpi(w1, "start_limited_time")) + login_config.start_limited_time = atoi(w2); + else if(!strcmpi(w1, "check_client_version")) + login_config.check_client_version = (bool)config_switch(w2); + else if(!strcmpi(w1, "client_version_to_connect")) + login_config.client_version_to_connect = strtoul(w2, NULL, 10); + else if(!strcmpi(w1, "use_MD5_passwords")) + login_config.use_md5_passwds = (bool)config_switch(w2); + else if(!strcmpi(w1, "group_id_to_connect")) + login_config.group_id_to_connect = atoi(w2); + else if(!strcmpi(w1, "min_group_id_to_connect")) + login_config.min_group_id_to_connect = atoi(w2); + else if(!strcmpi(w1, "date_format")) + safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); + else if(!strcmpi(w1, "console")) + login_config.console = (bool)config_switch(w2); + else if(!strcmpi(w1, "allowed_regs")) //account flood protection system + allowed_regs = atoi(w2); + else if(!strcmpi(w1, "time_allowed")) + time_allowed = atoi(w2); + else if(!strcmpi(w1, "use_dnsbl")) + login_config.use_dnsbl = (bool)config_switch(w2); + else if(!strcmpi(w1, "dnsbl_servers")) + safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); + else if(!strcmpi(w1, "ipban_cleanup_interval")) + login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); + else if(!strcmpi(w1, "ip_sync_interval")) + login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. + else if(!strcmpi(w1, "client_hash_check")) + login_config.client_hash_check = config_switch(w2); + else if(!strcmpi(w1, "client_hash")) { + int group = 0; + char md5[33]; + int i; + + if (sscanf(w2, "%d, %32s", &group, md5) == 2) { + struct client_hash_node *nnode; + CREATE(nnode, struct client_hash_node, 1); + + for (i = 0; i < 32; i += 2) { + char buf[3]; + unsigned int byte; + + memcpy(buf, &md5[i], 2); + buf[2] = 0; + + sscanf(buf, "%x", &byte); + nnode->hash[i / 2] = (uint8)(byte & 0xFF); + } + + nnode->group_id = group; + nnode->next = login_config.client_hash_nodes; + + login_config.client_hash_nodes = nnode; + } + } + else if(!strcmpi(w1, "import")) + login_config_read(w2); + else + if(!strcmpi(w1, "account.engine")) + safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine)); + else + {// try the account engines + int i; + for( i = 0; account_engines[i].constructor; ++i ) + { + AccountDB* db = account_engines[i].db; + if( db && db->set_property(db, w1, w2) ) + break; + } + // try others + ipban_config_read(w1, w2); + loginlog_config_read(w1, w2); + } + } + fclose(fp); + ShowInfo("Finished reading %s.\n", cfgName); + return 0; } /// Get the engine selected in the config settings. /// Updates the config setting with the selected engine if 'auto'. -static AccountDB *get_account_engine(void) +static AccountDB* get_account_engine(void) { - int i; - bool get_first = (strcmp(login_config.account_engine,"auto") == 0); - - for (i = 0; account_engines[i].constructor; ++i) { - char name[sizeof(login_config.account_engine)]; - AccountDB *db = account_engines[i].db; - if (db && db->get_property(db, "engine.name", name, sizeof(name)) && - (get_first || strcmp(name, login_config.account_engine) == 0)) { - if (get_first) - safestrncpy(login_config.account_engine, name, sizeof(login_config.account_engine)); - return db; - } - } - return NULL; + int i; + bool get_first = (strcmp(login_config.account_engine,"auto") == 0); + + for( i = 0; account_engines[i].constructor; ++i ) + { + char name[sizeof(login_config.account_engine)]; + AccountDB* db = account_engines[i].db; + if( db && db->get_property(db, "engine.name", name, sizeof(name)) && + (get_first || strcmp(name, login_config.account_engine) == 0) ) + { + if( get_first ) + safestrncpy(login_config.account_engine, name, sizeof(login_config.account_engine)); + return db; + } + } + return NULL; } //-------------------------------------- @@ -1695,44 +1727,47 @@ static AccountDB *get_account_engine(void) //-------------------------------------- void do_final(void) { - int i; - struct client_hash_node *hn = login_config.client_hash_nodes; - - while (hn) { - struct client_hash_node *tmp = hn; - hn = hn->next; - aFree(tmp); - } - - login_log(0, "login server", 100, "login server shutdown"); - ShowStatus("Terminating...\n"); - - if (login_config.log_login) - loginlog_final(); - - ipban_final(); - - for (i = 0; account_engines[i].constructor; ++i) { - // destroy all account engines - AccountDB *db = account_engines[i].db; - if (db) { - db->destroy(db); - account_engines[i].db = NULL; - } - } - accounts = NULL; // destroyed in account_engines - online_db->destroy(online_db, NULL); - auth_db->destroy(auth_db, NULL); - - for (i = 0; i < ARRAYLENGTH(server); ++i) - chrif_server_destroy(i); - - if (login_fd != -1) { - do_close(login_fd); - login_fd = -1; - } - - ShowStatus("Finished.\n"); + int i; + struct client_hash_node *hn = login_config.client_hash_nodes; + + while (hn) + { + struct client_hash_node *tmp = hn; + hn = hn->next; + aFree(tmp); + } + + login_log(0, "login server", 100, "login server shutdown"); + ShowStatus("Terminating...\n"); + + if( login_config.log_login ) + loginlog_final(); + + ipban_final(); + + for( i = 0; account_engines[i].constructor; ++i ) + {// destroy all account engines + AccountDB* db = account_engines[i].db; + if( db ) + { + db->destroy(db); + account_engines[i].db = NULL; + } + } + accounts = NULL; // destroyed in account_engines + online_db->destroy(online_db, NULL); + auth_db->destroy(auth_db, NULL); + + for( i = 0; i < ARRAYLENGTH(server); ++i ) + chrif_server_destroy(i); + + if( login_fd != -1 ) + { + do_close(login_fd); + login_fd = -1; + } + + ShowStatus("Finished.\n"); } //------------------------------ @@ -1745,101 +1780,104 @@ void do_abort(void) void set_server_type(void) { - SERVER_TYPE = ATHENA_SERVER_LOGIN; + SERVER_TYPE = ATHENA_SERVER_LOGIN; } /// Called when a terminate signal is received. void do_shutdown(void) { - if (runflag != LOGINSERVER_ST_SHUTDOWN) { - int id; - runflag = LOGINSERVER_ST_SHUTDOWN; - ShowStatus("Shutting down...\n"); - // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS] - for (id = 0; id < ARRAYLENGTH(server); ++id) - chrif_server_reset(id); - flush_fifos(); - runflag = CORE_ST_STOP; - } + if( runflag != LOGINSERVER_ST_SHUTDOWN ) + { + int id; + runflag = LOGINSERVER_ST_SHUTDOWN; + ShowStatus("Shutting down...\n"); + // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS] + for( id = 0; id < ARRAYLENGTH(server); ++id ) + chrif_server_reset(id); + flush_fifos(); + runflag = CORE_ST_STOP; + } } //------------------------------ // Login server initialization //------------------------------ -int do_init(int argc, char **argv) +int do_init(int argc, char** argv) { - int i; - - // intialize engines (to accept config settings) - for (i = 0; account_engines[i].constructor; ++i) - account_engines[i].db = account_engines[i].constructor(); - - // read login-server configuration - login_set_defaults(); - login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); - login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); - - rnd_init(); - - for (i = 0; i < ARRAYLENGTH(server); ++i) - chrif_server_init(i); - - // initialize logging - if (login_config.log_login) - loginlog_init(); - - // initialize static and dynamic ipban system - ipban_init(); - - // Online user database init - online_db = idb_alloc(DB_OPT_RELEASE_DATA); - add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); - - // Interserver auth init - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - - // set default parser as parse_login function - set_defaultparse(parse_login); - - // every 10 minutes cleanup online account db. - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); - - // add timer to detect ip address change and perform update - if (login_config.ip_sync_interval) { - add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); - add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); - } - - // Account database init - accounts = get_account_engine(); - if (accounts == NULL) { - ShowFatalError("do_init: account engine '%s' not found.\n", login_config.account_engine); - exit(EXIT_FAILURE); - } else { - - if (!accounts->init(accounts)) { - ShowFatalError("do_init: Failed to initialize account engine '%s'.\n", login_config.account_engine); - exit(EXIT_FAILURE); - } - } - - if (login_config.console) { - //##TODO invoke a CONSOLE_START plugin event - } - - // server port open & binding - login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); - - if (runflag != CORE_ST_STOP) { - shutdown_callback = do_shutdown; - runflag = LOGINSERVER_ST_RUNNING; - } - - ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); - login_log(0, "login server", 100, "login server started"); - - return 0; + int i; + + // intialize engines (to accept config settings) + for( i = 0; account_engines[i].constructor; ++i ) + account_engines[i].db = account_engines[i].constructor(); + + // read login-server configuration + login_set_defaults(); + login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); + login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); + + rnd_init(); + + for( i = 0; i < ARRAYLENGTH(server); ++i ) + chrif_server_init(i); + + // initialize logging + if( login_config.log_login ) + loginlog_init(); + + // initialize static and dynamic ipban system + ipban_init(); + + // Online user database init + online_db = idb_alloc(DB_OPT_RELEASE_DATA); + add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); + + // Interserver auth init + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + + // set default parser as parse_login function + set_defaultparse(parse_login); + + // every 10 minutes cleanup online account db. + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); + + // add timer to detect ip address change and perform update + if (login_config.ip_sync_interval) { + add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); + add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); + } + + // Account database init + accounts = get_account_engine(); + if( accounts == NULL ) { + ShowFatalError("do_init: account engine '%s' not found.\n", login_config.account_engine); + exit(EXIT_FAILURE); + } else { + + if(!accounts->init(accounts)) { + ShowFatalError("do_init: Failed to initialize account engine '%s'.\n", login_config.account_engine); + exit(EXIT_FAILURE); + } + } + + if( login_config.console ) + { + //##TODO invoke a CONSOLE_START plugin event + } + + // server port open & binding + login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); + + if( runflag != CORE_ST_STOP ) + { + shutdown_callback = do_shutdown; + runflag = LOGINSERVER_ST_RUNNING; + } + + ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); + login_log(0, "login server", 100, "login server started"); + + return 0; } diff --git a/src/login/login.h b/src/login/login.h index 97335aa89..bedf5e179 100644 --- a/src/login/login.h +++ b/src/login/login.h @@ -7,10 +7,11 @@ #include "../common/mmo.h" // NAME_LENGTH,SEX_* #include "../common/core.h" // CORE_ST_LAST -enum E_LOGINSERVER_ST { - LOGINSERVER_ST_RUNNING = CORE_ST_LAST, - LOGINSERVER_ST_SHUTDOWN, - LOGINSERVER_ST_LAST +enum E_LOGINSERVER_ST +{ + LOGINSERVER_ST_RUNNING = CORE_ST_LAST, + LOGINSERVER_ST_SHUTDOWN, + LOGINSERVER_ST_LAST }; #define LOGIN_CONF_NAME "conf/login_athena.conf" @@ -20,74 +21,74 @@ enum E_LOGINSERVER_ST { #define PASSWORDENC 3 struct login_session_data { - int account_id; - long login_id1; - long login_id2; - char sex;// 'F','M','S' - - char userid[NAME_LENGTH]; - char passwd[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords - int passwdenc; - char md5key[20]; - uint16 md5keylen; - - char lastlogin[24]; - uint8 group_id; - uint8 clienttype; - uint32 version; - - uint8 client_hash[16]; - int has_client_hash; - - int fd; + int account_id; + long login_id1; + long login_id2; + char sex;// 'F','M','S' + + char userid[NAME_LENGTH]; + char passwd[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords + int passwdenc; + char md5key[20]; + uint16 md5keylen; + + char lastlogin[24]; + uint8 group_id; + uint8 clienttype; + uint32 version; + + uint8 client_hash[16]; + int has_client_hash; + + int fd; }; struct mmo_char_server { - char name[20]; - int fd; - uint32 ip; - uint16 port; - uint16 users; // user count on this server - uint16 type; // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P - uint16 new_; // should display as 'new'? + char name[20]; + int fd; + uint32 ip; + uint16 port; + uint16 users; // user count on this server + uint16 type; // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P + uint16 new_; // should display as 'new'? }; struct client_hash_node { - int group_id; - uint8 hash[16]; - struct client_hash_node *next; + int group_id; + uint8 hash[16]; + struct client_hash_node *next; }; struct Login_Config { - uint32 login_ip; // the address to bind to - uint16 login_port; // the port to bind to - unsigned int ipban_cleanup_interval; // interval (in seconds) to clean up expired IP bans - unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) - bool log_login; // whether to log login server actions or not - char date_format[32]; // date format used in messages - bool console; // console input system enabled? - bool new_account_flag,new_acc_length_limit; // autoregistration via _M/_F ? / if yes minimum length is 4? - int start_limited_time; // new account expiration time (-1: unlimited) - bool use_md5_passwds; // work with password hashes instead of plaintext passwords? - int group_id_to_connect; // required group id to connect - int min_group_id_to_connect; // minimum group id to connect - bool check_client_version; // check the clientversion set in the clientinfo ? - uint32 client_version_to_connect; // the client version needed to connect (if checking is enabled) - - bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? - bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? - unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures - unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban - unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban - bool use_dnsbl; // dns blacklist blocking ? - char dnsbl_servs[1024]; // comma-separated list of dnsbl servers - - char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) - - int client_hash_check; // flags for checking client md5 - struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group + uint32 login_ip; // the address to bind to + uint16 login_port; // the port to bind to + unsigned int ipban_cleanup_interval; // interval (in seconds) to clean up expired IP bans + unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) + bool log_login; // whether to log login server actions or not + char date_format[32]; // date format used in messages + bool console; // console input system enabled? + bool new_account_flag,new_acc_length_limit; // autoregistration via _M/_F ? / if yes minimum length is 4? + int start_limited_time; // new account expiration time (-1: unlimited) + bool use_md5_passwds; // work with password hashes instead of plaintext passwords? + int group_id_to_connect; // required group id to connect + int min_group_id_to_connect; // minimum group id to connect + bool check_client_version; // check the clientversion set in the clientinfo ? + uint32 client_version_to_connect; // the client version needed to connect (if checking is enabled) + + bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? + bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? + unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures + unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban + unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban + bool use_dnsbl; // dns blacklist blocking ? + char dnsbl_servs[1024]; // comma-separated list of dnsbl servers + + char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) + + int client_hash_check; // flags for checking client md5 + struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group }; #define sex_num2str(num) ( (num == SEX_FEMALE ) ? 'F' : (num == SEX_MALE ) ? 'M' : 'S' ) diff --git a/src/login/loginlog.h b/src/login/loginlog.h index 63621c50a..a1ffaae85 100644 --- a/src/login/loginlog.h +++ b/src/login/loginlog.h @@ -6,10 +6,10 @@ unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes); -void login_log(uint32 ip, const char *username, int rcode, const char *message); +void login_log(uint32 ip, const char* username, int rcode, const char* message); bool loginlog_init(void); bool loginlog_final(void); -bool loginlog_config_read(const char *w1, const char *w2); +bool loginlog_config_read(const char* w1, const char* w2); #endif // __LOGINLOG_H_INCLUDED__ diff --git a/src/login/loginlog_sql.c b/src/login/loginlog_sql.c index 2d8a17528..d61172697 100644 --- a/src/login/loginlog_sql.c +++ b/src/login/loginlog_sql.c @@ -25,145 +25,160 @@ static char log_db_database[32] = ""; static char log_codepage[32] = ""; static char log_login_db[256] = "loginlog"; -static Sql *sql_handle = NULL; +static Sql* sql_handle = NULL; static bool enabled = false; // Returns the number of failed login attemps by the ip in the last minutes. unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes) { - unsigned long failures = 0; - - if (!enabled) - return 0; - - if (SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE", - log_login_db, ip2str(ip,NULL), minutes)) // how many times failed account? in one ip. - Sql_ShowDebug(sql_handle); - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - char *data; - Sql_GetData(sql_handle, 0, &data, NULL); - failures = strtoul(data, NULL, 10); - Sql_FreeResult(sql_handle); - } - return failures; + unsigned long failures = 0; + + if( !enabled ) + return 0; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE", + log_login_db, ip2str(ip,NULL), minutes) )// how many times failed account? in one ip. + Sql_ShowDebug(sql_handle); + + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + Sql_GetData(sql_handle, 0, &data, NULL); + failures = strtoul(data, NULL, 10); + Sql_FreeResult(sql_handle); + } + return failures; } /*============================================= * Records an event in the login log *---------------------------------------------*/ -void login_log(uint32 ip, const char *username, int rcode, const char *message) +void login_log(uint32 ip, const char* username, int rcode, const char* message) { - char esc_username[NAME_LENGTH*2+1]; - char esc_message[255*2+1]; - int retcode; + char esc_username[NAME_LENGTH*2+1]; + char esc_message[255*2+1]; + int retcode; - if (!enabled) - return; + if( !enabled ) + return; - Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); + Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); - retcode = Sql_Query(sql_handle, - "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')", - log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message); + retcode = Sql_Query(sql_handle, + "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')", + log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message); - if (retcode != SQL_SUCCESS) - Sql_ShowDebug(sql_handle); + if( retcode != SQL_SUCCESS ) + Sql_ShowDebug(sql_handle); } bool loginlog_init(void) { - const char *username; - const char *password; - const char *hostname; - uint16 port; - const char *database; - const char *codepage; - - if (log_db_hostname[0] != '\0') { - // local settings - username = log_db_username; - password = log_db_password; - hostname = log_db_hostname; - port = log_db_port; - database = log_db_database; - codepage = log_codepage; - } else { - // global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - sql_handle = Sql_Malloc(); - - if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) - Sql_ShowDebug(sql_handle); - - enabled = true; - - return true; + const char* username; + const char* password; + const char* hostname; + uint16 port; + const char* database; + const char* codepage; + + if( log_db_hostname[0] != '\0' ) + {// local settings + username = log_db_username; + password = log_db_password; + hostname = log_db_hostname; + port = log_db_port; + database = log_db_database; + codepage = log_codepage; + } + else + {// global settings + username = global_db_username; + password = global_db_password; + hostname = global_db_hostname; + port = global_db_port; + database = global_db_database; + codepage = global_codepage; + } + + sql_handle = Sql_Malloc(); + + if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) + { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + + if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) + Sql_ShowDebug(sql_handle); + + enabled = true; + + return true; } bool loginlog_final(void) { - Sql_Free(sql_handle); - sql_handle = NULL; - return true; + Sql_Free(sql_handle); + sql_handle = NULL; + return true; } -bool loginlog_config_read(const char *key, const char *value) +bool loginlog_config_read(const char* key, const char* value) { - const char *signature; - - signature = "sql."; - if (strncmpi(key, signature, strlen(signature)) == 0) { - key += strlen(signature); - if (strcmpi(key, "db_hostname") == 0) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else if (strcmpi(key, "db_port") == 0) - global_db_port = (uint16)strtoul(value, NULL, 10); - else if (strcmpi(key, "db_username") == 0) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else if (strcmpi(key, "db_password") == 0) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else if (strcmpi(key, "db_database") == 0) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else if (strcmpi(key, "codepage") == 0) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - if (strcmpi(key, "log_db_ip") == 0) - safestrncpy(log_db_hostname, value, sizeof(log_db_hostname)); - else if (strcmpi(key, "log_db_port") == 0) - log_db_port = (uint16)strtoul(value, NULL, 10); - else if (strcmpi(key, "log_db_id") == 0) - safestrncpy(log_db_username, value, sizeof(log_db_username)); - else if (strcmpi(key, "log_db_pw") == 0) - safestrncpy(log_db_password, value, sizeof(log_db_password)); - else if (strcmpi(key, "log_db_db") == 0) - safestrncpy(log_db_database, value, sizeof(log_db_database)); - else if (strcmpi(key, "log_codepage") == 0) - safestrncpy(log_codepage, value, sizeof(log_codepage)); - else if (strcmpi(key, "log_login_db") == 0) - safestrncpy(log_login_db, value, sizeof(log_login_db)); - else - return false; - - return true; + const char* signature; + + signature = "sql."; + if( strncmpi(key, signature, strlen(signature)) == 0 ) + { + key += strlen(signature); + if( strcmpi(key, "db_hostname") == 0 ) + safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); + else + if( strcmpi(key, "db_port") == 0 ) + global_db_port = (uint16)strtoul(value, NULL, 10); + else + if( strcmpi(key, "db_username") == 0 ) + safestrncpy(global_db_username, value, sizeof(global_db_username)); + else + if( strcmpi(key, "db_password") == 0 ) + safestrncpy(global_db_password, value, sizeof(global_db_password)); + else + if( strcmpi(key, "db_database") == 0 ) + safestrncpy(global_db_database, value, sizeof(global_db_database)); + else + if( strcmpi(key, "codepage") == 0 ) + safestrncpy(global_codepage, value, sizeof(global_codepage)); + else + return false;// not found + return true; + } + + if( strcmpi(key, "log_db_ip") == 0 ) + safestrncpy(log_db_hostname, value, sizeof(log_db_hostname)); + else + if( strcmpi(key, "log_db_port") == 0 ) + log_db_port = (uint16)strtoul(value, NULL, 10); + else + if( strcmpi(key, "log_db_id") == 0 ) + safestrncpy(log_db_username, value, sizeof(log_db_username)); + else + if( strcmpi(key, "log_db_pw") == 0 ) + safestrncpy(log_db_password, value, sizeof(log_db_password)); + else + if( strcmpi(key, "log_db_db") == 0 ) + safestrncpy(log_db_database, value, sizeof(log_db_database)); + else + if( strcmpi(key, "log_codepage") == 0 ) + safestrncpy(log_codepage, value, sizeof(log_codepage)); + else + if( strcmpi(key, "log_login_db") == 0 ) + safestrncpy(log_login_db, value, sizeof(log_login_db)); + else + return false; + + return true; } diff --git a/src/map/atcommand.c b/src/map/atcommand.c index a67c67108..394f4fb11 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -61,97 +61,100 @@ typedef struct AliasInfo AliasInfo; int atcmd_binding_count = 0; struct AtCommandInfo { - char command[ATCOMMAND_LENGTH]; - AtCommandFunc func; - char *at_groups;/* quick @commands "can-use" lookup */ - char *char_groups;/* quick @charcommands "can-use" lookup */ + char command[ATCOMMAND_LENGTH]; + AtCommandFunc func; + char* at_groups;/* quick @commands "can-use" lookup */ + char* char_groups;/* quick @charcommands "can-use" lookup */ }; struct AliasInfo { - AtCommandInfo *command; - char alias[ATCOMMAND_LENGTH]; + AtCommandInfo *command; + char alias[ATCOMMAND_LENGTH]; }; char atcommand_symbol = '@'; // first char of the commands char charcommand_symbol = '#'; -static char *msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) -static DBMap *atcommand_db = NULL; //name -> AtCommandInfo -static DBMap *atcommand_alias_db = NULL; //alias -> AtCommandInfo +static char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) +static DBMap* atcommand_db = NULL; //name -> AtCommandInfo +static DBMap* atcommand_alias_db = NULL; //alias -> AtCommandInfo static config_t atcommand_config; static char atcmd_output[CHAT_SIZE_MAX]; static char atcmd_player_name[NAME_LENGTH]; -static AtCommandInfo *get_atcommandinfo_byname(const char *name); // @help -static const char *atcommand_checkalias(const char *aliasname); // @help -static void atcommand_get_suggestions(struct map_session_data *sd, const char *name, bool atcommand); // @help +static AtCommandInfo* get_atcommandinfo_byname(const char *name); // @help +static const char* atcommand_checkalias(const char *aliasname); // @help +static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand); // @help // @commands (script-based) -struct atcmd_binding_data *get_atcommandbind_byname(const char *name) { - int i = 0; +struct atcmd_binding_data* get_atcommandbind_byname(const char* name) { + int i = 0; - if (*name == atcommand_symbol || *name == charcommand_symbol) - name++; // for backwards compatibility + if( *name == atcommand_symbol || *name == charcommand_symbol ) + name++; // for backwards compatibility - ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0); + ARR_FIND( 0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0 ); - return (i < atcmd_binding_count) ? atcmd_binding[i] : NULL; + return ( i < atcmd_binding_count ) ? atcmd_binding[i] : NULL; } //----------------------------------------------------------- // Return the message string of the specified number by [Yor] //----------------------------------------------------------- -const char *msg_txt(int msg_number) +const char* msg_txt(int msg_number) { - if (msg_number >= 0 && msg_number < MAX_MSG && - msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; + if (msg_number >= 0 && msg_number < MAX_MSG && + msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') + return msg_table[msg_number]; - return "??"; + return "??"; } /*========================================== * Read Message Data *------------------------------------------*/ -int msg_config_read(const char *cfgName) +int msg_config_read(const char* cfgName) { - int msg_number; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - static int called = 1; + int msg_number; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + static int called = 1; - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("Messages file not found: %s\n", cfgName); - return 1; - } + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("Messages file not found: %s\n", cfgName); + return 1; + } - if ((--called) == 0) - memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG); + if ((--called) == 0) + memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG); - while (fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; + while(fgets(line, sizeof(line), fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; - if (strcmpi(w1, "import") == 0) - msg_config_read(w2); - else { - msg_number = atoi(w1); - if (msg_number >= 0 && msg_number < MAX_MSG) { - if (msg_table[msg_number] != NULL) - aFree(msg_table[msg_number]); - msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof(char)); - strcpy(msg_table[msg_number],w2); - } - } - } + if (strcmpi(w1, "import") == 0) + msg_config_read(w2); + else + { + msg_number = atoi(w1); + if (msg_number >= 0 && msg_number < MAX_MSG) + { + if (msg_table[msg_number] != NULL) + aFree(msg_table[msg_number]); + msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); + strcpy(msg_table[msg_number],w2); + } + } + } - fclose(fp); + fclose(fp); - return 0; + return 0; } /*========================================== @@ -159,9 +162,9 @@ int msg_config_read(const char *cfgName) *------------------------------------------*/ void do_final_msg(void) { - int i; - for (i = 0; i < MAX_MSG; i++) - aFree(msg_table[i]); + int i; + for (i = 0; i < MAX_MSG; i++) + aFree(msg_table[i]); } /** @@ -170,34 +173,34 @@ void do_final_msg(void) * @param name the name of the command to retrieve help information for * @return the string associated with the command, or NULL */ -static const char *atcommand_help_string(const char *command) +static const char* atcommand_help_string(const char* command) { - const char *str = NULL; - config_setting_t *info; + const char* str = NULL; + config_setting_t* info; - if (*command == atcommand_symbol || *command == charcommand_symbol) { - // remove the prefix symbol for the raw name of the command - command ++; - } + if( *command == atcommand_symbol || *command == charcommand_symbol ) + {// remove the prefix symbol for the raw name of the command + command ++; + } - // convert alias to the real command name - command = atcommand_checkalias(command); + // convert alias to the real command name + command = atcommand_checkalias(command); - // attept to find the first default help command - info = config_lookup(&atcommand_config, "help"); + // attept to find the first default help command + info = config_lookup(&atcommand_config, "help"); - if (info == NULL) { - // failed to find the help property in the configuration file - return NULL; - } + if( info == NULL ) + {// failed to find the help property in the configuration file + return NULL; + } - if (!config_setting_lookup_string(info, command, &str)) { - // failed to find the matching help string - return NULL; - } + if( !config_setting_lookup_string( info, command, &str ) ) + {// failed to find the matching help string + return NULL; + } - // push the result from the method - return str; + // push the result from the method + return str; } @@ -206,243 +209,228 @@ static const char *atcommand_help_string(const char *command) *------------------------------------------*/ ACMD_FUNC(send) { - int len=0,off,end,type; - long num; + int len=0,off,end,type; + long num; - // read message type as hex number (without the 0x) - if (!message || !*message || - !((sscanf(message, "len %x", &type)==1 && (len=1)) - || sscanf(message, "%x", &type)==1)) { - int i; - for (i = 900; i <= 903; ++i) - clif_displaymessage(fd, msg_txt(i)); - return -1; - } + // read message type as hex number (without the 0x) + if(!message || !*message || + !((sscanf(message, "len %x", &type)==1 && (len=1)) + || sscanf(message, "%x", &type)==1) ) + { + int i; + for (i = 900; i <= 903; ++i) + clif_displaymessage(fd, msg_txt(i)); + return -1; + } #define PARSE_ERROR(error,p) \ - {\ - clif_displaymessage(fd, (error));\ - sprintf(atcmd_output, ">%s", (p));\ - clif_displaymessage(fd, atcmd_output);\ - } - //define PARSE_ERROR + {\ + clif_displaymessage(fd, (error));\ + sprintf(atcmd_output, ">%s", (p));\ + clif_displaymessage(fd, atcmd_output);\ + } +//define PARSE_ERROR #define CHECK_EOS(p) \ - if(*(p) == 0){\ - clif_displaymessage(fd, "Unexpected end of string");\ - return -1;\ - } - //define CHECK_EOS + if(*(p) == 0){\ + clif_displaymessage(fd, "Unexpected end of string");\ + return -1;\ + } +//define CHECK_EOS #define SKIP_VALUE(p) \ - {\ - while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ - while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ - } - //define SKIP_VALUE + {\ + while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ + while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ + } +//define SKIP_VALUE #define GET_VALUE(p,num) \ - {\ - if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ - PARSE_ERROR("Invalid number in:",(p));\ - return -1;\ - }\ - } - //define GET_VALUE - - if (type > 0 && type < MAX_PACKET_DB) { - - if (len) { - // show packet length - sprintf(atcmd_output, msg_txt(904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d - clif_displaymessage(fd, atcmd_output); - return 0; - } - - len=packet_db[sd->packet_ver][type].len; - off=2; - if (len == 0) { - // unknown packet - ERROR - sprintf(atcmd_output, msg_txt(905), type); // Unknown packet: 0x%x - clif_displaymessage(fd, atcmd_output); - return -1; - } else if (len == -1) { - // dynamic packet - len=SHRT_MAX-4; // maximum length - off=4; - } - WFIFOHEAD(fd, len); - WFIFOW(fd,0)=TOW(type); - - // parse packet contents - SKIP_VALUE(message); - while (*message != 0 && off < len) { - if (ISDIGIT(*message) || *message == '-' || *message == '+') { - // default (byte) - GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); - ++off; - } else if (TOUPPER(*message) == 'B') { - // byte - ++message; - GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); - ++off; - } else if (TOUPPER(*message) == 'W') { - // word (2 bytes) - ++message; - GET_VALUE(message,num); - WFIFOW(fd,off)=TOW(num); - off+=2; - } else if (TOUPPER(*message) == 'L') { - // long word (4 bytes) - ++message; - GET_VALUE(message,num); - WFIFOL(fd,off)=TOL(num); - off+=4; - } else if (TOUPPER(*message) == 'S') { - // string - escapes are valid - // get string length - num <= 0 means not fixed length (default) - ++message; - if (*message == '"') { - num=0; - } else { - GET_VALUE(message,num); - while (*message != '"') { - // find start of string - if (*message == 0 || ISSPACE(*message)) { - PARSE_ERROR(msg_txt(906),message); // Not a string: - return -1; - } - ++message; - } - } - - // parse string - ++message; - CHECK_EOS(message); - end=(num<=0? 0: min(off+((int)num),len)); - for (; *message != '"' && (off < end || end == 0); ++off) { - if (*message == '\\') { - ++message; - CHECK_EOS(message); - switch (*message) { - case 'a': - num=0x07; - break; // Bell - case 'b': - num=0x08; - break; // Backspace - case 't': - num=0x09; - break; // Horizontal tab - case 'n': - num=0x0A; - break; // Line feed - case 'v': - num=0x0B; - break; // Vertical tab - case 'f': - num=0x0C; - break; // Form feed - case 'r': - num=0x0D; - break; // Carriage return - case 'e': - num=0x1B; - break; // Escape - default: - num=*message; - break; - case 'x': { // Hexadecimal - ++message; - CHECK_EOS(message); - if (!ISXDIGIT(*message)) { - PARSE_ERROR(msg_txt(907),message); // Not a hexadecimal digit: - return -1; - } - num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); - if (ISXDIGIT(*message)) { - ++message; - CHECK_EOS(message); - num<<=8; - num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); - } - WFIFOB(fd,off)=TOB(num); - ++message; - CHECK_EOS(message); - continue; - } - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { // Octal - num=*message-'0'; // 1st octal digit - ++message; - CHECK_EOS(message); - if (ISDIGIT(*message) && *message < '8') { - num<<=3; - num+=*message-'0'; // 2nd octal digit - ++message; - CHECK_EOS(message); - if (ISDIGIT(*message) && *message < '8') { - num<<=3; - num+=*message-'0'; // 3rd octal digit - ++message; - CHECK_EOS(message); - } - } - WFIFOB(fd,off)=TOB(num); - continue; - } - } - } else - num=*message; - WFIFOB(fd,off)=TOB(num); - ++message; - CHECK_EOS(message); - }//for - while (*message != '"') { - // ignore extra characters - ++message; - CHECK_EOS(message); - } - - // terminate the string - if (off < end) { - // fill the rest with 0's - memset(WFIFOP(fd,off),0,end-off); - off=end; - } - } else { - // unknown - PARSE_ERROR(msg_txt(908),message); // Unknown type of value in: - return -1; - } - SKIP_VALUE(message); - } - - if (packet_db[sd->packet_ver][type].len == -1) { - // send dynamic packet - WFIFOW(fd,2)=TOW(off); - WFIFOSET(fd,off); - } else { - // send static packet - if (off < len) - memset(WFIFOP(fd,off),0,len-off); - WFIFOSET(fd,len); - } - } else { - clif_displaymessage(fd, msg_txt(259)); // Invalid packet - return -1; - } - sprintf(atcmd_output, msg_txt(258), type, type); // Sent packet 0x%x (%d) - clif_displaymessage(fd, atcmd_output); - return 0; + {\ + if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ + PARSE_ERROR("Invalid number in:",(p));\ + return -1;\ + }\ + } +//define GET_VALUE + + if (type > 0 && type < MAX_PACKET_DB) { + + if(len) + {// show packet length + sprintf(atcmd_output, msg_txt(904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d + clif_displaymessage(fd, atcmd_output); + return 0; + } + + len=packet_db[sd->packet_ver][type].len; + off=2; + if(len == 0) + {// unknown packet - ERROR + sprintf(atcmd_output, msg_txt(905), type); // Unknown packet: 0x%x + clif_displaymessage(fd, atcmd_output); + return -1; + } else if(len == -1) + {// dynamic packet + len=SHRT_MAX-4; // maximum length + off=4; + } + WFIFOHEAD(fd, len); + WFIFOW(fd,0)=TOW(type); + + // parse packet contents + SKIP_VALUE(message); + while(*message != 0 && off < len){ + if(ISDIGIT(*message) || *message == '-' || *message == '+') + {// default (byte) + GET_VALUE(message,num); + WFIFOB(fd,off)=TOB(num); + ++off; + } else if(TOUPPER(*message) == 'B') + {// byte + ++message; + GET_VALUE(message,num); + WFIFOB(fd,off)=TOB(num); + ++off; + } else if(TOUPPER(*message) == 'W') + {// word (2 bytes) + ++message; + GET_VALUE(message,num); + WFIFOW(fd,off)=TOW(num); + off+=2; + } else if(TOUPPER(*message) == 'L') + {// long word (4 bytes) + ++message; + GET_VALUE(message,num); + WFIFOL(fd,off)=TOL(num); + off+=4; + } else if(TOUPPER(*message) == 'S') + {// string - escapes are valid + // get string length - num <= 0 means not fixed length (default) + ++message; + if(*message == '"'){ + num=0; + } else { + GET_VALUE(message,num); + while(*message != '"') + {// find start of string + if(*message == 0 || ISSPACE(*message)){ + PARSE_ERROR(msg_txt(906),message); // Not a string: + return -1; + } + ++message; + } + } + + // parse string + ++message; + CHECK_EOS(message); + end=(num<=0? 0: min(off+((int)num),len)); + for(; *message != '"' && (off < end || end == 0); ++off){ + if(*message == '\\'){ + ++message; + CHECK_EOS(message); + switch(*message){ + case 'a': num=0x07; break; // Bell + case 'b': num=0x08; break; // Backspace + case 't': num=0x09; break; // Horizontal tab + case 'n': num=0x0A; break; // Line feed + case 'v': num=0x0B; break; // Vertical tab + case 'f': num=0x0C; break; // Form feed + case 'r': num=0x0D; break; // Carriage return + case 'e': num=0x1B; break; // Escape + default: num=*message; break; + case 'x': // Hexadecimal + { + ++message; + CHECK_EOS(message); + if(!ISXDIGIT(*message)){ + PARSE_ERROR(msg_txt(907),message); // Not a hexadecimal digit: + return -1; + } + num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); + if(ISXDIGIT(*message)){ + ++message; + CHECK_EOS(message); + num<<=8; + num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); + } + WFIFOB(fd,off)=TOB(num); + ++message; + CHECK_EOS(message); + continue; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': // Octal + { + num=*message-'0'; // 1st octal digit + ++message; + CHECK_EOS(message); + if(ISDIGIT(*message) && *message < '8'){ + num<<=3; + num+=*message-'0'; // 2nd octal digit + ++message; + CHECK_EOS(message); + if(ISDIGIT(*message) && *message < '8'){ + num<<=3; + num+=*message-'0'; // 3rd octal digit + ++message; + CHECK_EOS(message); + } + } + WFIFOB(fd,off)=TOB(num); + continue; + } + } + } else + num=*message; + WFIFOB(fd,off)=TOB(num); + ++message; + CHECK_EOS(message); + }//for + while(*message != '"') + {// ignore extra characters + ++message; + CHECK_EOS(message); + } + + // terminate the string + if(off < end) + {// fill the rest with 0's + memset(WFIFOP(fd,off),0,end-off); + off=end; + } + } else + {// unknown + PARSE_ERROR(msg_txt(908),message); // Unknown type of value in: + return -1; + } + SKIP_VALUE(message); + } + + if(packet_db[sd->packet_ver][type].len == -1) + {// send dynamic packet + WFIFOW(fd,2)=TOW(off); + WFIFOSET(fd,off); + } else + {// send static packet + if(off < len) + memset(WFIFOP(fd,off),0,len-off); + WFIFOSET(fd,len); + } + } else { + clif_displaymessage(fd, msg_txt(259)); // Invalid packet + return -1; + } + sprintf (atcmd_output, msg_txt(258), type, type); // Sent packet 0x%x (%d) + clif_displaymessage(fd, atcmd_output); + return 0; #undef PARSE_ERROR #undef CHECK_EOS #undef SKIP_VALUE @@ -454,53 +442,53 @@ ACMD_FUNC(send) *------------------------------------------*/ ACMD_FUNC(mapmove) { - char map_name[MAP_NAME_LENGTH_EXT]; - unsigned short mapindex; - short x = 0, y = 0; - int m = -1; + char map_name[MAP_NAME_LENGTH_EXT]; + unsigned short mapindex; + short x = 0, y = 0; + int m = -1; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(map_name, '\0', sizeof(map_name)); + memset(map_name, '\0', sizeof(map_name)); - if (!message || !*message || - (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 && - sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) { + if (!message || !*message || + (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 && + sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) { - clif_displaymessage(fd, msg_txt(909)); // Please enter a map (usage: @warp/@rura/@mapmove ). - return -1; - } + clif_displaymessage(fd, msg_txt(909)); // Please enter a map (usage: @warp/@rura/@mapmove ). + return -1; + } - mapindex = mapindex_name2id(map_name); - if (mapindex) - m = map_mapindex2mapid(mapindex); + mapindex = mapindex_name2id(map_name); + if (mapindex) + m = map_mapindex2mapid(mapindex); - if (!mapindex) { // m < 0 means on different server! [Kevin] - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } + if (!mapindex) { // m < 0 means on different server! [Kevin] + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } - if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS)) { - //This is to prevent the pc_setpos call from printing an error. - clif_displaymessage(fd, msg_txt(2)); - if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1)) - x = y = 0; //Invalid cell, use random spot. - } - if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } + if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS)) + { //This is to prevent the pc_setpos call from printing an error. + clif_displaymessage(fd, msg_txt(2)); + if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1)) + x = y = 0; //Invalid cell, use random spot. + } + if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); + return -1; + } + if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } - clif_displaymessage(fd, msg_txt(0)); // Warped. - return 0; + clif_displaymessage(fd, msg_txt(0)); // Warped. + return 0; } /*========================================== @@ -508,29 +496,29 @@ ACMD_FUNC(mapmove) *------------------------------------------*/ ACMD_FUNC(where) { - struct map_session_data *pl_sd; + struct map_session_data* pl_sd; - nullpo_retr(-1, sd); - memset(atcmd_player_name, '\0', sizeof atcmd_player_name); + nullpo_retr(-1, sd); + memset(atcmd_player_name, '\0', sizeof atcmd_player_name); - if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif_displaymessage(fd, msg_txt(910)); // Please enter a player name (usage: @where ). - return -1; - } + if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { + clif_displaymessage(fd, msg_txt(910)); // Please enter a player name (usage: @where ). + return -1; + } - pl_sd = map_nick2sd(atcmd_player_name); - if (pl_sd == NULL || - strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || - (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) - ) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + pl_sd = map_nick2sd(atcmd_player_name); + if (pl_sd == NULL || + strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || + (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + ) { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - snprintf(atcmd_output, sizeof atcmd_output, "%s %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage(fd, atcmd_output); + snprintf(atcmd_output, sizeof atcmd_output, "%s %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -538,40 +526,44 @@ ACMD_FUNC(where) *------------------------------------------*/ ACMD_FUNC(jumpto) { - struct map_session_data *pl_sd = NULL; + struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto ). - return -1; - } + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto ). + return -1; + } - if ((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) + { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map. - return -1; - } + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + { + clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map. + return -1; + } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - if (pc_isdead(sd)) { - clif_displaymessage(fd, msg_txt(664)); - return -1; - } + if( pc_isdead(sd) ) + { + clif_displaymessage(fd, msg_txt(664)); + return -1; + } - pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); - sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s - clif_displaymessage(fd, atcmd_output); + pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); + sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -579,35 +571,36 @@ ACMD_FUNC(jumpto) *------------------------------------------*/ ACMD_FUNC(jump) { - short x = 0, y = 0; + short x = 0, y = 0; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - sscanf(message, "%hd %hd", &x, &y); + sscanf(message, "%hd %hd", &x, &y); - if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - if (pc_isdead(sd)) { - clif_displaymessage(fd, msg_txt(664)); - return -1; - } + if( pc_isdead(sd) ) + { + clif_displaymessage(fd, msg_txt(664)); + return -1; + } - if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) { - //This is to prevent the pc_setpos call from printing an error. - clif_displaymessage(fd, msg_txt(2)); - if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) - x = y = 0; //Invalid cell, use random spot. - } + if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) + { //This is to prevent the pc_setpos call from printing an error. + clif_displaymessage(fd, msg_txt(2)); + if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) + x = y = 0; //Invalid cell, use random spot. + } - pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); - sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d - clif_displaymessage(fd, atcmd_output); - return 0; + pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); + sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d + clif_displaymessage(fd, atcmd_output); + return 0; } /*========================================== @@ -616,101 +609,101 @@ ACMD_FUNC(jump) *------------------------------------------*/ ACMD_FUNC(who) { - struct map_session_data *pl_sd = NULL; - struct s_mapiterator *iter = NULL; - char map_name[MAP_NAME_LENGTH_EXT] = ""; - char player_name[NAME_LENGTH] = ""; - int count = 0; - int level = 0; - StringBuf buf; - /** - * 1 = @who : Player name, [Title], [Party name], [Guild name] - * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job - * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y - */ - int display_type = 1; - int map_id = -1; - - nullpo_retr(-1, sd); - - if (strstr(command, "map") != NULL) { - if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0) - map_id = sd->bl.m; - } else { - sscanf(message, "%23s", player_name); - } - - if (strstr(command, "2") != NULL) - display_type = 2; - else if (strstr(command, "3") != NULL) - display_type = 3; - - level = pc_get_group_level(sd); - StringBuf_Init(&buf); - - iter = mapit_getallusers(); - for (pl_sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC *)mapit_next(iter)) { - if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level - if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive - || (map_id >= 0 && pl_sd->bl.m != map_id)) - continue; - switch (display_type) { - case 2: { - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - StringBuf_Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, - job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" - break; - } - case 3: { - if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) - StringBuf_Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - StringBuf_Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" - break; - } - default: { - struct party_data *p = party_search(pl_sd->status.party_id); - struct guild *g = guild_search(pl_sd->status.guild_id); - - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - if (p != NULL) - StringBuf_Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" - if (g != NULL) - StringBuf_Printf(&buf, msg_txt(346), g->name); // " | Guild: '%s'" - break; - } - } - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Clear(&buf); - count++; - } - } - mapit_free(iter); - - if (map_id < 0) { - if (count == 0) - StringBuf_Printf(&buf, msg_txt(28)); // No player found. - else if (count == 1) - StringBuf_Printf(&buf, msg_txt(29)); // 1 player found. - else - StringBuf_Printf(&buf, msg_txt(30), count); // %d players found. - } else { - if (count == 0) - StringBuf_Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'. - else if (count == 1) - StringBuf_Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'. - else - StringBuf_Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'. - } - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Destroy(&buf); - return 0; + struct map_session_data *pl_sd = NULL; + struct s_mapiterator *iter = NULL; + char map_name[MAP_NAME_LENGTH_EXT] = ""; + char player_name[NAME_LENGTH] = ""; + int count = 0; + int level = 0; + StringBuf buf; + /** + * 1 = @who : Player name, [Title], [Party name], [Guild name] + * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job + * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y + */ + int display_type = 1; + int map_id = -1; + + nullpo_retr(-1, sd); + + if (strstr(command, "map") != NULL) { + if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0) + map_id = sd->bl.m; + } else { + sscanf(message, "%23s", player_name); + } + + if (strstr(command, "2") != NULL) + display_type = 2; + else if (strstr(command, "3") != NULL) + display_type = 3; + + level = pc_get_group_level(sd); + StringBuf_Init(&buf); + + iter = mapit_getallusers(); + for (pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter)) { + if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level + if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive + || (map_id >= 0 && pl_sd->bl.m != map_id)) + continue; + switch (display_type) { + case 2: { + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StringBuf_Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, + job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" + break; + } + case 3: { + if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + StringBuf_Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StringBuf_Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" + break; + } + default: { + struct party_data *p = party_search(pl_sd->status.party_id); + struct guild *g = guild_search(pl_sd->status.guild_id); + + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + if (p != NULL) + StringBuf_Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" + if (g != NULL) + StringBuf_Printf(&buf, msg_txt(346), g->name); // " | Guild: '%s'" + break; + } + } + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Clear(&buf); + count++; + } + } + mapit_free(iter); + + if (map_id < 0) { + if (count == 0) + StringBuf_Printf(&buf, msg_txt(28)); // No player found. + else if (count == 1) + StringBuf_Printf(&buf, msg_txt(29)); // 1 player found. + else + StringBuf_Printf(&buf, msg_txt(30), count); // %d players found. + } else { + if (count == 0) + StringBuf_Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'. + else if (count == 1) + StringBuf_Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'. + else + StringBuf_Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'. + } + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Destroy(&buf); + return 0; } /*========================================== @@ -718,83 +711,85 @@ ACMD_FUNC(who) *------------------------------------------*/ ACMD_FUNC(whogm) { - struct map_session_data *pl_sd; - struct s_mapiterator *iter; - int j, count; - int pl_level, level; - char match_text[CHAT_SIZE_MAX]; - char player_name[NAME_LENGTH]; - struct guild *g; - struct party_data *p; - - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(match_text, '\0', sizeof(match_text)); - memset(player_name, '\0', sizeof(player_name)); - - if (sscanf(message, "%199[^\n]", match_text) < 1) - strcpy(match_text, ""); - for (j = 0; match_text[j]; j++) - match_text[j] = TOLOWER(match_text[j]); - - count = 0; - level = pc_get_group_level(sd); - - iter = mapit_getallusers(); - for (pl_sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC *)mapit_next(iter)) { - pl_level = pc_get_group_level(pl_sd); - if (!pl_level) - continue; - - if (match_text[0]) { - memcpy(player_name, pl_sd->status.name, NAME_LENGTH); - for (j = 0; player_name[j]; j++) - player_name[j] = TOLOWER(player_name[j]); - // search with no case sensitive - if (strstr(player_name, match_text) == NULL) - continue; - } - if (pl_level > level) { - if (pl_sd->sc.option & OPTION_INVISIBLE) - continue; - sprintf(atcmd_output, msg_txt(913), pl_sd->status.name); // Name: %s (GM) - clif_displaymessage(fd, atcmd_output); - count++; - continue; - } - - sprintf(atcmd_output, msg_txt(914), // Name: %s (GM:%d) | Location: %s %d %d - pl_sd->status.name, pl_level, - mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage(fd, atcmd_output); - - sprintf(atcmd_output, msg_txt(915), // BLvl: %d | Job: %s (Lvl: %d) - pl_sd->status.base_level, - job_name(pl_sd->status.class_), pl_sd->status.job_level); - clif_displaymessage(fd, atcmd_output); - - p = party_search(pl_sd->status.party_id); - g = guild_search(pl_sd->status.guild_id); - - sprintf(atcmd_output,msg_txt(916), // Party: '%s' | Guild: '%s' - p?p->party.name:msg_txt(917), g?g->name:msg_txt(917)); // None. - - clif_displaymessage(fd, atcmd_output); - count++; - } - mapit_free(iter); - - if (count == 0) - clif_displaymessage(fd, msg_txt(150)); // No GM found. - else if (count == 1) - clif_displaymessage(fd, msg_txt(151)); // 1 GM found. - else { - sprintf(atcmd_output, msg_txt(152), count); // %d GMs found. - clif_displaymessage(fd, atcmd_output); - } - - return 0; + struct map_session_data* pl_sd; + struct s_mapiterator* iter; + int j, count; + int pl_level, level; + char match_text[CHAT_SIZE_MAX]; + char player_name[NAME_LENGTH]; + struct guild *g; + struct party_data *p; + + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(match_text, '\0', sizeof(match_text)); + memset(player_name, '\0', sizeof(player_name)); + + if (sscanf(message, "%199[^\n]", match_text) < 1) + strcpy(match_text, ""); + for (j = 0; match_text[j]; j++) + match_text[j] = TOLOWER(match_text[j]); + + count = 0; + level = pc_get_group_level(sd); + + iter = mapit_getallusers(); + for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) ) + { + pl_level = pc_get_group_level(pl_sd); + if (!pl_level) + continue; + + if (match_text[0]) + { + memcpy(player_name, pl_sd->status.name, NAME_LENGTH); + for (j = 0; player_name[j]; j++) + player_name[j] = TOLOWER(player_name[j]); + // search with no case sensitive + if (strstr(player_name, match_text) == NULL) + continue; + } + if (pl_level > level) { + if (pl_sd->sc.option & OPTION_INVISIBLE) + continue; + sprintf(atcmd_output, msg_txt(913), pl_sd->status.name); // Name: %s (GM) + clif_displaymessage(fd, atcmd_output); + count++; + continue; + } + + sprintf(atcmd_output, msg_txt(914), // Name: %s (GM:%d) | Location: %s %d %d + pl_sd->status.name, pl_level, + mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); + clif_displaymessage(fd, atcmd_output); + + sprintf(atcmd_output, msg_txt(915), // BLvl: %d | Job: %s (Lvl: %d) + pl_sd->status.base_level, + job_name(pl_sd->status.class_), pl_sd->status.job_level); + clif_displaymessage(fd, atcmd_output); + + p = party_search(pl_sd->status.party_id); + g = guild_search(pl_sd->status.guild_id); + + sprintf(atcmd_output,msg_txt(916), // Party: '%s' | Guild: '%s' + p?p->party.name:msg_txt(917), g?g->name:msg_txt(917)); // None. + + clif_displaymessage(fd, atcmd_output); + count++; + } + mapit_free(iter); + + if (count == 0) + clif_displaymessage(fd, msg_txt(150)); // No GM found. + else if (count == 1) + clif_displaymessage(fd, msg_txt(151)); // 1 GM found. + else { + sprintf(atcmd_output, msg_txt(152), count); // %d GMs found. + clif_displaymessage(fd, atcmd_output); + } + + return 0; } /*========================================== @@ -802,17 +797,17 @@ ACMD_FUNC(whogm) *------------------------------------------*/ ACMD_FUNC(save) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); - if (sd->status.pet_id > 0 && sd->pd) - intif_save_petdata(sd->status.account_id, &sd->pd->pet); + pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); + if (sd->status.pet_id > 0 && sd->pd) + intif_save_petdata(sd->status.account_id, &sd->pd->pet); - chrif_save(sd,0); + chrif_save(sd,0); - clif_displaymessage(fd, msg_txt(6)); // Your save point has been changed. + clif_displaymessage(fd, msg_txt(6)); // Your save point has been changed. - return 0; + return 0; } /*========================================== @@ -820,24 +815,24 @@ ACMD_FUNC(save) *------------------------------------------*/ ACMD_FUNC(load) { - int m; + int m; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - m = map_mapindex2mapid(sd->status.save_point.map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map. - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + m = map_mapindex2mapid(sd->status.save_point.map); + if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map. + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); - clif_displaymessage(fd, msg_txt(7)); // Warping to save point.. + pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); + clif_displaymessage(fd, msg_txt(7)); // Warping to save point.. - return 0; + return 0; } /*========================================== @@ -845,22 +840,22 @@ ACMD_FUNC(load) *------------------------------------------*/ ACMD_FUNC(speed) { - int speed; + int speed; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &speed) < 1) { - sprintf(atcmd_output, msg_txt(918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &speed) < 1) { + sprintf(atcmd_output, msg_txt(918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>). + clif_displaymessage(fd, atcmd_output); + return -1; + } - sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED); - status_calc_bl(&sd->bl, SCB_SPEED); - clif_displaymessage(fd, msg_txt(8)); // Speed changed. - return 0; + sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED); + status_calc_bl(&sd->bl, SCB_SPEED); + clif_displaymessage(fd, msg_txt(8)); // Speed changed. + return 0; } /*========================================== @@ -868,20 +863,20 @@ ACMD_FUNC(speed) *------------------------------------------*/ ACMD_FUNC(storage) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag) - return -1; + if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag) + return -1; - if (storage_storageopen(sd) == 1) { - //Already open. - clif_displaymessage(fd, msg_txt(250)); - return -1; - } + if (storage_storageopen(sd) == 1) + { //Already open. + clif_displaymessage(fd, msg_txt(250)); + return -1; + } - clif_displaymessage(fd, msg_txt(919)); // Storage opened. + clif_displaymessage(fd, msg_txt(919)); // Storage opened. - return 0; + return 0; } @@ -890,29 +885,29 @@ ACMD_FUNC(storage) *------------------------------------------*/ ACMD_FUNC(guildstorage) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!sd->status.guild_id) { - clif_displaymessage(fd, msg_txt(252)); - return -1; - } + if (!sd->status.guild_id) { + clif_displaymessage(fd, msg_txt(252)); + return -1; + } - if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading) - return -1; + if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading) + return -1; - if (sd->state.storage_flag == 1) { - clif_displaymessage(fd, msg_txt(250)); - return -1; - } + if (sd->state.storage_flag == 1) { + clif_displaymessage(fd, msg_txt(250)); + return -1; + } - if (sd->state.storage_flag == 2) { - clif_displaymessage(fd, msg_txt(251)); - return -1; - } + if (sd->state.storage_flag == 2) { + clif_displaymessage(fd, msg_txt(251)); + return -1; + } - storage_guild_storageopen(sd); - clif_displaymessage(fd, msg_txt(920)); // Guild storage opened. - return 0; + storage_guild_storageopen(sd); + clif_displaymessage(fd, msg_txt(920)); // Guild storage opened. + return 0; } /*========================================== @@ -920,34 +915,34 @@ ACMD_FUNC(guildstorage) *------------------------------------------*/ ACMD_FUNC(option) { - int param1 = 0, param2 = 0, param3 = 0; - nullpo_retr(-1, sd); + int param1 = 0, param2 = 0, param3 = 0; + nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) { - // failed to match the parameters so inform the user of the options - const char *text = NULL; + if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) + {// failed to match the parameters so inform the user of the options + const char* text = NULL; - // attempt to find the setting information for this command - text = atcommand_help_string(command); + // attempt to find the setting information for this command + text = atcommand_help_string( command ); - // notify the user of the requirement to enter an option - clif_displaymessage(fd, msg_txt(921)); // Please enter at least one option. + // notify the user of the requirement to enter an option + clif_displaymessage(fd, msg_txt(921)); // Please enter at least one option. - if (text) { - // send the help text associated with this command - clif_displaymessage(fd, text); - } + if( text ) + {// send the help text associated with this command + clif_displaymessage( fd, text ); + } - return -1; - } + return -1; + } - sd->sc.opt1 = param1; - sd->sc.opt2 = param2; - pc_setoption(sd, param3); + sd->sc.opt1 = param1; + sd->sc.opt2 = param2; + pc_setoption(sd, param3); - clif_displaymessage(fd, msg_txt(9)); // Options changed. + clif_displaymessage(fd, msg_txt(9)); // Options changed. - return 0; + return 0; } /*========================================== @@ -955,41 +950,41 @@ ACMD_FUNC(option) *------------------------------------------*/ ACMD_FUNC(hide) { - nullpo_retr(-1, sd); - if (sd->sc.option & OPTION_INVISIBLE) { - sd->sc.option &= ~OPTION_INVISIBLE; - if (sd->disguise) - status_set_viewdata(&sd->bl, sd->disguise); - else - status_set_viewdata(&sd->bl, sd->status.class_); - clif_displaymessage(fd, msg_txt(10)); // Invisible: Off + nullpo_retr(-1, sd); + if (sd->sc.option & OPTION_INVISIBLE) { + sd->sc.option &= ~OPTION_INVISIBLE; + if (sd->disguise) + status_set_viewdata(&sd->bl, sd->disguise); + else + status_set_viewdata(&sd->bl, sd->status.class_); + clif_displaymessage(fd, msg_txt(10)); // Invisible: Off - // increment the number of pvp players on the map - map[sd->bl.m].users_pvp++; + // increment the number of pvp players on the map + map[sd->bl.m].users_pvp++; - if (map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank) { - // register the player for ranking calculations - sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); - } - //bugreport:2266 - map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); - } else { - sd->sc.option |= OPTION_INVISIBLE; - sd->vd.class_ = INVISIBLE_CLASS; - clif_displaymessage(fd, msg_txt(11)); // Invisible: On + if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank ) + {// register the player for ranking calculations + sd->pvp_timer = add_timer( gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0 ); + } + //bugreport:2266 + map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); + } else { + sd->sc.option |= OPTION_INVISIBLE; + sd->vd.class_ = INVISIBLE_CLASS; + clif_displaymessage(fd, msg_txt(11)); // Invisible: On - // decrement the number of pvp players on the map - map[sd->bl.m].users_pvp--; + // decrement the number of pvp players on the map + map[sd->bl.m].users_pvp--; - if (map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER) { - // unregister the player for ranking - delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); - sd->pvp_timer = INVALID_TIMER; - } - } - clif_changeoption(&sd->bl); + if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) + {// unregister the player for ranking + delete_timer( sd->pvp_timer, pc_calc_pvprank_timer ); + sd->pvp_timer = INVALID_TIMER; + } + } + clif_changeoption(&sd->bl); - return 0; + return 0; } /*========================================== @@ -997,53 +992,183 @@ ACMD_FUNC(hide) *------------------------------------------*/ ACMD_FUNC(jobchange) { - int job = 0, upper = 0; - const char *text; - nullpo_retr(-1, sd); - - if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) { - int i, found = 0; - - for (i = JOB_NOVICE; i < JOB_MAX; ++i) { - if (strncmpi(message, job_name(i), 16) == 0) { - job = i; - upper = 0; - found = 1; - break; - } - } - - if (!found) { - text = atcommand_help_string(command); - if (text) - clif_displaymessage(fd, text); - return -1; - } - } - - if (job == JOB_KNIGHT2 || job == JOB_CRUSADER2 || job == JOB_WEDDING || job == JOB_XMAS || job == JOB_SUMMER - || job == JOB_LORD_KNIGHT2 || job == JOB_PALADIN2 || job == JOB_BABY_KNIGHT2 || job == JOB_BABY_CRUSADER2 || job == JOB_STAR_GLADIATOR2 - || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2) - ) { // Deny direct transformation into dummy jobs - clif_displaymessage(fd, msg_txt(923)); //"You can not change to this job by command." - return 0; - } - - if (pcdb_checkid(job)) { - if (pc_jobchange(sd, job, upper) == 0) - clif_displaymessage(fd, msg_txt(12)); // Your job has been changed. - else { - clif_displaymessage(fd, msg_txt(155)); // You are unable to change your job. - return -1; - } - } else { - text = atcommand_help_string(command); - if (text) - clif_displaymessage(fd, text); - return -1; - } - - return 0; + //FIXME: redundancy, potentially wrong code, should use job_name() or similar instead of hardcoding the table [ultramage] + int job = 0, upper = 0; + const char* text; + nullpo_retr(-1, sd); + + if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) + { + int i, found = 0; + const struct { char name[24]; int id; } jobs[] = { + { "novice", 0 }, + { "swordman", 1 }, + { "swordsman", 1 }, + { "magician", 2 }, + { "mage", 2 }, + { "archer", 3 }, + { "acolyte", 4 }, + { "merchant", 5 }, + { "thief", 6 }, + { "knight", 7 }, + { "priest", 8 }, + { "priestess", 8 }, + { "wizard", 9 }, + { "blacksmith", 10 }, + { "hunter", 11 }, + { "assassin", 12 }, + { "crusader", 14 }, + { "monk", 15 }, + { "sage", 16 }, + { "rogue", 17 }, + { "alchemist", 18 }, + { "bard", 19 }, + { "dancer", 20 }, + { "super novice", 23 }, + { "supernovice", 23 }, + { "gunslinger", 24 }, + { "gunner", 24 }, + { "ninja", 25 }, + { "novice high", 4001 }, + { "high novice", 4001 }, + { "swordman high", 4002 }, + { "swordsman high", 4002 }, + { "magician high", 4003 }, + { "mage high", 4003 }, + { "archer high", 4004 }, + { "acolyte high", 4005 }, + { "merchant high", 4006 }, + { "thief high", 4007 }, + { "lord knight", 4008 }, + { "high priest", 4009 }, + { "high priestess", 4009 }, + { "high wizard", 4010 }, + { "whitesmith", 4011 }, + { "sniper", 4012 }, + { "assassin cross", 4013 }, + { "paladin", 4015 }, + { "champion", 4016 }, + { "professor", 4017 }, + { "stalker", 4018 }, + { "creator", 4019 }, + { "clown", 4020 }, + { "gypsy", 4021 }, + { "baby novice", 4023 }, + { "baby swordman", 4024 }, + { "baby swordsman", 4024 }, + { "baby magician", 4025 }, + { "baby mage", 4025 }, + { "baby archer", 4026 }, + { "baby acolyte", 4027 }, + { "baby merchant", 4028 }, + { "baby thief", 4029 }, + { "baby knight", 4030 }, + { "baby priest", 4031 }, + { "baby priestess", 4031 }, + { "baby wizard", 4032 }, + { "baby blacksmith",4033 }, + { "baby hunter", 4034 }, + { "baby assassin", 4035 }, + { "baby crusader", 4037 }, + { "baby monk", 4038 }, + { "baby sage", 4039 }, + { "baby rogue", 4040 }, + { "baby alchemist", 4041 }, + { "baby bard", 4042 }, + { "baby dancer", 4043 }, + { "super baby", 4045 }, + { "taekwon", 4046 }, + { "taekwon boy", 4046 }, + { "taekwon girl", 4046 }, + { "star gladiator", 4047 }, + { "soul linker", 4049 }, + { "gangsi", 4050 }, + { "bongun", 4050 }, + { "munak", 4050 }, + { "death knight", 4051 }, + { "dark collector", 4052 }, + { "rune knight", 4054 }, + { "warlock", 4055 }, + { "ranger", 4056 }, + { "arch bishop", 4057 }, + { "mechanic", 4058 }, + { "guillotine", 4059 }, + { "rune knight2", 4060 }, + { "warlock2", 4061 }, + { "ranger2", 4062 }, + { "arch bishop2", 4063 }, + { "mechanic2", 4064 }, + { "guillotine2", 4065 }, + { "royal guard", 4066 }, + { "sorcerer", 4067 }, + { "minstrel", 4068 }, + { "wanderer", 4069 }, + { "sura", 4070 }, + { "genetic", 4071 }, + { "shadow chaser", 4072 }, + { "royal guard2", 4073 }, + { "sorcerer2", 4074 }, + { "minstrel2", 4075 }, + { "wanderer2", 4076 }, + { "sura2", 4077 }, + { "genetic2", 4078 }, + { "shadow chaser2", 4079 }, + { "baby rune", 4096 }, + { "baby warlock", 4097 }, + { "baby ranger", 4098 }, + { "baby bishop", 4099 }, + { "baby mechanic", 4100 }, + { "baby cross", 4101 }, + { "baby guard", 4102 }, + { "baby sorcerer", 4103 }, + { "baby minstrel", 4104 }, + { "baby wanderer", 4105 }, + { "baby sura", 4106 }, + { "baby genetic", 4107 }, + { "baby chaser", 4108 }, + { "super novice e", 4190 }, + { "super baby e", 4191 }, + { "kagerou", 4211 }, + { "oboro", 4212 }, + }; + + for (i=0; i < ARRAYLENGTH(jobs); i++) { + if (strncmpi(message, jobs[i].name, 16) == 0) { + job = jobs[i].id; + upper = 0; + found = 1; + break; + } + } + + if (!found) { + text = atcommand_help_string(command); + if (text) clif_displaymessage(fd, text); + return -1; + } + } + + if (job == 13 || job == 21 || job == 22 || job == 26 || job == 27 || job == 4014 || job == 4022 || job == 4036 || job == 4044 || job == 4048 + || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2) + ) // Deny direct transformation into dummy jobs + {clif_displaymessage(fd, msg_txt(923)); //"You can not change to this job by command." + return 0;} + + if (pcdb_checkid(job)) + { + if (pc_jobchange(sd, job, upper) == 0) + clif_displaymessage(fd, msg_txt(12)); // Your job has been changed. + else { + clif_displaymessage(fd, msg_txt(155)); // You are unable to change your job. + return -1; + } + } else { + text = atcommand_help_string(command); + if (text) clif_displaymessage(fd, text); + return -1; + } + + return 0; } /*========================================== @@ -1051,12 +1176,12 @@ ACMD_FUNC(jobchange) *------------------------------------------*/ ACMD_FUNC(kill) { - nullpo_retr(-1, sd); - status_kill(&sd->bl); - clif_displaymessage(sd->fd, msg_txt(13)); // A pity! You've died. - if (fd != sd->fd) - clif_displaymessage(fd, msg_txt(14)); // Character killed. - return 0; + nullpo_retr(-1, sd); + status_kill(&sd->bl); + clif_displaymessage(sd->fd, msg_txt(13)); // A pity! You've died. + if (fd != sd->fd) + clif_displaymessage(fd, msg_txt(14)); // Character killed. + return 0; } /*========================================== @@ -1064,14 +1189,15 @@ ACMD_FUNC(kill) *------------------------------------------*/ ACMD_FUNC(alive) { - nullpo_retr(-1, sd); - if (!status_revive(&sd->bl, 100, 100)) { - clif_displaymessage(fd, msg_txt(667)); - return -1; - } - clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); - clif_displaymessage(fd, msg_txt(16)); // You've been revived! It's a miracle! - return 0; + nullpo_retr(-1, sd); + if (!status_revive(&sd->bl, 100, 100)) + { + clif_displaymessage(fd, msg_txt(667)); + return -1; + } + clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); + clif_displaymessage(fd, msg_txt(16)); // You've been revived! It's a miracle! + return 0; } /*========================================== @@ -1079,35 +1205,35 @@ ACMD_FUNC(alive) *------------------------------------------*/ ACMD_FUNC(kami) { - unsigned long color=0; - nullpo_retr(-1, sd); + unsigned long color=0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (*(command + 5) != 'c' && *(command + 5) != 'C') { - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(980)); // Please enter a message (usage: @kami ). - return -1; - } + if(*(command + 5) != 'c' && *(command + 5) != 'C') { + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(980)); // Please enter a message (usage: @kami ). + return -1; + } - sscanf(message, "%199[^\n]", atcmd_output); - if (strstr(command, "l") != NULL) - clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); - else - intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0); - } else { - if (!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { - clif_displaymessage(fd, msg_txt(981)); // Please enter color and message (usage: @kamic ). - return -1; - } + sscanf(message, "%199[^\n]", atcmd_output); + if (strstr(command, "l") != NULL) + clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); + else + intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0); + } else { + if(!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { + clif_displaymessage(fd, msg_txt(981)); // Please enter color and message (usage: @kamic ). + return -1; + } - if (color > 0xFFFFFF) { - clif_displaymessage(fd, msg_txt(982)); // Invalid color. - return -1; - } - intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); - } - return 0; + if(color > 0xFFFFFF) { + clif_displaymessage(fd, msg_txt(982)); // Invalid color. + return -1; + } + intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); + } + return 0; } /*========================================== @@ -1115,57 +1241,57 @@ ACMD_FUNC(kami) *------------------------------------------*/ ACMD_FUNC(heal) { - int hp = 0, sp = 0; // [Valaris] thanks to fov - nullpo_retr(-1, sd); - - sscanf(message, "%d %d", &hp, &sp); - - // some overflow checks - if (hp == INT_MIN) hp++; - if (sp == INT_MIN) sp++; - - if (hp == 0 && sp == 0) { - if (!status_percent_heal(&sd->bl, 100, 100)) - clif_displaymessage(fd, msg_txt(157)); // HP and SP have already been recovered. - else - clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. - return 0; - } - - if (hp > 0 && sp >= 0) { - if (!status_heal(&sd->bl, hp, sp, 0)) - clif_displaymessage(fd, msg_txt(157)); // HP and SP are already with the good value. - else - clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. - return 0; - } - - if (hp < 0 && sp <= 0) { - status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); - clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); - clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. - return 0; - } - - //Opposing signs. - if (hp) { - if (hp > 0) - status_heal(&sd->bl, hp, 0, 0); - else { - status_damage(NULL, &sd->bl, -hp, 0, 0, 0); - clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); - } - } - - if (sp) { - if (sp > 0) - status_heal(&sd->bl, 0, sp, 0); - else - status_damage(NULL, &sd->bl, 0, -sp, 0, 0); - } - - clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. - return 0; + int hp = 0, sp = 0; // [Valaris] thanks to fov + nullpo_retr(-1, sd); + + sscanf(message, "%d %d", &hp, &sp); + + // some overflow checks + if( hp == INT_MIN ) hp++; + if( sp == INT_MIN ) sp++; + + if ( hp == 0 && sp == 0 ) { + if (!status_percent_heal(&sd->bl, 100, 100)) + clif_displaymessage(fd, msg_txt(157)); // HP and SP have already been recovered. + else + clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. + return 0; + } + + if ( hp > 0 && sp >= 0 ) { + if(!status_heal(&sd->bl, hp, sp, 0)) + clif_displaymessage(fd, msg_txt(157)); // HP and SP are already with the good value. + else + clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. + return 0; + } + + if ( hp < 0 && sp <= 0 ) { + status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); + clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); + clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. + return 0; + } + + //Opposing signs. + if ( hp ) { + if (hp > 0) + status_heal(&sd->bl, hp, 0, 0); + else { + status_damage(NULL, &sd->bl, -hp, 0, 0, 0); + clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); + } + } + + if ( sp ) { + if (sp > 0) + status_heal(&sd->bl, 0, sp, 0); + else + status_damage(NULL, &sd->bl, 0, -sp, 0, 0); + } + + clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. + return 0; } /*========================================== @@ -1173,53 +1299,54 @@ ACMD_FUNC(heal) *------------------------------------------*/ ACMD_FUNC(item) { - char item_name[100]; - int number = 0, item_id, flag = 0; - struct item item_tmp; - struct item_data *item_data; - int get_count, i; - nullpo_retr(-1, sd); - - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && - sscanf(message, "%99s %d", item_name, &number) < 1 - )) { - clif_displaymessage(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). - return -1; - } - - if (number <= 0) - number = 1; - - if ((item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL) { - clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. - return -1; - } - - item_id = item_data->nameid; - get_count = number; - //Check if it's stackable. - if (!itemdb_isstackable2(item_data)) - get_count = 1; - - for (i = 0; i < number; i += get_count) { - // if not pet egg - if (!pet_create_egg(sd, item_id)) { - memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = item_id; - item_tmp.identify = 1; - - if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } - } - - if (flag == 0) - clif_displaymessage(fd, msg_txt(18)); // Item created. - return 0; + char item_name[100]; + int number = 0, item_id, flag = 0; + struct item item_tmp; + struct item_data *item_data; + int get_count, i; + nullpo_retr(-1, sd); + + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && + sscanf(message, "%99s %d", item_name, &number) < 1 + )) { + clif_displaymessage(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). + return -1; + } + + if (number <= 0) + number = 1; + + if ((item_data = itemdb_searchname(item_name)) == NULL && + (item_data = itemdb_exists(atoi(item_name))) == NULL) + { + clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. + return -1; + } + + item_id = item_data->nameid; + get_count = number; + //Check if it's stackable. + if (!itemdb_isstackable2(item_data)) + get_count = 1; + + for (i = 0; i < number; i += get_count) { + // if not pet egg + if (!pet_create_egg(sd, item_id)) { + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = item_id; + item_tmp.identify = 1; + + if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } + } + + if (flag == 0) + clif_displaymessage(fd, msg_txt(18)); // Item created. + return 0; } /*========================================== @@ -1227,76 +1354,76 @@ ACMD_FUNC(item) *------------------------------------------*/ ACMD_FUNC(item2) { - struct item item_tmp; - struct item_data *item_data; - char item_name[100]; - int item_id, number = 0; - int identify = 0, refine = 0, attr = 0; - int c1 = 0, c2 = 0, c3 = 0, c4 = 0; - int flag = 0; - int loop, get_count, i; - nullpo_retr(-1, sd); - - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && - sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 - )) { - clif_displaymessage(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 - clif_displaymessage(fd, msg_txt(985)); // ). - return -1; - } - - if (number <= 0) - number = 1; - - item_id = 0; - if ((item_data = itemdb_searchname(item_name)) != NULL || - (item_data = itemdb_exists(atoi(item_name))) != NULL) - item_id = item_data->nameid; - - if (item_id > 500) { - loop = 1; - get_count = number; - if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || - item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { - loop = number; - get_count = 1; - if (item_data->type == IT_PETEGG) { - identify = 1; - refine = 0; - } - if (item_data->type == IT_PETARMOR) - refine = 0; - if (refine > MAX_REFINE) - refine = MAX_REFINE; - } else { - identify = 1; - refine = attr = 0; - } - for (i = 0; i < loop; i++) { - memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = item_id; - item_tmp.identify = identify; - item_tmp.refine = refine; - item_tmp.attribute = attr; - item_tmp.card[0] = c1; - item_tmp.card[1] = c2; - item_tmp.card[2] = c3; - item_tmp.card[3] = c4; - if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } - - if (flag == 0) - clif_displaymessage(fd, msg_txt(18)); // Item created. - } else { - clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. - return -1; - } - - return 0; + struct item item_tmp; + struct item_data *item_data; + char item_name[100]; + int item_id, number = 0; + int identify = 0, refine = 0, attr = 0; + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + int flag = 0; + int loop, get_count, i; + nullpo_retr(-1, sd); + + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && + sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 + )) { + clif_displaymessage(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 + clif_displaymessage(fd, msg_txt(985)); // ). + return -1; + } + + if (number <= 0) + number = 1; + + item_id = 0; + if ((item_data = itemdb_searchname(item_name)) != NULL || + (item_data = itemdb_exists(atoi(item_name))) != NULL) + item_id = item_data->nameid; + + if (item_id > 500) { + loop = 1; + get_count = number; + if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || + item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { + loop = number; + get_count = 1; + if (item_data->type == IT_PETEGG) { + identify = 1; + refine = 0; + } + if (item_data->type == IT_PETARMOR) + refine = 0; + if (refine > MAX_REFINE) + refine = MAX_REFINE; + } else { + identify = 1; + refine = attr = 0; + } + for (i = 0; i < loop; i++) { + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = item_id; + item_tmp.identify = identify; + item_tmp.refine = refine; + item_tmp.attribute = attr; + item_tmp.card[0] = c1; + item_tmp.card[1] = c2; + item_tmp.card[2] = c3; + item_tmp.card[3] = c4; + if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } + + if (flag == 0) + clif_displaymessage(fd, msg_txt(18)); // Item created. + } else { + clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. + return -1; + } + + return 0; } /*========================================== @@ -1304,17 +1431,17 @@ ACMD_FUNC(item2) *------------------------------------------*/ ACMD_FUNC(itemreset) { - int i; - nullpo_retr(-1, sd); + int i; + nullpo_retr(-1, sd); - for (i = 0; i < MAX_INVENTORY; i++) { - if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) { - pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND); - } - } - clif_displaymessage(fd, msg_txt(20)); // All of your items have been removed. + for (i = 0; i < MAX_INVENTORY; i++) { + if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) { + pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND); + } + } + clif_displaymessage(fd, msg_txt(20)); // All of your items have been removed. - return 0; + return 0; } /*========================================== @@ -1322,59 +1449,59 @@ ACMD_FUNC(itemreset) *------------------------------------------*/ ACMD_FUNC(baselevelup) { - int level=0, i=0, status_point=0; - nullpo_retr(-1, sd); - level = atoi(message); - - if (!message || !*message || !level) { - clif_displaymessage(fd, msg_txt(986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup ). - return -1; - } - - if (level > 0) { - if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris - clif_displaymessage(fd, msg_txt(47)); // Base level can't go any higher. - return -1; - } // End Addition - if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positiv overflow - level = pc_maxbaselv(sd) - sd->status.base_level; - for (i = 0; i < level; i++) - status_point += pc_gets_status_point(sd->status.base_level + i); - - sd->status.status_point += status_point; - sd->status.base_level += (unsigned int)level; - status_percent_heal(&sd->bl, 100, 100); - clif_misceffect(&sd->bl, 0); - clif_displaymessage(fd, msg_txt(21)); // Base level raised. - } else { - if (sd->status.base_level == 1) { - clif_displaymessage(fd, msg_txt(158)); // Base level can't go any lower. - return -1; - } - level*=-1; - if ((unsigned int)level >= sd->status.base_level) - level = sd->status.base_level-1; - for (i = 0; i > -level; i--) - status_point += pc_gets_status_point(sd->status.base_level + i - 1); - if (sd->status.status_point < status_point) - pc_resetstate(sd); - if (sd->status.status_point < status_point) - sd->status.status_point = 0; - else - sd->status.status_point -= status_point; - sd->status.base_level -= (unsigned int)level; - clif_displaymessage(fd, msg_txt(22)); // Base level lowered. - } - sd->status.base_exp = 0; - clif_updatestatus(sd, SP_STATUSPOINT); - clif_updatestatus(sd, SP_BASELEVEL); - clif_updatestatus(sd, SP_BASEEXP); - clif_updatestatus(sd, SP_NEXTBASEEXP); - status_calc_pc(sd, 0); - pc_baselevelchanged(sd); - if (sd->status.party_id) - party_send_levelup(sd); - return 0; + int level=0, i=0, status_point=0; + nullpo_retr(-1, sd); + level = atoi(message); + + if (!message || !*message || !level) { + clif_displaymessage(fd, msg_txt(986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup ). + return -1; + } + + if (level > 0) { + if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris + clif_displaymessage(fd, msg_txt(47)); // Base level can't go any higher. + return -1; + } // End Addition + if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positiv overflow + level = pc_maxbaselv(sd) - sd->status.base_level; + for (i = 0; i < level; i++) + status_point += pc_gets_status_point(sd->status.base_level + i); + + sd->status.status_point += status_point; + sd->status.base_level += (unsigned int)level; + status_percent_heal(&sd->bl, 100, 100); + clif_misceffect(&sd->bl, 0); + clif_displaymessage(fd, msg_txt(21)); // Base level raised. + } else { + if (sd->status.base_level == 1) { + clif_displaymessage(fd, msg_txt(158)); // Base level can't go any lower. + return -1; + } + level*=-1; + if ((unsigned int)level >= sd->status.base_level) + level = sd->status.base_level-1; + for (i = 0; i > -level; i--) + status_point += pc_gets_status_point(sd->status.base_level + i - 1); + if (sd->status.status_point < status_point) + pc_resetstate(sd); + if (sd->status.status_point < status_point) + sd->status.status_point = 0; + else + sd->status.status_point -= status_point; + sd->status.base_level -= (unsigned int)level; + clif_displaymessage(fd, msg_txt(22)); // Base level lowered. + } + sd->status.base_exp = 0; + clif_updatestatus(sd, SP_STATUSPOINT); + clif_updatestatus(sd, SP_BASELEVEL); + clif_updatestatus(sd, SP_BASEEXP); + clif_updatestatus(sd, SP_NEXTBASEEXP); + status_calc_pc(sd, 0); + pc_baselevelchanged(sd); + if(sd->status.party_id) + party_send_levelup(sd); + return 0; } /*========================================== @@ -1382,51 +1509,51 @@ ACMD_FUNC(baselevelup) *------------------------------------------*/ ACMD_FUNC(joblevelup) { - int level=0; - nullpo_retr(-1, sd); - - level = atoi(message); - - if (!message || !*message || !level) { - clif_displaymessage(fd, msg_txt(987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup ). - return -1; - } - if (level > 0) { - if (sd->status.job_level >= pc_maxjoblv(sd)) { - clif_displaymessage(fd, msg_txt(23)); // Job level can't go any higher. - return -1; - } - if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow - level = pc_maxjoblv(sd) - sd->status.job_level; - sd->status.job_level += (unsigned int)level; - sd->status.skill_point += level; - clif_misceffect(&sd->bl, 1); - clif_displaymessage(fd, msg_txt(24)); // Job level raised. - } else { - if (sd->status.job_level == 1) { - clif_displaymessage(fd, msg_txt(159)); // Job level can't go any lower. - return -1; - } - level *=-1; - if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow - level = sd->status.job_level-1; - sd->status.job_level -= (unsigned int)level; - if (sd->status.skill_point < level) - pc_resetskill(sd,0); //Reset skills since we need to substract more points. - if (sd->status.skill_point < level) - sd->status.skill_point = 0; - else - sd->status.skill_point -= level; - clif_displaymessage(fd, msg_txt(25)); // Job level lowered. - } - sd->status.job_exp = 0; - clif_updatestatus(sd, SP_JOBLEVEL); - clif_updatestatus(sd, SP_JOBEXP); - clif_updatestatus(sd, SP_NEXTJOBEXP); - clif_updatestatus(sd, SP_SKILLPOINT); - status_calc_pc(sd, 0); - - return 0; + int level=0; + nullpo_retr(-1, sd); + + level = atoi(message); + + if (!message || !*message || !level) { + clif_displaymessage(fd, msg_txt(987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup ). + return -1; + } + if (level > 0) { + if (sd->status.job_level >= pc_maxjoblv(sd)) { + clif_displaymessage(fd, msg_txt(23)); // Job level can't go any higher. + return -1; + } + if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow + level = pc_maxjoblv(sd) - sd->status.job_level; + sd->status.job_level += (unsigned int)level; + sd->status.skill_point += level; + clif_misceffect(&sd->bl, 1); + clif_displaymessage(fd, msg_txt(24)); // Job level raised. + } else { + if (sd->status.job_level == 1) { + clif_displaymessage(fd, msg_txt(159)); // Job level can't go any lower. + return -1; + } + level *=-1; + if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow + level = sd->status.job_level-1; + sd->status.job_level -= (unsigned int)level; + if (sd->status.skill_point < level) + pc_resetskill(sd,0); //Reset skills since we need to substract more points. + if (sd->status.skill_point < level) + sd->status.skill_point = 0; + else + sd->status.skill_point -= level; + clif_displaymessage(fd, msg_txt(25)); // Job level lowered. + } + sd->status.job_exp = 0; + clif_updatestatus(sd, SP_JOBLEVEL); + clif_updatestatus(sd, SP_JOBEXP); + clif_updatestatus(sd, SP_NEXTJOBEXP); + clif_updatestatus(sd, SP_SKILLPOINT); + status_calc_pc(sd, 0); + + return 0; } /*========================================== @@ -1434,116 +1561,116 @@ ACMD_FUNC(joblevelup) *------------------------------------------*/ ACMD_FUNC(help) { - config_setting_t *help; - const char *text = NULL; - const char *command_name = NULL; - char *default_command = "help"; - - nullpo_retr(-1, sd); - - help = config_lookup(&atcommand_config, "help"); - if (help == NULL) { - clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available." - return -1; - } - - if (!message || !*message) { - command_name = default_command; // If no command_name specified, display help for @help. - } else { - if (*message == atcommand_symbol || *message == charcommand_symbol) - ++message; - command_name = atcommand_checkalias(message); - } - - if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) { - sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command" - clif_displaymessage(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); - return -1; - } - - if (!config_setting_lookup_string(help, command_name, &text)) { - sprintf(atcmd_output, msg_txt(988), atcommand_symbol, command_name); // There is no help for %c%s. - clif_displaymessage(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); - return -1; - } - - sprintf(atcmd_output, msg_txt(989), atcommand_symbol, command_name); // Help for command %c%s: - clif_displaymessage(fd, atcmd_output); - - { - // Display aliases - DBIterator *iter; - AtCommandInfo *command_info; - AliasInfo *alias_info = NULL; - StringBuf buf; - bool has_aliases = false; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, msg_txt(990)); // Available aliases: - command_info = get_atcommandinfo_byname(command_name); - iter = db_iterator(atcommand_alias_db); - for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) { - if (alias_info->command == command_info) { - StringBuf_Printf(&buf, " %s", alias_info->alias); - has_aliases = true; - } - } - dbi_destroy(iter); - if (has_aliases) - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Destroy(&buf); - } - - // Display help contents - clif_displaymessage(fd, text); - return 0; + config_setting_t *help; + const char *text = NULL; + const char *command_name = NULL; + char *default_command = "help"; + + nullpo_retr(-1, sd); + + help = config_lookup(&atcommand_config, "help"); + if (help == NULL) { + clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available." + return -1; + } + + if (!message || !*message) { + command_name = default_command; // If no command_name specified, display help for @help. + } else { + if (*message == atcommand_symbol || *message == charcommand_symbol) + ++message; + command_name = atcommand_checkalias(message); + } + + if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) { + sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command" + clif_displaymessage(fd, atcmd_output); + atcommand_get_suggestions(sd, command_name, true); + return -1; + } + + if (!config_setting_lookup_string(help, command_name, &text)) { + sprintf(atcmd_output, msg_txt(988), atcommand_symbol, command_name); // There is no help for %c%s. + clif_displaymessage(fd, atcmd_output); + atcommand_get_suggestions(sd, command_name, true); + return -1; + } + + sprintf(atcmd_output, msg_txt(989), atcommand_symbol, command_name); // Help for command %c%s: + clif_displaymessage(fd, atcmd_output); + + { // Display aliases + DBIterator* iter; + AtCommandInfo *command_info; + AliasInfo *alias_info = NULL; + StringBuf buf; + bool has_aliases = false; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, msg_txt(990)); // Available aliases: + command_info = get_atcommandinfo_byname(command_name); + iter = db_iterator(atcommand_alias_db); + for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) { + if (alias_info->command == command_info) { + StringBuf_Printf(&buf, " %s", alias_info->alias); + has_aliases = true; + } + } + dbi_destroy(iter); + if (has_aliases) + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Destroy(&buf); + } + + // Display help contents + clif_displaymessage(fd, text); + return 0; } // helper function, used in foreach calls to stop auto-attack timers // parameter: '0' - everyone, 'id' - only those attacking someone with that id static int atcommand_stopattack(struct block_list *bl,va_list ap) { - struct unit_data *ud = unit_bl2ud(bl); - int id = va_arg(ap, int); - if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) { - unit_stop_attack(bl); - return 1; - } - return 0; + struct unit_data *ud = unit_bl2ud(bl); + int id = va_arg(ap, int); + if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) + { + unit_stop_attack(bl); + return 1; + } + return 0; } /*========================================== * *------------------------------------------*/ static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap) { - TBL_PC *sd = (TBL_PC *)bl; - clif_pvpset(sd, 0, 0, 2); - if (sd->pvp_timer != INVALID_TIMER) { - delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); - sd->pvp_timer = INVALID_TIMER; - } - return 0; + TBL_PC* sd = (TBL_PC*)bl; + clif_pvpset(sd, 0, 0, 2); + if (sd->pvp_timer != INVALID_TIMER) { + delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); + sd->pvp_timer = INVALID_TIMER; + } + return 0; } ACMD_FUNC(pvpoff) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!map[sd->bl.m].flag.pvp) { - clif_displaymessage(fd, msg_txt(160)); // PvP is already Off. - return -1; - } + if (!map[sd->bl.m].flag.pvp) { + clif_displaymessage(fd, msg_txt(160)); // PvP is already Off. + return -1; + } - map[sd->bl.m].flag.pvp = 0; + map[sd->bl.m].flag.pvp = 0; - if (!battle_config.pk_mode) - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); - map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC); - map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); - clif_displaymessage(fd, msg_txt(31)); // PvP: Off. - return 0; + if (!battle_config.pk_mode) + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); + map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC); + map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + clif_displaymessage(fd, msg_txt(31)); // PvP: Off. + return 0; } /*========================================== @@ -1551,38 +1678,38 @@ ACMD_FUNC(pvpoff) *------------------------------------------*/ static int atcommand_pvpon_sub(struct block_list *bl,va_list ap) { - TBL_PC *sd = (TBL_PC *)bl; - if (sd->pvp_timer == INVALID_TIMER) { - sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); - sd->pvp_rank = 0; - sd->pvp_lastusers = 0; - sd->pvp_point = 5; - sd->pvp_won = 0; - sd->pvp_lost = 0; - } - return 0; + TBL_PC* sd = (TBL_PC*)bl; + if (sd->pvp_timer == INVALID_TIMER) { + sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); + sd->pvp_rank = 0; + sd->pvp_lastusers = 0; + sd->pvp_point = 5; + sd->pvp_won = 0; + sd->pvp_lost = 0; + } + return 0; } ACMD_FUNC(pvpon) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.pvp) { - clif_displaymessage(fd, msg_txt(161)); // PvP is already On. - return -1; - } + if (map[sd->bl.m].flag.pvp) { + clif_displaymessage(fd, msg_txt(161)); // PvP is already On. + return -1; + } - map[sd->bl.m].flag.pvp = 1; + map[sd->bl.m].flag.pvp = 1; - if (!battle_config.pk_mode) { - // display pvp circle and rank - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE); - map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC); - } + if (!battle_config.pk_mode) + {// display pvp circle and rank + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE); + map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC); + } - clif_displaymessage(fd, msg_txt(32)); // PvP: On. + clif_displaymessage(fd, msg_txt(32)); // PvP: On. - return 0; + return 0; } /*========================================== @@ -1590,19 +1717,19 @@ ACMD_FUNC(pvpon) *------------------------------------------*/ ACMD_FUNC(gvgoff) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!map[sd->bl.m].flag.gvg) { - clif_displaymessage(fd, msg_txt(162)); // GvG is already Off. - return -1; - } + if (!map[sd->bl.m].flag.gvg) { + clif_displaymessage(fd, msg_txt(162)); // GvG is already Off. + return -1; + } - map[sd->bl.m].flag.gvg = 0; - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); - map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); - clif_displaymessage(fd, msg_txt(33)); // GvG: Off. + map[sd->bl.m].flag.gvg = 0; + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); + map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + clif_displaymessage(fd, msg_txt(33)); // GvG: Off. - return 0; + return 0; } /*========================================== @@ -1610,18 +1737,18 @@ ACMD_FUNC(gvgoff) *------------------------------------------*/ ACMD_FUNC(gvgon) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.gvg) { - clif_displaymessage(fd, msg_txt(163)); // GvG is already On. - return -1; - } + if (map[sd->bl.m].flag.gvg) { + clif_displaymessage(fd, msg_txt(163)); // GvG is already On. + return -1; + } - map[sd->bl.m].flag.gvg = 1; - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE); - clif_displaymessage(fd, msg_txt(34)); // GvG: On. + map[sd->bl.m].flag.gvg = 1; + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE); + clif_displaymessage(fd, msg_txt(34)); // GvG: On. - return 0; + return 0; } /*========================================== @@ -1629,31 +1756,31 @@ ACMD_FUNC(gvgon) *------------------------------------------*/ ACMD_FUNC(model) { - int hair_style = 0, hair_color = 0, cloth_color = 0; - nullpo_retr(-1, sd); + int hair_style = 0, hair_color = 0, cloth_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) { - sprintf(atcmd_output, msg_txt(991), // Please enter at least one value (usage: @model ). - MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) { + sprintf(atcmd_output, msg_txt(991), // Please enter at least one value (usage: @model ). + MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && - hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && - cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { - pc_changelook(sd, LOOK_HAIR, hair_style); - pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); - pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && + hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && + cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { + pc_changelook(sd, LOOK_HAIR, hair_style); + pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); + pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1661,26 +1788,26 @@ ACMD_FUNC(model) *------------------------------------------*/ ACMD_FUNC(dye) { - int cloth_color = 0; - nullpo_retr(-1, sd); + int cloth_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) { - sprintf(atcmd_output, msg_txt(992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) { + sprintf(atcmd_output, msg_txt(992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { - pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { + pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1688,26 +1815,26 @@ ACMD_FUNC(dye) *------------------------------------------*/ ACMD_FUNC(hair_style) { - int hair_style = 0; - nullpo_retr(-1, sd); + int hair_style = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) { - sprintf(atcmd_output, msg_txt(993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) { + sprintf(atcmd_output, msg_txt(993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) { - pc_changelook(sd, LOOK_HAIR, hair_style); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) { + pc_changelook(sd, LOOK_HAIR, hair_style); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1715,26 +1842,26 @@ ACMD_FUNC(hair_style) *------------------------------------------*/ ACMD_FUNC(hair_color) { - int hair_color = 0; - nullpo_retr(-1, sd); + int hair_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) { - sprintf(atcmd_output, msg_txt(994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) { + sprintf(atcmd_output, msg_txt(994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) { - pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) { + pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1742,198 +1869,199 @@ ACMD_FUNC(hair_color) *------------------------------------------*/ ACMD_FUNC(go) { - int i; - int town; - char map_name[MAP_NAME_LENGTH]; - int m; - - const struct { - char map[MAP_NAME_LENGTH]; - int x, y; - } data[] = { - { MAP_PRONTERA, 156, 191 }, // 0=Prontera - { MAP_MORROC, 156, 93 }, // 1=Morroc - { MAP_GEFFEN, 119, 59 }, // 2=Geffen - { MAP_PAYON, 162, 233 }, // 3=Payon - { MAP_ALBERTA, 192, 147 }, // 4=Alberta + int i; + int town; + char map_name[MAP_NAME_LENGTH]; + int m; + + const struct { + char map[MAP_NAME_LENGTH]; + int x, y; + } data[] = { + { MAP_PRONTERA, 156, 191 }, // 0=Prontera + { MAP_MORROC, 156, 93 }, // 1=Morroc + { MAP_GEFFEN, 119, 59 }, // 2=Geffen + { MAP_PAYON, 162, 233 }, // 3=Payon + { MAP_ALBERTA, 192, 147 }, // 4=Alberta #ifdef RENEWAL - { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal) + { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal) #else - { MAP_IZLUDE, 128, 114 }, // 5=Izlude + { MAP_IZLUDE, 128, 114 }, // 5=Izlude #endif - { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran - { MAP_LUTIE, 147, 134 }, // 7=Lutie - { MAP_COMODO, 209, 143 }, // 8=Comodo - { MAP_YUNO, 157, 51 }, // 9=Yuno - { MAP_AMATSU, 198, 84 }, // 10=Amatsu - { MAP_GONRYUN, 160, 120 }, // 11=Gonryun - { MAP_UMBALA, 89, 157 }, // 12=Umbala - { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim - { MAP_LOUYANG, 217, 40 }, // 14=Louyang - { MAP_NOVICE, 53, 111 }, // 15=Training Grounds - { MAP_JAIL, 23, 61 }, // 16=Prison - { MAP_JAWAII, 249, 127 }, // 17=Jawaii - { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya - { MAP_EINBROCH, 64, 200 }, // 19=Einbroch - { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen - { MAP_EINBECH, 70, 95 }, // 21=Einbech - { MAP_HUGEL, 96, 145 }, // 22=Hugel - { MAP_RACHEL, 130, 110 }, // 23=Rachel - { MAP_VEINS, 216, 123 }, // 24=Veins - { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia - { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp - { MAP_MANUK, 282, 138 }, // 27=Manuk - { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide - { MAP_BRASILIS, 182, 239 }, // 29=Brasilis - { MAP_DICASTES, 198, 187 }, // 30=El Dicastes - { MAP_MORA, 44, 151 }, // 31=Mora - { MAP_DEWATA, 200, 180 }, // 32=Dewata - { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island - { MAP_MALAYA, 242, 211 }, // 34=Malaya Port - { MAP_ECLAGE, 110, 39 }, // 35=Eclage - }; - - nullpo_retr(-1, sd); - - if (map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(sd->fd,msg_txt(995)); // You cannot use @go on this map. - return 0; - } - - memset(map_name, '\0', sizeof(map_name)); - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - // get the number - town = atoi(message); - - if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data)) { - // no value matched so send the list of locations - const char *text; - - // attempt to find the text help string - text = atcommand_help_string(command); - - clif_displaymessage(fd, msg_txt(38)); // Invalid location number, or name. - - if (text) { - // send the text to the client - clif_displaymessage(fd, text); - } - - return -1; - } - - // get possible name of the city - map_name[MAP_NAME_LENGTH-1] = '\0'; - for (i = 0; map_name[i]; i++) - map_name[i] = TOLOWER(map_name[i]); - // try to identify the map name - if (strncmp(map_name, "prontera", 3) == 0) { - town = 0; - } else if (strncmp(map_name, "morocc", 4) == 0 || - strncmp(map_name, "morroc", 4) == 0) { - town = 1; - } else if (strncmp(map_name, "geffen", 3) == 0) { - town = 2; - } else if (strncmp(map_name, "payon", 3) == 0) { - town = 3; - } else if (strncmp(map_name, "alberta", 3) == 0) { - town = 4; - } else if (strncmp(map_name, "izlude", 3) == 0) { - town = 5; - } else if (strncmp(map_name, "aldebaran", 3) == 0) { - town = 6; - } else if (strncmp(map_name, "lutie", 3) == 0 || - strcmp(map_name, "christmas") == 0 || - strncmp(map_name, "xmas", 3) == 0 || - strncmp(map_name, "x-mas", 3) == 0) { - town = 7; - } else if (strncmp(map_name, "comodo", 3) == 0) { - town = 8; - } else if (strncmp(map_name, "juno", 3) == 0 || - strncmp(map_name, "yuno", 3) == 0) { - town = 9; - } else if (strncmp(map_name, "amatsu", 3) == 0) { - town = 10; - } else if (strncmp(map_name, "kunlun", 3) == 0 || - strncmp(map_name, "gonryun", 3) == 0) { - town = 11; - } else if (strncmp(map_name, "umbala", 3) == 0) { - town = 12; - } else if (strncmp(map_name, "niflheim", 3) == 0) { - town = 13; - } else if (strncmp(map_name, "louyang", 3) == 0) { - town = 14; - } else if (strncmp(map_name, "new_1-1", 3) == 0 || - strncmp(map_name, "startpoint", 3) == 0 || - strncmp(map_name, "beginning", 3) == 0) { - town = 15; - } else if (strncmp(map_name, "sec_pri", 3) == 0 || - strncmp(map_name, "prison", 3) == 0 || - strncmp(map_name, "jail", 3) == 0) { - town = 16; - } else if (strncmp(map_name, "jawaii", 3) == 0) { - town = 17; - } else if (strncmp(map_name, "ayothaya", 3) == 0) { - town = 18; - } else if (strncmp(map_name, "einbroch", 5) == 0) { - town = 19; - } else if (strncmp(map_name, "lighthalzen", 3) == 0) { - town = 20; - } else if (strncmp(map_name, "einbech", 5) == 0) { - town = 21; - } else if (strncmp(map_name, "hugel", 3) == 0) { - town = 22; - } else if (strncmp(map_name, "rachel", 3) == 0) { - town = 23; - } else if (strncmp(map_name, "veins", 3) == 0) { - town = 24; - } else if (strncmp(map_name, "moscovia", 3) == 0) { - town = 25; - } else if (strncmp(map_name, "mid_camp", 3) == 0) { - town = 26; - } else if (strncmp(map_name, "manuk", 3) == 0) { - town = 27; - } else if (strncmp(map_name, "splendide", 3) == 0) { - town = 28; - } else if (strncmp(map_name, "brasilis", 3) == 0) { - town = 29; - } else if (strncmp(map_name, "dicastes01", 3) == 0) { - town = 30; - } else if (strcmp(map_name, "mora") == 0) { - town = 31; - } else if (strncmp(map_name, "dewata", 3) == 0) { - town = 32; - } else if (strncmp(map_name, "malangdo", 5) == 0) { - town = 33; - } else if (strncmp(map_name, "malaya", 5) == 0) { - town = 34; - } else if (strncmp(map_name, "eclage", 3) == 0) { - town = 35; - } - - if (town >= 0 && town < ARRAYLENGTH(data)) { - m = map_mapname2mapid(data[town].map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { - clif_displaymessage(fd, msg_txt(0)); // Warped. - } else { - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } - } else { // if you arrive here, you have an error in town variable when reading of names - clif_displaymessage(fd, msg_txt(38)); // Invalid location number or name. - return -1; - } - - return 0; + { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran + { MAP_LUTIE, 147, 134 }, // 7=Lutie + { MAP_COMODO, 209, 143 }, // 8=Comodo + { MAP_YUNO, 157, 51 }, // 9=Yuno + { MAP_AMATSU, 198, 84 }, // 10=Amatsu + { MAP_GONRYUN, 160, 120 }, // 11=Gonryun + { MAP_UMBALA, 89, 157 }, // 12=Umbala + { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim + { MAP_LOUYANG, 217, 40 }, // 14=Louyang + { MAP_NOVICE, 53, 111 }, // 15=Training Grounds + { MAP_JAIL, 23, 61 }, // 16=Prison + { MAP_JAWAII, 249, 127 }, // 17=Jawaii + { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya + { MAP_EINBROCH, 64, 200 }, // 19=Einbroch + { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen + { MAP_EINBECH, 70, 95 }, // 21=Einbech + { MAP_HUGEL, 96, 145 }, // 22=Hugel + { MAP_RACHEL, 130, 110 }, // 23=Rachel + { MAP_VEINS, 216, 123 }, // 24=Veins + { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia + { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp + { MAP_MANUK, 282, 138 }, // 27=Manuk + { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide + { MAP_BRASILIS, 182, 239 }, // 29=Brasilis + { MAP_DICASTES, 198, 187 }, // 30=El Dicastes + { MAP_MORA, 44, 151 }, // 31=Mora + { MAP_DEWATA, 200, 180 }, // 32=Dewata + { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island + { MAP_MALAYA, 242, 211 }, // 34=Malaya Port + { MAP_ECLAGE, 110, 39 }, // 35=Eclage + }; + + nullpo_retr(-1, sd); + + if( map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { + clif_displaymessage(sd->fd,msg_txt(995)); // You cannot use @go on this map. + return 0; + } + + memset(map_name, '\0', sizeof(map_name)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + // get the number + town = atoi(message); + + if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data)) + {// no value matched so send the list of locations + const char* text; + + // attempt to find the text help string + text = atcommand_help_string( command ); + + clif_displaymessage(fd, msg_txt(38)); // Invalid location number, or name. + + if( text ) + {// send the text to the client + clif_displaymessage( fd, text ); + } + + return -1; + } + + // get possible name of the city + map_name[MAP_NAME_LENGTH-1] = '\0'; + for (i = 0; map_name[i]; i++) + map_name[i] = TOLOWER(map_name[i]); + // try to identify the map name + if (strncmp(map_name, "prontera", 3) == 0) { + town = 0; + } else if (strncmp(map_name, "morocc", 4) == 0 || + strncmp(map_name, "morroc", 4) == 0) { + town = 1; + } else if (strncmp(map_name, "geffen", 3) == 0) { + town = 2; + } else if (strncmp(map_name, "payon", 3) == 0) { + town = 3; + } else if (strncmp(map_name, "alberta", 3) == 0) { + town = 4; + } else if (strncmp(map_name, "izlude", 3) == 0) { + town = 5; + } else if (strncmp(map_name, "aldebaran", 3) == 0) { + town = 6; + } else if (strncmp(map_name, "lutie", 3) == 0 || + strcmp(map_name, "christmas") == 0 || + strncmp(map_name, "xmas", 3) == 0 || + strncmp(map_name, "x-mas", 3) == 0) { + town = 7; + } else if (strncmp(map_name, "comodo", 3) == 0) { + town = 8; + } else if (strncmp(map_name, "juno", 3) == 0 || + strncmp(map_name, "yuno", 3) == 0) { + town = 9; + } else if (strncmp(map_name, "amatsu", 3) == 0) { + town = 10; + } else if (strncmp(map_name, "kunlun", 3) == 0 || + strncmp(map_name, "gonryun", 3) == 0) { + town = 11; + } else if (strncmp(map_name, "umbala", 3) == 0) { + town = 12; + } else if (strncmp(map_name, "niflheim", 3) == 0) { + town = 13; + } else if (strncmp(map_name, "louyang", 3) == 0) { + town = 14; + } else if (strncmp(map_name, "new_1-1", 3) == 0 || + strncmp(map_name, "startpoint", 3) == 0 || + strncmp(map_name, "beginning", 3) == 0) { + town = 15; + } else if (strncmp(map_name, "sec_pri", 3) == 0 || + strncmp(map_name, "prison", 3) == 0 || + strncmp(map_name, "jail", 3) == 0) { + town = 16; + } else if (strncmp(map_name, "jawaii", 3) == 0) { + town = 17; + } else if (strncmp(map_name, "ayothaya", 3) == 0) { + town = 18; + } else if (strncmp(map_name, "einbroch", 5) == 0) { + town = 19; + } else if (strncmp(map_name, "lighthalzen", 3) == 0) { + town = 20; + } else if (strncmp(map_name, "einbech", 5) == 0) { + town = 21; + } else if (strncmp(map_name, "hugel", 3) == 0) { + town = 22; + } else if (strncmp(map_name, "rachel", 3) == 0) { + town = 23; + } else if (strncmp(map_name, "veins", 3) == 0) { + town = 24; + } else if (strncmp(map_name, "moscovia", 3) == 0) { + town = 25; + } else if (strncmp(map_name, "mid_camp", 3) == 0) { + town = 26; + } else if (strncmp(map_name, "manuk", 3) == 0) { + town = 27; + } else if (strncmp(map_name, "splendide", 3) == 0) { + town = 28; + } else if (strncmp(map_name, "brasilis", 3) == 0) { + town = 29; + } else if (strncmp(map_name, "dicastes01", 3) == 0) { + town = 30; + } else if (strcmp(map_name, "mora") == 0) { + town = 31; + } else if (strncmp(map_name, "dewata", 3) == 0) { + town = 32; + } else if (strncmp(map_name, "malangdo", 5) == 0) { + town = 33; + } else if (strncmp(map_name, "malaya", 5) == 0) { + town = 34; + } else if (strncmp(map_name, "eclage", 3) == 0) { + town = 35; + } + + if (town >= 0 && town < ARRAYLENGTH(data)) + { + m = map_mapname2mapid(data[town].map); + if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); + return -1; + } + if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { + clif_displaymessage(fd, msg_txt(0)); // Warped. + } else { + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } + } else { // if you arrive here, you have an error in town variable when reading of names + clif_displaymessage(fd, msg_txt(38)); // Invalid location number or name. + return -1; + } + + return 0; } /*========================================== @@ -1941,96 +2069,96 @@ ACMD_FUNC(go) *------------------------------------------*/ ACMD_FUNC(monster) { - char name[NAME_LENGTH]; - char monster[NAME_LENGTH]; - char eventname[EVENT_NAME_LENGTH] = ""; - int mob_id; - int number = 0; - int count; - int i, k, range; - short mx, my; - unsigned int size; - nullpo_retr(-1, sd); - - memset(name, '\0', sizeof(name)); - memset(monster, '\0', sizeof(monster)); - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(80)); // Give the display name or monster name/id please. - return -1; - } - if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 || - sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) { - //All data can be left as it is. - } else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) { - //Here, it is possible name was not given and we are using monster for it. - if (count < 3) //Blank mob's name. - name[0] = '\0'; - } else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) { - //All data can be left as it is. - } else if (sscanf(message, "%23s", monster) > 0) { - //As before, name may be already filled. - name[0] = '\0'; - } else { - clif_displaymessage(fd, msg_txt(80)); // Give a display name and monster name/id please. - return -1; - } - - if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) - mob_id = mobdb_checkid(atoi(monster)); - - if (mob_id == 0) { - clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. - return -1; - } - - if (mob_id == MOBID_EMPERIUM) { - clif_displaymessage(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned. - return -1; - } - - if (number <= 0) - number = 1; - - if (!name[0]) - strcpy(name, "--ja--"); - - // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive - if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) - number = battle_config.atc_spawn_quantity_limit; - - if (strcmp(command+1, "monstersmall") == 0) - size = SZ_MEDIUM; // This is just gorgeous [mkbu95] - else if (strcmp(command+1, "monsterbig") == 0) - size = SZ_BIG; - else - size = SZ_SMALL; - - if (battle_config.etc_log) - ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y); - - count = 0; - range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around) - for (i = 0; i < number; i++) { - map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); - k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE); - count += (k != 0) ? 1 : 0; - } - - if (count != 0) - if (number == count) - clif_displaymessage(fd, msg_txt(39)); // All monster summoned! - else { - sprintf(atcmd_output, msg_txt(240), count); // %d monster(s) summoned! - clif_displaymessage(fd, atcmd_output); - } - else { - clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. - return -1; - } - - return 0; + char name[NAME_LENGTH]; + char monster[NAME_LENGTH]; + char eventname[EVENT_NAME_LENGTH] = ""; + int mob_id; + int number = 0; + int count; + int i, k, range; + short mx, my; + unsigned int size; + nullpo_retr(-1, sd); + + memset(name, '\0', sizeof(name)); + memset(monster, '\0', sizeof(monster)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(80)); // Give the display name or monster name/id please. + return -1; + } + if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 || + sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) { + //All data can be left as it is. + } else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) { + //Here, it is possible name was not given and we are using monster for it. + if (count < 3) //Blank mob's name. + name[0] = '\0'; + } else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) { + //All data can be left as it is. + } else if (sscanf(message, "%23s", monster) > 0) { + //As before, name may be already filled. + name[0] = '\0'; + } else { + clif_displaymessage(fd, msg_txt(80)); // Give a display name and monster name/id please. + return -1; + } + + if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) + mob_id = mobdb_checkid(atoi(monster)); + + if (mob_id == 0) { + clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. + return -1; + } + + if (mob_id == MOBID_EMPERIUM) { + clif_displaymessage(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned. + return -1; + } + + if (number <= 0) + number = 1; + + if( !name[0] ) + strcpy(name, "--ja--"); + + // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive + if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) + number = battle_config.atc_spawn_quantity_limit; + + if (strcmp(command+1, "monstersmall") == 0) + size = SZ_MEDIUM; // This is just gorgeous [mkbu95] + else if (strcmp(command+1, "monsterbig") == 0) + size = SZ_BIG; + else + size = SZ_SMALL; + + if (battle_config.etc_log) + ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y); + + count = 0; + range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around) + for (i = 0; i < number; i++) { + map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); + k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE); + count += (k != 0) ? 1 : 0; + } + + if (count != 0) + if (number == count) + clif_displaymessage(fd, msg_txt(39)); // All monster summoned! + else { + sprintf(atcmd_output, msg_txt(240), count); // %d monster(s) summoned! + clif_displaymessage(fd, atcmd_output); + } + else { + clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. + return -1; + } + + return 0; } /*========================================== @@ -2038,44 +2166,44 @@ ACMD_FUNC(monster) *------------------------------------------*/ static int atkillmonster_sub(struct block_list *bl, va_list ap) { - struct mob_data *md; - int flag; + struct mob_data *md; + int flag; - nullpo_ret(md=(struct mob_data *)bl); - flag = va_arg(ap, int); + nullpo_ret(md=(struct mob_data *)bl); + flag = va_arg(ap, int); - if (md->guardian_data) - return 0; //Do not touch WoE mobs! + if (md->guardian_data) + return 0; //Do not touch WoE mobs! - if (flag) - status_zap(bl,md->status.hp, 0); - else - status_kill(bl); - return 1; + if (flag) + status_zap(bl,md->status.hp, 0); + else + status_kill(bl); + return 1; } ACMD_FUNC(killmonster) { - int map_id, drop_flag; - char map_name[MAP_NAME_LENGTH_EXT]; - nullpo_retr(-1, sd); + int map_id, drop_flag; + char map_name[MAP_NAME_LENGTH_EXT]; + nullpo_retr(-1, sd); - memset(map_name, '\0', sizeof(map_name)); + memset(map_name, '\0', sizeof(map_name)); - if (!message || !*message || sscanf(message, "%15s", map_name) < 1) - map_id = sd->bl.m; - else { - if ((map_id = map_mapname2mapid(map_name)) < 0) - map_id = sd->bl.m; - } + if (!message || !*message || sscanf(message, "%15s", map_name) < 1) + map_id = sd->bl.m; + else { + if ((map_id = map_mapname2mapid(map_name)) < 0) + map_id = sd->bl.m; + } - drop_flag = strcmp(command+1, "killmonster2"); + drop_flag = strcmp(command+1, "killmonster2"); - map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag); + map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag); - clif_displaymessage(fd, msg_txt(165)); // All monsters killed! + clif_displaymessage(fd, msg_txt(165)); // All monsters killed! - return 0; + return 0; } /*========================================== @@ -2083,77 +2211,77 @@ ACMD_FUNC(killmonster) *------------------------------------------*/ ACMD_FUNC(refine) { - int i,j, position = 0, refine = 0, current_position, final_refine; - int count; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) { - clif_displaymessage(fd, msg_txt(996)); // Please enter a position and an amount (usage: @refine <+/- amount>). - sprintf(atcmd_output, msg_txt(997), EQP_HEAD_LOW); // %d: Lower Headgear - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(998), EQP_HAND_R); // %d: Right Hand - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(999), EQP_GARMENT); // %d: Garment - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1000), EQP_ACC_L); // %d: Left Accessory - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1001), EQP_ARMOR); // %d: Body Armor - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1002), EQP_HAND_L); // %d: Left Hand - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1003), EQP_SHOES); // %d: Shoes - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1004), EQP_ACC_R); // %d: Right Accessory - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1005), EQP_HEAD_TOP); // %d: Top Headgear - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1006), EQP_HEAD_MID); // %d: Mid Headgear - clif_displaymessage(fd, atcmd_output); - return -1; - } - - refine = cap_value(refine, -MAX_REFINE, MAX_REFINE); - - count = 0; - for (j = 0; j < EQI_MAX-1; j++) { - if ((i = sd->equip_index[j]) < 0) - continue; - if (j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i) - continue; - if (j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i) - continue; - if (j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == i || sd->equip_index[EQI_HEAD_LOW] == i)) - continue; - - if (position && !(sd->status.inventory[i].equip & position)) - continue; - - final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE); - if (sd->status.inventory[i].refine != final_refine) { - sd->status.inventory[i].refine = final_refine; - current_position = sd->status.inventory[i].equip; - pc_unequipitem(sd, i, 3); - clif_refine(fd, 0, i, sd->status.inventory[i].refine); - clif_delitem(sd, i, 1, 3); - clif_additem(sd, i, 1, 0); - pc_equipitem(sd, i, current_position); - clif_misceffect(&sd->bl, 3); - count++; - } - } - - if (count == 0) - clif_displaymessage(fd, msg_txt(166)); // No item has been refined. - else if (count == 1) - clif_displaymessage(fd, msg_txt(167)); // 1 item has been refined. - else { - sprintf(atcmd_output, msg_txt(168), count); // %d items have been refined. - clif_displaymessage(fd, atcmd_output); - } - - return 0; + int i,j, position = 0, refine = 0, current_position, final_refine; + int count; + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) { + clif_displaymessage(fd, msg_txt(996)); // Please enter a position and an amount (usage: @refine <+/- amount>). + sprintf(atcmd_output, msg_txt(997), EQP_HEAD_LOW); // %d: Lower Headgear + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(998), EQP_HAND_R); // %d: Right Hand + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(999), EQP_GARMENT); // %d: Garment + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1000), EQP_ACC_L); // %d: Left Accessory + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1001), EQP_ARMOR); // %d: Body Armor + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1002), EQP_HAND_L); // %d: Left Hand + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1003), EQP_SHOES); // %d: Shoes + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1004), EQP_ACC_R); // %d: Right Accessory + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1005), EQP_HEAD_TOP); // %d: Top Headgear + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1006), EQP_HEAD_MID); // %d: Mid Headgear + clif_displaymessage(fd, atcmd_output); + return -1; + } + + refine = cap_value(refine, -MAX_REFINE, MAX_REFINE); + + count = 0; + for (j = 0; j < EQI_MAX-1; j++) { + if ((i = sd->equip_index[j]) < 0) + continue; + if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i) + continue; + if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i) + continue; + if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == i || sd->equip_index[EQI_HEAD_LOW] == i)) + continue; + + if(position && !(sd->status.inventory[i].equip & position)) + continue; + + final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE); + if (sd->status.inventory[i].refine != final_refine) { + sd->status.inventory[i].refine = final_refine; + current_position = sd->status.inventory[i].equip; + pc_unequipitem(sd, i, 3); + clif_refine(fd, 0, i, sd->status.inventory[i].refine); + clif_delitem(sd, i, 1, 3); + clif_additem(sd, i, 1, 0); + pc_equipitem(sd, i, current_position); + clif_misceffect(&sd->bl, 3); + count++; + } + } + + if (count == 0) + clif_displaymessage(fd, msg_txt(166)); // No item has been refined. + else if (count == 1) + clif_displaymessage(fd, msg_txt(167)); // 1 item has been refined. + else { + sprintf(atcmd_output, msg_txt(168), count); // %d items have been refined. + clif_displaymessage(fd, atcmd_output); + } + + return 0; } /*========================================== @@ -2161,58 +2289,58 @@ ACMD_FUNC(refine) *------------------------------------------*/ ACMD_FUNC(produce) { - char item_name[100]; - int item_id, attribute = 0, star = 0; - int flag = 0; - struct item_data *item_data; - struct item tmp_item; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 && - sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1 - )) { - clif_displaymessage(fd, msg_txt(1007)); // Please enter at least one item name/ID (usage: @produce <# of very's>). - return -1; - } - - if ((item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL) { - clif_displaymessage(fd, msg_txt(170)); //This item is not an equipment. - return -1; - } - - item_id = item_data->nameid; - - if (itemdb_isequip2(item_data)) { - if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) - attribute = ATTRIBUTE_NORMAL; - if (star < MIN_STAR || star > MAX_STAR) - star = 0; - memset(&tmp_item, 0, sizeof tmp_item); - tmp_item.nameid = item_id; - tmp_item.amount = 1; - tmp_item.identify = 1; - tmp_item.card[0] = CARD0_FORGE; - tmp_item.card[1] = item_data->type==IT_WEAPON? - ((star*5) << 8) + attribute:0; - tmp_item.card[2] = GetWord(sd->status.char_id, 0); - tmp_item.card[3] = GetWord(sd->status.char_id, 1); - clif_produceeffect(sd, 0, item_id); - clif_misceffect(&sd->bl, 3); - - if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } else { - sprintf(atcmd_output, msg_txt(169), item_id, item_data->name); // The item (%d: '%s') is not equipable. - clif_displaymessage(fd, atcmd_output); - return -1; - } - - return 0; + char item_name[100]; + int item_id, attribute = 0, star = 0; + int flag = 0; + struct item_data *item_data; + struct item tmp_item; + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 && + sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1 + )) { + clif_displaymessage(fd, msg_txt(1007)); // Please enter at least one item name/ID (usage: @produce <# of very's>). + return -1; + } + + if ( (item_data = itemdb_searchname(item_name)) == NULL && + (item_data = itemdb_exists(atoi(item_name))) == NULL ) { + clif_displaymessage(fd, msg_txt(170)); //This item is not an equipment. + return -1; + } + + item_id = item_data->nameid; + + if (itemdb_isequip2(item_data)) { + if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) + attribute = ATTRIBUTE_NORMAL; + if (star < MIN_STAR || star > MAX_STAR) + star = 0; + memset(&tmp_item, 0, sizeof tmp_item); + tmp_item.nameid = item_id; + tmp_item.amount = 1; + tmp_item.identify = 1; + tmp_item.card[0] = CARD0_FORGE; + tmp_item.card[1] = item_data->type==IT_WEAPON? + ((star*5) << 8) + attribute:0; + tmp_item.card[2] = GetWord(sd->status.char_id, 0); + tmp_item.card[3] = GetWord(sd->status.char_id, 1); + clif_produceeffect(sd, 0, item_id); + clif_misceffect(&sd->bl, 3); + + if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } else { + sprintf(atcmd_output, msg_txt(169), item_id, item_data->name); // The item (%d: '%s') is not equipable. + clif_displaymessage(fd, atcmd_output); + return -1; + } + + return 0; } /*========================================== @@ -2220,32 +2348,35 @@ ACMD_FUNC(produce) *------------------------------------------*/ ACMD_FUNC(memo) { - int position = 0; - nullpo_retr(-1, sd); + int position = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &position) < 1) { - int i; - clif_displaymessage(sd->fd, msg_txt(668)); - for (i = 0; i < MAX_MEMOPOINTS; i++) { - if (sd->status.memo_point[i].map) - sprintf(atcmd_output, "%d - %s (%d,%d)", i, mapindex_id2name(sd->status.memo_point[i].map), sd->status.memo_point[i].x, sd->status.memo_point[i].y); - else - sprintf(atcmd_output, msg_txt(171), i); // %d - void - clif_displaymessage(sd->fd, atcmd_output); - } - return 0; - } + if( !message || !*message || sscanf(message, "%d", &position) < 1 ) + { + int i; + clif_displaymessage(sd->fd, msg_txt(668)); + for( i = 0; i < MAX_MEMOPOINTS; i++ ) + { + if( sd->status.memo_point[i].map ) + sprintf(atcmd_output, "%d - %s (%d,%d)", i, mapindex_id2name(sd->status.memo_point[i].map), sd->status.memo_point[i].x, sd->status.memo_point[i].y); + else + sprintf(atcmd_output, msg_txt(171), i); // %d - void + clif_displaymessage(sd->fd, atcmd_output); + } + return 0; + } - if (position < 0 || position >= MAX_MEMOPOINTS) { - sprintf(atcmd_output, msg_txt(1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if( position < 0 || position >= MAX_MEMOPOINTS ) + { + sprintf(atcmd_output, msg_txt(1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - pc_memo(sd, position); - return 0; + pc_memo(sd, position); + return 0; } /*========================================== @@ -2253,24 +2384,24 @@ ACMD_FUNC(memo) *------------------------------------------*/ ACMD_FUNC(gat) { - int y; - nullpo_retr(-1, sd); + int y; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - for (y = 2; y >= -2; y--) { - sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", - map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, - map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); + for (y = 2; y >= -2; y--) { + sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", + map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, + map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); - clif_displaymessage(fd, atcmd_output); - } + clif_displaymessage(fd, atcmd_output); + } - return 0; + return 0; } /*========================================== @@ -2278,19 +2409,19 @@ ACMD_FUNC(gat) *------------------------------------------*/ ACMD_FUNC(displaystatus) { - int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0; - nullpo_retr(-1, sd); + int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0; + nullpo_retr(-1, sd); - if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) { - clif_displaymessage(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus { { {}}}). - return -1; - } - if (i < 2) flag = 1; - if (i < 3) tick = 0; + if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) { + clif_displaymessage(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus { { {}}}). + return -1; + } + if (i < 2) flag = 1; + if (i < 3) tick = 0; - clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3); + clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3); - return 0; + return 0; } /*========================================== @@ -2298,39 +2429,47 @@ ACMD_FUNC(displaystatus) *------------------------------------------*/ ACMD_FUNC(statuspoint) { - int point; - unsigned int new_status_point; - - if (!message || !*message || (point = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1010)); // Please enter a number (usage: @stpoint ). - return -1; - } - - if (point < 0) { - if (sd->status.status_point < (unsigned int)(-point)) { - new_status_point = 0; - } else { - new_status_point = sd->status.status_point + point; - } - } else if (UINT_MAX - sd->status.status_point < (unsigned int)point) { - new_status_point = UINT_MAX; - } else { - new_status_point = sd->status.status_point + point; - } - - if (new_status_point != sd->status.status_point) { - sd->status.status_point = new_status_point; - clif_updatestatus(sd, SP_STATUSPOINT); - clif_displaymessage(fd, msg_txt(174)); // Number of status points changed. - } else { - if (point < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int point; + unsigned int new_status_point; + + if (!message || !*message || (point = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1010)); // Please enter a number (usage: @stpoint ). + return -1; + } + + if(point < 0) + { + if(sd->status.status_point < (unsigned int)(-point)) + { + new_status_point = 0; + } + else + { + new_status_point = sd->status.status_point + point; + } + } + else if(UINT_MAX - sd->status.status_point < (unsigned int)point) + { + new_status_point = UINT_MAX; + } + else + { + new_status_point = sd->status.status_point + point; + } + + if (new_status_point != sd->status.status_point) { + sd->status.status_point = new_status_point; + clif_updatestatus(sd, SP_STATUSPOINT); + clif_displaymessage(fd, msg_txt(174)); // Number of status points changed. + } else { + if (point < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2338,40 +2477,48 @@ ACMD_FUNC(statuspoint) *------------------------------------------*/ ACMD_FUNC(skillpoint) { - int point; - unsigned int new_skill_point; - nullpo_retr(-1, sd); - - if (!message || !*message || (point = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint ). - return -1; - } - - if (point < 0) { - if (sd->status.skill_point < (unsigned int)(-point)) { - new_skill_point = 0; - } else { - new_skill_point = sd->status.skill_point + point; - } - } else if (UINT_MAX - sd->status.skill_point < (unsigned int)point) { - new_skill_point = UINT_MAX; - } else { - new_skill_point = sd->status.skill_point + point; - } - - if (new_skill_point != sd->status.skill_point) { - sd->status.skill_point = new_skill_point; - clif_updatestatus(sd, SP_SKILLPOINT); - clif_displaymessage(fd, msg_txt(175)); // Number of skill points changed. - } else { - if (point < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int point; + unsigned int new_skill_point; + nullpo_retr(-1, sd); + + if (!message || !*message || (point = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint ). + return -1; + } + + if(point < 0) + { + if(sd->status.skill_point < (unsigned int)(-point)) + { + new_skill_point = 0; + } + else + { + new_skill_point = sd->status.skill_point + point; + } + } + else if(UINT_MAX - sd->status.skill_point < (unsigned int)point) + { + new_skill_point = UINT_MAX; + } + else + { + new_skill_point = sd->status.skill_point + point; + } + + if (new_skill_point != sd->status.skill_point) { + sd->status.skill_point = new_skill_point; + clif_updatestatus(sd, SP_SKILLPOINT); + clif_displaymessage(fd, msg_txt(175)); // Number of skill points changed. + } else { + if (point < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2379,24 +2526,25 @@ ACMD_FUNC(skillpoint) *------------------------------------------*/ ACMD_FUNC(zeny) { - int zeny=0, ret=-1; - nullpo_retr(-1, sd); + int zeny=0, ret=-1; + nullpo_retr(-1, sd); - if (!message || !*message || (zeny = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny ). - return -1; - } + if (!message || !*message || (zeny = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny ). + return -1; + } - if (zeny > 0) { - if ((ret=pc_getzeny(sd,zeny,LOG_TYPE_COMMAND,NULL)) == 1) - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - } else { - if (sd->status.zeny < -zeny) zeny = -sd->status.zeny; - if ((ret=pc_payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - } - if (!ret) clif_displaymessage(fd, msg_txt(176)); //ret=0 mean cmd success - return 0; + if(zeny > 0){ + if((ret=pc_getzeny(sd,zeny,LOG_TYPE_COMMAND,NULL)) == 1) + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + } + else { + if( sd->status.zeny < -zeny ) zeny = -sd->status.zeny; + if((ret=pc_payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + } + if(!ret) clif_displaymessage(fd, msg_txt(176)); //ret=0 mean cmd success + return 0; } /*========================================== @@ -2404,61 +2552,61 @@ ACMD_FUNC(zeny) *------------------------------------------*/ ACMD_FUNC(param) { - int i, value = 0, new_value, max; - const char *param[] = { "str", "agi", "vit", "int", "dex", "luk" }; - short *status[6]; - //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { - clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). - return -1; - } - - ARR_FIND(0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0); - - if (i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... - clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). - return -1; - } - - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; - - if (battle_config.atcommand_max_stat_bypass) - max = SHRT_MAX; - else - max = pc_maxparameter(sd); - - if (value < 0 && *status[i] <= -value) { - new_value = 1; - } else if (max - *status[i] < value) { - new_value = max; - } else { - new_value = *status[i] + value; - } - - if (new_value != *status[i]) { - *status[i] = new_value; - clif_updatestatus(sd, SP_STR + i); - clif_updatestatus(sd, SP_USTR + i); - status_calc_pc(sd, 0); - clif_displaymessage(fd, msg_txt(42)); // Stat changed. - } else { - if (value < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int i, value = 0, new_value, max; + const char* param[] = { "str", "agi", "vit", "int", "dex", "luk" }; + short* status[6]; + //we don't use direct initialization because it isn't part of the c standard. + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { + clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). + return -1; + } + + ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0 ); + + if( i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... + clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). + return -1; + } + + status[0] = &sd->status.str; + status[1] = &sd->status.agi; + status[2] = &sd->status.vit; + status[3] = &sd->status.int_; + status[4] = &sd->status.dex; + status[5] = &sd->status.luk; + + if( battle_config.atcommand_max_stat_bypass ) + max = SHRT_MAX; + else + max = pc_maxparameter(sd); + + if(value < 0 && *status[i] <= -value) { + new_value = 1; + } else if(max - *status[i] < value) { + new_value = max; + } else { + new_value = *status[i] + value; + } + + if (new_value != *status[i]) { + *status[i] = new_value; + clif_updatestatus(sd, SP_STR + i); + clif_updatestatus(sd, SP_USTR + i); + status_calc_pc(sd, 0); + clif_displaymessage(fd, msg_txt(42)); // Stat changed. + } else { + if (value < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2466,58 +2614,58 @@ ACMD_FUNC(param) *------------------------------------------*/ ACMD_FUNC(stat_all) { - int index, count, value, max, new_value; - short *status[6]; - //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); - - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; - - if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { - value = pc_maxparameter(sd); - max = pc_maxparameter(sd); - } else { - if (battle_config.atcommand_max_stat_bypass) - max = SHRT_MAX; - else - max = pc_maxparameter(sd); - } - - count = 0; - for (index = 0; index < ARRAYLENGTH(status); index++) { - - if (value > 0 && *status[index] > max - value) - new_value = max; - else if (value < 0 && *status[index] <= -value) - new_value = 1; - else - new_value = *status[index] +value; - - if (new_value != (int)*status[index]) { - *status[index] = new_value; - clif_updatestatus(sd, SP_STR + index); - clif_updatestatus(sd, SP_USTR + index); - count++; - } - } - - if (count > 0) { // if at least 1 stat modified - status_calc_pc(sd, 0); - clif_displaymessage(fd, msg_txt(84)); // All stats changed! - } else { - if (value < 0) - clif_displaymessage(fd, msg_txt(177)); // You cannot decrease that stat anymore. - else - clif_displaymessage(fd, msg_txt(178)); // You cannot increase that stat anymore. - return -1; - } - - return 0; + int index, count, value, max, new_value; + short* status[6]; + //we don't use direct initialization because it isn't part of the c standard. + nullpo_retr(-1, sd); + + status[0] = &sd->status.str; + status[1] = &sd->status.agi; + status[2] = &sd->status.vit; + status[3] = &sd->status.int_; + status[4] = &sd->status.dex; + status[5] = &sd->status.luk; + + if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { + value = pc_maxparameter(sd); + max = pc_maxparameter(sd); + } else { + if( battle_config.atcommand_max_stat_bypass ) + max = SHRT_MAX; + else + max = pc_maxparameter(sd); + } + + count = 0; + for (index = 0; index < ARRAYLENGTH(status); index++) { + + if (value > 0 && *status[index] > max - value) + new_value = max; + else if (value < 0 && *status[index] <= -value) + new_value = 1; + else + new_value = *status[index] +value; + + if (new_value != (int)*status[index]) { + *status[index] = new_value; + clif_updatestatus(sd, SP_STR + index); + clif_updatestatus(sd, SP_USTR + index); + count++; + } + } + + if (count > 0) { // if at least 1 stat modified + status_calc_pc(sd, 0); + clif_displaymessage(fd, msg_txt(84)); // All stats changed! + } else { + if (value < 0) + clif_displaymessage(fd, msg_txt(177)); // You cannot decrease that stat anymore. + else + clif_displaymessage(fd, msg_txt(178)); // You cannot increase that stat anymore. + return -1; + } + + return 0; } /*========================================== @@ -2525,40 +2673,40 @@ ACMD_FUNC(stat_all) *------------------------------------------*/ ACMD_FUNC(guildlevelup) { - int level = 0; - short added_level; - struct guild *guild_info; - nullpo_retr(-1, sd); + int level = 0; + short added_level; + struct guild *guild_info; + nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) { - clif_displaymessage(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>). - return -1; - } + if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) { + clif_displaymessage(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>). + return -1; + } - if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) { - clif_displaymessage(fd, msg_txt(43)); // You're not in a guild. - return -1; - } - //if (strcmp(sd->status.name, guild_info->master) != 0) { - // clif_displaymessage(fd, msg_txt(44)); // You're not the master of your guild. - // return -1; - //} + if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) { + clif_displaymessage(fd, msg_txt(43)); // You're not in a guild. + return -1; + } + //if (strcmp(sd->status.name, guild_info->master) != 0) { + // clif_displaymessage(fd, msg_txt(44)); // You're not the master of your guild. + // return -1; + //} - added_level = (short)level; - if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow - added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv; - else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow - added_level = 1 - guild_info->guild_lv; + added_level = (short)level; + if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow + added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv; + else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow + added_level = 1 - guild_info->guild_lv; - if (added_level != 0) { - intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); - clif_displaymessage(fd, msg_txt(179)); // Guild level changed. - } else { - clif_displaymessage(fd, msg_txt(45)); // Guild level change failed. - return -1; - } + if (added_level != 0) { + intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); + clif_displaymessage(fd, msg_txt(179)); // Guild level changed. + } else { + clif_displaymessage(fd, msg_txt(45)); // Guild level change failed. + return -1; + } - return 0; + return 0; } /*========================================== @@ -2566,38 +2714,39 @@ ACMD_FUNC(guildlevelup) *------------------------------------------*/ ACMD_FUNC(makeegg) { - struct item_data *item_data; - int id, pet_id; - nullpo_retr(-1, sd); - - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg ). - return -1; - } - - if ((item_data = itemdb_searchname(message)) != NULL) // for egg name - id = item_data->nameid; - else if ((id = mobdb_searchname(message)) != 0) // for monster name - ; - else - id = atoi(message); - - pet_id = search_petDB_index(id, PET_CLASS); - if (pet_id < 0) - pet_id = search_petDB_index(id, PET_EGG); - if (pet_id >= 0) { - sd->catch_target_class = pet_db[pet_id].class_; - intif_create_pet( - sd->status.account_id, sd->status.char_id, - (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, - (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, - 100, 0, 1, pet_db[pet_id].jname); - } else { - clif_displaymessage(fd, msg_txt(180)); // The monster/egg name/id doesn't exist. - return -1; - } - - return 0; + struct item_data *item_data; + int id, pet_id; + nullpo_retr(-1, sd); + + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg ). + return -1; + } + + if ((item_data = itemdb_searchname(message)) != NULL) // for egg name + id = item_data->nameid; + else + if ((id = mobdb_searchname(message)) != 0) // for monster name + ; + else + id = atoi(message); + + pet_id = search_petDB_index(id, PET_CLASS); + if (pet_id < 0) + pet_id = search_petDB_index(id, PET_EGG); + if (pet_id >= 0) { + sd->catch_target_class = pet_db[pet_id].class_; + intif_create_pet( + sd->status.account_id, sd->status.char_id, + (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, + (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, + 100, 0, 1, pet_db[pet_id].jname); + } else { + clif_displaymessage(fd, msg_txt(180)); // The monster/egg name/id doesn't exist. + return -1; + } + + return 0; } /*========================================== @@ -2605,15 +2754,15 @@ ACMD_FUNC(makeegg) *------------------------------------------*/ ACMD_FUNC(hatch) { - nullpo_retr(-1, sd); - if (sd->status.pet_id <= 0) - clif_sendegg(sd); - else { - clif_displaymessage(fd, msg_txt(181)); // You already have a pet. - return -1; - } + nullpo_retr(-1, sd); + if (sd->status.pet_id <= 0) + clif_sendegg(sd); + else { + clif_displaymessage(fd, msg_txt(181)); // You already have a pet. + return -1; + } - return 0; + return 0; } /*========================================== @@ -2621,35 +2770,36 @@ ACMD_FUNC(hatch) *------------------------------------------*/ ACMD_FUNC(petfriendly) { - int friendly; - struct pet_data *pd; - nullpo_retr(-1, sd); + int friendly; + struct pet_data *pd; + nullpo_retr(-1, sd); - if (!message || !*message || (friendly = atoi(message)) < 0) { - clif_displaymessage(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>). - return -1; - } + if (!message || !*message || (friendly = atoi(message)) < 0) { + clif_displaymessage(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>). + return -1; + } - pd = sd->pd; - if (!pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } + pd = sd->pd; + if (!pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } - if (friendly < 0 || friendly > 1000) { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (friendly < 0 || friendly > 1000) + { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - if (friendly == pd->pet.intimate) { - clif_displaymessage(fd, msg_txt(183)); // Pet intimacy is already at maximum. - return -1; - } + if (friendly == pd->pet.intimate) { + clif_displaymessage(fd, msg_txt(183)); // Pet intimacy is already at maximum. + return -1; + } - pet_set_intimate(pd, friendly); - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(182)); // Pet intimacy changed. - return 0; + pet_set_intimate(pd, friendly); + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(182)); // Pet intimacy changed. + return 0; } /*========================================== @@ -2657,34 +2807,34 @@ ACMD_FUNC(petfriendly) *------------------------------------------*/ ACMD_FUNC(pethungry) { - int hungry; - struct pet_data *pd; - nullpo_retr(-1, sd); + int hungry; + struct pet_data *pd; + nullpo_retr(-1, sd); - if (!message || !*message || (hungry = atoi(message)) < 0) { - clif_displaymessage(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>). - return -1; - } + if (!message || !*message || (hungry = atoi(message)) < 0) { + clif_displaymessage(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>). + return -1; + } - pd = sd->pd; - if (!sd->status.pet_id || !pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } - if (hungry < 0 || hungry > 100) { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } - if (hungry == pd->pet.hungry) { - clif_displaymessage(fd, msg_txt(186)); // Pet hunger is already at maximum. - return -1; - } + pd = sd->pd; + if (!sd->status.pet_id || !pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } + if (hungry < 0 || hungry > 100) { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } + if (hungry == pd->pet.hungry) { + clif_displaymessage(fd, msg_txt(186)); // Pet hunger is already at maximum. + return -1; + } - pd->pet.hungry = hungry; - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(185)); // Pet hunger changed. + pd->pet.hungry = hungry; + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(185)); // Pet hunger changed. - return 0; + return 0; } /*========================================== @@ -2692,66 +2842,64 @@ ACMD_FUNC(pethungry) *------------------------------------------*/ ACMD_FUNC(petrename) { - struct pet_data *pd; - nullpo_retr(-1, sd); - if (!sd->status.pet_id || !sd->pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } - pd = sd->pd; - if (!pd->pet.rename_flag) { - clif_displaymessage(fd, msg_txt(188)); // You can already rename your pet. - return -1; - } + struct pet_data *pd; + nullpo_retr(-1, sd); + if (!sd->status.pet_id || !sd->pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } + pd = sd->pd; + if (!pd->pet.rename_flag) { + clif_displaymessage(fd, msg_txt(188)); // You can already rename your pet. + return -1; + } - pd->pet.rename_flag = 0; - intif_save_petdata(sd->status.account_id, &pd->pet); - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(187)); // You can now rename your pet. + pd->pet.rename_flag = 0; + intif_save_petdata(sd->status.account_id, &pd->pet); + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(187)); // You can now rename your pet. - return 0; + return 0; } /*========================================== * *------------------------------------------*/ -ACMD_FUNC(recall) -{ - struct map_session_data *pl_sd = NULL; +ACMD_FUNC(recall) { + struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(1018)); // Please enter a player name (usage: @recall ). - return -1; - } + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(1018)); // Please enter a player name (usage: @recall ). + return -1; + } - if ((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) + { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { - clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player. - return -1; - } + if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) + { + clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player. + return -1; + } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. - return -1; - } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. - return -1; - } - if (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y) { - return -1; - } - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); - sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled! - clif_displaymessage(fd, atcmd_output); + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. + return -1; + } + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. + return -1; + } + pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); + sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled! + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -2760,19 +2908,19 @@ ACMD_FUNC(recall) *------------------------------------------*/ ACMD_FUNC(char_block) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); + memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); - if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif_displaymessage(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block ). - return -1; - } + if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { + clif_displaymessage(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block ). + return -1; + } - chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block - clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it. + chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block + clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it. - return 0; + return 0; } /*========================================== @@ -2792,84 +2940,84 @@ ACMD_FUNC(char_block) *------------------------------------------*/ ACMD_FUNC(char_ban) { - char *modif_p; - int year, month, day, hour, minute, second, value; - time_t timestamp; - struct tm *tmtime; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); - - if (!message || !*message || sscanf(message, "%s %23[^\n]", atcmd_output, atcmd_player_name) < 2) { - clif_displaymessage(fd, msg_txt(1022)); // Please enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish