diff options
Diffstat (limited to 'src/char/char.c')
-rw-r--r-- | src/char/char.c | 404 |
1 files changed, 227 insertions, 177 deletions
diff --git a/src/char/char.c b/src/char/char.c index 91ad7d33d..6dd131976 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2,19 +2,16 @@ // For more information, see LICENCE in the main folder #include "../common/cbasetypes.h" -#include "../common/mmo.h" +#include "../common/core.h" #include "../common/db.h" #include "../common/lock.h" #include "../common/malloc.h" -#include "../common/core.h" +#include "../common/mapindex.h" +#include "../common/mmo.h" +#include "../common/showmsg.h" #include "../common/socket.h" #include "../common/strlib.h" -#include "../common/showmsg.h" #include "../common/timer.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/mapindex.h" -#include "../common/showmsg.h" #include "../common/utils.h" #include "../common/version.h" #include "inter.h" @@ -27,16 +24,8 @@ #include "char.h" #include <sys/types.h> -#ifdef WIN32 -#include <winsock2.h> -#else -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif #include <time.h> #include <signal.h> -#include <fcntl.h> #include <string.h> #include <stdarg.h> #include <stdio.h> @@ -51,8 +40,13 @@ char friends_txt[1024] = "save/friends.txt"; char hotkeys_txt[1024] = "save/hotkeys.txt"; char char_log_filename[1024] = "log/char.log"; -int save_log = 1; // show loading/saving messages +// show loading/saving messages +#ifndef TXT_SQL_CONVERT +int save_log = 1; +#endif +//If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING +//#undef TXT_SQL_CONVERT #ifndef TXT_SQL_CONVERT char db_path[1024] = "db"; @@ -85,9 +79,12 @@ int email_creation = 0; // disabled by default bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor] int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] -char unknown_char_name[1024] = "Unknown"; // Name to use when the requested name cannot be determined +char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined #define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] -char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor] +char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor] + +int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius] +int char_del_level = 0; //From which level u can delete character [Lupus] int log_char = 1; // loggin char or not [devil] int log_inter = 1; // loggin inter or not [devil] @@ -118,7 +115,7 @@ int char_num, char_max; int max_connect_user = 0; int gm_allow_level = 99; int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; -int start_zeny = 500; +int start_zeny = 0; int start_weapon = 1201; int start_armor = 2301; int guild_exp_rate = 100; @@ -173,7 +170,7 @@ struct online_char_data { int char_id; int fd; int waiting_disconnect; - short server; + short server; // -2: unknown server, -1: not connected, 0+: id of server }; static DBMap* online_char_db; // int account_id -> struct online_char_data* @@ -223,6 +220,7 @@ void set_char_online(int map_id, int char_id, int account_id) { struct online_char_data* character; + //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 ) { @@ -238,11 +236,13 @@ void set_char_online(int map_id, int char_id, int account_id) if( character->server > -1 ) server[character->server].users++; + //Get rid of disconnect timer if(character->waiting_disconnect != -1) { delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); character->waiting_disconnect = -1; } + //Notify login server if (login_fd > 0 && !session[login_fd]->flag.eof) { WFIFOHEAD(login_fd,6); @@ -261,7 +261,7 @@ void set_char_offline(int char_id, int account_id) if( character->server > -1 ) if( server[character->server].users > 0 ) // Prevent this value from going negative. server[character->server].users--; - + if(character->waiting_disconnect != -1){ delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); character->waiting_disconnect = -1; @@ -678,7 +678,7 @@ int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg tmp_int[46] = mapindex_name2id(tmp_str[2]); } // Char structure of version 1500 (homun + mapindex maps) - memcpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex] + safestrncpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex] p->char_id = tmp_int[0]; p->account_id = tmp_int[1]; p->slot = tmp_int[2]; @@ -1150,16 +1150,9 @@ int mmo_char_sync_timer(int tid, unsigned int tick, int id, intptr data) return 0; } -//----------------------------------- -// Function to create a new character -//----------------------------------- -int make_new_char(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 check_char_name(char * name) { - char name[NAME_LENGTH]; int i; - - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); // check length of character name if( name[0] == '\0' ) @@ -1174,33 +1167,64 @@ int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, i 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 + 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 + } + 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; - } // else, all letters/symbols are authorised (except control char removed before) + } // check name (already in use?) - ARR_FIND( 0, char_num, i, - (name_ignoring_case && strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0) || - (!name_ignoring_case && strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0) ); + if( name_ignoring_case ) + { + ARR_FIND( 0, char_num, i, strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0 ); + } + else + { + ARR_FIND( 0, char_num, i, strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0 ); + } if( i < char_num ) return -1; // name already exists + return 0; +} + +//----------------------------------- +// Function to create a new character +//----------------------------------- +int make_new_char(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) +{ + char name[NAME_LENGTH]; + int i, flag; + + safestrncpy(name, name_, NAME_LENGTH); + normalize_name(name,TRIM_CHARS); + + flag = check_char_name(name); + if( flag < 0 ) + return flag; + //check other inputs if((slot >= MAX_CHARS) // slots - || (hair_style >= 24) // hair style - || (hair_color >= 9) // hair color || (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 return -2; // invalid input + // check the number of already existing chars in this account + if( char_per_account != 0 ) { + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == -1 ); + + if( i >= char_per_account ) + return -2; // character account limit exceeded + } + // check char slot ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == sd->account_id && char_dat[i].status.slot == slot ); if( i < char_num ) @@ -1563,7 +1587,7 @@ void create_online_files(void) j = id[i]; // displaying the character name if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display - strcpy(temp, char_dat[j].status.name); + safestrncpy(temp, char_dat[j].status.name, sizeof(temp)); //l = isGM(char_dat[j].status.account_id); l = 0; //FIXME: how to get the gm level? if (online_display_option & 64) { @@ -1611,7 +1635,7 @@ void create_online_files(void) // displaying of the map if (online_display_option & 24) { // 8 or 16 // prepare map name - memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH); + safestrncpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), sizeof(temp)); // write map name if (online_display_option & 16) { // map-name AND coordinates fprintf(fp2, " <td>%s (%d, %d)</td>\n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); @@ -1670,10 +1694,11 @@ int count_users(void) int i, users; users = 0; - for(i = 0; i < MAX_MAP_SERVERS; i++) - if (server[i].fd >= 0) + for(i = 0; i < MAX_MAP_SERVERS; i++) { + if (server[i].fd > 0) { users += server[i].users; - + } + } return users; } @@ -1738,7 +1763,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) #endif #if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803 mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108)); - offset += 16; + offset += MAP_NAME_LENGTH_EXT; #endif return 106+offset; } @@ -1807,7 +1832,7 @@ int char_divorce(struct mmo_charstatus *cs) return 0; } -int char_married(int pl1,int pl2) +int char_married(int pl1, int pl2) { return (char_dat[pl1].status.char_id == char_dat[pl2].status.partner_id && char_dat[pl2].status.char_id == char_dat[pl1].status.partner_id); } @@ -1850,38 +1875,18 @@ int char_family(int cid1, int cid2, int cid3) return 0; } -//Clears the given party id from all characters. -//Since sometimes the party format changes and parties must be wiped, this -//method is required to prevent stress during the "party not found!" stages. -void char_clearparty(int party_id) -{ - int i; - for(i = 0; i < char_num; i++) - { - if (char_dat[i].status.party_id == party_id) - char_dat[i].status.party_id = 0; - } -} - //---------------------------------------------------------------------- // Force disconnection of an online player (with account value) by [Yor] //---------------------------------------------------------------------- -int disconnect_player(int account_id) +void disconnect_player(int account_id) { int i; - struct char_session_data *sd; + struct char_session_data* sd; // disconnect player if online on char-server - for(i = 0; i < fd_max; i++) { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) { - if (sd->account_id == account_id) { - set_eof(i); - return 1; - } - } - } - - return 0; + 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); } // キャラ削除に伴うデータ削除 @@ -2005,8 +2010,8 @@ int parse_fromlogin(int fd) //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"); - ShowInfo("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n"); - ShowInfo("The communication passwords can be changed in map_athena.conf and char_athena.conf\n"); + ShowError("Also, please make sure your accounts file (default: accounts.txt) 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"); } else { ShowStatus("Connected to login-server (connection #%d).\n", fd); @@ -2099,7 +2104,7 @@ int parse_fromlogin(int fd) if (RFIFOREST(fd) < 7) return 0; { - int i, j; + int j; unsigned char buf[7]; int acc = RFIFOL(fd,2); @@ -2107,7 +2112,7 @@ int parse_fromlogin(int fd) RFIFOSKIP(fd,7); if( acc > 0 ) - { + {// TODO: Is this even possible? struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); if( node != NULL ) node->sex = sex; @@ -2162,6 +2167,8 @@ int parse_fromlogin(int fd) // 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; @@ -2235,14 +2242,14 @@ int parse_fromlogin(int fd) RFIFOSKIP(fd,8 + RFIFOL(fd,4)); break; - // account_reg2変更通知 + // 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) = 0x2b11; 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)); @@ -2297,12 +2304,12 @@ int parse_fromlogin(int fd) RFIFOSKIP(fd,6); break; - // State change of account/ban notification (from login-server) by [Yor] + // 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 - { + + { // send to all map-servers to disconnect the player unsigned char buf[11]; WBUFW(buf,0) = 0x2b14; WBUFL(buf,2) = RFIFOL(fd,2); @@ -2312,6 +2319,7 @@ int parse_fromlogin(int fd) } // disconnect player if online on char-server disconnect_player(RFIFOL(fd,2)); + RFIFOSKIP(fd,11); break; @@ -2351,7 +2359,8 @@ int parse_fromlogin(int fd) 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]; @@ -2362,13 +2371,14 @@ int parse_fromlogin(int fd) new_ip = host2ip(login_ip_str); if (new_ip && new_ip != login_ip) - login_ip = new_ip; //Update login up. + 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); @@ -2380,7 +2390,7 @@ int parse_fromlogin(int fd) break; default: - ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", RFIFOW(fd,0)); + ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); set_eof(fd); return 0; } @@ -2498,7 +2508,7 @@ void char_read_fame_list(void) { fame_item.id = char_dat[id[i]].status.char_id; fame_item.fame = char_dat[id[i]].status.fame; - strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); + safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list)); j++; @@ -2513,7 +2523,7 @@ void char_read_fame_list(void) { fame_item.id = char_dat[id[i]].status.char_id; fame_item.fame = char_dat[id[i]].status.fame; - strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); + safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list)); @@ -2527,7 +2537,7 @@ void char_read_fame_list(void) { fame_item.id = char_dat[id[i]].status.char_id; fame_item.fame = char_dat[id[i]].status.fame; - strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); + safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list)); @@ -2536,6 +2546,7 @@ void char_read_fame_list(void) } DELETE_BUFFER(id); } + // Send map-servers the fame ranking lists int char_send_fame_list(int fd) { @@ -2565,7 +2576,7 @@ int char_send_fame_list(int fd) // add total packet length WBUFW(buf, 2) = len; - if(fd!=-1) + if (fd != -1) mapif_send(fd, buf, len); else mapif_sendall(buf, len); @@ -2575,7 +2586,7 @@ int char_send_fame_list(int fd) void char_update_fame_list(int type, int index, int fame) { - unsigned char buf[9]; + unsigned char buf[8]; WBUFW(buf,0) = 0x2b22; WBUFB(buf,2) = type; WBUFB(buf,3) = index; @@ -2588,14 +2599,18 @@ void char_update_fame_list(int type, int index, int fame) int char_loadName(int char_id, char* name) { int j; - for( j = 0; j < char_num && char_dat[j].status.char_id != char_id; ++j ) - ;// find char + + ARR_FIND( 0, char_num, j, char_dat[j].status.char_id == char_id ); if( j < char_num ) - strncpy(name, char_dat[j].status.name, NAME_LENGTH); + { + safestrncpy(name, char_dat[j].status.name, NAME_LENGTH); + return 1; + } else - strncpy(name, unknown_char_name, NAME_LENGTH); - - return (j < char_num) ? 1 : 0; + { + safestrncpy(name, unknown_char_name, NAME_LENGTH); + } + return 0; } int search_mapserver(unsigned short map, uint32 ip, uint16 port); @@ -2624,6 +2639,7 @@ int parse_frommap(int fd) WBUFW(buf,2) = j * 4 + 10; mapif_sendallwos(fd, buf, WBUFW(buf,2)); } + memset(&server[id], 0, sizeof(struct mmo_map_server)); server[id].fd = -1; online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. } @@ -2634,8 +2650,6 @@ int parse_frommap(int fd) while(RFIFOREST(fd) >= 2) { - //ShowDebug("Received packet 0x%4x (%d bytes) from map-server (connection %d)\n", RFIFOW(fd, 0), RFIFOREST(fd), fd); - switch(RFIFOW(fd,0)) { @@ -2727,7 +2741,7 @@ int parse_frommap(int fd) RFIFOSKIP(fd, 10); } break; - + case 0x2afe: //set MAP user count if (RFIFOREST(fd) < 4) return 0; @@ -2741,12 +2755,14 @@ int parse_frommap(int fd) 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++) { - int aid, cid; - struct online_char_data* character; aid = RFIFOL(fd,6+i*8); cid = RFIFOL(fd,6+i*8+4); character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data); @@ -2756,33 +2772,44 @@ int parse_frommap(int fd) 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->char_id = cid; character->server = id; + character->char_id = cid; } //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,6+i*8); + 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 mmo_charstatus* cs; - ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == RFIFOL(fd,4) && char_dat[i].status.char_id == RFIFOL(fd,8) ); - if( i < char_num ) + 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; + } + if( ( cs = search_character(aid, cid) ) != NULL ) { - memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - storage_save(char_dat[i].status.account_id, &char_dat[i].status.storage); + memcpy(cs, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); + storage_save(cs->account_id, &cs->storage); } if (RFIFOB(fd,12)) - { //Flag, set character offline. [Skotlex] - set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4)); + { //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) = RFIFOL(fd,4); - WFIFOL(fd,6) = RFIFOL(fd,8); + WFIFOL(fd,2) = aid; + WFIFOL(fd,6) = cid; WFIFOSET(fd,10); } - RFIFOSKIP(fd,RFIFOW(fd,2)); + RFIFOSKIP(fd,size); + } break; case 0x2b02: // req char selection @@ -2805,7 +2832,8 @@ int parse_frommap(int fd) 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->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] @@ -2823,22 +2851,15 @@ int parse_frommap(int fd) if (RFIFOREST(fd) < 35) return 0; { - unsigned short name; int map_id, map_fd = -1; struct online_char_data* data; struct mmo_charstatus* char_data; - name = RFIFOW(fd,18); - map_id = search_mapserver(name, ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. + 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; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == RFIFOL(fd,2) && - char_dat[i].status.char_id == RFIFOL(fd,14)) - break; - } - char_data = i < char_num ? &char_dat[i].status : NULL; + char_data = search_character(RFIFOL(fd,2), RFIFOL(fd,14)); if (map_fd >= 0 && session[map_fd] && char_data) { //Send the map server the auth of this player. @@ -2940,6 +2961,7 @@ int parse_frommap(int fd) 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 @@ -3053,10 +3075,10 @@ int parse_frommap(int fd) break; case 0x2b16: // Receive rates [Wizputer] - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8)) + if( RFIFOREST(fd) < 14 ) return 0; // Txt doesn't need this packet, so just skip it - RFIFOSKIP(fd,RFIFOW(fd,8)); + RFIFOSKIP(fd,14); break; case 0x2b17: // Character disconnected set online 0 [Wizputer] @@ -3238,7 +3260,7 @@ 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 ) { + 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].char_ip; } else { @@ -3255,7 +3277,7 @@ int parse_char(int fd) 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. @@ -3265,7 +3287,7 @@ int parse_char(int 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; @@ -3377,15 +3399,21 @@ int parse_char(int fd) ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].status.slot == slot ); if (ch == MAX_CHARS) { //Not found?? May be forged packet. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; // rejected from server + WFIFOSET(fd,3); break; } cd = &char_dat[sd->found_char[ch]].status; char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s.\n", sd->account_id, slot, cd->name); cd->sex = sd->sex; - + + ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, cd->name); + // searching map server - i = search_mapserver(cd->last_point.map,-1,-1); + i = search_mapserver(cd->last_point.map, -1, -1); // if map is not found, we check major cities if (i < 0) { @@ -3430,6 +3458,7 @@ int parse_char(int fd) 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) { @@ -3454,8 +3483,6 @@ int parse_char(int fd) WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] WFIFOSET(fd,28); - ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch); - // create temporary auth entry CREATE(node, struct auth_node, 1); node->account_id = sd->account_id; @@ -3495,8 +3522,9 @@ int parse_char(int fd) else { int len; + // send to player - WFIFOHEAD(fd,MAX_CHAR_BUF+2); + WFIFOHEAD(fd,2+MAX_CHAR_BUF); WFIFOW(fd,0) = 0x6d; len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat[i].status); WFIFOSET(fd,len); @@ -3504,7 +3532,7 @@ int parse_char(int fd) // 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; // position of the new char in the char_dat[] array + sd->found_char[ch] = i; // position of the new char in the char_dat[] array } RFIFOSKIP(fd,37); @@ -3519,12 +3547,13 @@ int parse_char(int fd) { int cid = RFIFOL(fd,2); struct mmo_charstatus* cs = NULL; + 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,RFIFOREST(fd)); // hack to make the other deletion packet work if (e_mail_check(email) == 0) - strncpy(email, "a@a.com", 40); // default e-mail + safestrncpy(email, "a@a.com", sizeof(email)); // default e-mail // BEGIN HACK: "change email using the char deletion 'confirm email' menu" // if we activated email creation and email is default email @@ -3587,6 +3616,17 @@ int parse_char(int fd) // deletion process cs = &char_dat[sd->found_char[i]].status; + + //check for config char del condition [Lupus] + if( ( char_del_level > 0 && cs->base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && cs->base_level <= (unsigned int)(-char_del_level) ) ) + { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 1; // This character cannot be deleted. + WFIFOSET(fd,3); + break; + } + char_delete(cs); if (sd->found_char[i] != char_num - 1) { int j, k; @@ -3632,9 +3672,25 @@ int parse_char(int fd) // R 028d <account ID>.l <char ID>.l <new name>.24B case 0x28d: FIFOSD_CHECK(34); - //not implemented - RFIFOSKIP(fd,34); - break; + { + //not implemented + RFIFOSKIP(fd,34); + } + break; + //Confirm change name. + // 0x28f <char_id>.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); + { + //not implemented + RFIFOSKIP(fd,6); + } + break; // captcha code request (not implemented) // R 07e5 <?>.w <aid>.l @@ -3752,7 +3808,6 @@ int parse_console(char* buf) return 0; } -// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) int mapif_sendall(unsigned char *buf, unsigned int len) { int i, c; @@ -3771,7 +3826,6 @@ int mapif_sendall(unsigned char *buf, unsigned int len) return c; } -// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) { int i, c; @@ -3789,19 +3843,19 @@ int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) return c; } -// MAPサーバーにデータ送信(map鯖生存確認有り) + int mapif_send(int fd, unsigned char *buf, unsigned int len) { int i; if (fd >= 0) { - for(i = 0; i < MAX_MAP_SERVERS; i++) { - if (fd == server[i].fd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - return 1; - } + ARR_FIND( 0, MAX_MAP_SERVERS, i, fd == server[i].fd ); + if( i < MAX_MAP_SERVERS ) + { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + return 1; } } return 0; @@ -4028,7 +4082,7 @@ int char_config_read(const char *cfgName) remove_control_chars(w1); remove_control_chars(w2); if(strcmpi(w1,"timestamp_format") == 0) { - strncpy(timestamp_format, w2, 20); + safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); } else if(strcmpi(w1,"console_silent")==0){ ShowInfo("Console Silent Setting: %d\n", atoi(w2)); msg_silent = atoi(w2); @@ -4036,23 +4090,21 @@ int char_config_read(const char *cfgName) } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ stdout_with_ansisequence = config_switch(w2); } else if (strcmpi(w1, "userid") == 0) { - strncpy(userid, w2, 24); + safestrncpy(userid, w2, sizeof(userid)); } else if (strcmpi(w1, "passwd") == 0) { - strncpy(passwd, w2, 24); + safestrncpy(passwd, w2, sizeof(passwd)); } else if (strcmpi(w1, "server_name") == 0) { - strncpy(server_name, w2, 20); - server_name[sizeof(server_name) - 1] = '\0'; + safestrncpy(server_name, w2, sizeof(server_name)); ShowStatus("%s server has been initialized\n", w2); } else if (strcmpi(w1, "wisp_server_name") == 0) { if (strlen(w2) >= 4) { - memcpy(wisp_server_name, w2, sizeof(wisp_server_name)); - wisp_server_name[sizeof(wisp_server_name) - 1] = '\0'; + 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) { - strncpy(login_ip_str, w2, sizeof(login_ip_str)); + 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) { @@ -4061,14 +4113,14 @@ int char_config_read(const char *cfgName) char ip_str[16]; char_ip = host2ip(w2); if (char_ip){ - strncpy(char_ip_str, w2, sizeof(char_ip_str)); + 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) { - strncpy(bind_ip_str, w2, sizeof(bind_ip_str)); + 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) { @@ -4082,14 +4134,14 @@ int char_config_read(const char *cfgName) } else if (strcmpi(w1, "email_creation") == 0) { email_creation = config_switch(w2); } else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex - strcpy(scdata_txt, w2); + safestrncpy(scdata_txt, w2, sizeof(scdata_txt)); #endif } else if (strcmpi(w1, "char_txt") == 0) { - strcpy(char_txt, w2); + safestrncpy(char_txt, w2, sizeof(char_txt)); } else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw - strcpy(friends_txt, w2); + safestrncpy(friends_txt, w2, sizeof(friends_txt)); } else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw - strcpy(hotkeys_txt, w2); + safestrncpy(hotkeys_txt, w2, sizeof(hotkeys_txt)); #ifndef TXT_SQL_CONVERT } else if (strcmpi(w1, "max_connect_user") == 0) { max_connect_user = atoi(w2); @@ -4111,10 +4163,8 @@ int char_config_read(const char *cfgName) if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) continue; start_point.map = mapindex_name2id(map); - if (!start_point.map) { + if (!start_point.map) ShowError("Specified start_point %s not found in map-index cache.\n", map); - start_point.map = 0; - } start_point.x = x; start_point.y = y; } else if (strcmpi(w1, "start_zeny") == 0) { @@ -4132,21 +4182,25 @@ int char_config_read(const char *cfgName) } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] log_char = atoi(w2); } else if (strcmpi(w1, "unknown_char_name") == 0) { - strcpy(unknown_char_name, w2); + safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); unknown_char_name[NAME_LENGTH-1] = '\0'; } else if (strcmpi(w1, "char_log_filename") == 0) { - strcpy(char_log_filename, w2); + safestrncpy(char_log_filename, w2, sizeof(char_log_filename)); } 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) { - strcpy(char_name_letters, w2); + 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); + } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] + char_del_level = atoi(w2); // online files options } else if (strcmpi(w1, "online_txt_filename") == 0) { - strcpy(online_txt_filename, w2); + safestrncpy(online_txt_filename, w2, sizeof(online_txt_filename)); } else if (strcmpi(w1, "online_html_filename") == 0) { - strcpy(online_html_filename, w2); + safestrncpy(online_html_filename, w2, sizeof(online_html_filename)); } else if (strcmpi(w1, "online_sorting_option") == 0) { online_sorting_option = atoi(w2); } else if (strcmpi(w1, "online_display_option") == 0) { @@ -4160,7 +4214,7 @@ int char_config_read(const char *cfgName) if (online_refresh_html < 1) online_refresh_html = 1; } else if(strcmpi(w1,"db_path")==0) { - strcpy(db_path,w2); + 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) { @@ -4195,11 +4249,6 @@ int char_config_read(const char *cfgName) } #ifndef TXT_SQL_CONVERT -int chardb_final(int key, void* data, va_list va) -{ - aFree(data); - return 0; -} void do_final(void) { ShowStatus("Terminating server.\n"); @@ -4209,9 +4258,10 @@ void do_final(void) set_all_offline(-1); flush_fifos(); // write online players files with no player - online_char_db->clear(online_char_db, NULL); //clean the db... + online_char_db->clear(online_char_db, NULL); create_online_files(); - online_char_db->destroy(online_char_db, NULL); //dispose the db... + + online_char_db->destroy(online_char_db, NULL); auth_db->destroy(auth_db, NULL); if(char_dat) aFree(char_dat); @@ -4294,11 +4344,11 @@ int do_init(int argc, char **argv) else ShowStatus("Defaulting to %s as our IP address\n", ip_str); if (!login_ip) { - strcpy(login_ip_str, ip_str); + safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); login_ip = str2ip(login_ip_str); } if (!char_ip) { - strcpy(char_ip_str, ip_str); + safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); char_ip = str2ip(char_ip_str); } } |