From aede64e8f9fd60c0e1aa91b420280bf423b14e57 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 12 Apr 2008 07:59:42 +0000 Subject: I live in a giant bucket. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12570 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 47 - src/char/char.c | 4290 ------------------------------------------------ src/char/char.h | 54 - src/char/int_guild.c | 1579 ------------------ src/char/int_guild.h | 26 - src/char/int_homun.c | 365 ---- src/char/int_homun.h | 15 - src/char/int_party.c | 732 --------- src/char/int_party.h | 20 - src/char/int_pet.c | 380 ----- src/char/int_pet.h | 21 - src/char/int_status.c | 183 --- src/char/int_status.h | 23 - src/char/int_storage.c | 481 ------ src/char/int_storage.h | 25 - src/char/inter.c | 711 -------- src/char/inter.h | 30 - src/login/Makefile.in | 46 - src/login/admin.c | 879 ---------- src/login/login.c | 2362 -------------------------- src/login/login.h | 94 -- 21 files changed, 12363 deletions(-) delete mode 100644 src/char/Makefile.in delete mode 100644 src/char/char.c delete mode 100644 src/char/char.h delete mode 100644 src/char/int_guild.c delete mode 100644 src/char/int_guild.h delete mode 100644 src/char/int_homun.c delete mode 100644 src/char/int_homun.h delete mode 100644 src/char/int_party.c delete mode 100644 src/char/int_party.h delete mode 100644 src/char/int_pet.c delete mode 100644 src/char/int_pet.h delete mode 100644 src/char/int_status.c delete mode 100644 src/char/int_status.h delete mode 100644 src/char/int_storage.c delete mode 100644 src/char/int_storage.h delete mode 100644 src/char/inter.c delete mode 100644 src/char/inter.h delete mode 100644 src/login/Makefile.in delete mode 100644 src/login/admin.c delete mode 100644 src/login/login.c delete mode 100644 src/login/login.h diff --git a/src/char/Makefile.in b/src/char/Makefile.in deleted file mode 100644 index 37b464991..000000000 --- a/src/char/Makefile.in +++ /dev/null @@ -1,47 +0,0 @@ - -COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ - ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ - ../common/obj_all/mapindex.o ../common/obj_all/ers.o -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ - ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/malloc.h ../common/showmsg.h ../common/utils.h \ - ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h - -CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ - obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o -CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h - -@SET_MAKE@ - -##################################################################### -.PHONY : all char-server clean help - -all: char-server - -char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ - -clean: - rm -rf *.o obj_txt ../../char-server@EXEEXT@ - -help: - @echo "possible targets are 'char-server' 'all' 'clean' 'help'" - @echo "'char-server' - char server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -obj_txt: - -mkdir obj_txt - -obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - -# missing common object files -../common/obj_all/%.o: - @$(MAKE) -C ../common txt diff --git a/src/char/char.c b/src/char/char.c deleted file mode 100644 index 13da079ab..000000000 --- a/src/char/char.c +++ /dev/null @@ -1,4290 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/core.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" -#include "int_guild.h" -#include "int_homun.h" -#include "int_pet.h" -#include "int_party.h" -#include "int_storage.h" -#include "int_status.h" -#include "char.h" - -#include -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -// private declarations -#define CHAR_CONF_NAME "conf/char_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" - -char char_txt[1024] = "save/athena.txt"; -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 - -#ifndef TXT_SQL_CONVERT -char db_path[1024] = "db"; - -struct mmo_map_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; -char userid[24]; -char passwd[24]; -char server_name[20]; -char wisp_server_name[NAME_LENGTH] = "Server"; -char login_ip_str[128]; -uint32 login_ip = 0; -uint16 login_port = 6900; -char char_ip_str[128]; -uint32 char_ip = 0; -char bind_ip_str[128]; -uint32 bind_ip = INADDR_ANY; -uint16 char_port = 6121; -int char_maintenance = 0; -bool char_new = true; -int char_new_display = 0; - -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 -#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] -bool char_rename = true; - -int log_char = 1; // loggin char or not [devil] -int log_inter = 1; // loggin inter or not [devil] - -static int online_check = 1; //If one, it won't let players connect when their account is already registered online and will send the relevant map server a kick user request. [Skotlex] - -// Advanced subnet check [LuzZza] -struct s_subnet { - 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 char_id_count = START_CHAR_NUM; -struct character_data *char_dat; - -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_weapon = 1201; -int start_armor = 2301; -int guild_exp_rate = 100; - -//Custom limits for the fame lists. [Skotlex] -int fame_list_size_chemist = MAX_FAME_LIST; -int fame_list_size_smith = MAX_FAME_LIST; -int fame_list_size_taekwon = MAX_FAME_LIST; - -// Char-server-side stored fame lists [DracoRPG] -struct fame_list smith_fame_list[MAX_FAME_LIST]; -struct fame_list chemist_fame_list[MAX_FAME_LIST]; -struct fame_list taekwon_fame_list[MAX_FAME_LIST]; - -// Initial position (it's possible to set it in conf file) -struct point start_point = { 0, 53, 111 }; - -struct gm_account *gm_account = NULL; -int GM_num = 0; - -// online players by [Yor] -char online_txt_filename[1024] = "online.txt"; -char online_html_filename[1024] = "online.html"; -int online_sorting_option = 0; // sorting option to display online players in online files -int online_display_option = 1; // display options: to know which columns must be displayed -int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer -int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it - -int console = 0; - -//----------------------------------------------------- -// Auth database -//----------------------------------------------------- -#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) -}; - -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; -}; - -static DBMap* online_char_db; // int account_id -> struct online_char_data* -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data); - -static void* 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 = -1; - return character; -} - -void set_char_online(int map_id, int char_id, int account_id) -{ - struct online_char_data* character; - - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); - if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id && map_id != -3) - { - //char == 99 <- Character logging in, so someone has logged in while one - //char is still on map-server, so kick him out, but don't print "error" - //as this is normal behaviour. [Skotlex] - if (char_id != 99) - 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); - } - - if( character->server > -1 ) - server[character->server].users++; - - if(character->waiting_disconnect != -1) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = -1; - } - - //If user is NOT at char screen, delete entry [Kevin] - if(character->char_id != -1) - { - idb_remove(online_char_db, account_id); - } - - 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 ((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 ) - server[character->server].users--; - - character->char_id = -1; - character->server = -1; - if(character->waiting_disconnect != -1){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = -1; - } - } - - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272c; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } -} - -static int char_db_setoffline(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int server = va_arg(ap, int); - if (server == -1) { - character->char_id = -1; - character->server = -1; - if(character->waiting_disconnect != -1){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = -1; - } - } else if (character->server == server) - character->server = -2; //In some map server that we aren't connected to. - return 0; -} - -static int char_db_kickoffline(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int server_id = va_arg(ap, int); - - if (server_id > -1 && character->server != server_id) - return 0; - - //Kick out any connected characters, and set them offline as appropiate. - if (character->server > -1) - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); - else if (character->waiting_disconnect == -1) - set_char_offline(character->char_id, character->account_id); - else - return 0; // fail - - 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); -} - -//------------------------------ -// Writing function of logs file -//------------------------------ -int char_log(char *fmt, ...) -{ - if(log_char) - { - FILE *logfp; - va_list ap; - time_t raw_time; - char tmpstr[2048]; - - va_start(ap, fmt); - - logfp = fopen(char_log_filename, "a"); - if (logfp) { - if (fmt[0] == '\0') // jump a line if no message - fprintf(logfp, "\n"); - else { - time(&raw_time); - strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime(&raw_time)); - sprintf(tmpstr + 19, ": %s", fmt); - vfprintf(logfp, tmpstr, ap); - } - fclose(logfp); - } - va_end(ap); - } - return 0; -} - -//---------------------------------------------------------------------- -// Determine if an account (id) is a GM account -// and returns its level (or 0 if it isn't a GM account or if not found) -//---------------------------------------------------------------------- -int isGM(int account_id) -{ - int i; - - for(i = 0; i < GM_num; i++) - if (gm_account[i].account_id == account_id) - return gm_account[i].level; - return 0; -} - -//Search character data from the aid/cid givem -struct mmo_charstatus* search_character(int aid, int cid) -{ - int i; - for (i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == cid && char_dat[i].status.account_id == aid) - return &char_dat[i].status; - } - return NULL; -} - -struct mmo_charstatus* search_character_byname(char* character_name) -{ - int i = search_character_index(character_name); - if (i == -1) return NULL; - return &char_dat[i].status; -} - -// Searches if the given character is online, and returns the fd of the -// map-server it is connected to. -int search_character_online(int aid, int cid) -{ - //Look for online character. - struct online_char_data* character; - character = idb_get(online_char_db, aid); - if(character && - character->char_id == cid && - character->server > -1) - return server[character->server].fd; - return -1; -} - -//---------------------------------------------- -// Search an character id -// (return character index or -1 (if not found)) -// If exact character name is not found, -// the function checks without case sensitive -// and returns index if only 1 character is found -// and similar to the searched name. -//---------------------------------------------- -int search_character_index(char* character_name) -{ - int i, quantity, index; - - quantity = 0; - index = -1; - for(i = 0; i < char_num; i++) { - // Without case sensitive check (increase the number of similar character names found) - if (stricmp(char_dat[i].status.name, character_name) == 0) { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(char_dat[i].status.name, character_name) == 0) - return i; - quantity++; - index = i; - } - } - // Here, the exact character name is not found - // We return the found index of a similar account ONLY if there is 1 similar character - if (quantity == 1) - return index; - - // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found - return -1; -} - -/*--------------------------------------------------- - Make a data line for friends list - --------------------------------------------------*/ -int mmo_friends_list_data_str(char *str, struct mmo_charstatus *p) -{ - int i; - char *str_p = str; - str_p += sprintf(str_p, "%d", p->char_id); - - for (i=0;ifriends[i].account_id > 0 && p->friends[i].char_id > 0 && p->friends[i].name[0]) - str_p += sprintf(str_p, ",%d,%d,%s", p->friends[i].account_id, p->friends[i].char_id, p->friends[i].name); - } - - str_p += '\0'; - - return 0; -} - -/*--------------------------------------------------- - Make a data line for hotkeys list - --------------------------------------------------*/ -int mmo_hotkeys_tostr(char *str, struct mmo_charstatus *p) -{ -#ifdef HOTKEY_SAVING - int i; - char *str_p = str; - str_p += sprintf(str_p, "%d", p->char_id); - for (i=0;ihotkeys[i].type, p->hotkeys[i].id, p->hotkeys[i].lv); - str_p += '\0'; -#endif - - return 0; -} - -//------------------------------------------------- -// Function to create the character line (for save) -//------------------------------------------------- -int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int reg_num) -{ - int i,j; - char *str_p = str; - - str_p += sprintf(str_p, - "%d\t%d,%d\t%s\t%d,%d,%d\t%u,%u,%d" //Up to Zeny field - "\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" //Up to Skill Point - "\t%d,%d,%d\t%d,%d,%d,%d" //Up to hom id - "\t%d,%d,%d\t%d,%d,%d,%d,%d" //Up to head bottom - "\t%d,%d,%d\t%d,%d,%d" //last point + save point - ",%d,%d,%d,%d,%d\t", //Family info - p->char_id, p->account_id, p->slot, p->name, // - p->class_, p->base_level, p->job_level, - p->base_exp, p->job_exp, p->zeny, - p->hp, p->max_hp, p->sp, p->max_sp, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->status_point, p->skill_point, - p->option, p->karma, p->manner, // - p->party_id, p->guild_id, p->pet_id, p->hom_id, - p->hair, p->hair_color, p->clothes_color, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, - p->last_point.map, p->last_point.x, p->last_point.y, // - p->save_point.map, p->save_point.x, p->save_point.y, - p->partner_id,p->father,p->mother,p->child,p->fame); - for(i = 0; i < MAX_MEMOPOINTS; i++) - if (p->memo_point[i].map) { - str_p += sprintf(str_p, "%d,%d,%d ", p->memo_point[i].map, p->memo_point[i].x, p->memo_point[i].y); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_INVENTORY; i++) - if (p->inventory[i].nameid) { - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->inventory[i].id,p->inventory[i].nameid,p->inventory[i].amount,p->inventory[i].equip, - p->inventory[i].identify,p->inventory[i].refine,p->inventory[i].attribute); - for(j=0; jinventory[i].card[j]); - str_p += sprintf(str_p," "); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_CART; i++) - if (p->cart[i].nameid) { - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->cart[i].id,p->cart[i].nameid,p->cart[i].amount,p->cart[i].equip, - p->cart[i].identify,p->cart[i].refine,p->cart[i].attribute); - for(j=0; jcart[i].card[j]); - str_p += sprintf(str_p," "); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_SKILL; i++) - if (p->skill[i].id && p->skill[i].flag != 1) { - str_p += sprintf(str_p, "%d,%d ", p->skill[i].id, (p->skill[i].flag == 0) ? p->skill[i].lv : p->skill[i].flag-2); - } - *(str_p++) = '\t'; - - for(i = 0; i < reg_num; i++) - if (reg[i].str[0]) - str_p += sprintf(str_p, "%s,%s ", reg[i].str, reg[i].value); - *(str_p++) = '\t'; - - *str_p = '\0'; - return 0; -} -#endif //TXT_SQL_CONVERT -//------------------------------------------------------------------------- -// Function to set the character from the line (at read of characters file) -//------------------------------------------------------------------------- -int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num) -{ - char tmp_str[3][128]; //To avoid deleting chars with too long names. - int tmp_int[256]; - unsigned int tmp_uint[2]; //To read exp.... - int next, len, i, j; - - // initilialise character - memset(p, '\0', sizeof(struct mmo_charstatus)); - -// Char structure of version 1500 (homun + mapindex maps) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - &tmp_int[45], &tmp_int[35], &tmp_int[36], - &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 48) - { - tmp_int[44] = 0; //Hom ID. -// Char structure of version 1488 (fame field addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 47) - { - tmp_int[43] = 0; //Fame -// Char structure of version 1363 (family data addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &next) != 46) - { - tmp_int[40] = 0; // father - tmp_int[41] = 0; // mother - tmp_int[42] = 0; // child -// Char structure version 1008 (marriage partner addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], &next) != 43) - { - tmp_int[39] = 0; // partner id -// Char structure version 384 (pet addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 42) - { - tmp_int[26] = 0; // pet id -// Char structure of a version 1 (original data structure) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], // - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 41) - { - ShowError("Char-loading: Unrecognized character data version, info lost!\n"); - ShowDebug("Character info: %s\n", str); - return 0; - } - } // Char structure version 384 (pet addition) - } // Char structure version 1008 (marriage partner addition) - } // Char structure of version 1363 (family data addition) - } // Char structure of version 1488 (fame field addition) - //Convert save data from string to integer for older formats - tmp_int[45] = mapindex_name2id(tmp_str[1]); - 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] - p->char_id = tmp_int[0]; - p->account_id = tmp_int[1]; - p->slot = tmp_int[2]; - p->class_ = tmp_int[3]; - p->base_level = tmp_int[4]; - p->job_level = tmp_int[5]; - p->base_exp = tmp_uint[0]; - p->job_exp = tmp_uint[1]; - p->zeny = tmp_int[8]; - p->hp = tmp_int[9]; - p->max_hp = tmp_int[10]; - p->sp = tmp_int[11]; - p->max_sp = tmp_int[12]; - p->str = tmp_int[13]; - p->agi = tmp_int[14]; - p->vit = tmp_int[15]; - p->int_ = tmp_int[16]; - p->dex = tmp_int[17]; - p->luk = tmp_int[18]; - p->status_point = min(tmp_int[19], USHRT_MAX); - p->skill_point = min(tmp_int[20], USHRT_MAX); - p->option = tmp_int[21]; - p->karma = tmp_int[22]; - p->manner = tmp_int[23]; - p->party_id = tmp_int[24]; - p->guild_id = tmp_int[25]; - p->pet_id = tmp_int[26]; - p->hair = tmp_int[27]; - p->hair_color = tmp_int[28]; - p->clothes_color = tmp_int[29]; - p->weapon = tmp_int[30]; - p->shield = tmp_int[31]; - p->head_top = tmp_int[32]; - p->head_mid = tmp_int[33]; - p->head_bottom = tmp_int[34]; - p->last_point.x = tmp_int[35]; - p->last_point.y = tmp_int[36]; - p->save_point.x = tmp_int[37]; - p->save_point.y = tmp_int[38]; - p->partner_id = tmp_int[39]; - p->father = tmp_int[40]; - p->mother = tmp_int[41]; - p->child = tmp_int[42]; - p->fame = tmp_int[43]; - p->hom_id = tmp_int[44]; - p->last_point.map = tmp_int[45]; - p->save_point.map = tmp_int[46]; - -#ifndef TXT_SQL_CONVERT - // Some checks - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == p->char_id) { - ShowError(CL_RED"mmmo_auth_init: a character has an identical id to another.\n"); - ShowError(" character id #%d -> new character not readed.\n", p->char_id); - ShowError(" Character saved in log file."CL_RESET"\n"); - return -1; - } else if (strcmp(char_dat[i].status.name, p->name) == 0) { - ShowError(CL_RED"mmmo_auth_init: a character name already exists.\n"); - ShowError(" character name '%s' -> new character not read.\n", p->name); - ShowError(" Character saved in log file."CL_RESET"\n"); - return -2; - } - } - - if (strcmpi(wisp_server_name, p->name) == 0) { - ShowWarning("mmo_auth_init: ******WARNING: character name has wisp server name.\n"); - ShowWarning(" Character name '%s' = wisp server name '%s'.\n", p->name, wisp_server_name); - ShowWarning(" Character readed. Suggestion: change the wisp server name.\n"); - char_log("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'.\n", - p->name, wisp_server_name); - } -#endif //TXT_SQL_CONVERT - if (str[next] == '\n' || str[next] == '\r') - return 1; // 新規データ - - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - //mapindex memo format - if (sscanf(str+next, "%d,%d,%d%n", &tmp_int[2], &tmp_int[0], &tmp_int[1], &len) != 3) - { //Old string-based memo format. - if (sscanf(str+next, "%[^,],%d,%d%n", tmp_str[0], &tmp_int[0], &tmp_int[1], &len) != 3) - return -3; - tmp_int[2] = mapindex_name2id(tmp_str[0]); - } - if (i < MAX_MEMOPOINTS) - { //Avoid overflowing (but we must also read through all saved memos) - p->memo_point[i].x = tmp_int[0]; - p->memo_point[i].y = tmp_int[1]; - p->memo_point[i].map = tmp_int[2]; - } - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) - { - p->inventory[i].id = tmp_int[0]; - p->inventory[i].nameid = tmp_int[1]; - p->inventory[i].amount = tmp_int[2]; - p->inventory[i].equip = tmp_int[3]; - p->inventory[i].identify = tmp_int[4]; - p->inventory[i].refine = tmp_int[5]; - p->inventory[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) - p->inventory[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } else // invalid structure - return -4; - } - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) - { - p->cart[i].id = tmp_int[0]; - p->cart[i].nameid = tmp_int[1]; - p->cart[i].amount = tmp_int[2]; - p->cart[i].equip = tmp_int[3]; - p->cart[i].identify = tmp_int[4]; - p->cart[i].refine = tmp_int[5]; - p->cart[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) - p->cart[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } else // invalid structure - return -5; - } - - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if (sscanf(str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != 2) - return -6; - p->skill[tmp_int[0]].id = tmp_int[0]; - p->skill[tmp_int[0]].lv = tmp_int[1]; - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for(i = 0; str[next] && str[next] != '\t' && str[next] != '\n' && str[next] != '\r'; i++) { // global_reg実装以前のathena.txt互換のため一応'\n'チェック - if (sscanf(str + next, "%[^,],%[^ ] %n", reg[i].str, reg[i].value, &len) != 2) { - // because some scripts are not correct, the str can be "". So, we must check that. - // If it's, we must not refuse the character, but just this REG value. - // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good) - if (str[next] == ',' && sscanf(str + next, ",%[^ ] %n", reg[i].value, &len) == 1) - i--; - else - return -7; - } - next += len; - if (str[next] == ' ') - next++; - } - *reg_num = i; - - return 1; -} - -//--------------------------------- -// Function to read friend list -//--------------------------------- -int parse_friend_txt(struct mmo_charstatus *p) -{ - char line[1024], temp[1024]; - int pos = 0, count = 0, next; - int i,len; - FILE *fp; - - // Open the file and look for the ID - fp = fopen(friends_txt, "r"); - - if(fp == NULL) - return -1; - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) - continue; //Not this line... - //Read friends - len = strlen(line); - next = pos; - for (count = 0; next < len && count < MAX_FRIENDS; count++) - { //Read friends. - if (sscanf(line+next, ",%d,%d,%23[^,^\n]%n",&p->friends[count].account_id,&p->friends[count].char_id, p->friends[count].name, &pos) < 3) - { //Invalid friend? - memset(&p->friends[count], 0, sizeof(p->friends[count])); - break; - } - next+=pos; - //What IF the name contains a comma? while the next field is not a - //number, we assume it belongs to the current name. [Skotlex] - //NOTE: Of course, this will fail if someone sets their name to something like - //Bob,2005 but... meh, it's the problem of parsing a text file (encasing it in " - //won't do as quotes are also valid name chars!) - while(next < len && sscanf(line+next, ",%23[^,^\n]%n", temp, &pos) > 0) - { - if (atoi(temp)) //We read the next friend, just continue. - break; - //Append the name. - next+=pos; - i = strlen(p->friends[count].name); - if (i + strlen(temp) +1 < NAME_LENGTH) - { - p->friends[count].name[i] = ','; - strcpy(p->friends[count].name+i+1, temp); - } - } //End Guess Block - } //Friend's for. - break; //Found friends. - } - fclose(fp); - return count; -} - -//--------------------------------- -// Function to read hotkey list -//--------------------------------- -int parse_hotkey_txt(struct mmo_charstatus *p) -{ -#ifdef HOTKEY_SAVING - char line[1024]; - int pos = 0, count = 0, next; - int i,len; - int type, id, lv; - FILE *fp; - - // Open the file and look for the ID - fp = fopen(hotkeys_txt, "r"); - if(fp == NULL) - return -1; - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) - continue; //Not this line... - //Read hotkeys - len = strlen(line); - next = pos; - for (count = 0; next < len && count < MAX_HOTKEYS; count++) - { - if (sscanf(line+next, ",%d,%d,%d%n",&type,&id,&lv, &pos) < 3) - //Invalid entry? - break; - p->hotkeys[count].type = type; - p->hotkeys[count].id = id; - p->hotkeys[count].lv = lv; - next+=pos; - } - break; //Found hotkeys. - } - fclose(fp); - return count; -#else - return 0; -#endif -} - - - -#ifndef TXT_SQL_CONVERT -//--------------------------------- -// Function to read characters file -//--------------------------------- -int mmo_char_init(void) -{ - char line[65536]; - int ret, line_count; - FILE* fp; - - char_num = 0; - char_max = 0; - char_dat = NULL; - - fp = fopen(char_txt, "r"); - - if (fp == NULL) { - ShowError("Characters file not found: %s.\n", char_txt); - char_log("Characters file not found: %s.\n", char_txt); - char_log("Id for the next created character: %d.\n", char_id_count); - return 0; - } - - line_count = 0; - while(fgets(line, sizeof(line), fp)) - { - int i, j; - line_count++; - - if (line[0] == '/' && line[1] == '/') - continue; - - j = 0; - if (sscanf(line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) { - if (char_id_count < i) - char_id_count = i; - continue; - } - - if (char_num >= char_max) { - char_max += 256; - char_dat = (struct character_data*)aRealloc(char_dat, sizeof(struct character_data) * char_max); - if (!char_dat) { - ShowFatalError("Out of memory: mmo_char_init (realloc of char_dat).\n"); - char_log("Out of memory: mmo_char_init (realloc of char_dat).\n"); - exit(EXIT_FAILURE); - } - } - - ret = mmo_char_fromstr(line, &char_dat[char_num].status, char_dat[char_num].global, &char_dat[char_num].global_num); - - // Initialize friends list - parse_friend_txt(&char_dat[char_num].status); // Grab friends for the character - // Initialize hotkey list - parse_hotkey_txt(&char_dat[char_num].status); // Grab hotkeys for the character - - if (ret > 0) { // negative value or zero for errors - if (char_dat[char_num].status.char_id >= char_id_count) - char_id_count = char_dat[char_num].status.char_id + 1; - char_num++; - } else { - ShowError("mmo_char_init: in characters file, unable to read the line #%d.\n", line_count); - ShowError(" -> Character saved in log file.\n"); - switch (ret) { - case -1: - char_log("Duplicate character id in the next character line (character not readed):\n"); - break; - case -2: - char_log("Duplicate character name in the next character line (character not readed):\n"); - break; - case -3: - char_log("Invalid memo point structure in the next character line (character not readed):\n"); - break; - case -4: - char_log("Invalid inventory item structure in the next character line (character not readed):\n"); - break; - case -5: - char_log("Invalid cart item structure in the next character line (character not readed):\n"); - break; - case -6: - char_log("Invalid skill structure in the next character line (character not readed):\n"); - break; - case -7: - char_log("Invalid register structure in the next character line (character not readed):\n"); - break; - default: // 0 - char_log("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):\n"); - break; - } - char_log("%s", line); - } - } - fclose(fp); - - if (char_num == 0) { - ShowNotice("mmo_char_init: No character found in %s.\n", char_txt); - char_log("mmo_char_init: No character found in %s.\n", char_txt); - } else if (char_num == 1) { - ShowStatus("mmo_char_init: 1 character read in %s.\n", char_txt); - char_log("mmo_char_init: 1 character read in %s.\n", char_txt); - } else { - ShowStatus("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); - char_log("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); - } - - char_log("Id for the next created character: %d.\n", char_id_count); - - return 0; -} - -//--------------------------------------------------------- -// Function to save characters in files (speed up by [Yor]) -//--------------------------------------------------------- -void mmo_char_sync(void) -{ - char line[65536],f_line[1024]; - int i, j, k; - int lock; - FILE *fp,*f_fp; - CREATE_BUFFER(id, int, char_num); - - // Sorting before save (by [Yor]) - for(i = 0; i < char_num; i++) { - id[i] = i; - for(j = 0; j < i; j++) { - if ((char_dat[i].status.account_id < char_dat[id[j]].status.account_id) || - // if same account id, we sort by slot. - (char_dat[i].status.account_id == char_dat[id[j]].status.account_id && - char_dat[i].status.slot < char_dat[id[j]].status.slot)) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } - - // Data save - fp = lock_fopen(char_txt, &lock); - if (fp == NULL) { - ShowWarning("Server cannot save characters.\n"); - char_log("WARNING: Server cannot save characters.\n"); - } else { - for(i = 0; i < char_num; i++) { - mmo_char_tostr(line, &char_dat[id[i]].status, char_dat[id[i]].global, char_dat[id[i]].global_num); // use of sorted index - fprintf(fp, "%s\n", line); - } - fprintf(fp, "%d\t%%newid%%\n", char_id_count); - lock_fclose(fp, char_txt, &lock); - } - - // Friends List data save (davidsiaw) - f_fp = lock_fopen(friends_txt, &lock); - for(i = 0; i < char_num; i++) { - mmo_friends_list_data_str(f_line, &char_dat[id[i]].status); - fprintf(f_fp, "%s\n", f_line); - } - - lock_fclose(f_fp, friends_txt, &lock); - -#ifdef HOTKEY_SAVING - // Hotkey List data save (Skotlex) - f_fp = lock_fopen(hotkeys_txt, &lock); - for(i = 0; i < char_num; i++) { - mmo_hotkeys_tostr(f_line, &char_dat[id[i]].status); - fprintf(f_fp, "%s\n", f_line); - } - - lock_fclose(f_fp, hotkeys_txt, &lock); -#endif - - DELETE_BUFFER(id); - - return; -} - -//---------------------------------------------------- -// Function to save (in a periodic way) datas in files -//---------------------------------------------------- -int mmo_char_sync_timer(int tid, unsigned int tick, int id, int data) -{ - if (save_log) - ShowInfo("Saving all files...\n"); - mmo_char_sync(); - inter_save(); - 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; - - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); - - // check length of character name - if( name[0] == '\0' ) - return -2; // empty character name - - // 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; - } // 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( i < char_num ) - return -1; // name already exists - - //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 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 ) - return -2; // slot already in use - - if (char_num >= char_max) { - char_max += 256; - RECREATE(char_dat, struct character_data, char_max); - if (!char_dat) { - ShowFatalError("Out of memory: make_new_char (realloc of char_dat).\n"); - char_log("Out of memory: make_new_char (realloc of char_dat).\n"); - exit(EXIT_FAILURE); - } - } - - // validation success, log result - char_log("make new char: account: %d, slot %d, name: %s, stats: %d/%d/%d/%d/%d/%d, hair: %d, hair color: %d.\n", - sd->account_id, slot, name, str, agi, vit, int_, dex, luk, hair_style, hair_color); - - i = char_num; - memset(&char_dat[i], 0, sizeof(struct character_data)); - - char_dat[i].status.char_id = char_id_count++; - char_dat[i].status.account_id = sd->account_id; - char_dat[i].status.slot = slot; - safestrncpy(char_dat[i].status.name,name,NAME_LENGTH); - char_dat[i].status.class_ = 0; - char_dat[i].status.base_level = 1; - char_dat[i].status.job_level = 1; - char_dat[i].status.base_exp = 0; - char_dat[i].status.job_exp = 0; - char_dat[i].status.zeny = start_zeny; - char_dat[i].status.str = str; - char_dat[i].status.agi = agi; - char_dat[i].status.vit = vit; - char_dat[i].status.int_ = int_; - char_dat[i].status.dex = dex; - char_dat[i].status.luk = luk; - char_dat[i].status.max_hp = 40 * (100 + char_dat[i].status.vit) / 100; - char_dat[i].status.max_sp = 11 * (100 + char_dat[i].status.int_) / 100; - char_dat[i].status.hp = char_dat[i].status.max_hp; - char_dat[i].status.sp = char_dat[i].status.max_sp; - char_dat[i].status.status_point = 0; - char_dat[i].status.skill_point = 0; - char_dat[i].status.option = 0; - char_dat[i].status.karma = 0; - char_dat[i].status.manner = 0; - char_dat[i].status.party_id = 0; - char_dat[i].status.guild_id = 0; - char_dat[i].status.hair = hair_style; - char_dat[i].status.hair_color = hair_color; - char_dat[i].status.clothes_color = 0; - char_dat[i].status.inventory[0].nameid = start_weapon; // Knife - char_dat[i].status.inventory[0].amount = 1; - char_dat[i].status.inventory[0].identify = 1; - char_dat[i].status.inventory[1].nameid = start_armor; // Cotton Shirt - char_dat[i].status.inventory[1].amount = 1; - char_dat[i].status.inventory[1].identify = 1; - char_dat[i].status.weapon = 0; // W_FIST - char_dat[i].status.shield = 0; - char_dat[i].status.head_top = 0; - char_dat[i].status.head_mid = 0; - char_dat[i].status.head_bottom = 0; - memcpy(&char_dat[i].status.last_point, &start_point, sizeof(start_point)); - memcpy(&char_dat[i].status.save_point, &start_point, sizeof(start_point)); - char_num++; - - ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, i, slot, name); - mmo_char_sync(); - return i; -} - -//---------------------------------------------------- -// This function return the name of the job (by [Yor]) -//---------------------------------------------------- -char * job_name(int class_) -{ - switch (class_) { - case JOB_NOVICE: return "Novice"; - case JOB_SWORDMAN: return "Swordsman"; - case JOB_MAGE: return "Mage"; - case JOB_ARCHER: return "Archer"; - case JOB_ACOLYTE: return "Acolyte"; - case JOB_MERCHANT: return "Merchant"; - case JOB_THIEF: return "Thief"; - case JOB_KNIGHT: return "Knight"; - case JOB_PRIEST: return "Priest"; - case JOB_WIZARD: return "Wizard"; - case JOB_BLACKSMITH: return "Blacksmith"; - case JOB_HUNTER: return "Hunter"; - case JOB_ASSASSIN: return "Assassin"; - case JOB_KNIGHT2: return "Peco-Knight"; - case JOB_CRUSADER: return "Crusader"; - case JOB_MONK: return "Monk"; - case JOB_SAGE: return "Sage"; - case JOB_ROGUE: return "Rogue"; - case JOB_ALCHEMIST: return "Alchemist"; - case JOB_BARD: return "Bard"; - case JOB_DANCER: return "Dancer"; - case JOB_CRUSADER2: return "Peco-Crusader"; - case JOB_WEDDING: return "Wedding"; - case JOB_SUPER_NOVICE: return "Super Novice"; - case JOB_GUNSLINGER: return "Gunslinger"; - case JOB_NINJA: return "Ninja"; - case JOB_XMAS: return "Christmas"; - case JOB_NOVICE_HIGH: return "Novice High"; - case JOB_SWORDMAN_HIGH: return "Swordsman High"; - case JOB_MAGE_HIGH: return "Mage High"; - case JOB_ARCHER_HIGH: return "Archer High"; - case JOB_ACOLYTE_HIGH: return "Acolyte High"; - case JOB_MERCHANT_HIGH: return "Merchant High"; - case JOB_THIEF_HIGH: return "Thief High"; - case JOB_LORD_KNIGHT: return "Lord Knight"; - case JOB_HIGH_PRIEST: return "High Priest"; - case JOB_HIGH_WIZARD: return "High Wizard"; - case JOB_WHITESMITH: return "Whitesmith"; - case JOB_SNIPER: return "Sniper"; - case JOB_ASSASSIN_CROSS: return "Assassin Cross"; - case JOB_LORD_KNIGHT2: return "Peko Knight"; - case JOB_PALADIN: return "Paladin"; - case JOB_CHAMPION: return "Champion"; - case JOB_PROFESSOR: return "Professor"; - case JOB_STALKER: return "Stalker"; - case JOB_CREATOR: return "Creator"; - case JOB_CLOWN: return "Clown"; - case JOB_GYPSY: return "Gypsy"; - case JOB_PALADIN2: return "Peko Paladin"; - case JOB_BABY: return "Baby Novice"; - case JOB_BABY_SWORDMAN: return "Baby Swordsman"; - case JOB_BABY_MAGE: return "Baby Mage"; - case JOB_BABY_ARCHER: return "Baby Archer"; - case JOB_BABY_ACOLYTE: return "Baby Acolyte"; - case JOB_BABY_MERCHANT: return "Baby Merchant"; - case JOB_BABY_THIEF: return "Baby Thief"; - case JOB_BABY_KNIGHT: return "Baby Knight"; - case JOB_BABY_PRIEST: return "Baby Priest"; - case JOB_BABY_WIZARD: return "Baby Wizard"; - case JOB_BABY_BLACKSMITH: return "Baby Blacksmith"; - case JOB_BABY_HUNTER: return "Baby Hunter"; - case JOB_BABY_ASSASSIN: return "Baby Assassin"; - case JOB_BABY_KNIGHT2: return "Baby Peco Knight"; - case JOB_BABY_CRUSADER: return "Baby Crusader"; - case JOB_BABY_MONK: return "Baby Monk"; - case JOB_BABY_SAGE: return "Baby Sage"; - case JOB_BABY_ROGUE: return "Baby Rogue"; - case JOB_BABY_ALCHEMIST: return "Baby Alchemist"; - case JOB_BABY_BARD: return "Baby Bard"; - case JOB_BABY_DANCER: return "Baby Dancer"; - case JOB_BABY_CRUSADER2: return "Baby Peco Crusader"; - case JOB_SUPER_BABY: return "Super Baby"; - case JOB_TAEKWON: return "Taekwon"; - case JOB_STAR_GLADIATOR: return "Star Gladiator"; - case JOB_STAR_GLADIATOR2: return "Flying Star Gladiator"; - case JOB_SOUL_LINKER: return "Soul Linker"; - } - return "Unknown Job"; -} - -static int create_online_files_sub(DBKey key, void* data, va_list va) -{ - struct online_char_data *character; - int* players; - int *id; - int j,k,l; - character = (struct online_char_data*) data; - players = va_arg(va, int*); - id = va_arg(va, int*); - - // check if map-server is online - if (character->server == -1 || character->char_id == -1) { //Character not currently online. - return -1; - } - - j = character->server; - if (server[j].fd < 0) { - server[j].users = 0; - return -1; - } - // search position of character in char_dat and sort online characters. - for(j = 0; j < char_num; j++) { - if (char_dat[j].status.char_id != character->char_id) - continue; - id[*players] = j; - // use sorting option - switch (online_sorting_option) { - case 1: // by name (without case sensitive) - for(k = 0; k < *players; k++) - if (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0 || - // if same name, we sort with case sensitive. - (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) == 0 && - strcmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 2: // by zeny - for(k = 0; k < *players; k++) - if (char_dat[j].status.zeny < char_dat[id[k]].status.zeny || - // if same number of zenys, we sort by name. - (char_dat[j].status.zeny == char_dat[id[k]].status.zeny && - stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 3: // by base level - for(k = 0; k < *players; k++) - if (char_dat[j].status.base_level < char_dat[id[k]].status.base_level || - // if same base level, we sort by base exp. - (char_dat[j].status.base_level == char_dat[id[k]].status.base_level && - char_dat[j].status.base_exp < char_dat[id[k]].status.base_exp)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 4: // by job (and job level) - for(k = 0; k < *players; k++) - if (char_dat[j].status.class_ < char_dat[id[k]].status.class_ || - // if same job, we sort by job level. - (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && - char_dat[j].status.job_level < char_dat[id[k]].status.job_level) || - // if same job and job level, we sort by job exp. - (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && - char_dat[j].status.job_level == char_dat[id[k]].status.job_level && - char_dat[j].status.job_exp < char_dat[id[k]].status.job_exp)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 5: // by location map name - { - const char *map1, *map2; - map1 = mapindex_id2name(char_dat[j].status.last_point.map); - - for(k = 0; k < *players; k++) { - map2 = mapindex_id2name(char_dat[id[k]].status.last_point.map); - if (!map1 || !map2 || //Avoid sorting if either one failed to resolve. - stricmp(map1, map2) < 0 || - // if same map name, we sort by name. - (stricmp(map1, map2) == 0 && - stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - } - } - break; - default: // 0 or invalid value: no sorting - break; - } - (*players)++; - break; - } - return 0; -} -//------------------------------------------------------------- -// Function to create the online files (txt and html). by [Yor] -//------------------------------------------------------------- -void create_online_files(void) -{ - unsigned int k, j; // for loop with strlen comparing - int i, l; // for loops - int players; // count the number of players - FILE *fp; // for the txt file - FILE *fp2; // for the html file - char temp[256]; // to prepare what we must display - time_t time_server; // for number of seconds - struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ... - int id[4096]; - - if (online_display_option == 0) // we display nothing, so return - return; - - // Get number of online players, id of each online players, and verify if a server is offline - players = 0; - online_char_db->foreach(online_char_db, create_online_files_sub, &players, &id); - - // write files - fp = fopen(online_txt_filename, "w"); - if (fp != NULL) { - fp2 = fopen(online_html_filename, "w"); - if (fp2 != NULL) { - // get time - time(&time_server); // get time in seconds since 1/1/1970 - datetime = localtime(&time_server); // convert seconds in structure - strftime(temp, sizeof(temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52) - // write heading - fprintf(fp2, "\n"); - fprintf(fp2, " \n", online_refresh_html); // update on client explorer every x seconds - fprintf(fp2, " \n"); - fprintf(fp2, " Online Players on %s\n", server_name); - fprintf(fp2, " \n"); - fprintf(fp2, " \n"); - fprintf(fp2, "

Online Players on %s (%s):

\n", server_name, temp); - fprintf(fp, "Online Players on %s (%s):\n", server_name, temp); - fprintf(fp, "\n"); - - for (i = 0; i < players; i++) { - // if it's the first player - if (i == 0) { - j = 0; // count the number of characters for the txt version and to set the separate line - fprintf(fp2, " \n"); - fprintf(fp2, " \n"); - if ((online_display_option & 1) || (online_display_option & 64)) { - fprintf(fp2, " \n"); - if (online_display_option & 64) { - fprintf(fp, "Name "); // 30 - j += 30; - } else { - fprintf(fp, "Name "); // 25 - j += 25; - } - } - if ((online_display_option & 6) == 6) { - fprintf(fp2, " \n"); - fprintf(fp, "Job Levels "); // 27 - j += 27; - } else if (online_display_option & 2) { - fprintf(fp2, " \n"); - fprintf(fp, "Job "); // 19 - j += 19; - } else if (online_display_option & 4) { - fprintf(fp2, " \n"); - fprintf(fp, " Levels "); // 8 - j += 8; - } - if (online_display_option & 24) { // 8 or 16 - fprintf(fp2, " \n"); - if (online_display_option & 16) { - fprintf(fp, "Location ( x , y ) "); // 23 - j += 23; - } else { - fprintf(fp, "Location "); // 13 - j += 13; - } - } - if (online_display_option & 32) { - fprintf(fp2, " \n"); - fprintf(fp, " Zenys "); // 16 - j += 16; - } - fprintf(fp2, " \n"); - fprintf(fp, "\n"); - for (k = 0; k < j; k++) - fprintf(fp, "-"); - fprintf(fp, "\n"); - } - fprintf(fp2, " \n"); - // get id of the character (more speed) - 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); - l = isGM(char_dat[j].status.account_id); - if (online_display_option & 64) { - if (l >= online_gm_display_min_level) - fprintf(fp, "%-24s (GM) ", temp); - else - fprintf(fp, "%-24s ", temp); - } else - fprintf(fp, "%-24s ", temp); - // name of the character in the html (no < >, because that create problem in html code) - fprintf(fp2, " \n"); - } - // displaying of the job - if (online_display_option & 6) { - char * jobname = job_name(char_dat[j].status.class_); - if ((online_display_option & 6) == 6) { - fprintf(fp2, " \n", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); - fprintf(fp, "%-18s %3d/%3d ", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); - } else if (online_display_option & 2) { - fprintf(fp2, " \n", jobname); - fprintf(fp, "%-18s ", jobname); - } else if (online_display_option & 4) { - fprintf(fp2, " \n", char_dat[j].status.base_level, char_dat[j].status.job_level); - fprintf(fp, "%3d/%3d ", char_dat[j].status.base_level, char_dat[j].status.job_level); - } - } - // 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); - // write map name - if (online_display_option & 16) { // map-name AND coordinates - fprintf(fp2, " \n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); - fprintf(fp, "%-12s (%3d,%3d) ", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); - } else { - fprintf(fp2, " \n", temp); - fprintf(fp, "%-12s ", temp); - } - } - // displaying nimber of zenys - if (online_display_option & 32) { - // write number of zenys - if (char_dat[j].status.zeny == 0) { // if no zeny - fprintf(fp2, " \n"); - fprintf(fp, " no zeny "); - } else { - fprintf(fp2, " \n", char_dat[j].status.zeny); - fprintf(fp, "%13d z ", char_dat[j].status.zeny); - } - } - fprintf(fp, "\n"); - fprintf(fp2, " \n"); - } - // If we display at least 1 player - if (players > 0) { - fprintf(fp2, "
NameJob (levels)JobLevelsLocationzenys
"); - if ((online_display_option & 64) && l >= online_gm_display_min_level) - fprintf(fp2, ""); - for (k = 0; k < strlen(temp); k++) { - switch(temp[k]) { - case '<': // < - fprintf(fp2, "<"); - break; - case '>': // > - fprintf(fp2, ">"); - break; - default: - fprintf(fp2, "%c", temp[k]); - break; - }; - } - if ((online_display_option & 64) && l >= online_gm_display_min_level) - fprintf(fp2, " (GM)"); - fprintf(fp2, "%s %d/%d%s%d/%d%s (%d, %d)%sno zeny%d z
\n"); - fprintf(fp, "\n"); - } - - // Displaying number of online players - if (players == 0) { - fprintf(fp2, "

No user is online.

\n"); - fprintf(fp, "No user is online.\n"); - } else if (players == 1) { - fprintf(fp2, "

%d user is online.

\n", players); - fprintf(fp, "%d user is online.\n", players); - } else { - fprintf(fp2, "

%d users are online.

\n", players); - fprintf(fp, "%d users are online.\n", players); - } - fprintf(fp2, " \n"); - fprintf(fp2, "\n"); - fclose(fp2); - } - fclose(fp); - } - - return; -} - -//--------------------------------------------------------------------- -// This function return the number of online players in all map-servers -//--------------------------------------------------------------------- -int count_users(void) -{ - int i, users; - - users = 0; - for(i = 0; i < MAX_MAP_SERVERS; 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 (106 or 108) -int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p) -{ - if( buf == NULL || p == NULL ) - return 0; - - WBUFL(buf,0) = p->char_id; - WBUFL(buf,4) = min(p->base_exp, LONG_MAX); - WBUFL(buf,8) = p->zeny; - WBUFL(buf,12) = min(p->job_exp, LONG_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, SHRT_MAX); - WBUFW(buf,42) = min(p->hp, SHRT_MAX); - WBUFW(buf,44) = min(p->max_hp, SHRT_MAX); - WBUFW(buf,46) = min(p->sp, SHRT_MAX); - WBUFW(buf,48) = min(p->max_sp, SHRT_MAX); - WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; - WBUFW(buf,52) = p->class_; - WBUFW(buf,54) = p->hair; - WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? - WBUFW(buf,58) = p->base_level; - WBUFW(buf,60) = min(p->skill_point, SHRT_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, UCHAR_MAX); - WBUFB(buf,99) = min(p->agi, UCHAR_MAX); - WBUFB(buf,100) = min(p->vit, UCHAR_MAX); - WBUFB(buf,101) = min(p->int_, UCHAR_MAX); - WBUFB(buf,102) = min(p->dex, UCHAR_MAX); - WBUFB(buf,103) = min(p->luk, UCHAR_MAX); - WBUFW(buf,104) = p->slot; - if (char_rename) { - WBUFW(buf,106) = 1;// Rename bit (0=rename,1=no rename) - return 108; - } else { - return 106; - } -} - -//---------------------------------------- -// Function to send characters to a player -//---------------------------------------- -int mmo_char_send006b(int fd, struct char_session_data* sd) -{ - int i, j, found_num; - - found_num = 0; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == sd->account_id) { - sd->found_char[found_num] = i; - if( ++found_num == MAX_CHARS ) - break; - } - } - for(i = found_num; i < MAX_CHARS; i++) - sd->found_char[i] = -1; - - j = 24; // offset - WFIFOHEAD(fd,j + found_num*108); // or 106(!) - WFIFOW(fd,0) = 0x6b; - memset(WFIFOP(fd,4), 0, 20); // unknown bytes - for(i = 0; i < found_num; i++) - j += mmo_char_tobuf(WFIFOP(fd,j), &char_dat[sd->found_char[i]].status); - WFIFOW(fd,2) = j; // packet len - WFIFOSET(fd,j); - - return 0; -} - -// 離婚(char削除時に使用) -int char_divorce(struct mmo_charstatus *cs) -{ - if (cs == NULL) - return 0; - - if (cs->partner_id > 0){ - int i, j; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == cs->partner_id && char_dat[i].status.partner_id == cs->char_id) { - cs->partner_id = 0; - char_dat[i].status.partner_id = 0; - for(j = 0; j < MAX_INVENTORY; j++) - if (char_dat[i].status.inventory[j].nameid == WEDDING_RING_M || char_dat[i].status.inventory[j].nameid == WEDDING_RING_F) - memset(&char_dat[i].status.inventory[j], 0, sizeof(char_dat[i].status.inventory[0])); - if (cs->inventory[j].nameid == WEDDING_RING_M || cs->inventory[j].nameid == WEDDING_RING_F) - memset(&cs->inventory[j], 0, sizeof(cs->inventory[0])); - return 0; - } - } - } - return 0; -} - -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); -} - -int char_child(int parent_id, int child_id) -{ - return (char_dat[parent_id].status.child == char_dat[child_id].status.char_id && - ((char_dat[parent_id].status.char_id == char_dat[child_id].status.father) || - (char_dat[parent_id].status.char_id == char_dat[child_id].status.mother))); -} - -int char_family(int cid1, int cid2, int cid3) -{ - int i, idx1 = -1, idx2 =-1;//, idx3 =-1; - for(i = 0; i < char_num && (idx1 == -1 || idx2 == -1/* || idx3 == 1*/); i++) - { - if (char_dat[i].status.char_id == cid1) - idx1 = i; - if (char_dat[i].status.char_id == cid2) - idx2 = i; -// if (char_dat[i].status.char_id == cid2) -// idx3 = i; - } - if (idx1 == -1 || idx2 == -1/* || idx3 == -1*/) - return 0; //Some character not found?? - - //Unless the dbs are corrupted, these 3 checks should suffice, even though - //we could do a lot more checks and force cross-reference integrity. - if(char_dat[idx1].status.partner_id == cid2 && - char_dat[idx1].status.child == cid3) - return cid3; //cid1/cid2 parents. cid3 child. - - if(char_dat[idx1].status.partner_id == cid3 && - char_dat[idx1].status.child == cid2) - return cid2; //cid1/cid3 parents. cid2 child. - - if(char_dat[idx2].status.partner_id == cid3 && - char_dat[idx2].status.child == cid1) - return cid1; //cid2/cid3 parents. cid1 child. - 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) -{ - int i; - 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; -} - -// キャラ削除に伴うデータ削除 -static int char_delete(struct mmo_charstatus *cs) -{ - int j; - - // ペット削除 - if (cs->pet_id) - inter_pet_delete(cs->pet_id); - if (cs->hom_id) - inter_homun_delete(cs->hom_id); - for (j = 0; j < MAX_INVENTORY; j++) - if (cs->inventory[j].card[0] == (short)0xff00) - inter_pet_delete(MakeDWord(cs->inventory[j].card[1],cs->inventory[j].card[2])); - for (j = 0; j < MAX_CART; j++) - if (cs->cart[j].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(cs->cart[j].card[1],cs->cart[j].card[2]) ); - // ギルド脱退 - if (cs->guild_id) - inter_guild_leave(cs->guild_id, cs->account_id, cs->char_id); - // パーティー脱退 - if (cs->party_id) - inter_party_leave(cs->party_id, cs->account_id, cs->char_id); - // 離婚 - if (cs->partner_id){ - // 離婚情報をmapに通知 - unsigned char buf[10]; - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = cs->char_id; - WBUFL(buf,6) = cs->partner_id; - mapif_sendall(buf,10); - // 離婚 - char_divorce(cs); - } -#ifdef ENABLE_SC_SAVING - status_delete_scdata(cs->account_id, cs->char_id); -#endif - return 0; -} - -static void char_auth_ok(int fd, struct char_session_data *sd) -{ - struct online_char_data* character; - if (max_connect_user && count_users() >= max_connect_user && isGM(sd->account_id) < gm_allow_level) - { - // refuse connection (over populated) - WFIFOW(fd,0) = 0x6c; - WFIFOW(fd,2) = 0; - WFIFOSET(fd,3); - return; - } - - if( online_check && (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 == -1) - character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); - 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. - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - character->fd = fd; - } - - if (login_fd > 0) { - // request to login-server to obtain e-mail/time limit - //FIXME: isn't this part of the auth_ok packet? [ultramage] - 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_online(-1, 99, sd->account_id); - - // send characters to player - mmo_char_send006b(fd, sd); -} - -int send_accounts_tologin(int tid, unsigned int tick, int id, int data); - -int parse_fromlogin(int fd) -{ - int i; - struct char_session_data *sd; - - // only login-server can have an access to here. - // so, if it isn't the login-server, we disconnect the session. - if( fd != login_fd ) - set_eof(fd); - - if(session[fd]->flag.eof) { - if (fd == login_fd) { - ShowWarning("Connection to login-server lost (connection #%d).\n", fd); - login_fd = -1; - } - do_close(fd); - return 0; - } - - 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"); - 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"); - } else { - ShowStatus("Connected to login-server (connection #%d).\n", fd); - - //Send online accounts to login server. - send_accounts_tologin(-1, gettick(), 0, 0); - - // if no map-server already connected, display a message... - ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd > 0 && server[i].map[0] ); - if( i == MAX_MAP_SERVERS ) - ShowStatus("Awaiting maps from map-server.\n"); - } - RFIFOSKIP(fd,3); - break; - - // acknowledgement of account authentication request - case 0x2713: - if (RFIFOREST(fd) < 59) - return 0; - { - int account_id = RFIFOL(fd,2); - int login_id1 = RFIFOL(fd,6); - int login_id2 = RFIFOL(fd,10); - bool result = RFIFOB(fd,14); - const char* email = (const char*)RFIFOP(fd,15); - time_t expiration_time = (time_t)RFIFOL(fd,55); - - // find the session with this account id - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && - sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 ); - if( i < fd_max ) - { - if( result ) { // failure - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x6c; - WFIFOB(i,2) = 0x42; - WFIFOSET(i,3); - } else { // success - memcpy(sd->email, email, 40); - if (e_mail_check(sd->email) == 0) - strncpy(sd->email, "a@a.com", 40); // default e-mail - sd->expiration_time = expiration_time; - char_auth_ok(i, sd); - } - } - } - RFIFOSKIP(fd,59); - break; - - // Receiving of an e-mail/time limit from the login-server (answer of a request because a player comes back from map-server to char-server) by [Yor] - case 0x2717: - if (RFIFOREST(fd) < 50) - return 0; - for(i = 0; i < fd_max; i++) { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) { - if (sd->account_id == RFIFOL(fd,2)) { - memcpy(sd->email, RFIFOP(fd,6), 40); - if (e_mail_check(sd->email) == 0) - strncpy(sd->email, "a@a.com", 40); // default e-mail - sd->expiration_time = (time_t)RFIFOL(fd,46); - break; - } - } - } - RFIFOSKIP(fd,50); - break; - - // login-server alive packet - case 0x2718: - if (RFIFOREST(fd) < 2) - return 0; - RFIFOSKIP(fd,2); - break; - - // changesex reply - case 0x2723: - if (RFIFOREST(fd) < 7) - return 0; - { - int i, j; - unsigned char buf[7]; - - int acc = RFIFOL(fd,2); - int sex = RFIFOB(fd,6); - RFIFOSKIP(fd,7); - - if( acc > 0 ) - { - struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); - if( node != NULL ) - node->sex = sex; - - ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == acc ); - if( i < char_num ) - { - int jobclass = char_dat[i].status.class_; - char_dat[i].status.sex = sex; - if (jobclass == JOB_BARD || jobclass == JOB_DANCER || - jobclass == JOB_CLOWN || jobclass == JOB_GYPSY || - jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { - // job modification - if (jobclass == JOB_BARD || jobclass == JOB_DANCER) { - char_dat[i].status.class_ = (sex) ? JOB_BARD : JOB_DANCER; - } else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) { - char_dat[i].status.class_ = (sex) ? JOB_CLOWN : JOB_GYPSY; - } else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { - char_dat[i].status.class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER; - } - // remove specifical skills of classes 19, 4020 and 4042 - for(j = 315; j <= 322; j++) { - if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) { - if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv) - char_dat[i].status.skill_point = USHRT_MAX; - else - char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; - char_dat[i].status.skill[j].id = 0; - char_dat[i].status.skill[j].lv = 0; - } - } - // remove specifical skills of classes 20, 4021 and 4043 - for(j = 323; j <= 330; j++) { - if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) { - if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv) - char_dat[i].status.skill_point = USHRT_MAX; - else - char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; - - char_dat[i].status.skill[j].id = 0; - char_dat[i].status.skill[j].lv = 0; - } - } - } - // to avoid any problem with equipment and invalid sex, equipment is unequiped. - for (j = 0; j < MAX_INVENTORY; j++) { - if (char_dat[i].status.inventory[j].nameid && char_dat[i].status.inventory[j].equip) - char_dat[i].status.inventory[j].equip = 0; - } - char_dat[i].status.weapon = 0; - char_dat[i].status.shield = 0; - char_dat[i].status.head_top = 0; - char_dat[i].status.head_mid = 0; - char_dat[i].status.head_bottom = 0; - - if (char_dat[i].status.guild_id) //If there is a guild, update the guild_member data [Skotlex] - inter_guild_sex_changed(char_dat[i].status.guild_id, acc, char_dat[i].status.char_id, sex); - } - // disconnect player if online on char-server - disconnect_player(acc); - } - WBUFW(buf,0) = 0x2b0d; - WBUFL(buf,2) = acc; - WBUFB(buf,6) = sex; - mapif_sendall(buf, 7); - } - break; - - case 0x2726: // Request to send a broadcast message (no answer) - if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) - return 0; - if (RFIFOL(fd,4) < 1) - char_log("Receiving a message for broadcast, but message is void.\n"); - else - { - // at least 1 map-server - ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd >= 0 ); - if (i == MAX_MAP_SERVERS) - char_log("'ladmin': Receiving a message for broadcast, but no map-server is online.\n"); - else { - unsigned char buf[128]; - char message[4096]; // +1 to add a null terminated if not exist in the packet - int lp; - char *p; - memset(message, '\0', sizeof(message)); - memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); - message[sizeof(message)-1] = '\0'; - remove_control_chars(message); - // remove all first spaces - p = message; - while(p[0] == ' ') - p++; - // if message is only composed of spaces - if (p[0] == '\0') - char_log("Receiving a message for broadcast, but message is only a lot of spaces.\n"); - // else send message to all map-servers - else { - if (RFIFOW(fd,2) == 0) { - char_log("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n", - message); - lp = 4; - } else { - char_log("'ladmin': Receiving a message for broadcast (message (in blue): %s)\n", - message); - lp = 8; - } - // split message to max 80 char - while(p[0] != '\0') { // if not finish - if (p[0] == ' ') // jump if first char is a space - p++; - else { - char split[80]; - char* last_space; - sscanf(p, "%79[^\t]", split); // max 79 char, any char (\t is control char and control char was removed before) - split[sizeof(split)-1] = '\0'; // last char always \0 - if ((last_space = strrchr(split, ' ')) != NULL) { // searching space from end of the string - last_space[0] = '\0'; // replace it by NULL to have correct length of split - p++; // to jump the new NULL - } - p += strlen(split); - // send broadcast to all map-servers - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = lp + strlen(split) + 1; - WBUFL(buf,4) = 0x65756c62; // only write if in blue (lp = 8) - memcpy(WBUFP(buf,lp), split, strlen(split) + 1); - mapif_sendall(buf, WBUFW(buf,2)); - } - } - } - } - } - RFIFOSKIP(fd,8 + RFIFOL(fd,4)); - break; - - // account_reg2変更通知 - case 0x2729: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { //Receive account_reg2 registry, forward to map servers. - unsigned char buf[ACCOUNT_REG2_NUM*(256+32+2)+16]; - 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)); - } - break; - - // Account deletion notification (from login-server) - case 0x2730: - if (RFIFOREST(fd) < 6) - return 0; - // Deletion of all characters of the account - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == RFIFOL(fd,2)) { - char_delete(&char_dat[i].status); - if (i < char_num - 1) { - memcpy(&char_dat[i], &char_dat[char_num-1], sizeof(struct character_data)); - // if moved character owns to deleted account, check again it's character - if (char_dat[i].status.account_id == RFIFOL(fd,2)) { - i--; - // Correct moved character reference in the character's owner by [Yor] - } else { - int j, k; - struct char_session_data *sd2; - for (j = 0; j < fd_max; j++) { - if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) && - sd2->account_id == char_dat[char_num-1].status.account_id) { - for (k = 0; k < MAX_CHARS; k++) { - if (sd2->found_char[k] == char_num-1) { - sd2->found_char[k] = i; - break; - } - } - break; - } - } - } - } - char_num--; - } - } - // Deletion of the storage - inter_storage_delete(RFIFOL(fd,2)); - // send to all map-servers to disconnect the player - { - unsigned char buf[6]; - WBUFW(buf,0) = 0x2b13; - WBUFL(buf,2) = RFIFOL(fd,2); - mapif_sendall(buf, 6); - } - // disconnect player if online on char-server - disconnect_player(RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - // State change of account/ban notification (from login-server) by [Yor] - 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; - - // Receiving GM acounts info from login-server (by [Yor]) - case 0x2732: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - unsigned char buf[32000]; //FIXME: this will crash - if (gm_account != NULL) - aFree(gm_account); - CREATE(gm_account, struct gm_account, (RFIFOW(fd,2) - 4)/5); - GM_num = 0; - for (i = 4; i < RFIFOW(fd,2); i = i + 5) { - gm_account[GM_num].account_id = RFIFOL(fd,i); - gm_account[GM_num].level = (int)RFIFOB(fd,i+4); - //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level); - GM_num++; - } - ShowStatus("From login-server: receiving information of %d GM accounts.\n", GM_num); - char_log("From login-server: receiving information of %d GM accounts.\n", GM_num); - // send new gm acccounts level to map-servers - memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf,0) = 0x2b15; - mapif_sendall(buf, RFIFOW(fd,2)); - - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - 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 == -1) - 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 //Shouldn't happen, but just in case. - set_char_offline(99, aid); - } - } - } - break; - - 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 up. - - 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); - 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", RFIFOW(fd,0)); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; -} - -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; -} - -//Send packet forward to login-server for account saving -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; -} - -//Receive Registry information for a character. -int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int buf_len) -{ - int i,j,p,len; - for (i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == account_id && char_dat[i].status.char_id == char_id) - break; - } - if(i >= char_num) //Character not found? - return 1; - for(j=0,p=0;j= char_num){ //Character not found? Sent empty packet. - WFIFOW(fd,2)=13; - }else{ - for (p=13,j = 0; j < char_dat[i].global_num; j++) { - if (char_dat[i].global[j].str[0]) { - p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].value)+1; - } - } - WFIFOW(fd,2)=p; - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - -void char_read_fame_list(void) -{ - int i, j, k; - struct fame_list fame_item; - CREATE_BUFFER(id, int, char_num); - - for(i = 0; i < char_num; i++) { - id[i] = i; - for(j = 0; j < i; j++) { - if (char_dat[i].status.fame > char_dat[id[j]].status.fame) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } - - // 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 - for (i = 0, j = 0; i < char_num && j < fame_list_size_smith; i++) { - if (char_dat[id[i]].status.fame && ( - char_dat[id[i]].status.class_ == JOB_BLACKSMITH || - char_dat[id[i]].status.class_ == JOB_WHITESMITH || - char_dat[id[i]].status.class_ == JOB_BABY_BLACKSMITH)) - { - 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); - - memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list)); - j++; - } - } - // Build Alchemist ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_chemist; i++) { - if (char_dat[id[i]].status.fame && ( - char_dat[id[i]].status.class_ == JOB_ALCHEMIST || - char_dat[id[i]].status.class_ == JOB_CREATOR || - char_dat[id[i]].status.class_ == JOB_BABY_ALCHEMIST)) - { - 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); - - memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list)); - - j++; - } - } - // Build Taekwon ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_taekwon; i++) { - if (char_dat[id[i]].status.fame && - char_dat[id[i]].status.class_ == JOB_TAEKWON) - { - 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); - - memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list)); - - j++; - } - } - DELETE_BUFFER(id); -} -// 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; -} - -void char_update_fame_list(int type, int index, int fame) -{ - unsigned char buf[9]; - 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 j; - for( j = 0; j < char_num && char_dat[j].status.char_id != char_id; ++j ) - ;// find char - if( j < char_num ) - strncpy(name, char_dat[j].status.name, NAME_LENGTH); - else - strncpy(name, unknown_char_name, NAME_LENGTH); - - return (j < char_num) ? 1 : 0; -} - -int search_mapserver(unsigned short map, uint32 ip, uint16 port); - -int parse_frommap(int fd) -{ - int i, j; - int id; - - ARR_FIND( 0, MAX_MAP_SERVERS, id, server[id].fd == fd ); - if(id == MAX_MAP_SERVERS) - set_eof(fd); - if(session[fd]->flag.eof) { - if (id < MAX_MAP_SERVERS) { - unsigned char buf[16384]; - ShowStatus("Map-server %d (session #%d) has disconnected.\n", 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)); - } - server[id].fd = -1; - online_char_db->foreach(online_char_db,char_db_setoffline,i); //Tag relevant chars as 'in disconnected' server. - } - do_close(fd); - create_online_files(); - return 0; - } - - 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)) - { - - case 0x2af7: // request from map-server to reload GM accounts. Transmission to login-server - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2709; - WFIFOSET(login_fd,2); - } - RFIFOSKIP(fd,2); - break; - - 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); - char_log("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete.\n", - id, j, CONVIP(server[id].ip), server[id].port, 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); - char_log("WARNING: 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 < MAX_MAP_SERVERS; x++) { - if (server[x].fd > 0 && x != id) { - WFIFOHEAD(fd,10 +4*MAX_MAP_PER_SERVER); - WFIFOW(fd,0) = 0x2b04; - WFIFOL(fd,4) = htonl(server[x].ip); - WFIFOW(fd,8) = htons(server[x].port); - j = 0; - for(i = 0; i < MAX_MAP_PER_SERVER; 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; - struct scdata *data; - aid = RFIFOL(fd,2); - cid = RFIFOL(fd,6); - data = status_search_scdata(aid, cid); - if (data->count > 0) - { //Deliver status change data. - WFIFOW(fd,0) = 0x2b1d; - WFIFOW(fd,2) = 14 + data->count*sizeof(struct status_change_data); - WFIFOL(fd,4) = aid; - WFIFOL(fd,8) = cid; - WFIFOW(fd,12) = data->count; - for (i = 0; i < data->count; i++) - memcpy(WFIFOP(fd,14+i*sizeof(struct status_change_data)), &data->data[i], sizeof(struct status_change_data)); - WFIFOSET(fd, WFIFOW(fd,2)); - status_delete_scdata(aid, cid); //Data sent, so it needs be discarded now. - } -#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. - 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); - if (online_check && 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->char_id = cid; - character->server = id; - } - //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,6+i*8); - break; - - case 0x2b01: // Receive character data from map-server for saving - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == RFIFOL(fd,4) && - char_dat[i].status.char_id == RFIFOL(fd,8)) - break; - } - if (i != char_num) - memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - if (RFIFOB(fd,12)) - { //Flag, set character offline. [Skotlex] - set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4)); - WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. - WFIFOL(fd,2) = RFIFOL(fd,4); - WFIFOL(fd,6) = RFIFOL(fd,8); - WFIFOSET(fd,10); - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - 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); - - // 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) - idb_put(auth_db, account_id, node); - - //Set char to "@ char select" in online db [Kevin] - set_char_online(-3, 99, account_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 0; - WFIFOSET(fd,7); - } - break; - - case 0x2b05: // request "change map server" - 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. - 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; - //Tell the new map server about this player using Kevin's new auth packet. [Skotlex] - if (map_fd >= 0 && session[map_fd] && char_data) - { //Send the map server the auth of this player. - //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); - - WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus)); - WFIFOW(map_fd,0) = 0x2afd; - WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus); - WFIFOL(map_fd,4) = RFIFOL(fd,2); //Account ID - WFIFOL(map_fd,8) = RFIFOL(fd,6); //Login1 - WFIFOL(map_fd,16) = RFIFOL(fd,10); //Login2 - WFIFOL(map_fd,12) = (unsigned long)0; //TODO: expiration_time, how do I figure it out right now? - memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus)); - WFIFOSET(map_fd, WFIFOW(map_fd,2)); - - data = (struct online_char_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,35); - } - 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 character_name[NAME_LENGTH]; - - 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); - - safestrncpy(character_name, name, NAME_LENGTH); - i = search_character_index(character_name); - if( i < 0 ) - { - result = 1; // 1-player not found - } - else - { - char name[NAME_LENGTH]; - int account_id; - - account_id = char_dat[i].status.account_id; - safestrncpy(name, char_dat[i].status.name, NAME_LENGTH); - - if( login_fd <= 0 ) - result = 3; // 3-login-server offline - 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; - } - } - - // send answer if a player ask, not if the server ask - if( acc != -1 ) { - 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; - - case 0x2b16: // Receive rates [Wizputer] - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8)) - return 0; - // Txt doesn't need this packet, so just skip it - RFIFOSKIP(fd,RFIFOW(fd,8)); - 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; - struct scdata *data; - - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); - count = RFIFOW(fd, 12); - - data = status_search_scdata(aid, cid); - if (data->count != count) - { - data->count = count; - data->data = (struct status_change_data*)aRealloc(data->data, count*sizeof(struct status_change_data)); - } - for (i = 0; i < count; i++) - memcpy (&data->data[i], RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); -#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 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; - - 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; -} - -// 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 < MAX_MAP_SERVERS; 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; -} - -// char_mapifの初期化処理(現在はinter_mapif初期化のみ) -static int char_mapif_init(int fd) -{ - return inter_mapif_init(fd); -} - -//-------------------------------------------- -// Test to know if an IP come from LAN or WAN. -//-------------------------------------------- -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].char_ip; - } else { - ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); - return 0; - } -} - -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 ) - { - struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id); - if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] - set_char_offline(-1,sd->account_id); - if( data != NULL && data->fd == fd) - data->fd = -1; - } - 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 GM_value; - - 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; - } - - if( (GM_value = isGM(account_id)) != 0 ) - ShowInfo("Account Logged On; Account ID: %d (GM level %d).\n", account_id, GM_value); - else - ShowInfo("Account Logged On; Account ID: %d.\n", account_id); - - CREATE(session[fd]->session_data, struct char_session_data, 1); - sd = (struct char_session_data*)session[fd]->session_data; - strncpy(sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail - sd->expiration_time = 0; // unknown or unlimited (not displaying on map-server) - 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); - - // 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,19); - 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); - WFIFOSET(login_fd,19); - } 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 *cd; - uint32 subnet_map_ip; - struct auth_node* node; - - int slot = RFIFOB(fd,2); - RFIFOSKIP(fd,3); - - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - // otherwise, load the character - 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. - 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; - - // searching map server - i = search_mapserver(cd->last_point.map,-1,-1); - - // if map is not found, we check major cities - if (i < 0) { - unsigned short j; - //First check that there's actually a map server online. - ARR_FIND( 0, MAX_MAP_SERVERS, j, server[j].fd >= 0 && server[j].map[0] ); - if (j == MAX_MAP_SERVERS) { - 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)); - - // Advanced subnet check [LuzZza] - subnet_map_ip = lan_subnetcheck(ipl); - 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); - - ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch); - - //Send auth ok to map server - WFIFOHEAD(map_fd,20 + sizeof(struct mmo_charstatus)); - WFIFOW(map_fd,0) = 0x2afd; - WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus); - WFIFOL(map_fd,4) = sd->account_id; - WFIFOL(map_fd,8) = sd->login_id1; - WFIFOL(map_fd,16) = sd->login_id2; - WFIFOL(map_fd,12) = (unsigned long)sd->expiration_time; - memcpy(WFIFOP(map_fd,20), cd, sizeof(struct mmo_charstatus)); - WFIFOSET(map_fd, WFIFOW(map_fd,2)); - - // 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->ip = ipl; - idb_put(auth_db, sd->account_id, node); - } - break; - - // create new char - // S 0067 .24B .B .B .B .B .B .B .B .W .W - case 0x67: - FIFOSD_CHECK(37); - - if( !char_new ) //turn character creation on/off [Kevin] - i = -2; - else - i = make_new_char(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)); - - //'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) = 0x02; break; - case -3: WFIFOB(fd,2) = 0x01; break; - } - WFIFOSET(fd,3); - } - else - { - int len; - // send to player - WFIFOHEAD(fd,110); - WFIFOW(fd,0) = 0x6d; - len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat[i].status); - 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; // position of the new char in the char_dat[] array - } - - RFIFOSKIP(fd,37); - 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); - 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 - - // BEGIN HACK: "change email using the char deletion 'confirm email' menu" - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online - // if sended email is incorrect e-mail - if (strcmp(email, "a@a.com") == 0) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - // we change the packet to set it like selection. - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == cid ); - if( i < MAX_CHARS ) - { - // we save new e-mail - memcpy(sd->email, email, 40); - // we send new e-mail to login-server ('online' login-server is checked before) - WFIFOHEAD(login_fd,46); - WFIFOW(login_fd,0) = 0x2715; - WFIFOL(login_fd,2) = sd->account_id; - memcpy(WFIFOP(login_fd, 6), email, 40); - WFIFOSET(login_fd,46); - - // change value to put new packet (char selection) - RFIFOSKIP(fd,-3); //FIXME: Will this work? Messing with the received buffer is ugly anyway... - RFIFOW(fd,0) = 0x66; - RFIFOB(fd,2) = char_dat[sd->found_char[i]].status.slot; - // not send packet, it's modify of actual packet - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - } - break; - } - // END HACK - - // otherwise, we delete the character - if (strcmpi(email, sd->email) != 0) { // if it's an invalid email - 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] != -1 && char_dat[sd->found_char[i]].status.char_id == 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; - } - - // deletion process - cs = &char_dat[sd->found_char[i]].status; - char_delete(cs); - if (sd->found_char[i] != char_num - 1) { - int j, k; - struct char_session_data *sd2; - memcpy(&char_dat[sd->found_char[i]], &char_dat[char_num-1], sizeof(struct mmo_charstatus)); - // Correct moved character reference in the character's owner - for (j = 0; j < fd_max; j++) { - if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) && - sd2->account_id == char_dat[char_num-1].status.account_id) { - for (k = 0; k < MAX_CHARS; k++) { - if (sd2->found_char[k] == char_num-1) { - sd2->found_char[k] = sd->found_char[i]; - break; - } - } - break; - } - } - } - char_num--; - - // 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; - - /* 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); - //not implemented - RFIFOSKIP(fd,34); - 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, MAX_MAP_SERVERS, i, server[i].fd <= 0 ); - if (i == MAX_MAP_SERVERS || strcmp(l_user, userid) || strcmp(l_pass, passwd)) { - 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); - // send gm acccounts level to map-servers - WFIFOHEAD(fd,4+5*GM_num); - WFIFOW(fd,0) = 0x2b15; - for(i = 0; i < GM_num; i++) { - WFIFOL(fd,4+5*i) = gm_account[i].account_id; - WFIFOB(fd,4+5*i+4) = (unsigned char)gm_account[i].level; - } - WFIFOW(fd,2) = 4+5*GM_num; - WFIFOSET(fd,WFIFOW(fd,2)); - } - - RFIFOSKIP(fd,60); - } - return 0; // avoid processing of followup packets here - - // Athena info get - case 0x7530: - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x7531; - WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; - WFIFOB(fd,3) = ATHENA_MINOR_VERSION; - WFIFOB(fd,4) = ATHENA_REVISION; - WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; - WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; - WFIFOB(fd,7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR; - WFIFOW(fd,8) = ATHENA_MOD_VERSION; - WFIFOSET(fd,10); - - RFIFOSKIP(fd,2); - break; - - // 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(char* buf) -{ - char command[256]; - - memset(command, 0, sizeof(command)); - - sscanf(buf, "%[^\n]", command); - - //login_log("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(CL_BOLD"Help of commands:"CL_RESET"\n"); - ShowInfo(" To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|qui|end'\n"); - ShowInfo(" To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - } - - return 0; -} - -// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendall(unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < MAX_MAP_SERVERS; i++) { - int fd; - if ((fd = server[i].fd) > 0) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; -} - -// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < MAX_MAP_SERVERS; 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; -} -// 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; - } - } - } - return 0; -} - -int broadcast_user_count(int tid, unsigned int tick, int id, int 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); - - // refresh online files (txt and html) - create_online_files(); - - return 0; -} - -/// load this char's account id into the 'online accounts' packet -static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)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, int 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; -} - -int check_connect_login_server(int tid, unsigned int tick, int id, int 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); - 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); - WFIFOL(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; -} - -// sends a ping packet to login server (will receive pong 0x2718) -int ping_login_server(int tid, unsigned int tick, int id, int data) -{ - if (login_fd > 0 && session[login_fd] != NULL) - { - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2719; - WFIFOSET(login_fd,2); - } - return 0; -} - -//------------------------------------------------ -//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't -//replies/disconnect the player we tried to kick. [Skotlex] -//------------------------------------------------ -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int 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 = -1; - set_char_offline(character->char_id, character->account_id); - } - return 0; -} - -static int online_data_cleanup_sub(DBKey key, void *data, va_list ap) -{ - struct online_char_data *character= (struct online_char_data*)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, int data) -{ - online_char_db->foreach(online_char_db, online_data_cleanup_sub); - return 0; -} - -//---------------------------------- -// Reading Lan Support configuration -// Rewrote: Anvanced subnet check [LuzZza] -//---------------------------------- -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; - } - - ShowInfo("Reading the configuration file %s...\n", lancfgName); - - 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++; - } - } - - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; -} -#endif //TXT_SQL_CONVERT - -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; - } - - ShowInfo("Reading configuration file %s...\n", cfgName); - 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) { - strncpy(timestamp_format, w2, 20); - } else if(strcmpi(w1,"console_silent")==0){ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - msg_silent = atoi(w2); -#ifndef TXT_SQL_CONVERT - } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ - stdout_with_ansisequence = config_switch(w2); - } else if (strcmpi(w1, "userid") == 0) { - strncpy(userid, w2, 24); - } else if (strcmpi(w1, "passwd") == 0) { - strncpy(passwd, w2, 24); - } else if (strcmpi(w1, "server_name") == 0) { - strncpy(server_name, w2, 20); - server_name[sizeof(server_name) - 1] = '\0'; - 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'; - } - } 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)); - 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){ - strncpy(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)); - 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, "email_creation") == 0) { - email_creation = config_switch(w2); - } else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex - strcpy(scdata_txt, w2); -#endif - } else if (strcmpi(w1, "char_txt") == 0) { - strcpy(char_txt, w2); - } else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw - strcpy(friends_txt, w2); - } else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw - strcpy(hotkeys_txt, w2); -#ifndef TXT_SQL_CONVERT - } 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_level") == 0) { - gm_allow_level = atoi(w2); - if(gm_allow_level < 0) - gm_allow_level = 99; - } else if (strcmpi(w1, "online_check") == 0) { - online_check = config_switch(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.map = 0; - } - 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) { - strcpy(unknown_char_name, w2); - unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "char_log_filename") == 0) { - strcpy(char_log_filename, w2); - } 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); - } else if (strcmpi(w1, "char_rename") == 0) { - char_rename = config_switch(w2); -// online files options - } else if (strcmpi(w1, "online_txt_filename") == 0) { - strcpy(online_txt_filename, w2); - } else if (strcmpi(w1, "online_html_filename") == 0) { - strcpy(online_html_filename, w2); - } else if (strcmpi(w1, "online_sorting_option") == 0) { - online_sorting_option = atoi(w2); - } else if (strcmpi(w1, "online_display_option") == 0) { - online_display_option = atoi(w2); - } else if (strcmpi(w1, "online_gm_display_min_level") == 0) { // minimum GM level to display 'GM' when we want to display it - online_gm_display_min_level = atoi(w2); - if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough - online_gm_display_min_level = 5; - } else if (strcmpi(w1, "online_refresh_html") == 0) { - online_refresh_html = atoi(w2); - if (online_refresh_html < 1) - online_refresh_html = 1; - } else if(strcmpi(w1,"db_path")==0) { - strcpy(db_path,w2); - } 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); -#endif //TXT_SQL_CONVERT - } else if (strcmpi(w1, "import") == 0) { - char_config_read(w2); - } - } - fclose(fp); - - ShowInfo("Done reading %s.\n", cfgName); - return 0; -} - -#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"); - - mmo_char_sync(); - inter_save(); - set_all_offline(-1); - flush_fifos(); - // write online players files with no player - online_char_db->clear(online_char_db, NULL); //clean the db... - create_online_files(); - online_char_db->destroy(online_char_db, NULL); //dispose the db... - auth_db->destroy(auth_db, NULL); - - if(gm_account) aFree(gm_account); - if(char_dat) aFree(char_dat); - - if (login_fd > 0) - do_close(login_fd); - if (char_fd > 0) - do_close(char_fd); - -#ifdef ENABLE_SC_SAVING - status_final(); -#endif - inter_final(); - mapindex_final(); - - char_log("----End of char-server (normal end with closing of all files).\n"); -} - -//------------------------------ -// Function called when the server -// has received a crash signal. -//------------------------------ -void do_abort(void) -{ -} - -void set_server_type(void) -{ - SERVER_TYPE = ATHENA_SERVER_CHAR; -} - -int do_init(int argc, char **argv) -{ - int i; - - for(i = 0; i < MAX_MAP_SERVERS; i++) { - memset(&server[i], 0, sizeof(struct mmo_map_server)); - server[i].fd = -1; - } - - //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); - - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { - ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your save/account.txt file 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"); - } - - ShowInfo("Finished reading the char-server configuration.\n"); - - // a newline in the log... - char_log(""); - // moved behind char_config_read in case we changed the filename [celest] - char_log("The char-server starting...\n"); - - ShowInfo("Initializing char server.\n"); - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); - mmo_char_init(); - char_read_fame_list(); //Read fame lists. -#ifdef ENABLE_SC_SAVING - status_init(); -#endif - inter_init_txt((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化 - ShowInfo("char server initialized.\n"); - - set_defaultparse(parse_char); - - 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) { - strcpy(login_ip_str, ip_str); - login_ip = str2ip(login_ip_str); - } - if (!char_ip) { - strcpy(char_ip_str, ip_str); - char_ip = str2ip(char_ip_str); - } - } - - // 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); - - // keep the char-login connection alive - add_timer_func_list(ping_login_server, "ping_login_server"); - add_timer_interval(gettick() + 1000, ping_login_server, 0, 0, ((int)stall_time-2) * 1000); - - // 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); - - // 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 - - // ??? - add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); - - // ??? - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); - - // periodic flush of all saved data to disk - add_timer_func_list(mmo_char_sync_timer, "mmo_char_sync_timer"); - add_timer_interval(gettick() + 1000, mmo_char_sync_timer, 0, 0, autosave_interval); - - if( console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - char_fd = make_listen_bind(bind_ip, char_port); - char_log("The char-server is ready (Server is listening on the port %d).\n", char_port); - ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); - - return 0; -} - -#endif //TXT_SQL_CONVERT diff --git a/src/char/char.h b/src/char/char.h deleted file mode 100644 index 72077ac09..000000000 --- a/src/char/char.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _CHAR_H_ -#define _CHAR_H_ - -#include "../common/mmo.h" - -#define START_CHAR_NUM 150000 -#define MAX_MAP_SERVERS 30 - -#define DEFAULT_AUTOSAVE_INTERVAL 300*1000 - -struct character_data { - struct mmo_charstatus status; - int global_num; - struct global_reg global[GLOBAL_REG_NUM]; -}; - -struct mmo_charstatus* search_character(int aid, int cid); -struct mmo_charstatus* search_character_byname(char* character_name); -int search_character_index(char* character_name); -char* search_character_name(int index); -int search_character_online(int aid, int cid); - -int mapif_sendall(unsigned char *buf, unsigned int len); -int mapif_sendallwos(int fd,unsigned char *buf, unsigned int len); -int mapif_send(int fd,unsigned char *buf, unsigned int len); - -int char_married(int pl1,int pl2); -int char_child(int parent_id, int child_id); -int char_family(int cid1, int cid2, int cid3); -void char_clearparty(int party_id); - -int char_log(char *fmt, ...); - -int request_accreg2(int account_id, int char_id); -int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int len); -int save_accreg2(unsigned char *buf, int len); -int char_account_reg_reply(int fd,int account_id,int char_id); - -extern int char_name_option; -extern char char_name_letters[]; -extern int autosave_interval; -extern char db_path[]; -extern int guild_exp_rate; -extern int log_inter; -//Exported for use in the TXT-SQL converter. -extern char char_txt[]; -int char_config_read(const char *cfgName); -int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num); -int parse_friend_txt(struct mmo_charstatus *p); - -#endif /* _CHAR_H_ */ diff --git a/src/char/int_guild.c b/src/char/int_guild.c deleted file mode 100644 index e8379c130..000000000 --- a/src/char/int_guild.c +++ /dev/null @@ -1,1579 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "char.h" -#include "inter.h" -#include "int_storage.h" -#include "int_guild.h" - -#include -#include -#include - -char guild_txt[1024] = "save/guild.txt"; -char castle_txt[1024] = "save/castle.txt"; - -#ifndef TXT_SQL_CONVERT -static DBMap* guild_db; // int guild_id -> struct guild* -static DBMap* castle_db; // int castle_id -> struct guild_castle* - -static int guild_newid = 10000; - -static unsigned int guild_exp[100]; - -int mapif_guild_broken(int guild_id, int flag); -static bool guild_check_empty(struct guild *g); -int guild_calcinfo(struct guild *g); -int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len); -int mapif_guild_info(int fd, struct guild *g); -int guild_break_sub(DBKey key, void *data, va_list ap); - -/// serializes the guild data structure into the provided string -int inter_guild_tostr(char* str, struct guild* g) -{ - int i, c, len; - - // save guild base info - len = sprintf(str, "%d\t%s\t%s\t%d,%d,%u,%d,%d\t%s#\t%s#\t", - g->guild_id, g->name, g->master, g->guild_lv, g->max_member, g->exp, g->skill_point, 0, g->mes1, g->mes2); - - // save guild member info - for(i = 0; i < g->max_member; i++) - { - struct guild_member *m = &g->member[i]; - len += sprintf(str + len, "%d,%d,%d,%d,%d,%d,%d,%u,%d,%d\t%s\t", - m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->class_, m->lv, m->exp, m->exp_payper, m->position, - ((m->account_id > 0) ? m->name : "-")); - } - - // save guild position info - for(i = 0; i < MAX_GUILDPOSITION; i++) { - struct guild_position *p = &g->position[i]; - len += sprintf(str + len, "%d,%d\t%s#\t", p->mode, p->exp_mode, p->name); - } - - // save guild emblem - len += sprintf(str + len, "%d,%d,", g->emblem_len, g->emblem_id); - for(i = 0; i < g->emblem_len; i++) { - len += sprintf(str + len, "%02x", (unsigned char)(g->emblem_data[i])); - } - len += sprintf(str + len, "$\t"); - - // save guild alliance info - c = 0; - for(i = 0; i < MAX_GUILDALLIANCE; i++) - if (g->alliance[i].guild_id > 0) - c++; - len += sprintf(str + len, "%d\t", c); - for(i = 0; i < MAX_GUILDALLIANCE; i++) { - struct guild_alliance *a = &g->alliance[i]; - if (a->guild_id > 0) - len += sprintf(str + len, "%d,%d\t%s\t", a->guild_id, a->opposition, a->name); - } - - // save guild expulsion info - c = 0; - for(i = 0; i < MAX_GUILDEXPULSION; i++) - if (g->expulsion[i].account_id > 0) - c++; - len += sprintf(str + len, "%d\t", c); - for(i = 0; i < MAX_GUILDEXPULSION; i++) { - struct guild_expulsion *e = &g->expulsion[i]; - if (e->account_id > 0) - len += sprintf(str + len, "%d,%d,%d,%d\t%s\t%s\t%s#\t", - e->account_id, 0, 0, 0, e->name, "#", e->mes ); - } - - // save guild skill info - for(i = 0; i < MAX_GUILDSKILL; i++) { - len += sprintf(str + len, "%d,%d ", g->skill[i].id, g->skill[i].lv); - } - len += sprintf(str + len, "\t"); - - return 0; -} -#endif //TXT_SQL_CONVERT - -/// parses the guild data string into a guild data structure -int inter_guild_fromstr(char* str, struct guild* g) -{ - int i, c; - char *pstr; - - memset(g, 0, sizeof(struct guild)); - - {// load guild base info - int guildid; - char name[256]; // only 24 used - char master[256]; // only 24 used - int guildlv; - int max_member; - unsigned int exp; - int skpoint; - char mes1[256]; // only 60 used - char mes2[256]; // only 120 used - int len; - - if( sscanf(str, "%d\t%[^\t]\t%[^\t]\t%d,%d,%u,%d,%*d\t%[^\t]\t%[^\t]\t%n", - &guildid, name, master, &guildlv, &max_member, &exp, &skpoint, mes1, mes2, &len) < 9 ) - return 1; - - // remove '#' - mes1[strlen(mes1)-1] = '\0'; - mes2[strlen(mes2)-1] = '\0'; - - g->guild_id = guildid; - g->guild_lv = guildlv; - g->max_member = max_member; - g->exp = exp; - g->skill_point = skpoint; - safestrncpy(g->name, name, sizeof(g->name)); - safestrncpy(g->master, master, sizeof(g->master)); - safestrncpy(g->mes1, mes1, sizeof(g->mes1)); - safestrncpy(g->mes2, mes2, sizeof(g->mes2)); - - str+= len; - } - - {// load guild member info - int accountid; - int charid; - int hair, hair_color, gender; - int class_, lv; - unsigned int exp; - int exp_payper; - int position; - char name[256]; // only 24 used - int len; - int i; - - for( i = 0; i < g->max_member; i++ ) - { - struct guild_member* m = &g->member[i]; - if (sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%u,%d,%d\t%[^\t]\t%n", - &accountid, &charid, &hair, &hair_color, &gender, - &class_, &lv, &exp, &exp_payper, &position, - name, &len) < 11) - return 1; - - m->account_id = accountid; - m->char_id = charid; - m->hair = hair; - m->hair_color = hair_color; - m->gender = gender; - m->class_ = class_; - m->lv = lv; - m->exp = exp; - m->exp_payper = exp_payper; - m->position = position; - safestrncpy(m->name, name, NAME_LENGTH); - - str+= len; - } - } - - {// load guild position info - int mode, exp_mode; - char name[256]; // only 24 used - int len; - int i = 0; - int j; - - while (sscanf(str, "%d,%d%n", &mode, &exp_mode, &j) == 2 && str[j] == '\t') - { - struct guild_position *p = &g->position[i]; - if (sscanf(str, "%d,%d\t%[^\t]\t%n", &mode, &exp_mode, name, &len) < 3) - return 1; - - p->mode = mode; - p->exp_mode = exp_mode; - name[strlen(name)-1] = 0; - safestrncpy(p->name, name, NAME_LENGTH); - - i++; - str+= len; - } - } - - {// load guild emblem - int emblemlen; - int emblemid; - char emblem[4096]; - int len; - - emblemid = 0; - if( sscanf(str, "%d,%d,%[^\t]\t%n", &emblemlen, &emblemid, emblem, &len) < 3 ) - if( sscanf(str, "%d,%[^\t]\t%n", &emblemlen, emblem, &len) < 2 ) //! pre-svn format - return 1; - - g->emblem_len = emblemlen; - g->emblem_id = emblemid; - for(i = 0, pstr = emblem; i < g->emblem_len; i++, pstr += 2) { - int c1 = pstr[0], c2 = pstr[1], x1 = 0, x2 = 0; - if (c1 >= '0' && c1 <= '9') x1 = c1 - '0'; - if (c1 >= 'a' && c1 <= 'f') x1 = c1 - 'a' + 10; - if (c1 >= 'A' && c1 <= 'F') x1 = c1 - 'A' + 10; - if (c2 >= '0' && c2 <= '9') x2 = c2 - '0'; - if (c2 >= 'a' && c2 <= 'f') x2 = c2 - 'a' + 10; - if (c2 >= 'A' && c2 <= 'F') x2 = c2 - 'A' + 10; - g->emblem_data[i] = (x1<<4) | x2; - } - - str+= len; - } - - {// load guild alliance info - int guildid; - int opposition; - char name[256]; // only 24 used - int len; - - if (sscanf(str, "%d\t%n", &c, &len) < 1) - return 1; - str+= len; - - for(i = 0; i < c; i++) - { - struct guild_alliance* a = &g->alliance[i]; - if (sscanf(str, "%d,%d\t%[^\t]\t%n", &guildid, &opposition, name, &len) < 3) - return 1; - - a->guild_id = guildid; - a->opposition = opposition; - safestrncpy(a->name, name, NAME_LENGTH); - - str+= len; - } - } - - {// load guild expulsion info - int accountid; - char name[256]; // only 24 used - char message[256]; // only 40 used - int len; - int i; - - if (sscanf(str, "%d\t%n", &c, &len) < 1) - return 1; - str+= len; - - for(i = 0; i < c; i++) - { - struct guild_expulsion *e = &g->expulsion[i]; - if (sscanf(str, "%d,%*d,%*d,%*d\t%[^\t]\t%*[^\t]\t%[^\t]\t%n", &accountid, name, message, &len) < 3) - return 1; - - e->account_id = accountid; - safestrncpy(e->name, name, sizeof(e->name)); - message[strlen(message)-1] = 0; // remove '#' - safestrncpy(e->mes, message, sizeof(e->mes)); - - str+= len; - } - } - - {// load guild skill info - int skillid; - int skilllv; - int len; - int i; - - for(i = 0; i < MAX_GUILDSKILL; i++) - { - if (sscanf(str, "%d,%d %n", &skillid, &skilllv, &len) < 2) - break; - g->skill[i].id = skillid; - g->skill[i].lv = skilllv; - - str+= len; - } - str = strchr(str, '\t'); - } - - return 0; -} - -#ifndef TXT_SQL_CONVERT -// ギルド城データの文字列への変換 -int inter_guildcastle_tostr(char *str, struct guild_castle *gc) -{ - int len; - - len = sprintf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, - gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC, - gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, - gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible); - - return 0; -} -#endif ///TXT_SQL_CONVERT - -// ギルド城データの文字列からの変換 -int inter_guildcastle_fromstr(char *str, struct guild_castle *gc) -{ - int castleid, guildid, economy, defense, triggerE, triggerD, nextTime, payTime, createTime, visibleC; - int guardian[8]; - int dummy; - - memset(gc, 0, sizeof(struct guild_castle)); - // structure of guild castle with the guardian hp included - if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, - &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7], - &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy) != 26 ) - // structure of guild castle without the hps (current one) - if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, - &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7]) != 18 ) - return 1; - - gc->castle_id = castleid; - gc->guild_id = guildid; - gc->economy = economy; - gc->defense = defense; - gc->triggerE = triggerE; - gc->triggerD = triggerD; - gc->nextTime = nextTime; - gc->payTime = payTime; - gc->createTime = createTime; - gc->visibleC = visibleC; - gc->guardian[0].visible = guardian[0]; - gc->guardian[1].visible = guardian[1]; - gc->guardian[2].visible = guardian[2]; - gc->guardian[3].visible = guardian[3]; - gc->guardian[4].visible = guardian[4]; - gc->guardian[5].visible = guardian[5]; - gc->guardian[6].visible = guardian[6]; - gc->guardian[7].visible = guardian[7]; - - return 0; -} - -#ifndef TXT_SQL_CONVERT -// ギルド関連データベース読み込み -int inter_guild_readdb(void) -{ - int i; - FILE *fp; - char line[1024]; - char path[1024]; - - sprintf(path, "%s%s", db_path, "/exp_guild.txt"); - fp = fopen(path, "r"); - if (fp == NULL) { - ShowError("can't read db/exp_guild.txt\n"); - 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_init() -{ - char line[16384]; - struct guild *g; - struct guild_castle *gc; - FILE *fp; - int i, j, c = 0; - - inter_guild_readdb(); - - guild_db = idb_alloc(DB_OPT_RELEASE_DATA); - castle_db = idb_alloc(DB_OPT_RELEASE_DATA); - - if ((fp = fopen(guild_txt,"r")) == NULL) - return 1; - while(fgets(line, sizeof(line), fp)) - { - j = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && guild_newid <= i) { - guild_newid = i; - continue; - } - - g = (struct guild *) aCalloc(sizeof(struct guild), 1); - if(g == NULL){ - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(g, 0, sizeof(struct guild)); not needed... - if (inter_guild_fromstr(line, g) == 0 && g->guild_id > 0) { - if (g->guild_id >= guild_newid) - guild_newid = g->guild_id + 1; - idb_put(guild_db, g->guild_id, g); - guild_check_empty(g); - guild_calcinfo(g); - } else { - ShowError("int_guild: broken data [%s] line %d\n", guild_txt, c); - aFree(g); - } - c++; - } - fclose(fp); - - c = 0;//カウンタ初期化 - - if ((fp = fopen(castle_txt, "r")) == NULL) { - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); - if(gc == NULL){ - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(gc, 0, sizeof(struct guild_castle)); No need... - if (inter_guildcastle_fromstr(line, gc) == 0) { - idb_put(castle_db, gc->castle_id, gc); - } else { - ShowError("int_guild: broken data [%s] line %d\n", castle_txt, c); - aFree(gc); - } - c++; - } - - fclose(fp); - - if (!c) { - ShowStatus(" %s - making Default Data...\n", castle_txt); - //デフォルトデータを作成 - for(i = 0; i < MAX_GUILDCASTLE; i++) { - gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); - if (gc == NULL) { - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } - gc->castle_id = i; - idb_put(castle_db, gc->castle_id, gc); - } - ShowStatus(" %s - making done\n",castle_txt); - return 0; - } - - return 0; -} - -void inter_guild_final() -{ - castle_db->destroy(castle_db, NULL); - guild_db->destroy(guild_db, NULL); - return; -} - -struct guild *inter_guild_search(int guild_id) -{ - return (struct guild*)idb_get(guild_db, guild_id); -} - -// ギルドデータのセーブ -int inter_guild_save() -{ - FILE *fp; - int lock; - DBIterator* iter; - struct guild* g; - struct guild_castle* gc; - - // save guild data - if ((fp = lock_fopen(guild_txt, &lock)) == NULL) { - ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", guild_txt); - return 1; - } - - iter = guild_db->iterator(guild_db); - for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) - { - char line[16384]; - inter_guild_tostr(line, g); - fprintf(fp, "%s\n", line); - } - iter->destroy(iter); - -// fprintf(fp, "%d\t%%newid%%\n", guild_newid); - lock_fclose(fp, guild_txt, &lock); - - // save castle data - if ((fp = lock_fopen(castle_txt,&lock)) == NULL) { - ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", castle_txt); - return 1; - } - - iter = castle_db->iterator(castle_db); - for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) - { - char line[16384]; - inter_guildcastle_tostr(line, gc); - fprintf(fp, "%s\n", line); - } - iter->destroy(iter); - - lock_fclose(fp, castle_txt, &lock); - - return 0; -} - -// ギルド名検索 -struct guild* search_guildname(char *str) -{ - DBIterator* iter; - struct guild* g; - - iter = guild_db->iterator(guild_db); - for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) - { - if (strcmpi(g->name, str) == 0) - break; - } - iter->destroy(iter); - - return g; -} - -// ギルドが空かどうかチェック -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 - - // 誰もいないので解散 - guild_db->foreach(guild_db, guild_break_sub, g->guild_id); - inter_guild_storage_delete(g->guild_id); - mapif_guild_broken(g->guild_id, 0); - idb_remove(guild_db, g->guild_id); - return true; -} - -unsigned int guild_nextexp(int level) -{ - if (level == 0) - return 1; - if (level > 0 && level < 100) - return guild_exp[level-1]; - - return 0; -} - -// ギルドスキルがあるか確認 -int guild_checkskill(struct guild *g, int id) -{ - int idx = id - GD_SKILLBASE; - - - if(idx < 0 || idx >= MAX_GUILDSKILL) - - return 0; - - return g->skill[idx].lv; -} - -// ギルドの情報の再計算 -int guild_calcinfo(struct guild *g) -{ - int i, c; - unsigned int nextexp; - struct guild before = *g; - - // スキルIDの設定 - for(i = 0; i < MAX_GUILDSKILL; i++) - g->skill[i].id=i+GD_SKILLBASE; - - // ギルドレベル - if (g->guild_lv <= 0) - g->guild_lv = 1; - nextexp = guild_nextexp(g->guild_lv); - if (nextexp > 0) { - 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); - } - } - - // ギルドの次の経験値 - g->next_exp = guild_nextexp(g->guild_lv); - - // メンバ上限(ギルド拡張適用) - g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; //Guild Extention skill - currently adds 6 to max per skill lv. - 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; - } - - // 平均レベルとオンライン人数 - g->average_lv = 0; - g->connect_member = 0; - c = 0; - for(i = 0; i < g->max_member; i++) { - if (g->member[i].account_id > 0) { - g->average_lv += g->member[i].lv; - c++; - if (g->member[i].online > 0) - g->connect_member++; - } - } - if(c) g->average_lv /= c; - - // 全データを送る必要がありそう - if (g->max_member != before.max_member || - g->guild_lv != before.guild_lv || - g->skill_point != before.skill_point) { - mapif_guild_info(-1, g); - return 1; - } - - return 0; -} - -//------------------------------------------------------------------- -// map serverへの通信 - -// ギルド作成可否 -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("Created Guild (%d %s)\n", g->guild_id, g->name); - }else{ - WFIFOL(fd,6) = 0; - } - WFIFOSET(fd,10); - return 0; -} - -// ギルド情報見つからず -int mapif_guild_noinfo(int fd, int guild_id) -{ - WFIFOHEAD(fd, 8); - WFIFOW(fd,0) = 0x3831; - WFIFOW(fd,2) = 8; - WFIFOL(fd,4) = guild_id; - WFIFOSET(fd,8); - ShowNotice("int_guild: info not found %d\n", guild_id); - - return 0; -} - -// ギルド情報まとめ送り -int mapif_guild_info(int fd, struct guild *g) -{ - unsigned char buf[8+sizeof(struct guild)]; - - WBUFW(buf,0) = 0x3831; - memcpy(buf + 4, g, sizeof(struct guild)); - WBUFW(buf,2) = 4 + sizeof(struct guild); - if (fd < 0) - mapif_sendall(buf, WBUFW(buf,2)); - else - mapif_send(fd, buf, WBUFW(buf,2)); - - return 0; -} - -// メンバ追加可否 -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; -} - -// 脱退/追放通知 -int mapif_guild_leaved(int guild_id, int account_id, int char_id, int flag, const char *name, const char *mes) -{ - unsigned char buf[79]; - - 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); -// mapif_sendall(buf, 79); - ShowInfo("Character left guild (Guild %d, %d - %s: %s)\n", guild_id, account_id, name, mes); - - return 0; -} - -// オンライン状態とLv更新通知 -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; -} - -// 解散通知 -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("Guild Break (%d)\n", guild_id); - - return 0; -} - -// ギルド内発言 -int mapif_guild_message(int guild_id, int account_id, char *mes, int len, int sfd) -{ - unsigned char buf[2048]; - - 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; -} - -// ギルド基本情報変更通知 -int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len) -{ - unsigned char buf[2048]; - - 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; -} - -// ギルドメンバ情報変更通知 -int mapif_guild_memberinfochanged(int guild_id, int account_id, int char_id, int type, const void *data, int len) -{ - unsigned char buf[4096]; - - 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; -} - -// ギルドスキルアップ通知 -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; -} - -// ギルド同盟/敵対通知 -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[67]; - - 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); -/* - memcpy(WBUFP(buf,43), name2, NAME_LENGTH); - mapif_sendall(buf, 67); -*/ - return 0; -} - -// ギルド役職変更通知 -int mapif_guild_position(struct guild *g, int idx) -{ - unsigned char buf[2048]; - - 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; -} - -// ギルド告知変更通知 -int mapif_guild_notice(struct guild *g) -{ - unsigned char buf[186]; - - WBUFW(buf,0) = 0x383e; - WBUFL(buf,2) = g->guild_id; - memcpy(WBUFP(buf,6), g->mes1, 60); - memcpy(WBUFP(buf,66), g->mes2, 120); - mapif_sendall(buf, 186); - - return 0; -} - -// ギルドエンブレム変更通知 -int mapif_guild_emblem(struct guild *g) -{ - unsigned char buf[2048]; - - 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; -} - -int mapif_guild_castle_dataload(int castle_id, int index, int value) -{ - unsigned char buf[9]; - - WBUFW(buf,0) = 0x3840; - WBUFW(buf,2) = castle_id; - WBUFB(buf,4) = index; - WBUFL(buf,5) = value; - mapif_sendall(buf,9); - - return 0; -} - -int mapif_guild_castle_datasave(int castle_id, int index, int value) -{ - unsigned char buf[9]; - - WBUFW(buf,0) = 0x3841; - WBUFW(buf,2) = castle_id; - WBUFB(buf,4) = index; - WBUFL(buf,5) = value; - mapif_sendall(buf,9); - - return 0; -} - -int mapif_guild_castle_alldataload(int fd) -{ - DBIterator* iter; - struct guild_castle* gc; - int len = 4; - - WFIFOHEAD(fd, 4 + MAX_GUILDCASTLE*sizeof(struct guild_castle)); - WFIFOW(fd,0) = 0x3842; - iter = castle_db->iterator(castle_db); - for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) - { - memcpy(WFIFOP(fd,len), gc, sizeof(struct guild_castle)); - len += sizeof(struct guild_castle); - } - iter->destroy(iter); - WFIFOW(fd,2) = len; - WFIFOSET(fd, len); - - return 0; -} - -//------------------------------------------------------------------- -// map serverからの通信 - -// ギルド作成要求 -int mapif_parse_CreateGuild(int fd, int account_id, char *name, struct guild_member *master) -{ - struct guild *g; - int i; - - for(i = 0; i < NAME_LENGTH && name[i]; i++) { - if (!(name[i] & 0xe0) || name[i] == 0x7f) { - ShowInfo("Create Guild: illegal guild name [%s]\n", name); - mapif_guild_created(fd, account_id, NULL); - return 0; - } - } - - if ((g = search_guildname(name)) != NULL) { - ShowInfo("Create Guild: same name guild 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 *) aCalloc(sizeof(struct guild), 1); - if (g == NULL) { - ShowFatalError("int_guild: CreateGuild: out of memory !\n"); - mapif_guild_created(fd, account_id, NULL); - exit(EXIT_FAILURE); - } -// memset(g, 0, sizeof(struct guild)); Meh... - g->guild_id = guild_newid++; - memcpy(g->name, name, NAME_LENGTH); - memcpy(g->master, master->name, NAME_LENGTH); - memcpy(&g->member[0], master, sizeof(struct guild_member)); - - g->position[0].mode = 0x11; - strcpy(g->position[ 0].name, "GuildMaster"); - strcpy(g->position[MAX_GUILDPOSITION-1].name, "Newbie"); - for(i = 1; i < MAX_GUILDPOSITION-1; i++) - sprintf(g->position[i].name, "Position %d", i + 1); - - // ここでギルド情報計算が必要と思われる - g->max_member = 16; - g->average_lv = master->lv; - g->connect_member = 1; - for(i = 0; i < MAX_GUILDSKILL; i++) - g->skill[i].id=i + GD_SKILLBASE; - - idb_put(guild_db, g->guild_id, g); - - 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; -} - -// ギルド情報要求 -int mapif_parse_GuildInfo(int fd, int guild_id) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g != NULL){ - guild_calcinfo(g); - mapif_guild_info(fd, g); - } else - mapif_guild_noinfo(fd, guild_id); - - return 0; -} - -// ギルドメンバ追加要求 -int mapif_parse_GuildAddMember(int fd, int guild_id, struct guild_member *m) -{ - struct guild *g; - int i; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) { - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 1); - return 0; - } - - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == 0 ); - if( i < g->max_member ) - { - memcpy(&g->member[i], m, sizeof(struct guild_member)); - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 0); - guild_calcinfo(g); - mapif_guild_info(-1, g); - } - else - 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 = (struct guild*)idb_get(guild_db, guild_id); - if( g == NULL ) - { - //TODO - 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 ) - { // 追放の場合追放リストに入れる - ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); - if (j == MAX_GUILDEXPULSION) - { // 一杯なので古いのを消す - 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_leaved(guild_id, account_id, char_id, flag, g->member[i].name, mes); - - memset(&g->member[i], 0, sizeof(struct guild_member)); - - if (guild_check_empty(g) == 0) - mapif_guild_info(-1,g);// まだ人がいるのでデータ送信 - - return 0; -} - -// オンライン/Lv更新 -int mapif_parse_GuildChangeMemberInfoShort(int fd, int guild_id, int account_id, int char_id, int online, int lv, int class_) -{ - struct guild *g; - int i, sum, c; - - g = (struct guild*)idb_get(guild_db, 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_; - mapif_guild_memberinfoshort(g, i); - } - - g->average_lv = 0; - g->connect_member = 0; - c = 0; // member count - sum = 0; // total sum of base levels - - 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; - - //FIXME: how about sending a mapif_guild_info() update to the mapserver? [ultramage] - - return 0; -} - -// ギルド解散処理用(同盟/敵対を解除) -int guild_break_sub(DBKey key, void *data, va_list ap) -{ - struct guild *g = (struct guild *)data; - int guild_id = va_arg(ap, int); - int i; - - for(i = 0; i < MAX_GUILDALLIANCE; i++) { - if (g->alliance[i].guild_id == guild_id) - g->alliance[i].guild_id = 0; - } - return 0; -} - -// ギルド解散要求 -int mapif_parse_BreakGuild(int fd, int guild_id) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if(g == NULL) - return 0; - - guild_db->foreach(guild_db, guild_break_sub, guild_id); - inter_guild_storage_delete(guild_id); - mapif_guild_broken(guild_id, 0); - - if(log_inter) - inter_log("guild %s (id=%d) broken\n", g->name, guild_id); - - idb_remove(guild_db, guild_id); - return 0; -} - -// ギルドメッセージ送信 -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); -} - -// ギルド基本データ変更要求 -int mapif_parse_GuildBasicInfoChange(int fd, int guild_id, int type, const char *data, int len) -{ - struct guild *g; - short dw = *((short *)data); - - g = (struct guild*)idb_get(guild_db, 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); - return 0; - default: - ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n", type); - break; - } - mapif_guild_basicinfochanged(guild_id, type, data, len); - - return 0; -} - -// ギルドメンバデータ変更要求 -int mapif_parse_GuildMemberInfoChange(int fd, int guild_id, int account_id, int char_id, int type, const char *data, int len) -{ - int i; - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if(g == NULL) - return 0; - - for(i = 0; i < g->max_member; i++) - if (g->member[i].account_id == account_id && g->member[i].char_id == char_id) - break; - if (i == g->max_member) { - ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in %d[%s]\n", account_id, char_id, guild_id, g->name); - return 0; - } - switch(type) { - case GMI_POSITION: // 役職 - g->member[i].position = *((int *)data); - break; - case GMI_EXP: // EXP - { - unsigned int exp, old_exp=g->member[i].exp; - g->member[i].exp=*((unsigned int *)data); - if (g->member[i].exp > old_exp) - { - exp = g->member[i].exp - old_exp; - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; - if (exp > UINT_MAX - g->exp) - g->exp = UINT_MAX; - else - g->exp+=exp; - guild_calcinfo(g); - mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,4); - } - break; - } - case GMI_HAIR: - { - g->member[i].hair=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_HAIR_COLOR: - { - g->member[i].hair_color=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_GENDER: - { - g->member[i].gender=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_CLASS: - { - g->member[i].class_=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_LEVEL: - { - g->member[i].lv=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - - default: - ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n", type); - break; - } - mapif_guild_memberinfochanged(guild_id, account_id, char_id, type, data, len); - - return 0; -} - -int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender) -{ - return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); -} - -// ギルド役職名変更要求 -int mapif_parse_GuildPosition(int fd, int guild_id, int idx, struct guild_position *p) -{ - struct guild *g = (struct guild*)idb_get(guild_db, 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); - ShowInfo("int_guild: position [%d] changed\n", idx); - - return 0; -} - -// ギルドスキルアップ要求 -int mapif_parse_GuildSkillUp(int fd, int guild_id, int skill_num, int account_id) -{ - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); - int idx = skill_num - GD_SKILLBASE; - - if (g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) - return 0; - - if (g->skill_point > 0 && g->skill[idx].id > 0 && g->skill[idx].lv < 10) { - g->skill[idx].lv++; - g->skill_point--; - if (guild_calcinfo(g) == 0) - mapif_guild_info(-1, g); - mapif_guild_skillupack(guild_id, skill_num, account_id); - } - - 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]; - for(i=0;ialliance[i].guild_id == guild_id) - { - strcpy(name, g->alliance[i].name); - g->alliance[i].guild_id=0; - break; - } - if (i == MAX_GUILDALLIANCE) - return -1; - - mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); - return 0; -} - -// ギルド同盟要求 -int mapif_parse_GuildAlliance(int fd, int guild_id1, int guild_id2, int account_id1, int account_id2, int flag) -{ - struct guild *g[2]; - int j, i; - - g[0] = (struct guild*)idb_get(guild_db, guild_id1); - g[1] = (struct guild*)idb_get(guild_db, guild_id2); - - if(g[0] && g[1]==NULL && (flag&0x8)) //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 & 0x8)) { - for(i = 0; i < 2 - (flag & 1); i++) { - for(j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == 0) { - g[i]->alliance[j].guild_id = g[1-i]->guild_id; - memcpy(g[i]->alliance[j].name, g[1-i]->name, NAME_LENGTH); - g[i]->alliance[j].opposition = flag & 1; - break; - } - } - } else { // 関係解消 - for(i = 0; i < 2 - (flag & 1); i++) { - for(j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag & 1)) { - g[i]->alliance[j].guild_id = 0; - break; - } - } - } - mapif_guild_alliance(guild_id1, guild_id2, account_id1, account_id2, flag, g[0]->name, g[1]->name); - - return 0; -} - -// ギルド告知変更要求 -int mapif_parse_GuildNotice(int fd, int guild_id, const char *mes1, const char *mes2) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) - return 0; - memcpy(g->mes1, mes1, 60); - memcpy(g->mes2, mes2, 120); - - return mapif_guild_notice(g); -} - -// ギルドエンブレム変更要求 -int mapif_parse_GuildEmblem(int fd, int len, int guild_id, int dummy, const char *data) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) - return 0; - memcpy(g->emblem_data, data, len); - g->emblem_len = len; - g->emblem_id++; - - return mapif_guild_emblem(g); -} - -int mapif_parse_GuildCastleDataLoad(int fd, int castle_id, int index) -{ - struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); - - if (gc == NULL) { - return mapif_guild_castle_dataload(castle_id, 0, 0); - } - switch(index) { - case 1: return mapif_guild_castle_dataload(gc->castle_id, index, gc->guild_id); - case 2: return mapif_guild_castle_dataload(gc->castle_id, index, gc->economy); - case 3: return mapif_guild_castle_dataload(gc->castle_id, index, gc->defense); - case 4: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerE); - case 5: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerD); - case 6: return mapif_guild_castle_dataload(gc->castle_id, index, gc->nextTime); - case 7: return mapif_guild_castle_dataload(gc->castle_id, index, gc->payTime); - case 8: return mapif_guild_castle_dataload(gc->castle_id, index, gc->createTime); - case 9: return mapif_guild_castle_dataload(gc->castle_id, index, gc->visibleC); - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - return mapif_guild_castle_dataload(gc->castle_id, index, gc->guardian[index-10].visible); - default: - ShowError("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", index); - return 0; - } - - return 0; -} - -int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) -{ - struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); - - if (gc == NULL) - return mapif_guild_castle_datasave(castle_id, index, value); - - switch(index) { - case 1: - if (gc->guild_id != value) { - int gid = (value) ? value : gc->guild_id; - struct guild *g = (struct guild*)idb_get(guild_db, gid); - if(log_inter) - inter_log("guild %s (id=%d) %s castle id=%d\n", - (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); - } - gc->guild_id = value; - if(gc->guild_id == 0) { - //Delete guardians. - memset(&gc->guardian, 0, sizeof(gc->guardian)); - } - 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; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - gc->guardian[index-10].visible = value; break; - default: - ShowError("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", index); - return 0; - } - - return mapif_guild_castle_datasave(gc->castle_id, index, value); -} - -int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) -{ - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); - struct guild_member gm; - int pos; - - if(g==NULL || g->guild_id<=0 || len > NAME_LENGTH) - return 0; - - 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?? - - 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)); - - g->member[pos].position = g->member[0].position; - g->member[0].position = 0; //Position 0: guild Master. - safestrncpy(g->master, name, NAME_LENGTH); - - ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",name, guild_id, g->name); - return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -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)); 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), RFIFOB(fd,4)); break; - case 0x3041: mapif_parse_GuildCastleDataSave(fd, RFIFOW(fd,2), RFIFOB(fd,4), RFIFOL(fd,5)); break; - - default: - return 0; - } - - return 1; -} - -// processes a mapserver connection event -int inter_guild_mapif_init(int fd) -{ - return mapif_guild_castle_alldataload(fd); -} - -// サーバーから脱退要求(キャラ削除用) -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 **"); -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_guild.h b/src/char/int_guild.h deleted file mode 100644 index 06293eb0f..000000000 --- a/src/char/int_guild.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_GUILD_H_ -#define _INT_GUILD_H_ - -struct guild; -struct guild_castle; - -int inter_guild_init(void); -void inter_guild_final(void); -int inter_guild_save(void); -int inter_guild_parse_frommap(int fd); -struct guild *inter_guild_search(int guild_id); -int inter_guild_mapif_init(int fd); -int inter_guild_leave(int guild_id,int account_id,int char_id); -int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender); - -extern char guild_txt[1024]; -extern char castle_txt[1024]; - -//For the TXT->SQL converter -int inter_guild_fromstr(char *str, struct guild *g); -int inter_guildcastle_fromstr(char *str, struct guild_castle *gc); - -#endif /* _INT_GUILD_H_ */ diff --git a/src/char/int_homun.c b/src/char/int_homun.c deleted file mode 100644 index d547b60f7..000000000 --- a/src/char/int_homun.c +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "char.h" -#include "inter.h" -#include "int_homun.h" - -#include -#include -#include - -char homun_txt[1024]="save/homun.txt"; - -static DBMap* homun_db; // int hom_id -> struct s_homunculus* -static int homun_newid = 100; - -int inter_homun_tostr(char *str,struct s_homunculus *p) -{ - int i; - - str+=sprintf(str,"%d,%d\t%s\t%d,%d,%d,%d,%d," - "%u,%d,%d,%d," - "%u,%d,%d," - "%d,%d,%d,%d,%d,%d\t", - p->hom_id, p->class_, p->name, - p->char_id, p->hp, p->max_hp, p->sp, p->max_sp, - p->intimacy, p->hunger, p->skillpts, p->level, - p->exp, p->rename_flag, p->vaporize, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk); - - for (i = 0; i < MAX_HOMUNSKILL; i++) - { - if (p->hskill[i].id && !p->hskill[i].flag) - str+=sprintf(str,"%d,%d,", p->hskill[i].id, p->hskill[i].lv); - } - - return 0; -} - -int inter_homun_fromstr(char *str,struct s_homunculus *p) -{ - int i, next, len; - int tmp_int[25]; - unsigned int tmp_uint[5]; - char tmp_str[256]; - - memset(p,0,sizeof(struct s_homunculus)); - - i=sscanf(str,"%d,%d\t%127[^\t]\t%d,%d,%d,%d,%d," - "%u,%d,%d,%d," - "%u,%d,%d," - "%d,%d,%d,%d,%d,%d\t%n", - &tmp_int[0],&tmp_int[1],tmp_str, - &tmp_int[2],&tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6], - &tmp_uint[0],&tmp_int[7],&tmp_int[8],&tmp_int[9], - &tmp_uint[1],&tmp_int[10],&tmp_int[11], - &tmp_int[12],&tmp_int[13],&tmp_int[14],&tmp_int[15],&tmp_int[16],&tmp_int[17], - &next); - - if(i!=21) - return 1; - - p->hom_id = tmp_int[0]; - p->class_ = tmp_int[1]; - memcpy(p->name, tmp_str, NAME_LENGTH); - - p->char_id = tmp_int[2]; - p->hp = tmp_int[3]; - p->max_hp = tmp_int[4]; - p->sp = tmp_int[5]; - p->max_sp = tmp_int[6]; - - p->intimacy = tmp_uint[0]; - p->hunger = tmp_int[7]; - p->skillpts = tmp_int[8]; - p->level = tmp_int[9]; - - p->exp = tmp_uint[1]; - p->rename_flag = tmp_int[10]; - p->vaporize = tmp_int[11]; - - p->str = tmp_int[12]; - p->agi = tmp_int[13]; - p->vit = tmp_int[14]; - p->int_= tmp_int[15]; - p->dex = tmp_int[16]; - p->luk = tmp_int[17]; - - //Read skills. - while(str[next] && str[next] != '\n' && str[next] != '\r') { - if (sscanf(str+next, "%d,%d,%n", &tmp_int[0], &tmp_int[1], &len) != 2) - return 2; - - if (tmp_int[0] >= HM_SKILLBASE && tmp_int[0] < HM_SKILLBASE+MAX_HOMUNSKILL) - { - i = tmp_int[0] - HM_SKILLBASE; - p->hskill[i].id = tmp_int[0]; - p->hskill[i].lv = tmp_int[1]; - } else - ShowError("Read Homun: Unsupported Skill ID %d for homunculus (Homun ID=%d)\n", tmp_int[0], p->hom_id); - next += len; - if (str[next] == ' ') - next++; - } - return 0; -} - -int inter_homun_init() -{ - char line[8192]; - struct s_homunculus *p; - FILE *fp; - int c=0; - - homun_db= idb_alloc(DB_OPT_RELEASE_DATA); - - if( (fp=fopen(homun_txt,"r"))==NULL ) - return 1; - while(fgets(line, sizeof(line), fp)) - { - p = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1); - if(p==NULL){ - ShowFatalError("int_homun: out of memory!\n"); - exit(EXIT_FAILURE); - } - if(inter_homun_fromstr(line,p)==0 && p->hom_id>0){ - if( p->hom_id >= homun_newid) - homun_newid=p->hom_id+1; - idb_put(homun_db,p->hom_id,p); - }else{ - ShowError("int_homun: broken data [%s] line %d\n",homun_txt,c); - aFree(p); - } - c++; - } - fclose(fp); - return 0; -} - -void inter_homun_final() -{ - homun_db->destroy(homun_db, NULL); - return; -} - -int inter_homun_save_sub(DBKey key,void *data,va_list ap) -{ - char line[8192]; - FILE *fp; - inter_homun_tostr(line,(struct s_homunculus *)data); - fp=va_arg(ap,FILE *); - fprintf(fp,"%s\n",line); - return 0; -} - -int inter_homun_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(homun_txt,&lock))==NULL ){ - ShowError("int_homun: can't write [%s] !!! data is lost !!!\n",homun_txt); - return 1; - } - homun_db->foreach(homun_db,inter_homun_save_sub,fp); - lock_fclose(fp,homun_txt,&lock); - return 0; -} - -int inter_homun_delete(int hom_id) -{ - struct s_homunculus *p; - p = (struct s_homunculus*)idb_get(homun_db,hom_id); - if( p == NULL) - return 0; - idb_remove(homun_db,hom_id); - ShowInfo("Deleted homun (hom_id: %d)\n",hom_id); - return 1; -} - -int mapif_homun_created(int fd,int account_id, struct s_homunculus *p) -{ - 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)= p->hom_id?1:0; - memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); - WFIFOSET(fd, WFIFOW(fd,2)); - return 0; -} - -int mapif_homun_info(int fd,int account_id,struct s_homunculus *p) -{ - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3891; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - WFIFOB(fd,8) = 1; // account loaded with success - - memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - -int mapif_homun_noinfo(int fd,int account_id) -{ - WFIFOHEAD(fd,sizeof(struct s_homunculus) + 9); - WFIFOW(fd,0)=0x3891; - WFIFOW(fd,2)=sizeof(struct s_homunculus) + 9; - WFIFOL(fd,4)=account_id; - WFIFOB(fd,8)=0; - memset(WFIFOP(fd,9),0,sizeof(struct s_homunculus)); - WFIFOSET(fd,WFIFOW(fd,2)); - - return 0; -} - -int mapif_save_homun_ack(int fd,int account_id,int flag) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd,0)=0x3892; - WFIFOL(fd,2)=account_id; - WFIFOB(fd,6)=flag; - WFIFOSET(fd,7); - return 0; -} - -int mapif_delete_homun_ack(int fd,int flag) -{ - WFIFOHEAD(fd, 3); - WFIFOW(fd,0)=0x3893; - WFIFOB(fd,2)=flag; - WFIFOSET(fd,3); - return 0; -} - -int mapif_rename_homun_ack(int fd, int account_id, int char_id, int 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; - memcpy(WFIFOP(fd, 11), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+12); - - return 0; -} - -int mapif_create_homun(int fd) -{ - struct s_homunculus *p; - p= (struct s_homunculus *) aCalloc(sizeof(struct s_homunculus), 1); - if(p==NULL){ - ShowFatalError("int_homun: out of memory !\n"); - //Sending the received data will pass hom_id == 0 <- fail. - mapif_homun_created(fd,RFIFOL(fd,4),(struct s_homunculus*)RFIFOP(fd,8)); - return 0; - } - memcpy(p, RFIFOP(fd,8), sizeof(struct s_homunculus)); - p->hom_id = homun_newid++; //New ID - idb_put(homun_db,p->hom_id,p); - mapif_homun_created(fd,RFIFOL(fd,4),p); - return 0; -} - -int mapif_load_homun(int fd) -{ - struct s_homunculus *p; - int account_id; - account_id = RFIFOL(fd,2); - - p = (struct s_homunculus*)idb_get(homun_db,RFIFOL(fd,6)); - if(p==NULL) { - mapif_homun_noinfo(fd,account_id); - return 0; - } - mapif_homun_info(fd,account_id,p); - return 0; -} - -static void* create_homun(DBKey key, va_list args) { - struct s_homunculus *p; - p=(struct s_homunculus *)aCalloc(sizeof(struct s_homunculus),1); - p->hom_id = key.i; - return p; -} -int mapif_save_homun(int fd,int account_id,struct s_homunculus *data) -{ - struct s_homunculus *p; - int hom_id; - - if (data->hom_id == 0) - data->hom_id = homun_newid++; - hom_id = data->hom_id; - p = (struct s_homunculus*)idb_ensure(homun_db,hom_id,create_homun); - memcpy(p,data,sizeof(struct s_homunculus)); - mapif_save_homun_ack(fd,account_id,1); - return 0; -} - -int mapif_delete_homun(int fd,int hom_id) -{ - mapif_delete_homun_ack(fd,inter_homun_delete(hom_id)); - return 0; -} - -int mapif_rename_homun(int fd, int account_id, int char_id, 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) { - mapif_rename_homun_ack(fd, account_id, char_id, 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_rename_homun_ack(fd, account_id, char_id, 0, name); - return 0; - } - } - - mapif_rename_homun_ack(fd, account_id, char_id, 1, name); - return 0; -} - -int mapif_parse_SaveHomun(int fd) -{ - mapif_save_homun(fd,RFIFOL(fd,4),(struct s_homunculus *)RFIFOP(fd,8)); - return 0; -} - -int mapif_parse_DeleteHomun(int fd) -{ - mapif_delete_homun(fd,RFIFOL(fd,2)); - return 0; -} - -int mapif_parse_RenameHomun(int fd) -{ - mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), (char*)RFIFOP(fd, 10)); - return 0; -} - -int inter_homun_parse_frommap(int fd) -{ - switch(RFIFOW(fd,0)){ - case 0x3090: mapif_create_homun(fd); break; - case 0x3091: mapif_load_homun(fd); break; - case 0x3092: mapif_parse_SaveHomun(fd); break; - case 0x3093: mapif_parse_DeleteHomun(fd); break; - case 0x3094: mapif_parse_RenameHomun(fd); break; - default: - return 0; - } - return 1; -} diff --git a/src/char/int_homun.h b/src/char/int_homun.h deleted file mode 100644 index 1858ed4ba..000000000 --- a/src/char/int_homun.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_HOMUN_H_ -#define _INT_HOMUN_H_ - -int inter_homun_init(void); -void inter_homun_final(void); -int inter_homun_save(void); -int inter_homun_delete(int homun_id); -int inter_homun_parse_frommap(int fd); - -extern char homun_txt[1024]; - -#endif /* _INT_HOMUN_H_ */ diff --git a/src/char/int_party.c b/src/char/int_party.c deleted file mode 100644 index f0668a820..000000000 --- a/src/char/int_party.c +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "char.h" -#include "inter.h" -#include "int_party.h" - -#include -#include -#include - -char party_txt[1024] = "save/party.txt"; -#ifndef TXT_SQL_CONVERT -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. -}; - -static DBMap* party_db; // int party_id -> struct party_data* -static int party_newid = 100; - -int mapif_party_broken(int party_id, int flag); -int party_check_empty(struct party *p); -int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id); -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) - 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 == 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 inter_party_tostr(char *str, struct party *p) { - int i, len; - - len = sprintf(str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, p->item); - for(i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - len += sprintf(str + len, "%d,%d,%d\t", m->account_id, m->char_id, m->leader); - } - - return 0; -} -#endif //TXT_SQL_CONVERT -// パ?ティデ?タの文字列からの?換 -int inter_party_fromstr(char *str, struct party *p) { - int i, j; - int tmp_int[16]; - char tmp_str[256]; -#ifndef TXT_SQL_CONVERT - struct mmo_charstatus* status; -#endif - - memset(p, 0, sizeof(struct party)); - - if (sscanf(str, "%d\t%255[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], &tmp_int[2]) != 4) - return 1; - - p->party_id = tmp_int[0]; - memcpy(p->name, tmp_str, NAME_LENGTH); - p->exp = tmp_int[1]?1:0; - p->item = tmp_int[2]; - - for(j = 0; j < 3 && str != NULL; j++) - str = strchr(str + 1, '\t'); - - for(i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - if (str == NULL) - return 1; - - if (sscanf(str + 1, "%d,%d,%d\t", &tmp_int[0], &tmp_int[1], &tmp_int[2]) != 3) - return 1; - - m->account_id = tmp_int[0]; - m->char_id = tmp_int[1]; - m->leader = tmp_int[2]?1:0; - - str = strchr(str + 1, '\t'); -#ifndef TXT_SQL_CONVERT - if (!m->account_id) continue; - //Lookup player for rest of data. - status = search_character(m->account_id, m->char_id); - if (!status) continue; - - memcpy(m->name, status->name, NAME_LENGTH); - m->class_ = status->class_; - m->map = status->last_point.map; - m->lv = status->base_level; -#endif //TXT_SQL_CONVERT - } - - return 0; -} -#ifndef TXT_SQL_CONVERT -// パ?ティデ?タのロ?ド -int inter_party_init() { - char line[8192]; - struct party_data *p; - FILE *fp; - int c = 0; - int i, j; - - party_db = idb_alloc(DB_OPT_RELEASE_DATA); - - if ((fp = fopen(party_txt, "r")) == NULL) - return 1; - - while(fgets(line, sizeof(line), fp)) - { - j = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && party_newid <= i) { - party_newid = i; - continue; - } - - p = (struct party_data*)aCalloc(sizeof(struct party_data), 1); - if (p == NULL){ - ShowFatalError("int_party: out of memory!\n"); - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(struct party_data)); - if (inter_party_fromstr(line, &p->party) == 0 && p->party.party_id > 0) { - int_party_calc_state(p); - if (p->party.party_id >= party_newid) - party_newid = p->party.party_id + 1; - idb_put(party_db, p->party.party_id, p); - party_check_empty(&p->party); - } else { - ShowError("int_party: broken data [%s] line %d\n", party_txt, c + 1); - aFree(p); - } - c++; - } - fclose(fp); - - return 0; -} - -void inter_party_final() -{ - party_db->destroy(party_db, NULL); - return; -} - -// パ?ティ?デ?タのセ?ブ用 -int inter_party_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - FILE *fp; - - inter_party_tostr(line, &((struct party_data*)data)->party); - fp = va_arg(ap, FILE *); - fprintf(fp, "%s\n", line); - - return 0; -} - -// パ?ティ?デ?タのセ?ブ -int inter_party_save() { - FILE *fp; - int lock; - - if ((fp = lock_fopen(party_txt, &lock)) == NULL) { - ShowError("int_party: can't write [%s] !!! data is lost !!!\n", party_txt); - return 1; - } - party_db->foreach(party_db, inter_party_save_sub, fp); - lock_fclose(fp,party_txt, &lock); - return 0; -} - -// パ?ティ名?索用 -int search_partyname_sub(DBKey key,void *data,va_list ap) { - struct party_data *p = (struct party_data *)data,**dst; - char *str; - - str = va_arg(ap, char *); - dst = va_arg(ap, struct party_data **); - if (strncmpi(p->party.name, str, NAME_LENGTH) == 0) - *dst = p; - - return 0; -} - -// パ?ティ名?索 -struct party_data* search_partyname(char *str) { - struct party_data *p = NULL; - party_db->foreach(party_db, search_partyname_sub, str, &p); - 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); -} - -// パ?ティが空かどうかチェック -int party_check_empty(struct party *p) { - int i; - - for(i = 0; i < MAX_PARTY; i++) { - if (p->member[i].account_id > 0) { - return 0; - } - } - mapif_party_broken(p->party_id, 0); - idb_remove(party_db, p->party_id); - - return 1; -} - -// キャラの競合がないかチェック用 -int party_check_conflict_sub(DBKey key, void *data, va_list ap) { - struct party_data *p = (struct party_data *)data; - int party_id, account_id, char_id, i; - - party_id=va_arg(ap, int); - account_id=va_arg(ap, int); - char_id=va_arg(ap, int); - - if (p->party.party_id == party_id) //No conflict to check - 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) - { - ShowWarning("int_party: party conflict! %d %d %d\n", account_id, party_id, p->party.party_id); - mapif_parse_PartyLeave(-1, p->party.party_id, account_id, char_id); - } - } - - return 0; -} - -// キャラの競合がないかチェック -int party_check_conflict(int party_id, int account_id, int char_id) { - party_db->foreach(party_db, party_check_conflict_sub, party_id, account_id, char_id); - return 0; -} - -//------------------------------------------------------------------- -// map serverへの通信 - -// パ?ティ作成可否 -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("Created party (%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; -} - -// パ?ティ情報見つからず -int mapif_party_noinfo(int fd, int party_id) { - WFIFOHEAD(fd, 8); - WFIFOW(fd,0) = 0x3821; - WFIFOW(fd,2) = 8; - WFIFOL(fd,4) = party_id; - WFIFOSET(fd,8); - ShowWarning("int_party: info not found %d\n", party_id); - - return 0; -} - -// パ?ティ情報まとめ送り -int mapif_party_info(int fd, struct party *p) { - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3821; - memcpy(buf + 4, p, sizeof(struct party)); - WBUFW(buf,2) = 4 + sizeof(struct party); - if (fd < 0) - mapif_sendall(buf, WBUFW(buf,2)); - else - mapif_send(fd, buf, WBUFW(buf,2)); - 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; -} - -// パ?ティ設定?更通知 -int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag) { - unsigned char buf[15]; - - 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; -} - -// パ?ティ?退通知 -int mapif_party_leaved(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_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; -} - -// パ?ティ解散通知 -int mapif_party_broken(int party_id, int flag) { - unsigned char buf[7]; - WBUFW(buf,0) = 0x3826; - WBUFL(buf,2) = party_id; - WBUFB(buf,6) = flag; - mapif_sendall(buf, 7); - ShowInfo("Party broken (%d)\n", party_id); - - return 0; -} - -// パ?ティ??言 -int mapif_party_message(int party_id, int account_id, char *mes, int len, int sfd) { - unsigned char buf[2048]; - - 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; -} - -//------------------------------------------------------------------- -// map serverからの通信 - - -// パ?ティ -int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) { - struct party_data *p; - int i; - - for(i = 0; i < NAME_LENGTH && name[i]; i++) { - if (!(name[i] & 0xe0) || name[i] == 0x7f) { - ShowInfo("int_party: illegal party name [%s]\n", name); - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); - return 0; - } - } - - if ((p = search_partyname(name)) != NULL) { - ShowInfo("int_party: same name party exists [%s]\n", name); - 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(sizeof(struct party_data), 1); - if (p == NULL) { - ShowFatalError("int_party: out of memory !\n"); - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - p->party.party_id = party_newid++; - 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; - int_party_calc_state(p); - idb_put(party_db, p->party.party_id, p); - - mapif_party_created(fd, leader->account_id, leader->char_id, &p->party); - mapif_party_info(fd, &p->party); - - return 0; -} - -// パ?ティ情報要求 -int mapif_parse_PartyInfo(int fd, int party_id) -{ - struct party_data *p; - - p = (struct party_data*)idb_get(party_db, party_id); - if (p != NULL) - mapif_party_info(fd, &p->party); - else { - mapif_party_noinfo(fd, party_id); - char_clearparty(party_id); - } - - return 0; -} - -// パーティ追加要求 -int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) -{ - struct party_data *p; - int i; - - p = (struct party_data*)idb_get(party_db, 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 == 3) //Check family state. - 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_memberadded(fd, party_id, member->account_id, member->char_id, 0); - mapif_party_info(-1, &p->party); - - return 0; -} - -// パ?ティ?設定?更要求 -int mapif_parse_PartyChangeOption(int fd, int party_id, int account_id, int exp, int item) -{ - struct party_data *p; - int flag = 0; - - p = (struct party_data*)idb_get(party_db, party_id); - if (p == NULL) - return 0; - - p->party.exp = exp; - if (exp>0 && !party_check_exp_share(p)) { - flag |= 0x01; - p->party.exp = 0; - } - p->party.item = item&0x3; - mapif_party_optionchanged(fd, &p->party, account_id, flag); - return 0; -} - -// パ?ティ?退要求 -int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) -{ - struct party_data *p; - int i,lv; - - p = (struct party_data*)idb_get(party_db, party_id); - if (!p) 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) - { - mapif_party_leaved(party_id, account_id, char_id); - lv = 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 (lv == p->min_lv || lv == p->max_lv || p->family) - { - if(p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - if (party_check_empty(&p->party) == 0) - mapif_party_info(-1, &p->party); - return 0; - } - } - return 0; -} - -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 = (struct party_data*)idb_get(party_db, 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; -} - -// パ?ティ解散要求 -int mapif_parse_BreakParty(int fd, int party_id) { - - idb_remove(party_db, party_id); - mapif_party_broken(fd, party_id); - - return 0; -} - -// パ?ティメッセ?ジ送信 -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); -} -// パ?ティチェック要求 -int mapif_parse_PartyCheck(int fd, int party_id, int account_id, int char_id) { - return party_check_conflict(party_id, account_id, char_id); -} - -int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) -{ - struct party_data *p; - int i; - - p = (struct party_data*)idb_get(party_db, party_id); - if (p == NULL) - 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; - } - return 1; -} - -// map server からの通信 -// ?1パケットのみ解析すること -// ?パケット長デ?タはinter.cにセットしておくこと -// ?パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ?エラ?なら0(false)、そうでないなら1(true)をかえさなければならない -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)); 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 0x3028: mapif_parse_PartyCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - default: - return 0; - } - - return 1; -} - -// サ?バ?から?退要求(キャラ削除用) -int inter_party_leave(int party_id, int account_id, int char_id) { - return mapif_parse_PartyLeave(-1, party_id, account_id, char_id); -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_party.h b/src/char/int_party.h deleted file mode 100644 index ad724e475..000000000 --- a/src/char/int_party.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_PARTY_H_ -#define _INT_PARTY_H_ - -struct party; - -int inter_party_init(void); -void inter_party_final(void); -int inter_party_save(void); -int inter_party_parse_frommap(int fd); -int inter_party_leave(int party_id,int account_id, int char_id); - -extern char party_txt[1024]; - -//For the TXT->SQL converter -int inter_party_fromstr(char *str, struct party *p); - -#endif /* _INT_PARTY_H_ */ diff --git a/src/char/int_pet.c b/src/char/int_pet.c deleted file mode 100644 index 41d61fbc3..000000000 --- a/src/char/int_pet.c +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "char.h" -#include "inter.h" -#include "int_pet.h" - -#include -#include -#include - -char pet_txt[1024]="save/pet.txt"; - -#ifndef TXT_SQL_CONVERT -static DBMap* pet_db; // int pet_id -> struct s_pet* -static int pet_newid = 100; - -int inter_pet_tostr(char *str,struct s_pet *p) -{ - int len; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - len=sprintf(str,"%d,%d,%s\t%d,%d,%d,%d,%d,%d,%d,%d,%d", - p->pet_id,p->class_,p->name,p->account_id,p->char_id,p->level,p->egg_id, - p->equip,p->intimate,p->hungry,p->rename_flag,p->incuvate); - - return 0; -} -#endif //TXT_SQL_CONVERT -int inter_pet_fromstr(char *str,struct s_pet *p) -{ - int s; - int tmp_int[16]; - char tmp_str[256]; - - memset(p,0,sizeof(struct s_pet)); - - s=sscanf(str,"%d,%d,%[^\t]\t%d,%d,%d,%d,%d,%d,%d,%d,%d",&tmp_int[0],&tmp_int[1],tmp_str,&tmp_int[2], - &tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6],&tmp_int[7],&tmp_int[8],&tmp_int[9],&tmp_int[10]); - - if(s!=12) - return 1; - - p->pet_id = tmp_int[0]; - p->class_ = tmp_int[1]; - memcpy(p->name,tmp_str,NAME_LENGTH); - p->account_id = tmp_int[2]; - p->char_id = tmp_int[3]; - p->level = tmp_int[4]; - p->egg_id = tmp_int[5]; - p->equip = tmp_int[6]; - p->intimate = tmp_int[7]; - p->hungry = tmp_int[8]; - p->rename_flag = tmp_int[9]; - p->incuvate = tmp_int[10]; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - return 0; -} -#ifndef TXT_SQL_CONVERT -int inter_pet_init() -{ - char line[8192]; - struct s_pet *p; - FILE *fp; - int c=0; - - pet_db= idb_alloc(DB_OPT_RELEASE_DATA); - - if( (fp=fopen(pet_txt,"r"))==NULL ) - return 1; - while(fgets(line, sizeof(line), fp)) - { - p = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); - if(p==NULL){ - ShowFatalError("int_pet: out of memory!\n"); - exit(EXIT_FAILURE); - } - memset(p,0,sizeof(struct s_pet)); - if(inter_pet_fromstr(line,p)==0 && p->pet_id>0){ - if( p->pet_id >= pet_newid) - pet_newid=p->pet_id+1; - idb_put(pet_db,p->pet_id,p); - }else{ - ShowError("int_pet: broken data [%s] line %d\n",pet_txt,c); - aFree(p); - } - c++; - } - fclose(fp); - return 0; -} - -void inter_pet_final() -{ - pet_db->destroy(pet_db, NULL); - return; -} - -int inter_pet_save_sub(DBKey key,void *data,va_list ap) -{ - char line[8192]; - FILE *fp; - inter_pet_tostr(line,(struct s_pet *)data); - fp=va_arg(ap,FILE *); - fprintf(fp,"%s\n",line); - return 0; -} - -int inter_pet_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(pet_txt,&lock))==NULL ){ - ShowError("int_pet: can't write [%s] !!! data is lost !!!\n",pet_txt); - return 1; - } - pet_db->foreach(pet_db,inter_pet_save_sub,fp); - lock_fclose(fp,pet_txt,&lock); - return 0; -} - -int inter_pet_delete(int pet_id) -{ - struct s_pet *p; - p = (struct s_pet*)idb_get(pet_db,pet_id); - if( p == NULL) - return 1; - else { - idb_remove(pet_db,pet_id); - ShowInfo("Deleted pet (pet_id: %d)\n",pet_id); - } - 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("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_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); - - 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); - - 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) -{ - struct s_pet *p; - p= (struct s_pet *) aCalloc(sizeof(struct s_pet), 1); - if(p==NULL){ - ShowFatalError("int_pet: out of memory !\n"); - mapif_pet_created(fd,account_id,NULL); - return 0; - } -// memset(p,0,sizeof(struct s_pet)); unnecessary after aCalloc [Skotlex] - p->pet_id = pet_newid++; - memcpy(p->name,pet_name,NAME_LENGTH); - if(incuvate == 1) - p->account_id = p->char_id = 0; - else { - p->account_id = account_id; - p->char_id = char_id; - } - p->class_ = pet_class; - p->level = pet_lv; - p->egg_id = pet_egg_id; - p->equip = pet_equip; - p->intimate = intimate; - p->hungry = hungry; - p->rename_flag = rename_flag; - p->incuvate = incuvate; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - idb_put(pet_db,p->pet_id,p); - - mapif_pet_created(fd,account_id,p); - - return 0; -} - -int mapif_load_pet(int fd,int account_id,int char_id,int pet_id) -{ - struct s_pet *p; - p = (struct s_pet*)idb_get(pet_db,pet_id); - if(p!=NULL) { - if(p->incuvate == 1) { - p->account_id = p->char_id = 0; - mapif_pet_info(fd,account_id,p); - } - else if(account_id == p->account_id && char_id == p->char_id) - mapif_pet_info(fd,account_id,p); - else - mapif_pet_noinfo(fd,account_id); - } - else - mapif_pet_noinfo(fd,account_id); - - return 0; -} - -static void* create_pet(DBKey key, va_list args) { - struct s_pet *p; - p=(struct s_pet *)aCalloc(sizeof(struct s_pet),1); - p->pet_id = key.i; - return p; -} -int mapif_save_pet(int fd,int account_id,struct s_pet *data) -{ - struct s_pet *p; - int pet_id, 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{ - pet_id = data->pet_id; - if (pet_id == 0) - pet_id = data->pet_id = pet_newid++; - p = (struct s_pet*)idb_ensure(pet_db,pet_id,create_pet); - 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; - memcpy(p,data,sizeof(struct s_pet)); - if(p->incuvate == 1) - p->account_id = p->char_id = 0; - - 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)); - - 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_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; -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -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; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_pet.h b/src/char/int_pet.h deleted file mode 100644 index 9234af109..000000000 --- a/src/char/int_pet.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_PET_H_ -#define _INT_PET_H_ - -struct s_pet; - -int inter_pet_init(void); -void inter_pet_final(void); -int inter_pet_save(void); -int inter_pet_delete(int pet_id); - -int inter_pet_parse_frommap(int fd); - -extern char pet_txt[1024]; - -//Exported for use in the TXT-SQL converter. -int inter_pet_fromstr(char *str,struct s_pet *p); - -#endif /* _INT_PET_H_ */ diff --git a/src/char/int_status.c b/src/char/int_status.c deleted file mode 100644 index bf5d94155..000000000 --- a/src/char/int_status.c +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "int_status.h" - -#include - -// Contains all the status change data in-memory. [Skotlex] -static DBMap* scdata_db = NULL; // int char_id -> struct scdata* -char scdata_txt[1024]="save/scdata.txt"; //By [Skotlex] - -#ifdef ENABLE_SC_SAVING -static void* create_scdata(DBKey key, va_list args) -{ - struct scdata *data; - data = (struct scdata*)aCalloc(1, sizeof(struct scdata)); - data->account_id = va_arg(args, int); - data->char_id = key.i; - return data; -} - -/*========================================== - * Loads status change data of the player given. [Skotlex] - *------------------------------------------*/ -struct scdata* status_search_scdata(int aid, int cid) -{ - return (struct scdata*)scdata_db->ensure(scdata_db, i2key(cid), create_scdata, aid); -} - -/*========================================== - * Deletes status change data of the player given. [Skotlex] - * Should be invoked after the data of said player was successfully loaded. - *------------------------------------------*/ -void status_delete_scdata(int aid, int cid) -{ - struct scdata* scdata = (struct scdata*)idb_remove(scdata_db, cid); - if (scdata) - { - if (scdata->data) - aFree(scdata->data); - aFree(scdata); - } -} - - -static void inter_status_tostr(char* line, struct scdata *sc_data) -{ - int i, len; - - len = sprintf(line, "%d,%d,%d\t", sc_data->account_id, sc_data->char_id, sc_data->count); - for(i = 0; i < sc_data->count; i++) { - len += sprintf(line + len, "%d,%d,%d,%d,%d,%d\t", sc_data->data[i].type, sc_data->data[i].tick, - sc_data->data[i].val1, sc_data->data[i].val2, sc_data->data[i].val3, sc_data->data[i].val4); - } - return; -} - -static int inter_scdata_fromstr(char *line, struct scdata *sc_data) -{ - int i, len, next; - - if (sscanf(line,"%d,%d,%d\t%n",&sc_data->account_id, &sc_data->char_id, &sc_data->count, &next) < 3) - return 0; - - if (sc_data->count < 1) - return 0; - - sc_data->data = (struct status_change_data*)aCalloc(sc_data->count, sizeof (struct status_change_data)); - - for (i = 0; i < sc_data->count; i++) - { - if (sscanf(line + next, "%hu,%d,%d,%d,%d,%d\t%n", &sc_data->data[i].type, &sc_data->data[i].tick, - &sc_data->data[i].val1, &sc_data->data[i].val2, &sc_data->data[i].val3, &sc_data->data[i].val4, &len) < 6) - { - aFree(sc_data->data); - return 0; - } - next+=len; - } - return 1; -} -/*========================================== - * Loads all scdata from the given filename. - *------------------------------------------*/ -void status_load_scdata(const char* filename) -{ - FILE *fp; - int sd_count=0, sc_count=0; - char line[8192]; - struct scdata *sc; - - if ((fp = fopen(filename, "r")) == NULL) { - ShowError("status_load_scdata: Cannot open file %s!\n", filename); - return; - } - - while(fgets(line, sizeof(line), fp)) - { - sc = (struct scdata*)aCalloc(1, sizeof(struct scdata)); - if (inter_scdata_fromstr(line, sc)) { - sd_count++; - sc_count+= sc->count; - sc = (struct scdata*)idb_put(scdata_db, sc->char_id, sc); - if (sc) { - ShowError("Duplicate entry in %s for character %d\n", filename, sc->char_id); - if (sc->data) aFree(sc->data); - aFree(sc); - } - } else { - ShowError("status_load_scdata: Broken line data: %s\n", line); - aFree(sc); - } - } - fclose(fp); - ShowStatus("Loaded %d saved status changes for %d characters.\n", sc_count, sd_count); -} - -static int inter_status_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - struct scdata * sc_data; - FILE *fp; - - sc_data = (struct scdata *)data; - if (sc_data->count < 1) - return 0; - - fp = va_arg(ap, FILE *); - inter_status_tostr(line, sc_data); - fprintf(fp, "%s\n", line); - return 0; -} - -/*========================================== - * Saves all scdata to the given filename. - *------------------------------------------*/ -void inter_status_save() -{ - FILE *fp; - int lock; - - if ((fp = lock_fopen(scdata_txt, &lock)) == NULL) { - ShowError("int_status: can't write [%s] !!! data is lost !!!\n", scdata_txt); - return; - } - scdata_db->foreach(scdata_db, inter_status_save_sub, fp); - lock_fclose(fp,scdata_txt, &lock); -} - -/*========================================== - * Initializes db. - *------------------------------------------*/ -void status_init() -{ - scdata_db = idb_alloc(DB_OPT_BASE); - status_load_scdata(scdata_txt); -} - -/*========================================== - * Frees up memory. - *------------------------------------------*/ -static int scdata_db_final(DBKey k,void *d,va_list ap) -{ - struct scdata *data = (struct scdata*)d; - if (data->data) - aFree(data->data); - aFree(data); - return 0; -} - -/*========================================== - * Final cleanup. - *------------------------------------------*/ -void status_final(void) -{ - scdata_db->destroy(scdata_db, scdata_db_final); -} - -#endif //ENABLE_SC_SAVING diff --git a/src/char/int_status.h b/src/char/int_status.h deleted file mode 100644 index 3202cd88e..000000000 --- a/src/char/int_status.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_STATUS_H_ -#define _INT_STATUS_H_ - -struct status_change_data; - -struct scdata { - int account_id, char_id; - int count; - struct status_change_data* data; -}; - -extern char scdata_txt[1024]; - -struct scdata* status_search_scdata(int aid, int cid); -void status_delete_scdata(int aid, int cid); -void inter_status_save(void); -void status_init(void); -void status_final(void); - -#endif /* _INT_STATUS_H_ */ diff --git a/src/char/int_storage.c b/src/char/int_storage.c deleted file mode 100644 index 5ae51b833..000000000 --- a/src/char/int_storage.c +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "../common/utils.h" -#include "char.h" -#include "inter.h" -#include "int_storage.h" -#include "int_pet.h" -#include "int_guild.h" - -#include -#include -#include - -// ファイル名のデフォルト -// inter_config_read()で再設定される -char storage_txt[1024]="save/storage.txt"; -char guild_storage_txt[1024]="save/g_storage.txt"; - -#ifndef TXT_SQL_CONVERT -static DBMap* storage_db; // int account_id -> struct storage* -static DBMap* guild_storage_db; // int guild_id -> struct guild_storage* - -// 倉庫データを文字列に変換 -int storage_tostr(char *str,struct storage *p) -{ - int i,j,f=0; - char *str_p = str; - str_p += sprintf(str_p,"%d,%d\t",p->account_id,p->storage_amount); - - for(i=0;istorage_[i].nameid) && (p->storage_[i].amount) ){ - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip, - p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute); - for(j=0; jstorage_[i].card[j]); - str_p += sprintf(str_p," "); - f++; - } - - *(str_p++)='\t'; - - *str_p='\0'; - if(!f) - str[0]=0; - return 0; -} -#endif //TXT_SQL_CONVERT -// 文字列を倉庫データに変換 -int storage_fromstr(char *str,struct storage *p) -{ - int tmp_int[256]; - char tmp_str[256]; - int set,next,len,i,j; - - set=sscanf(str,"%d,%d%n",&tmp_int[0],&tmp_int[1],&next); - p->storage_amount=tmp_int[1]; - - if(set!=2) - return 1; - if(str[next]=='\n' || str[next]=='\r') - return 0; - next++; - for(i=0;str[next] && str[next]!='\t' && i < MAX_STORAGE;i++){ - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) - p->storage_[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } - else return 1; - } - if (i >= MAX_STORAGE && str[next] && str[next]!='\t') - ShowWarning("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", MAX_STORAGE); - return 0; -} -#ifndef TXT_SQL_CONVERT -int guild_storage_tostr(char *str,struct guild_storage *p) -{ - int i,j,f=0; - char *str_p = str; - str_p+=sprintf(str,"%d,%d\t",p->guild_id,p->storage_amount); - - for(i=0;istorage_[i].nameid) && (p->storage_[i].amount) ){ - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip, - p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute); - for(j=0; jstorage_[i].card[j]); - str_p += sprintf(str_p," "); - f++; - } - - *(str_p++)='\t'; - - *str_p='\0'; - if(!f) - str[0]=0; - return 0; -} -#endif //TXT_SQL_CONVERT -int guild_storage_fromstr(char *str,struct guild_storage *p) -{ - int tmp_int[256]; - char tmp_str[256]; - int set,next,len,i,j; - - set=sscanf(str,"%d,%d%n",&tmp_int[0],&tmp_int[1],&next); - p->storage_amount=tmp_int[1]; - - if(set!=2) - return 1; - if(str[next]=='\n' || str[next]=='\r') - return 0; - next++; - for(i=0;str[next] && str[next]!='\t' && i < MAX_GUILD_STORAGE;i++){ - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) - { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) - p->storage_[i].card[j] = tmp_int[0]; - next += len; - if (str[next] == ' ') - next++; - } - else return 1; - } - if (i >= MAX_GUILD_STORAGE && str[next] && str[next]!='\t') - ShowWarning("guild_storage_fromstr: Found a storage line with more items than MAX_GUILD_STORAGE (%d), remaining items have been discarded!\n", MAX_GUILD_STORAGE); - return 0; -} -#ifndef TXT_SQL_CONVERT -static void* create_storage(DBKey key, va_list args) { - struct storage *s; - s = (struct storage *) aCalloc(sizeof(struct storage), 1); - s->account_id=key.i; - return s; -} - -// アカウントから倉庫データインデックスを得る(新規倉庫追加可能) -struct storage *account2storage(int account_id) -{ - struct storage *s; - s = (struct storage*)idb_ensure(storage_db, account_id, create_storage); - return s; -} - -static void* create_guildstorage(DBKey key, va_list args) { - struct guild_storage *gs = NULL; - gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1); - gs->guild_id=key.i; - return gs; -} - -struct guild_storage *guild2storage(int guild_id) -{ - struct guild_storage *gs = NULL; - if(inter_guild_search(guild_id) != NULL) - gs = (struct guild_storage*)idb_ensure(guild_storage_db, guild_id, create_guildstorage); - return gs; -} - -//--------------------------------------------------------- -// 倉庫データを読み込む -int inter_storage_init() -{ - char line[65536]; - int c=0,tmp_int; - struct storage *s; - struct guild_storage *gs; - FILE *fp; - - storage_db = idb_alloc(DB_OPT_RELEASE_DATA); - - fp=fopen(storage_txt,"r"); - if(fp==NULL){ - ShowError("can't read : %s\n",storage_txt); - return 1; - } - while(fgets(line, sizeof(line), fp)) - { - sscanf(line,"%d",&tmp_int); - s = (struct storage*)aCalloc(sizeof(struct storage), 1); - if(s==NULL){ - ShowFatalError("int_storage: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(s,0,sizeof(struct storage)); aCalloc does this... - s->account_id=tmp_int; - if(s->account_id > 0 && storage_fromstr(line,s) == 0) { - idb_put(storage_db,s->account_id,s); - } - else{ - ShowError("int_storage: broken data [%s] line %d\n",storage_txt,c); - aFree(s); - } - c++; - } - fclose(fp); - - c = 0; - guild_storage_db = idb_alloc(DB_OPT_RELEASE_DATA); - - fp=fopen(guild_storage_txt,"r"); - if(fp==NULL){ - ShowError("can't read : %s\n",guild_storage_txt); - return 1; - } - while(fgets(line, sizeof(line), fp)) - { - sscanf(line,"%d",&tmp_int); - gs = (struct guild_storage*)aCalloc(sizeof(struct guild_storage), 1); - if(gs==NULL){ - ShowFatalError("int_storage: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(gs,0,sizeof(struct guild_storage)); aCalloc... - gs->guild_id=tmp_int; - if(gs->guild_id > 0 && guild_storage_fromstr(line,gs) == 0) { - idb_put(guild_storage_db,gs->guild_id,gs); - } - else{ - ShowError("int_storage: broken data [%s] line %d\n",guild_storage_txt,c); - aFree(gs); - } - c++; - } - fclose(fp); - - return 0; -} - -void inter_storage_final() { - storage_db->destroy(storage_db, NULL); - guild_storage_db->destroy(guild_storage_db, NULL); - return; -} - -int inter_storage_save_sub(DBKey key,void *data,va_list ap) -{ - char line[65536]; - FILE *fp; - storage_tostr(line,(struct storage *)data); - fp=va_arg(ap,FILE *); - if(*line) - fprintf(fp,"%s\n",line); - return 0; -} -//--------------------------------------------------------- -// 倉庫データを書き込む -int inter_storage_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(storage_txt,&lock))==NULL ){ - ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",storage_txt); - return 1; - } - storage_db->foreach(storage_db,inter_storage_save_sub,fp); - lock_fclose(fp,storage_txt,&lock); - return 0; -} - -int inter_guild_storage_save_sub(DBKey key,void *data,va_list ap) -{ - char line[65536]; - FILE *fp; - if(inter_guild_search(((struct guild_storage *)data)->guild_id) != NULL) { - guild_storage_tostr(line,(struct guild_storage *)data); - fp=va_arg(ap,FILE *); - if(*line) - fprintf(fp,"%s\n",line); - } - return 0; -} -//--------------------------------------------------------- -// 倉庫データを書き込む -int inter_guild_storage_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(guild_storage_txt,&lock))==NULL ){ - ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",guild_storage_txt); - return 1; - } - guild_storage_db->foreach(guild_storage_db,inter_guild_storage_save_sub,fp); - lock_fclose(fp,guild_storage_txt,&lock); - return 0; -} - -// 倉庫データ削除 -int inter_storage_delete(int account_id) -{ - struct storage *s = (struct storage*)idb_get(storage_db,account_id); - if(s) { - int i; - for(i=0;istorage_amount;i++){ - if(s->storage_[i].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(s->storage_[i].card[1],s->storage_[i].card[2]) ); - } - idb_remove(storage_db,account_id); - } - return 0; -} - -// ギルド倉庫データ削除 -int inter_guild_storage_delete(int guild_id) -{ - struct guild_storage *gs = (struct guild_storage*)idb_get(guild_storage_db,guild_id); - if(gs) { - int i; - for(i=0;istorage_amount;i++){ - if(gs->storage_[i].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(gs->storage_[i].card[1],gs->storage_[i].card[2]) ); - } - idb_remove(guild_storage_db,guild_id); - } - return 0; -} - -//--------------------------------------------------------- -// map serverへの通信 - -// 倉庫データの送信 -int mapif_load_storage(int fd,int account_id) -{ - struct storage *s=account2storage(account_id); - WFIFOHEAD(fd, sizeof(struct storage)+8); - WFIFOW(fd,0)=0x3810; - WFIFOW(fd,2)=sizeof(struct storage)+8; - WFIFOL(fd,4)=account_id; - memcpy(WFIFOP(fd,8),s,sizeof(struct storage)); - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} -// 倉庫データ保存完了送信 -int mapif_save_storage_ack(int fd,int account_id) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd,0)=0x3811; - WFIFOL(fd,2)=account_id; - WFIFOB(fd,6)=0; - WFIFOSET(fd,7); - return 0; -} - -int mapif_load_guild_storage(int fd,int account_id,int guild_id) -{ - struct guild_storage *gs=guild2storage(guild_id); - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); - WFIFOW(fd,0)=0x3818; - if(gs) { - WFIFOW(fd,2)=sizeof(struct guild_storage)+12; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=guild_id; - memcpy(WFIFOP(fd,12),gs,sizeof(struct guild_storage)); - } - else { - WFIFOW(fd,2)=12; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=0; - } - WFIFOSET(fd,WFIFOW(fd,2)); - - 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; -} - -//--------------------------------------------------------- -// map serverからの通信 - -// 倉庫データ要求受信 -int mapif_parse_LoadStorage(int fd) -{ - RFIFOHEAD(fd); - mapif_load_storage(fd,RFIFOL(fd,2)); - return 0; -} -// 倉庫データ受信&保存 -int mapif_parse_SaveStorage(int fd) -{ - struct storage *s; - int account_id, len; - RFIFOHEAD(fd); - account_id=RFIFOL(fd,4); - len=RFIFOW(fd,2); - if(sizeof(struct storage)!=len-8){ - ShowError("inter storage: data size error %d %d\n",sizeof(struct storage),len-8); - } - else { - s=account2storage(account_id); - memcpy(s,RFIFOP(fd,8),sizeof(struct storage)); - mapif_save_storage_ack(fd,account_id); - } - return 0; -} - -int mapif_parse_LoadGuildStorage(int fd) -{ - RFIFOHEAD(fd); - mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - return 0; -} -int mapif_parse_SaveGuildStorage(int fd) -{ - struct guild_storage *gs; - int guild_id, 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 { - gs=guild2storage(guild_id); - if(gs) { - memcpy(gs,RFIFOP(fd,12),sizeof(struct guild_storage)); - mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0); - } - else - mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1); - } - return 0; -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_storage_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)){ - case 0x3010: mapif_parse_LoadStorage(fd); break; - case 0x3011: mapif_parse_SaveStorage(fd); break; - case 0x3018: mapif_parse_LoadGuildStorage(fd); break; - case 0x3019: mapif_parse_SaveGuildStorage(fd); break; - default: - return 0; - } - return 1; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_storage.h b/src/char/int_storage.h deleted file mode 100644 index dbc487c4c..000000000 --- a/src/char/int_storage.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_STORAGE_H_ -#define _INT_STORAGE_H_ - -struct storage; -struct guild_storage; - -int inter_storage_init(void); -void inter_storage_final(void); -int inter_storage_save(void); -int inter_guild_storage_save(void); -int inter_storage_delete(int account_id); -int inter_guild_storage_delete(int guild_id); -int inter_storage_parse_frommap(int fd); - -extern char storage_txt[1024]; -extern char guild_storage_txt[1024]; - -//Exported for use in the TXT-SQL converter. -int storage_fromstr(char *str,struct storage *p); -int guild_storage_fromstr(char *str,struct guild_storage *p); - -#endif /* _INT_STORAGE_H_ */ diff --git a/src/char/inter.c b/src/char/inter.c deleted file mode 100644 index c987ce8f2..000000000 --- a/src/char/inter.c +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/db.h" -#include "../common/mmo.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "char.h" -#include "inter.h" -#include "int_party.h" -#include "int_guild.h" -#include "int_status.h" -#include "int_storage.h" -#include "int_pet.h" -#include "int_homun.h" - -#include -#include -#include - -#define WISDATA_TTL (60*1000) // Existence time of Wisp/page data (60 seconds) - // that is the waiting time of answers of all map-servers -#define WISDELLIST_MAX 256 // Number of elements of Wisp/page data deletion list - -char accreg_txt[1024] = "save/accreg.txt"; -#ifndef TXT_SQL_CONVERT -char inter_log_filename[1024] = "log/inter.log"; -char main_chat_nick[16] = "Main"; - -static DBMap* accreg_db = NULL; // int account_id -> struct accreg* - -unsigned int party_share_level = 10; - -// sending packet list -// NOTE: This variable ain't used at all! And it's confusing.. where do I add that the length of packet 0x2b07 is 10? x.x [Skotlex] -int inter_send_packet_length[]={ - -1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f - -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, - 35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, - 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, - 9, 9,-1, 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, - 11,-1, 7, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; -// recv. packet list -int inter_recv_packet_length[]={ - -1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f - -1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1, //0x3030-0x303f - 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3040-0x304f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3050-0x305f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3060-0x306f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3070-0x307f - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3090-0x309f Homunculus packets [albator] -}; - -struct WisData { - int id, fd, count, len; - unsigned long tick; - unsigned char src[24], dst[24], msg[1024]; -}; -static DBMap* wis_db = NULL; // int wis_id -> struct WisData* -static int wis_dellist[WISDELLIST_MAX], wis_delnum; - - -//-------------------------------------------------------- - -// アカウント変数を文字列へ変換 -int inter_accreg_tostr(char *str, struct accreg *reg) { - int j; - char *p = str; - - p += sprintf(p, "%d\t", reg->account_id); - for(j = 0; j < reg->reg_num; j++) { - p += sprintf(p,"%s,%s ", reg->reg[j].str, reg->reg[j].value); - } - - return 0; -} -#endif //TXT_SQL_CONVERT -// アカウント変数を文字列から変換 -int inter_accreg_fromstr(const char *str, struct accreg *reg) { - int j, n; - const char *p = str; - - if (sscanf(p, "%d\t%n", ®->account_id, &n ) != 1 || reg->account_id <= 0) - return 1; - - for(j = 0, p += n; j < ACCOUNT_REG_NUM; j++, p += n) { - if (sscanf(p, "%[^,],%[^ ] %n", reg->reg[j].str, reg->reg[j].value, &n) != 2) - break; - } - reg->reg_num = j; - - return 0; -} -#ifndef TXT_SQL_CONVERT -// アカウント変数の読み込み -int inter_accreg_init(void) { - char line[8192]; - FILE *fp; - int c = 0; - struct accreg *reg; - - accreg_db = idb_alloc(DB_OPT_RELEASE_DATA); - - if( (fp = fopen(accreg_txt, "r")) == NULL) - return 1; - while(fgets(line, sizeof(line), fp)) - { - reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); - if (reg == NULL) { - ShowFatalError("inter: accreg: out of memory!\n"); - exit(EXIT_FAILURE); - } - if (inter_accreg_fromstr(line, reg) == 0 && reg->account_id > 0) { - idb_put(accreg_db, reg->account_id, reg); - } else { - ShowError("inter: accreg: broken data [%s] line %d\n", accreg_txt, c); - aFree(reg); - } - c++; - } - fclose(fp); - - return 0; -} - -// アカウント変数のセーブ用 -int inter_accreg_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - FILE *fp; - struct accreg *reg = (struct accreg *)data; - - if (reg->reg_num > 0) { - inter_accreg_tostr(line,reg); - fp = va_arg(ap, FILE *); - fprintf(fp, "%s\n", line); - } - - return 0; -} - -// アカウント変数のセーブ -int inter_accreg_save(void) { - FILE *fp; - int lock; - - if ((fp = lock_fopen(accreg_txt,&lock)) == NULL) { - ShowError("int_accreg: can't write [%s] !!! data is lost !!!\n", accreg_txt); - return 1; - } - accreg_db->foreach(accreg_db, inter_accreg_save_sub,fp); - lock_fclose(fp, accreg_txt, &lock); - - return 0; -} - -//-------------------------------------------------------- -#endif //TXT_SQL_CONVERT -/*========================================== - * 設定ファイルを読み込む - *------------------------------------------*/ -static int inter_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, "storage_txt") == 0) { - strncpy(storage_txt, w2, sizeof(storage_txt)); - } else if (strcmpi(w1, "party_txt") == 0) { - strncpy(party_txt, w2, sizeof(party_txt)); - } else if (strcmpi(w1, "pet_txt") == 0) { - strncpy(pet_txt, w2, sizeof(pet_txt)); - } else if (strcmpi(w1, "accreg_txt") == 0) { - strncpy(accreg_txt, w2, sizeof(accreg_txt)); - } else if (strcmpi(w1, "guild_txt") == 0) { - strncpy(guild_txt, w2, sizeof(guild_txt)); - } else if (strcmpi(w1, "castle_txt") == 0) { - strncpy(castle_txt, w2, sizeof(castle_txt)); - } else if (strcmpi(w1, "guild_storage_txt") == 0) { - strncpy(guild_storage_txt, w2, sizeof(guild_storage_txt)); -#ifndef TXT_SQL_CONVERT - } else if (strcmpi(w1, "homun_txt") == 0) { - strncpy(homun_txt, w2, sizeof(homun_txt)); - } else if (strcmpi(w1, "party_share_level") == 0) { - party_share_level = (unsigned int)atof(w2); - } else if (strcmpi(w1, "inter_log_filename") == 0) { - strncpy(inter_log_filename, w2, sizeof(inter_log_filename)); - } else if(strcmpi(w1,"log_inter")==0) { - log_inter = atoi(w2); - } else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza] - strcpy(main_chat_nick, w2); -#endif //TXT_SQL_CONVERT - } else if (strcmpi(w1, "import") == 0) { - inter_config_read(w2); - } - } - fclose(fp); - - return 0; -} -#ifndef TXT_SQL_CONVERT -// ログ書き出し -int inter_log(char *fmt,...) { - FILE *logfp; - va_list ap; - - va_start(ap,fmt); - logfp = fopen(inter_log_filename, "a"); - if (logfp) { - vfprintf(logfp, fmt, ap); - fclose(logfp); - } - va_end(ap); - - return 0; -} - -// セーブ -int inter_save(void) { -#ifdef ENABLE_SC_SAVING - inter_status_save(); -#endif - inter_party_save(); - inter_guild_save(); - inter_storage_save(); - inter_guild_storage_save(); - inter_pet_save(); - inter_homun_save(); - inter_accreg_save(); - - return 0; -} -#endif //TXT_SQL_CONVERT -// 初期化 -int inter_init_txt(const char *file) { - inter_config_read(file); - -#ifndef TXT_SQL_CONVERT - wis_db = idb_alloc(DB_OPT_RELEASE_DATA); - - inter_party_init(); - inter_guild_init(); - inter_storage_init(); - inter_pet_init(); - inter_homun_init(); - inter_accreg_init(); -#endif //TXT_SQL_CONVERT - return 0; -} -#ifndef TXT_SQL_CONVERT -// finalize -void inter_final(void) { - accreg_db->destroy(accreg_db, NULL); - wis_db->destroy(wis_db, NULL); - - inter_party_final(); - inter_guild_final(); - inter_storage_final(); - inter_pet_final(); - inter_homun_final(); - - return; -} - -// マップサーバー接続 -int inter_mapif_init(int fd) { - inter_guild_mapif_init(fd); - - return 0; -} - -//-------------------------------------------------------- -// sended packets to map-server - -// GMメッセージ送信 -int mapif_GMmessage(unsigned char *mes, int len, unsigned long color, int sfd) { - unsigned char buf[2048]; - - if (len > 2048) len = 2047; //Make it fit to avoid crashes. [Skotlex] - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = len; - WBUFL(buf,4) = color; - memcpy(WBUFP(buf,8), mes, len - 8); - mapif_sendallwos(sfd, buf, len); - - return 0; -} - -// Wisp/page transmission to one map-server -int mapif_wis_message2(struct WisData *wd, int fd) { - WFIFOHEAD(fd, 56+wd->len); - WFIFOW(fd, 0) = 0x3801; - WFIFOW(fd, 2) = 56 + wd->len; - WFIFOL(fd, 4) = wd->id; - memcpy(WFIFOP(fd, 8), wd->src, NAME_LENGTH); - memcpy(WFIFOP(fd,32), wd->dst, NAME_LENGTH); - memcpy(WFIFOP(fd,56), wd->msg, wd->len); - wd->count = 1; - WFIFOSET(fd,WFIFOW(fd,2)); - return 1; -} - -// Wisp/page transmission to all map-server -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; -} - -int mapif_wis_fail(int fd, char *src) { - unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), src, 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); - return 0; - -} - -// Wisp/page transmission result to map-server -int mapif_wis_end(struct WisData *wd, int flag) -{ - unsigned char buf[27]; - - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), wd->src, 24); - WBUFB(buf,26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - 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)); -} - -// アカウント変数要求返信 -int mapif_account_reg_reply(int fd,int account_id, int char_id) -{ - struct accreg *reg = (struct accreg*)idb_get(accreg_db,account_id); - - WFIFOHEAD(fd, ACCOUNT_REG_NUM * 288+ 13); - WFIFOW(fd,0) = 0x3804; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 2; //Acc Reg - if (reg == NULL) { - WFIFOW(fd,2) = 13; - } else { - int i, p; - for (p=13,i = 0; i < reg->reg_num; 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; - } - 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) - return -1; - - WFIFOHEAD(fd, 7); - WFIFOW(fd,0) = 0x2b1f; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = reason; - WFIFOSET(fd,7); - - return 0; -} - -//-------------------------------------------------------- - -// Existence check of WISP data -int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) { - unsigned long tick; - struct WisData *wd = (struct WisData *)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; - - 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; -} - -//-------------------------------------------------------- -// received packets from map-server - -// GMメッセージ送信 -int mapif_parse_GMmessage(int fd) { - RFIFOHEAD(fd); - mapif_GMmessage(RFIFOP(fd,8), RFIFOW(fd,2), RFIFOL(fd,4), fd); - - return 0; -} - -static struct WisData* mapif_create_whisper(int fd, char* src, char* dst, char* mes, int meslen) -{ - static int wisid = 0; - struct WisData* wd = (struct WisData *)aCalloc(sizeof(struct WisData), 1); - if (wd == NULL){ - ShowFatalError("inter: WisRequest: out of memory !\n"); - return NULL; - } - wd->id = ++wisid; - wd->fd = fd; - wd->len= meslen; - memcpy(wd->src, src, NAME_LENGTH); - memcpy(wd->dst, dst, NAME_LENGTH); - memcpy(wd->msg, mes, meslen); - wd->tick = gettick(); - return wd; -} - -// Wisp/page request to send -int mapif_parse_WisRequest(int fd) -{ - struct mmo_charstatus* char_status; - struct WisData* wd; - char name[NAME_LENGTH]; - int fd2; - - 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] - - // search if character exists before to ask all map-servers - char_status = search_character_byname(name); - if (char_status == NULL) - return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); - - // Character exists. - // to be sure of the correct name, rewrite it - memset(name, 0, NAME_LENGTH); - strncpy(name, char_status->name, NAME_LENGTH); - // if source is destination, don't ask other servers. - if (strcmp((char*)RFIFOP(fd,4),name) == 0) - return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); - - //Look for online character. - fd2 = search_character_online(char_status->account_id, char_status->char_id); - if (fd2 >= 0) { //Character online, send whisper. - wd = mapif_create_whisper(fd, (char*)RFIFOP(fd, 4), (char*)RFIFOP(fd,28), (char*)RFIFOP(fd,52), RFIFOW(fd,2)-52); - if (!wd) return 1; - idb_put(wis_db, wd->id, wd); - mapif_wis_message2(wd, fd2); - return 0; - } - //Not found. - return mapif_wis_fail(fd, (char*)RFIFOP(fd,4)); -} - -// Wisp/page transmission result -int mapif_parse_WisReply(int fd) { - int id, flag; - struct WisData *wd; - RFIFOHEAD(fd); - 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 or 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); - } - - 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 - - ShowDebug("Sent packet back!\n"); - memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf, 0) = 0x3803; - mapif_sendall(buf, RFIFOW(fd,2)); - - return 0; -} - -static void* create_accreg(DBKey key, va_list args) { - struct accreg *reg; - reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); - reg->account_id = key.i; - return reg; -} - -// アカウント変数保存要求 -int mapif_parse_Registry(int fd) { - int j, p, len; - struct accreg *reg; - RFIFOHEAD(fd); - - switch (RFIFOB(fd,12)) { - case 3: //Character registry - return char_parse_Registry(RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,13), RFIFOW(fd,2)-13); - case 2: //Acc Reg - break; - case 1: //Acc Reg2, forward to login - return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); - default: //Error? - return 1; - } - reg = (struct accreg*)idb_ensure(accreg_db, RFIFOL(fd,4), create_accreg); - - 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; - mapif_account_reg(fd, RFIFOP(fd,0)); // 他のMAPサーバーに送信 - - return 0; -} - -// Request the value of all registries. -int mapif_parse_RegistryRequest(int fd) -{ - RFIFOHEAD(fd); - //Load Char Registry - if (RFIFOB(fd,12)) - char_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - //Load Account Registry - if (RFIFOB(fd,11)) - mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - //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); -} - -int mapif_parse_NameChangeRequest(int fd) -{ - int account_id, char_id, type; - char* name; - int i; - - RFIFOHEAD(fd); - 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; -} - -//-------------------------------------------------------- - -// map server からの通信(1パケットのみ解析すること) -// エラーなら0(false)、処理できたなら1、 -// パケット長が足りなければ2をかえさなければならない -int inter_parse_frommap(int fd) { - int cmd, len; - RFIFOHEAD(fd); - cmd = RFIFOW(fd,0); - len = 0; - - // inter鯖管轄かを調べる - if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length)) - return 0; - - if (inter_recv_packet_length[cmd-0x3000] == 0) //This is necessary, because otherwise we return 2 and the char server will just hang waiting for packets! [Skotlex] - return 0; - - // パケット長を調べる - if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; - - switch(cmd) { - case 0x3000: mapif_parse_GMmessage(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; - default: - if (inter_party_parse_frommap(fd)) - break; - if (inter_guild_parse_frommap(fd)) - break; - if (inter_storage_parse_frommap(fd)) - break; - if (inter_pet_parse_frommap(fd)) - break; - if (inter_homun_parse_frommap(fd)) - break; - return 0; - } - RFIFOSKIP(fd, len); - return 1; -} - -// RFIFOのパケット長確認 -// 必要パケット長があればパケット長、まだ足りなければ0 -int inter_check_length(int fd, int length) { - if (length == -1) { // 可変パケット長 - RFIFOHEAD(fd); - if (RFIFOREST(fd) < 4) // パケット長が未着 - return 0; - length = RFIFOW(fd,2); - } - - if ((int)RFIFOREST(fd) < length) // パケットが未着 - return 0; - - return length; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/inter.h b/src/char/inter.h deleted file mode 100644 index 4752f600c..000000000 --- a/src/char/inter.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INTER_H_ -#define _INTER_H_ - -struct accreg; - -int inter_init_txt(const char *file); -void inter_final(void); -int inter_save(void); -int inter_parse_frommap(int fd); -int inter_mapif_init(int fd); -int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason); - -int inter_check_length(int fd,int length); - -int inter_log(char *fmt,...); - -#define inter_cfgName "conf/inter_athena.conf" - -extern unsigned int party_share_level; -extern char inter_log_filename[1024]; -extern char main_chat_nick[16]; - -//For TXT->SQL conversion -extern char accreg_txt[]; -int inter_accreg_fromstr(const char *str, struct accreg *reg); - -#endif /* _INTER_H_ */ diff --git a/src/login/Makefile.in b/src/login/Makefile.in deleted file mode 100644 index aeb41b667..000000000 --- a/src/login/Makefile.in +++ /dev/null @@ -1,46 +0,0 @@ - -COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ - ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ - ../common/obj_all/ers.o ../common/obj_all/md5calc.o -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ - ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ - ../common/grfio.h ../common/mapindex.h \ - ../common/ers.h ../common/md5calc.h - -LOGIN_OBJ = obj_txt/login.o obj_txt/admin.o -LOGIN_H = login.h - -@SET_MAKE@ - -##################################################################### -.PHONY : all login-server clean help - -all: login-server - -login-server: obj_txt $(LOGIN_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ - -clean: - rm -rf *.o obj_txt ../../login-server@EXEEXT@ - -help: - @echo "possible targets are 'login-server' 'all' 'clean' 'help'" - @echo "'login-server' - login server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -obj_txt: - -mkdir obj_txt - -obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - -# missing common object files -../common/obj_all/%.o: - @$(MAKE) -C ../common sql diff --git a/src/login/admin.c b/src/login/admin.c deleted file mode 100644 index 9bce1a02f..000000000 --- a/src/login/admin.c +++ /dev/null @@ -1,879 +0,0 @@ -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/core.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/version.h" -#include "../common/md5calc.h" -#include "../common/lock.h" -#include "login.h" - -#include -#include -#include -#include // for stat/lstat/fstat - -extern struct Login_Config login_config; - -#define MAX_SERVERS 30 -extern struct mmo_char_server server[MAX_SERVERS]; -extern struct mmo_account* auth_dat; -extern uint32 auth_num; -extern int account_id_count; -extern char GM_account_filename[1024]; - -int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len); -int search_account_index(char* account_name); -int mmo_auth_new(struct mmo_account* account); -void mmo_auth_sync(void); -int mmo_auth_tostr(char* str, struct mmo_account* p); -int read_gm_account(void); -void send_GM_accounts(int fd); -int isGM(int account_id); - -//--------------------------------------- -// Packet parsing for administation login -//--------------------------------------- -int parse_admin(int fd) -{ - unsigned int i, j; - char* account_name; - - uint32 ipl = session[fd]->client_addr; - char ip[16]; - ip2str(ipl, ip); - - if( session[fd]->flag.eof ) - { - do_close(fd); - ShowInfo("Remote administration has disconnected (session #%d).\n", fd); - return 0; - } - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x7530: // Request of the server version - ShowStatus("'ladmin': Sending of the server version (ip: %s)\n", ip); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x7531; - WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; - WFIFOB(fd,3) = ATHENA_MINOR_VERSION; - WFIFOB(fd,4) = ATHENA_REVISION; - WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; - WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; - WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; - WFIFOW(fd,8) = ATHENA_MOD_VERSION; - WFIFOSET(fd,10); - RFIFOSKIP(fd,2); - break; - - case 0x7920: // Request of an accounts list - if (RFIFOREST(fd) < 10) - return 0; - { - int st, ed; - uint16 len; - CREATE_BUFFER(id, int, auth_num); - st = RFIFOL(fd,2); - ed = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - WFIFOW(fd,0) = 0x7921; - if (st < 0) - st = 0; - if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0) - ed = END_ACCOUNT_NUM; - ShowStatus("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", st, ed, ip); - // Sort before send - for(i = 0; i < auth_num; i++) { - unsigned int k; - id[i] = i; - for(j = 0; j < i; j++) { - if (auth_dat[id[i]].account_id < auth_dat[id[j]].account_id) { - for(k = i; k > j; k--) { - id[k] = id[k-1]; - } - id[j] = i; // id[i] - break; - } - } - } - // Sending accounts information - len = 4; - for(i = 0; i < auth_num && len < 30000; i++) { - int account_id = auth_dat[id[i]].account_id; // use sorted index - if (account_id >= st && account_id <= ed) { - j = id[i]; - WFIFOL(fd,len) = account_id; - WFIFOB(fd,len+4) = (unsigned char)isGM(account_id); - memcpy(WFIFOP(fd,len+5), auth_dat[j].userid, 24); - WFIFOB(fd,len+29) = auth_dat[j].sex; - WFIFOL(fd,len+30) = auth_dat[j].logincount; - if (auth_dat[j].state == 0 && auth_dat[j].unban_time != 0) // if no state and banished - WFIFOL(fd,len+34) = 7; // 6 = Your are Prohibited to log in until %s - else - WFIFOL(fd,len+34) = auth_dat[j].state; - len += 38; - } - } - WFIFOW(fd,2) = len; - WFIFOSET(fd,len); - //if (id) free(id); - DELETE_BUFFER(id); - } - break; - - case 0x7930: // Request for an account creation - if (RFIFOREST(fd) < 91) - return 0; - { - struct mmo_account ma; - safestrncpy(ma.userid, (char*)RFIFOP(fd, 2), NAME_LENGTH); - safestrncpy(ma.pass, (char*)RFIFOP(fd,26), NAME_LENGTH); - safestrncpy(ma.email, (char*)RFIFOP(fd,51), 40); - memcpy(ma.lastlogin, "-", 2); - ma.sex = RFIFOB(fd,50); - RFIFOSKIP(fd,91); - - WFIFOW(fd,0) = 0x7931; - WFIFOL(fd,2) = 0xffffffff; // invalid account id - safestrncpy((char*)WFIFOP(fd,6), ma.userid, 24); - if (strlen(ma.userid) < 4 || strlen(ma.pass) < 4) { - ShowNotice("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n", ip); - } else if (ma.sex != 'F' && ma.sex != 'M') { - ShowNotice("'ladmin': Attempt to create an invalid account (account: %s, received pass: %s, invalid sex, ip: %s)\n", ma.userid, ma.pass, ip); - } else if (account_id_count > END_ACCOUNT_NUM) { - ShowNotice("'ladmin': Attempt to create an account, but there is no more available id number (account: %s, pass: %s, sex: %c, ip: %s)\n", ma.userid, ma.pass, ma.sex, ip); - } else { - remove_control_chars(ma.userid); - remove_control_chars(ma.pass); - remove_control_chars(ma.email); - ARR_FIND( 0, auth_num, i, strncmp(auth_dat[i].userid, ma.userid, 24) == 0 ); - if( i < auth_num ) - ShowNotice("'ladmin': Attempt to create an already existing account (account: %s, pass: %s, received pass: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ma.pass, ip); - else - { - int new_id; - new_id = mmo_auth_new(&ma); - ShowNotice("'ladmin': Account creation (account: %s (id: %d), pass: %s, sex: %c, email: %s, ip: %s)\n", ma.userid, new_id, ma.pass, ma.sex, auth_dat[i].email, ip); - WFIFOL(fd,2) = new_id; - mmo_auth_sync(); - } - } - WFIFOSET(fd,30); - } - break; - - case 0x7932: // Request for an account deletion - if (RFIFOREST(fd) < 26) - return 0; - WFIFOW(fd,0) = 0x7933; - WFIFOL(fd,2) = 0xFFFFFFFF; - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - // Char-server is notified of deletion (for characters deletion). - unsigned char buf[65535]; - WBUFW(buf,0) = 0x2730; - WBUFL(buf,2) = auth_dat[i].account_id; - charif_sendallwos(-1, buf, 6); - // send answer - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - // save deleted account in log file - ShowNotice("'ladmin': Account deletion (account: %s, id: %d, ip: %s) - saved in next line:\n", auth_dat[i].userid, auth_dat[i].account_id, ip); - mmo_auth_tostr((char*)buf, &auth_dat[i]); - ShowNotice("%s\n", buf); - // delete account - memset(auth_dat[i].userid, '\0', sizeof(auth_dat[i].userid)); - auth_dat[i].account_id = -1; - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,26); - break; - - case 0x7934: // Request to change a password - if (RFIFOREST(fd) < 50) - return 0; - WFIFOW(fd,0) = 0x7935; - WFIFOL(fd,2) = 0xFFFFFFFF; /// WTF??? an unsigned being set to a -1 - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memcpy(auth_dat[i].pass, RFIFOP(fd,26), 24); - auth_dat[i].pass[23] = '\0'; - remove_control_chars(auth_dat[i].pass); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip); - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,50); - break; - - case 0x7936: // Request to modify a state - if (RFIFOREST(fd) < 50) - return 0; - { - char error_message[20]; - uint32 statut; - WFIFOW(fd,0) = 0x7937; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - statut = RFIFOL(fd,26); - memcpy(error_message, RFIFOP(fd,30), 20); - error_message[19] = '\0'; - remove_control_chars(error_message); - if (statut != 7 || error_message[0] == '\0') { // 7: // 6 = Your are Prohibited to log in until %s - strcpy(error_message, "-"); - } - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - if (auth_dat[i].state == statut && strcmp(auth_dat[i].error_message, error_message) == 0) - ShowNotice("'ladmin': Modification of a state, but the state of the account is already the good state (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip); - else { - if (statut == 7) - ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d - prohibited to login until '%s', ip: %s)\n", auth_dat[i].userid, statut, error_message, ip); - else - ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", auth_dat[i].userid, statut, ip); - if (auth_dat[i].state == 0) { - unsigned char buf[16]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 0; // 0: change of statut, 1: ban - WBUFL(buf,7) = statut; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - auth_dat[i].state = statut; - memcpy(auth_dat[i].error_message, error_message, 20); - mmo_auth_sync(); - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip); - } - WFIFOL(fd,30) = statut; - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,50); - break; - - case 0x7938: // Request for servers list and # of online players - { - uint8 server_num = 0; - ShowStatus("'ladmin': Sending of servers list (ip: %s)\n", ip); - for(i = 0; i < MAX_SERVERS; i++) { - if (server[i].fd >= 0) { - WFIFOL(fd,4+server_num*32) = htonl(server[i].ip); - WFIFOW(fd,4+server_num*32+4) = htons(server[i].port); - memcpy(WFIFOP(fd,4+server_num*32+6), server[i].name, 20); - WFIFOW(fd,4+server_num*32+26) = server[i].users; - WFIFOW(fd,4+server_num*32+28) = server[i].maintenance; - WFIFOW(fd,4+server_num*32+30) = server[i].new_; - server_num++; - } - } - WFIFOW(fd,0) = 0x7939; - WFIFOW(fd,2) = 4 + 32 * server_num; - WFIFOSET(fd,4+32*server_num); - RFIFOSKIP(fd,2); - break; - } - - case 0x793a: // Request to password check - if (RFIFOREST(fd) < 50) - return 0; - WFIFOW(fd,0) = 0x793b; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - char pass[25]; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memcpy(pass, RFIFOP(fd,26), 24); - pass[24] = '\0'; - remove_control_chars(pass); - if (strcmp(auth_dat[i].pass, pass) == 0) { - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip); - } else { - ShowNotice("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", auth_dat[i].userid, pass, ip); - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,50); - break; - - case 0x793c: // Request to modify sex - if (RFIFOREST(fd) < 27) - return 0; - WFIFOW(fd,0) = 0x793d; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - memcpy(WFIFOP(fd,6), account_name, 24); - { - char sex; - sex = RFIFOB(fd,26); - if (sex != 'F' && sex != 'M') { - if (sex > 31) - ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); - else - ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", account_name, ip); - } else { - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - if (auth_dat[i].sex != ((sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm'))) { - unsigned char buf[16]; - WFIFOL(fd,2) = auth_dat[i].account_id; - auth_dat[i].sex = (sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm'); - ShowNotice("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip); - mmo_auth_sync(); - // send to all char-server the change - WBUFW(buf,0) = 0x2723; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = auth_dat[i].sex; - charif_sendallwos(-1, buf, 7); - } else { - ShowNotice("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); - } - } - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,27); - break; - - case 0x793e: // Request to modify GM level - if (RFIFOREST(fd) < 27) - return 0; - WFIFOW(fd,0) = 0x793f; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - memcpy(WFIFOP(fd,6), account_name, 24); - { - char new_gm_level; - new_gm_level = RFIFOB(fd,26); - if (new_gm_level < 0 || new_gm_level > 99) { - ShowNotice("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); - } else { - i = search_account_index(account_name); - if (i != -1) { - int acc = auth_dat[i].account_id; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - if (isGM(acc) != new_gm_level) { - // modification of the file - FILE *fp, *fp2; - int lock; - char line[512]; - int GM_account, GM_level; - int modify_flag; - char tmpstr[24]; - time_t raw_time; - if ((fp2 = lock_fopen(GM_account_filename, &lock)) != NULL) { - if ((fp = fopen(GM_account_filename, "r")) != NULL) { - time(&raw_time); - strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); - modify_flag = 0; - // read/write GM file - while(fgets(line, sizeof(line), fp)) - { - while(line[0] != '\0' && (line[strlen(line)-1] == '\n' || line[strlen(line)-1] == '\r')) - line[strlen(line)-1] = '\0'; // TODO: remove this - if ((line[0] == '/' && line[1] == '/') || line[0] == '\0') - fprintf(fp2, "%s\n", line); - else { - if (sscanf(line, "%d %d", &GM_account, &GM_level) != 2 && sscanf(line, "%d: %d", &GM_account, &GM_level) != 2) - fprintf(fp2, "%s\n", line); - else if (GM_account != acc) - fprintf(fp2, "%s\n", line); - else if (new_gm_level < 1) { - fprintf(fp2, "// %s: 'ladmin' GM level removed on account %d '%s' (previous level: %d)\n//%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level); - modify_flag = 1; - } else { - fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: %d)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level); - modify_flag = 1; - } - } - } - if (modify_flag == 0) - fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: 0)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, acc, new_gm_level); - fclose(fp); - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to read GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - if (lock_fclose(fp2, GM_account_filename, &lock) == 0) { - WFIFOL(fd,2) = acc; - ShowNotice("'ladmin': Modification of a GM level (account: %s (%d), new GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - // read and send new GM informations - read_gm_account(); - send_GM_accounts(-1); - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); - } - } - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,27); - break; - - case 0x7940: // Request to modify e-mail - if (RFIFOREST(fd) < 66) - return 0; - WFIFOW(fd,0) = 0x7941; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - memcpy(WFIFOP(fd,6), account_name, 24); - { - char email[40]; - memcpy(email, RFIFOP(fd,26), 40); - if (e_mail_check(email) == 0) { - ShowNotice("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", account_name, ip); - } else { - remove_control_chars(email); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memcpy(auth_dat[i].email, email, 40); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", auth_dat[i].userid, email, ip); - mmo_auth_sync(); - } else { - ShowNotice("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", account_name, email, ip); - } - } - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,66); - break; - - case 0x7942: // Request to modify memo field - if ((int)RFIFOREST(fd) < 28 || (int)RFIFOREST(fd) < (28 + RFIFOW(fd,26))) - return 0; - WFIFOW(fd,0) = 0x7943; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - int size_of_memo = sizeof(auth_dat[i].memo); - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memset(auth_dat[i].memo, '\0', size_of_memo); - if (RFIFOW(fd,26) == 0) { - strncpy(auth_dat[i].memo, "-", size_of_memo); - } else if (RFIFOW(fd,26) > size_of_memo - 1) { - memcpy(auth_dat[i].memo, RFIFOP(fd,28), size_of_memo - 1); - } else { - memcpy(auth_dat[i].memo, RFIFOP(fd,28), RFIFOW(fd,26)); - } - auth_dat[i].memo[size_of_memo - 1] = '\0'; - remove_control_chars(auth_dat[i].memo); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].memo, ip); - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,28 + RFIFOW(fd,26)); - break; - - case 0x7944: // Request to found an account id - if (RFIFOREST(fd) < 26) - return 0; - WFIFOW(fd,0) = 0x7945; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,26); - break; - - case 0x7946: // Request to found an account name - if (RFIFOREST(fd) < 6) - return 0; - WFIFOW(fd,0) = 0x7947; - WFIFOL(fd,2) = RFIFOL(fd,2); - memset(WFIFOP(fd,6), '\0', 24); - for(i = 0; i < auth_num; i++) { - if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { - strncpy((char*)WFIFOP(fd,6), auth_dat[i].userid, 24); - ShowNotice("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); - break; - } - } - if (i == auth_num) { - ShowNotice("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); - strncpy((char*)WFIFOP(fd,6), "", 24); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,6); - break; - - case 0x7948: // Request to change the validity limit (timestamp) (absolute value) - if (RFIFOREST(fd) < 30) - return 0; - { - time_t timestamp; - char tmpstr[2048]; - WFIFOW(fd,0) = 0x7949; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - timestamp = (time_t)RFIFOL(fd,26); - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - ShowNotice("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); - auth_dat[i].expiration_time = timestamp; - WFIFOL(fd,2) = auth_dat[i].account_id; - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); - } - WFIFOL(fd,30) = (unsigned int)timestamp; - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,30); - break; - - case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value) - if (RFIFOREST(fd) < 30) - return 0; - { - time_t timestamp; - char tmpstr[2048]; - WFIFOW(fd,0) = 0x794b; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - timestamp = (time_t)RFIFOL(fd,26); - if (timestamp <= time(NULL)) - timestamp = 0; - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); - if (auth_dat[i].unban_time != timestamp) { - if (timestamp != 0) { - unsigned char buf[16]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 1; // 0: change of statut, 1: ban - WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - auth_dat[i].unban_time = timestamp; - mmo_auth_sync(); - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); - } - WFIFOL(fd,30) = (unsigned int)timestamp; - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,30); - break; - - case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change) - if (RFIFOREST(fd) < 38) - return 0; - { - time_t timestamp; - struct tm *tmtime; - char tmpstr[2048]; - WFIFOW(fd,0) = 0x794d; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - WFIFOL(fd,2) = auth_dat[i].account_id; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) - timestamp = time(NULL); - else - timestamp = auth_dat[i].unban_time; - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); - tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); - tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); - tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); - tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); - tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); - timestamp = mktime(tmtime); - if (timestamp != -1) { - if (timestamp <= time(NULL)) - timestamp = 0; - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - ShowNotice("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); - if (auth_dat[i].unban_time != timestamp) { - if (timestamp != 0) { - unsigned char buf[16]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 1; // 0: change of statut, 1: ban - WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - auth_dat[i].unban_time = timestamp; - mmo_auth_sync(); - } - } else { - strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].unban_time)); - ShowNotice("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].unban_time, (auth_dat[i].unban_time == 0 ? "no banishment" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); - } - WFIFOL(fd,30) = (unsigned long)auth_dat[i].unban_time; - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", account_name, ip); - WFIFOL(fd,30) = 0; - } - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,38); - break; - - case 0x794e: // Request to send a broadcast message - if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) - return 0; - WFIFOW(fd,0) = 0x794f; - WFIFOW(fd,2) = 0xFFFF; // WTF??? - if (RFIFOL(fd,4) < 1) { - ShowNotice("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", ip); - } else { - // at least 1 char-server - for(i = 0; i < MAX_SERVERS; i++) - if (server[i].fd >= 0) - break; - if (i == MAX_SERVERS) { - ShowNotice("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", ip); - } else { - unsigned char buf[32000]; - char message[32000]; - WFIFOW(fd,2) = 0; - memset(message, '\0', sizeof(message)); - memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); - message[sizeof(message)-1] = '\0'; - remove_control_chars(message); - if (RFIFOW(fd,2) == 0) - ShowNotice("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", message, ip); - else - ShowNotice("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", message, ip); - // send same message to all char-servers (no answer) - memcpy(WBUFP(buf,0), RFIFOP(fd,0), 8 + RFIFOL(fd,4)); - WBUFW(buf,0) = 0x2726; - charif_sendallwos(-1, buf, 8 + RFIFOL(fd,4)); - } - } - WFIFOSET(fd,4); - RFIFOSKIP(fd,8 + RFIFOL(fd,4)); - break; - - case 0x7950: // Request to change the validity limite (timestamp) (relative change) - if (RFIFOREST(fd) < 38) - return 0; - { - time_t timestamp; - struct tm *tmtime; - char tmpstr[2048]; - char tmpstr2[2048]; - WFIFOW(fd,0) = 0x7951; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - WFIFOL(fd,2) = auth_dat[i].account_id; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - timestamp = auth_dat[i].expiration_time; - if (timestamp == 0 || timestamp < time(NULL)) - timestamp = time(NULL); - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); - tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); - tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); - tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); - tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); - tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); - timestamp = mktime(tmtime); - if (timestamp != -1) { - strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); - strftime(tmpstr2, 24, login_config.date_format, localtime(×tamp)); - ShowNotice("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "unlimited" : tmpstr2), ip); - auth_dat[i].expiration_time = timestamp; - mmo_auth_sync(); - WFIFOL(fd,30) = (unsigned long)auth_dat[i].expiration_time; - } else { - strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); - ShowNotice("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); - WFIFOL(fd,30) = 0; - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", account_name, ip); - WFIFOL(fd,30) = 0; - } - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,38); - break; - - case 0x7952: // Request about informations of an account (by account name) - if (RFIFOREST(fd) < 26) - return 0; - WFIFOW(fd,0) = 0x7953; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - WFIFOL(fd,2) = auth_dat[i].account_id; - WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id); - memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24); - WFIFOB(fd,31) = auth_dat[i].sex; - WFIFOL(fd,32) = auth_dat[i].logincount; - WFIFOL(fd,36) = auth_dat[i].state; - memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20); - memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24); - memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16); - memcpy(WFIFOP(fd,100), auth_dat[i].email, 40); - WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time; - WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time; - WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo); - if (auth_dat[i].memo[0]) { - memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo)); - } - ShowNotice("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); - WFIFOSET(fd,150+strlen(auth_dat[i].memo)); - } else { - memcpy(WFIFOP(fd,7), account_name, 24); - WFIFOW(fd,148) = 0; - ShowNotice("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); - WFIFOSET(fd,150); - } - RFIFOSKIP(fd,26); - break; - - case 0x7954: // Request about information of an account (by account id) - if (RFIFOREST(fd) < 6) - return 0; - WFIFOW(fd,0) = 0x7953; - WFIFOL(fd,2) = RFIFOL(fd,2); - memset(WFIFOP(fd,7), '\0', 24); - for(i = 0; i < auth_num; i++) { - if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { - ShowNotice("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); - WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id); - memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24); - WFIFOB(fd,31) = auth_dat[i].sex; - WFIFOL(fd,32) = auth_dat[i].logincount; - WFIFOL(fd,36) = auth_dat[i].state; - memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20); - memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24); - memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16); - memcpy(WFIFOP(fd,100), auth_dat[i].email, 40); - WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time; - WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time; - WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo); - if (auth_dat[i].memo[0]) { - memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo)); - } - WFIFOSET(fd,150+strlen(auth_dat[i].memo)); - break; - } - } - if (i == auth_num) { - ShowNotice("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); - strncpy((char*)WFIFOP(fd,7), "", 24); - WFIFOW(fd,148) = 0; - WFIFOSET(fd,150); - } - RFIFOSKIP(fd,6); - break; - - case 0x7955: // Request to reload GM file (no answer) - ShowStatus("'ladmin': Request to re-load GM configuration file (ip: %s).\n", ip); - read_gm_account(); - // send GM accounts to all char-servers - send_GM_accounts(-1); - RFIFOSKIP(fd,2); - break; - - default: - ShowStatus("'ladmin': End of connection, unknown packet (ip: %s)\n", ip); - set_eof(fd); - return 0; - } - } - RFIFOSKIP(fd,RFIFOREST(fd)); - return 0; -} diff --git a/src/login/login.c b/src/login/login.c deleted file mode 100644 index 9bb77e093..000000000 --- a/src/login/login.c +++ /dev/null @@ -1,2362 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/core.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/version.h" -#include "../common/md5calc.h" -#include "../common/lock.h" -#include "login.h" - -#include -#include -#include -#include // for stat/lstat/fstat - -struct Login_Config login_config; - -int login_fd; // login server socket -#define MAX_SERVERS 30 -struct mmo_char_server server[MAX_SERVERS]; // char server data - -#define sex_num2str(num) ( (num == 0 ) ? 'F' : (num == 1 ) ? 'M' : 'S' ) -#define sex_str2num(str) ( (str == 'F' ) ? 0 : (str == 'M' ) ? 1 : 2 ) - -// Advanced subnet check [LuzZza] -struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; -} subnet[16]; - -int subnet_count = 0; - -// GM account management -struct gm_account* gm_account_db = NULL; -unsigned int GM_num = 0; // number of gm accounts -char GM_account_filename[1024] = "conf/GM_account.txt"; -long creation_time_GM_account_file; // tracks the last-changed timestamp of the gm accounts file -int gm_account_filename_check_timer = 15; // Timer to check if GM_account file has been changed and reload GM account automaticaly (in seconds; default: 15) - -//Account registration flood protection [Kevin] -int allowed_regs = 1; -int time_allowed = 10; //in seconds -unsigned int new_reg_tick = 0; - - -// data handling (TXT) -char account_filename[1024] = "save/account.txt"; - -// account database -struct mmo_account* auth_dat = NULL; -unsigned int auth_num = 0, auth_max = 0; - -int account_id_count = START_ACCOUNT_NUM; - -// define the number of times that some players must authentify them before to save account file. -// it's just about normal authentication. If an account is created or modified, save is immediatly done. -// An authentication just change last connected IP and date. It already save in log file. -// set minimum auth change before save: -#define AUTH_BEFORE_SAVE_FILE 10 -// set divider of auth_num to found number of change before save -#define AUTH_SAVE_FILE_DIVIDER 50 -int auth_before_save_file = 0; // Counter. First save when 1st char-server do connection. - - -// ladmin configuration -bool admin_state = false; -char admin_pass[24] = ""; -uint32 admin_allowed_ip = 0; - -int parse_admin(int fd); - - -//----------------------------------------------------- -// Auth database -//----------------------------------------------------- -#define AUTH_TIMEOUT 30000 - -struct auth_node { - int account_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - char sex; -}; - -static DBMap* auth_db; // int account_id -> struct auth_node* - -//----------------------------------------------------- -// Online User Database [Wizputer] -//----------------------------------------------------- - -struct online_login_data { - int account_id; - int waiting_disconnect; - int char_server; -}; - -static DBMap* online_db; // int account_id -> struct online_login_data* -static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data); - -static void* 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 = -1; - return p; -} - -struct online_login_data* add_online_user(int char_server, int account_id) -{ - struct online_login_data* p; - if( !login_config.online_check ) - return NULL; - p = (struct online_login_data*)idb_ensure(online_db, account_id, create_online_user); - p->char_server = char_server; - if( p->waiting_disconnect != -1 ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = -1; - } - return p; -} - -void remove_online_user(int account_id) -{ - struct online_login_data* p; - if( !login_config.online_check ) - return; - p = (struct online_login_data*)idb_get(online_db, account_id); - if( p == NULL ) - return; - if( p->waiting_disconnect != -1 ) - 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, int 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 = -1; - remove_online_user(id); - idb_remove(auth_db, id); - } - 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 i, c; - - for( i = 0, c = 0; i < MAX_SERVERS; ++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; -} - -//---------------------------------------------------------------------- -// Determine if an account (id) is a GM account -// and returns its level (or 0 if it isn't a GM account or if not found) -//---------------------------------------------------------------------- -int isGM(int account_id) -{ - unsigned int i; - ARR_FIND( 0, GM_num, i, gm_account_db[i].account_id == account_id ); - return ( i < GM_num ) ? gm_account_db[i].level : 0; -} - -//---------------------------------------------------------------------- -// Adds a new GM using acc id and level -//---------------------------------------------------------------------- -void addGM(int account_id, int level) -{ - static unsigned int GM_max = 0; - unsigned int i; - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - return; // no such account - - ARR_FIND( 0, GM_num, i, gm_account_db[i].account_id == account_id ); - if( i < GM_num ) - { - if (gm_account_db[i].level == level) - ShowWarning("addGM: GM account %d defined twice (same level: %d).\n", account_id, level); - else { - ShowWarning("addGM: GM account %d defined twice (levels: %d and %d).\n", account_id, gm_account_db[i].level, level); - gm_account_db[i].level = level; - } - return; // entry already present - } - - // new account - if (GM_num >= GM_max) { - GM_max += 256; - RECREATE(gm_account_db, struct gm_account, GM_max); - } - gm_account_db[GM_num].account_id = account_id; - gm_account_db[GM_num].level = level; - GM_num++; - if (GM_num >= 4000) - ShowWarning("4000 GM accounts found. Next GM accounts are not read.\n"); -} - -//------------------------------------------------------- -// Reading function of GM accounts file (and their level) -//------------------------------------------------------- -int read_gm_account(void) -{ - char line[512]; - FILE *fp; - int account_id, level; - int line_counter; - struct stat file_stat; - int start_range = 0, end_range = 0, is_range = 0, current_id = 0; - - if(gm_account_db) aFree(gm_account_db); - CREATE(gm_account_db, struct gm_account, 1); - GM_num = 0; - - // get last modify time/date - if (stat(GM_account_filename, &file_stat)) - creation_time_GM_account_file = 0; // error - else - creation_time_GM_account_file = (long)file_stat.st_mtime; - - if ((fp = fopen(GM_account_filename, "r")) == NULL) { - ShowError("read_gm_account: GM accounts file [%s] not found.\n", GM_account_filename); - return 1; - } - - line_counter = 0; - // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???) - // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows) - while(fgets(line, sizeof(line), fp) && GM_num < 4000) - { - line_counter++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\0' || line[0] == '\n' || line[0] == '\r') - continue; - is_range = (sscanf(line, "%d%*[-~]%d %d",&start_range,&end_range,&level)==3); // ID Range [MC Cameri] - if (!is_range && sscanf(line, "%d %d", &account_id, &level) != 2 && sscanf(line, "%d: %d", &account_id, &level) != 2) - ShowError("read_gm_account: file [%s], invalid 'acount_id|range level' format (line #%d).\n", GM_account_filename, line_counter); - else if (level <= 0) - ShowError("read_gm_account: file [%s] %dth account (line #%d) (invalid level [0 or negative]: %d).\n", GM_account_filename, GM_num+1, line_counter, level); - else { - if (level > 99) { - ShowNotice("read_gm_account: file [%s] %dth account (invalid level, but corrected: %d->99).\n", GM_account_filename, GM_num+1, level); - level = 99; - } - if (is_range) { - if (start_range==end_range) - ShowError("read_gm_account: file [%s] invalid range, beginning of range is equal to end of range (line #%d).\n", GM_account_filename, line_counter); - else if (start_range>end_range) - ShowError("read_gm_account: file [%s] invalid range, beginning of range must be lower than end of range (line #%d).\n", GM_account_filename, line_counter); - else - for (current_id = start_range;current_id<=end_range;current_id++) - addGM(current_id,level); - } else { - addGM(account_id,level); - } - } - } - fclose(fp); - - ShowStatus("read_gm_account: file '%s' read (%d GM accounts found).\n", GM_account_filename, GM_num); - - return 0; -} - - -//----------------------------------------------- -// Search an account id -// (return account index or -1 (if not found)) -// If exact account name is not found, -// the function checks without case sensitive -// and returns index if only 1 account is found -// and similar to the searched name. -//----------------------------------------------- -int search_account_index(char* account_name) -{ - unsigned int i, quantity; - int index; - - quantity = 0; - index = -1; - - for(i = 0; i < auth_num; i++) { - // Without case sensitive check (increase the number of similar account names found) - if (stricmp(auth_dat[i].userid, account_name) == 0) { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(auth_dat[i].userid, account_name) == 0) - return i; - quantity++; - index = i; - } - } - // Here, the exact account name is not found - // We return the found index of a similar account ONLY if there is 1 similar account - if (quantity == 1) - return index; - - // Exact account name is not found and 0 or more than 1 similar accounts have been found ==> we say not found - return -1; -} - -//-------------------------------------------------------- -// Create a string to save the account in the account file -//-------------------------------------------------------- -int mmo_auth_tostr(char* str, struct mmo_account* p) -{ - int i; - char *str_p = str; - - str_p += sprintf(str_p, "%d\t%s\t%s\t%s\t%c\t%d\t%u\t%s\t%s\t%ld\t%s\t%s\t%ld\t", - p->account_id, p->userid, p->pass, p->lastlogin, p->sex, - p->logincount, p->state, p->email, p->error_message, - (long)p->expiration_time, p->last_ip, p->memo, (long)p->unban_time); - - for(i = 0; i < p->account_reg2_num; i++) - if (p->account_reg2[i].str[0]) - str_p += sprintf(str_p, "%s,%s ", p->account_reg2[i].str, p->account_reg2[i].value); - - return 0; -} - -//--------------------------------- -// Reading of the accounts database -//--------------------------------- -int mmo_auth_init(void) -{ - FILE *fp; - int account_id; - uint32 state; - int logincount, n; - uint32 i, j; - char line[2048], *p, userid[2048], pass[2048], lastlogin[2048], sex, email[2048], error_message[2048], last_ip[2048], memo[2048]; - long unban_time; - long expiration_time; - char str[2048]; - char v[2048]; - int GM_count = 0; - int server_count = 0; - - auth_max = 256; - CREATE(auth_dat, struct mmo_account, auth_max); - - if ((fp = fopen(account_filename, "r")) == NULL) { - // no account file -> no account -> no login, including char-server (ERROR) - ShowError(CL_RED"mmmo_auth_init: Accounts file [%s] not found."CL_RESET"\n", account_filename); - return 0; - } - - while(fgets(line, sizeof(line), fp) != NULL) - { - if (line[0] == '/' && line[1] == '/') - continue; - - p = line; - - memset(userid, 0, sizeof(userid)); - memset(pass, 0, sizeof(pass)); - memset(lastlogin, 0, sizeof(lastlogin)); - memset(email, 0, sizeof(email)); - memset(error_message, 0, sizeof(error_message)); - memset(last_ip, 0, sizeof(last_ip)); - memset(memo, 0, sizeof(memo)); - - // database version reading (v2) - if (((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t" - "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]\t%ld%n", - &account_id, userid, pass, lastlogin, &sex, &logincount, &state, - email, error_message, &expiration_time, last_ip, memo, &unban_time, &n)) == 13 && line[n] == '\t') || - ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t" - "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]%n", - &account_id, userid, pass, lastlogin, &sex, &logincount, &state, - email, error_message, &expiration_time, last_ip, memo, &n)) == 12 && line[n] == '\t')) { - n = n + 1; - - // Some checks - if (account_id > END_ACCOUNT_NUM) { - ShowError(CL_RED"mmmo_auth_init: an account has an id higher than %d\n", END_ACCOUNT_NUM); - ShowError(" account id #%d -> account not read (data is lost!)."CL_RESET"\n", account_id); - continue; - } - userid[23] = '\0'; - remove_control_chars(userid); - for(j = 0; j < auth_num; j++) { - if (auth_dat[j].account_id == account_id) { - ShowError(CL_RED"mmmo_auth_init: an account has an identical id to another.\n"); - ShowError(" account id #%d -> new account not read (data is lost!)."CL_RED"\n", account_id); - break; - } else if (strcmp(auth_dat[j].userid, userid) == 0) { - ShowError(CL_RED"mmmo_auth_init: account name already exists.\n"); - ShowError(" account name '%s' -> new account not read (data is lost!)."CL_RESET"\n", userid); // 2 lines, account name can be long. - break; - } - } - if (j != auth_num) - continue; - - if (auth_num >= auth_max) { - auth_max += 256; - auth_dat = (struct mmo_account*)aRealloc(auth_dat, sizeof(struct mmo_account) * auth_max); - } - - memset(&auth_dat[auth_num], '\0', sizeof(struct mmo_account)); - - auth_dat[auth_num].account_id = account_id; - - strncpy(auth_dat[auth_num].userid, userid, 24); - - pass[32] = '\0'; - remove_control_chars(pass); - strncpy(auth_dat[auth_num].pass, pass, 32); - - lastlogin[23] = '\0'; - remove_control_chars(lastlogin); - strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24); - - auth_dat[auth_num].sex = sex; - - if (logincount >= 0) - auth_dat[auth_num].logincount = logincount; - else - auth_dat[auth_num].logincount = 0; - - if (state > 255) - auth_dat[auth_num].state = 100; - else - auth_dat[auth_num].state = state; - - if (e_mail_check(email) == 0) { - ShowNotice("Account %s (%d): invalid e-mail (replaced par a@a.com).\n", auth_dat[auth_num].userid, auth_dat[auth_num].account_id); - strncpy(auth_dat[auth_num].email, "a@a.com", 40); - } else { - remove_control_chars(email); - strncpy(auth_dat[auth_num].email, email, 40); - } - - error_message[19] = '\0'; - remove_control_chars(error_message); - if (error_message[0] == '\0' || state != 7) { // 7, because state is packet 0x006a value + 1 - strncpy(auth_dat[auth_num].error_message, "-", 20); - } else { - strncpy(auth_dat[auth_num].error_message, error_message, 20); - } - - if (i == 13) - auth_dat[auth_num].unban_time = (time_t)unban_time; - else - auth_dat[auth_num].unban_time = 0; - - auth_dat[auth_num].expiration_time = (time_t)expiration_time; - - last_ip[15] = '\0'; - remove_control_chars(last_ip); - strncpy(auth_dat[auth_num].last_ip, last_ip, 16); - - memo[254] = '\0'; - remove_control_chars(memo); - strncpy(auth_dat[auth_num].memo, memo, 255); - - for(j = 0; j < ACCOUNT_REG2_NUM; j++) { - p += n; - if (sscanf(p, "%[^\t,],%[^\t ] %n", str, v, &n) != 2) { - // We must check if a str is void. If it's, we can continue to read other REG2. - // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) - if (p[0] == ',' && sscanf(p, ",%[^\t ] %n", v, &n) == 1) { - j--; - continue; - } else - break; - } - str[31] = '\0'; - remove_control_chars(str); - strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32); - strncpy(auth_dat[auth_num].account_reg2[j].value,v,256); - } - auth_dat[auth_num].account_reg2_num = j; - - if (isGM(account_id) > 0) - GM_count++; - if (auth_dat[auth_num].sex == 'S') - server_count++; - - auth_num++; - if (account_id >= account_id_count) - account_id_count = account_id + 1; - - // Old athena database version reading (v1) - } else if ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t%n", - &account_id, userid, pass, lastlogin, &sex, &logincount, &state, &n)) >= 5) { - if (account_id > END_ACCOUNT_NUM) { - ShowError(CL_RED"mmmo_auth_init: an account has an id higher than %d\n", END_ACCOUNT_NUM); - ShowError(" account id #%d -> account not read (data is lost!)."CL_RESET"\n", account_id); - continue; - } - userid[23] = '\0'; - remove_control_chars(userid); - for(j = 0; j < auth_num; j++) { - if (auth_dat[j].account_id == account_id) { - ShowError(CL_RED"mmo_auth_init: an account has an identical id to another.\n"); - ShowError(" account id #%d -> new account not read (data is lost!)."CL_RESET"\n", account_id); - break; - } else if (strcmp(auth_dat[j].userid, userid) == 0) { - ShowError(CL_RED"mmo_auth_init: account name already exists.\n"); - ShowError(" account name '%s' -> new account not read (data is lost!)."CL_RESET"\n", userid); - break; - } - } - if (j != auth_num) - continue; - - if (auth_num >= auth_max) { - auth_max += 256; - RECREATE(auth_dat, struct mmo_account, auth_max); - } - - memset(&auth_dat[auth_num], '\0', sizeof(struct mmo_account)); - - auth_dat[auth_num].account_id = account_id; - - strncpy(auth_dat[auth_num].userid, userid, 24); - - pass[23] = '\0'; - remove_control_chars(pass); - strncpy(auth_dat[auth_num].pass, pass, 24); - - lastlogin[23] = '\0'; - remove_control_chars(lastlogin); - strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24); - - auth_dat[auth_num].sex = sex; - - if (i >= 6) { - if (logincount >= 0) - auth_dat[auth_num].logincount = logincount; - else - auth_dat[auth_num].logincount = 0; - } else - auth_dat[auth_num].logincount = 0; - - if (i >= 7) { - if (state > 255) - auth_dat[auth_num].state = 100; - else - auth_dat[auth_num].state = state; - } else - auth_dat[auth_num].state = 0; - - // Initialization of new data - strncpy(auth_dat[auth_num].email, "a@a.com", 40); - strncpy(auth_dat[auth_num].error_message, "-", 20); - auth_dat[auth_num].unban_time = 0; - auth_dat[auth_num].expiration_time = 0; - strncpy(auth_dat[auth_num].last_ip, "-", 16); - strncpy(auth_dat[auth_num].memo, "-", 255); - - for(j = 0; j < ACCOUNT_REG2_NUM; j++) { - p += n; - if (sscanf(p, "%[^\t,],%[^\t ] %n", str, v, &n) != 2) { - // We must check if a str is void. If it's, we can continue to read other REG2. - // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) - if (p[0] == ',' && sscanf(p, ",%[^\t ] %n", v, &n) == 1) { - j--; - continue; - } else - break; - } - str[31] = '\0'; - remove_control_chars(str); - strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32); - strncpy(auth_dat[auth_num].account_reg2[j].value,v,256); - } - auth_dat[auth_num].account_reg2_num = j; - - if (isGM(account_id) > 0) - GM_count++; - if (auth_dat[auth_num].sex == 'S') - server_count++; - - auth_num++; - if (account_id >= account_id_count) - account_id_count = account_id + 1; - - } else { - int i = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &account_id, &i) == 1 && - i > 0 && account_id > account_id_count) - account_id_count = account_id; - } - } - fclose(fp); - - if( auth_num == 0 ) - ShowNotice("mmo_auth_init: No account found in %s.\n", account_filename); - else - if( auth_num == 1 ) - ShowStatus("mmo_auth_init: 1 account read in %s,\n", account_filename); - else - ShowStatus("mmo_auth_init: %d accounts read in %s,\n", auth_num, account_filename); - - if( GM_count == 0 ) - ShowStatus(" of which is no GM account, and \n"); - else - if( GM_count == 1 ) - ShowStatus(" of which is 1 GM account, and \n"); - else - ShowStatus(" of which is %d GM accounts, and \n", GM_count); - - if( server_count == 0 ) - ShowStatus(" no server account ('S').\n"); - else - if( server_count == 1 ) - ShowStatus(" 1 server account ('S').\n"); - else - ShowStatus(" %d server accounts ('S').\n", server_count); - - return 0; -} - -//------------------------------------------ -// Writing of the accounts database file -// (accounts are sorted by id before save) -//------------------------------------------ -void mmo_auth_sync(void) -{ - FILE *fp; - unsigned int i, j, k; - int lock; - int account_id; - CREATE_BUFFER(id, int, auth_num); - char line[65536]; - - // Sorting before save - for(i = 0; i < auth_num; i++) { - id[i] = i; - account_id = auth_dat[i].account_id; - for(j = 0; j < i; j++) { - if (account_id < auth_dat[id[j]].account_id) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } - - // Data save - if ((fp = lock_fopen(account_filename, &lock)) == NULL) { - //if (id) aFree(id); - DELETE_BUFFER(id); - return; - } - - fprintf(fp, "// Accounts file: here are saved all information about the accounts.\n"); - fprintf(fp, "// Structure: ID, account name, password, last login time, sex, # of logins, state, email, error message for state 7, validity time, last (accepted) login ip, memo field, ban timestamp, repeated(register text, register value)\n"); - fprintf(fp, "// Some explanations:\n"); - fprintf(fp, "// account name : between 4 to 23 char for a normal account (standard client can't send less than 4 char).\n"); - fprintf(fp, "// account password: between 4 to 23 char\n"); - fprintf(fp, "// sex : M or F for normal accounts, S for server accounts\n"); - fprintf(fp, "// state : 0: account is ok, 1 to 256: error code of packet 0x006a + 1\n"); - fprintf(fp, "// email : between 3 to 39 char (a@a.com is like no email)\n"); - fprintf(fp, "// error message : text for the state 7: 'Your are Prohibited to login until '. Max 19 char\n"); - fprintf(fp, "// valitidy time : 0: unlimited account, : date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); - fprintf(fp, "// memo field : max 254 char\n"); - fprintf(fp, "// ban time : 0: no ban, : banned until the date: date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); - for(i = 0; i < auth_num; i++) { - k = id[i]; // use of sorted index - if (auth_dat[k].account_id == -1) - continue; - - mmo_auth_tostr(line, &auth_dat[k]); - fprintf(fp, "%s\n", line); - } - fprintf(fp, "%d\t%%newid%%\n", account_id_count); - - lock_fclose(fp, account_filename, &lock); - - // set new counter to minimum number of auth before save - auth_before_save_file = auth_num / AUTH_SAVE_FILE_DIVIDER; // Re-initialise counter. We have save. - if (auth_before_save_file < AUTH_BEFORE_SAVE_FILE) - auth_before_save_file = AUTH_BEFORE_SAVE_FILE; - - //if (id) aFree(id); - DELETE_BUFFER(id); - - return; -} - -//----------------------------------------------------- -// Check if we must save accounts file or not -// every minute, we check if we must save because we -// have do some authentications without arrive to -// the minimum of authentications for the save. -// Note: all other modification of accounts (deletion, -// change of some informations excepted lastip/ -// lastlogintime, creation) are always save -// immediatly and set the minimum of -// authentications to its initialization value. -//----------------------------------------------------- -int check_auth_sync(int tid, unsigned int tick, int id, int data) -{ - // we only save if necessary: - // we have do some authentications without do saving - if (auth_before_save_file < AUTH_BEFORE_SAVE_FILE || - auth_before_save_file < (int)(auth_num / AUTH_SAVE_FILE_DIVIDER)) - mmo_auth_sync(); - - return 0; -} - -//----------------------------------------------------- -// periodic ip address synchronization -//----------------------------------------------------- -static int sync_ip_addresses(int tid, unsigned int tick, int id, int data) -{ - uint8 buf[2]; - ShowInfo("IP Sync in progress...\n"); - WBUFW(buf,0) = 0x2735; - charif_sendallwos(-1, buf, 2); - return 0; -} - -//----------------------------------------------------- -// Send GM accounts to one or all char-servers -//----------------------------------------------------- -void send_GM_accounts(int fd) -{ - unsigned int i; - uint8 buf[32767]; - uint16 len; - - len = 4; - WBUFW(buf,0) = 0x2732; - for(i = 0; i < GM_num; i++) - // send only existing accounts. We can not create a GM account when server is online. - if (gm_account_db[i].level > 0) { - WBUFL(buf,len) = gm_account_db[i].account_id; - WBUFB(buf,len+4) = (uint8)gm_account_db[i].level; - len += 5; - if (len >= 32000) { - ShowWarning("send_GM_accounts: Too many accounts! Only %d out of %d were sent.\n", i, GM_num); - break; - } - } - - WBUFW(buf,2) = len; - if (fd == -1) // send to all charservers - charif_sendallwos(-1, buf, len); - else { // send only to target - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } - - return; -} - -//----------------------------------------------------- -// Check if GM file account have been changed -//----------------------------------------------------- -int check_GM_file(int tid, unsigned int tick, int id, int data) -{ - struct stat file_stat; - long new_time; - - // if we would not check - if (gm_account_filename_check_timer < 1) - return 0; - - // get last modify time/date - if (stat(GM_account_filename, &file_stat)) - new_time = 0; // error - else - new_time = (long)file_stat.st_mtime; - - if (new_time != creation_time_GM_account_file) { - read_gm_account(); - send_GM_accounts(-1); - } - - return 0; -} - - -//----------------------------------------------------- -// encrypted/unencrypted password check -//----------------------------------------------------- -bool check_encrypted(const char* str1, const char* str2, const char* passwd) -{ - char md5str[64], md5bin[32]; - - snprintf(md5str, sizeof(md5str), "%s%s", str1, str2); - md5str[sizeof(md5str)-1] = '\0'; - MD5_String2binary(md5str, md5bin); - - return (0==memcmp(passwd, md5bin, 16)); -} - -bool check_password(struct login_session_data* sd, int passwdenc, const char* passwd, const char* refpass) -{ - if(passwdenc == 0) - { - return (0==strcmp(passwd, refpass)); - } - else if(sd != NULL) - { - // password mode set to 1 -> (md5key, refpass) enable with - // password mode set to 2 -> (refpass, md5key) enable with - - return ((passwdenc&0x01) && check_encrypted(sd->md5key, refpass, passwd)) || - ((passwdenc&0x02) && check_encrypted(refpass, sd->md5key, passwd)); - } - return false; -} - - -//------------------------------------- -// Make new account -//------------------------------------- -int mmo_auth_new(struct mmo_account* account) -{ - static int num_regs = 0; // registration counter - unsigned int tick = gettick(); - - time_t expiration_time = 0; - unsigned int i = auth_num; - - // check if the account doesn't exist already - ARR_FIND( 0, auth_num, i, strcmp(account->userid, auth_dat[i].userid) == 0 ); - if( i < auth_num ) - { - ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", account->userid, account->sex, auth_dat[i].pass, account->pass); - return 1; // 1 = Incorrect Password - } - - //Account Registration Flood Protection by [Kevin] - if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) - { - ShowNotice("Account registration denied (registration limit exceeded)\n"); - return 3; - } - - if (auth_num >= auth_max) { - auth_max += 256; - auth_dat = (struct mmo_account*)aRealloc(auth_dat, sizeof(struct mmo_account) * auth_max); - } - - memset(&auth_dat[i], '\0', sizeof(struct mmo_account)); - - // find a suitable non-gm account id - while (isGM(account_id_count) > 0) - account_id_count++; - - auth_dat[i].account_id = account_id_count++; - safestrncpy(auth_dat[i].userid, account->userid, NAME_LENGTH); - if( login_config.use_md5_passwds ) - MD5_String(account->pass, auth_dat[i].pass); - else - safestrncpy(auth_dat[i].pass, account->pass, NAME_LENGTH); - safestrncpy(auth_dat[i].lastlogin, "-", sizeof(auth_dat[i].lastlogin)); - auth_dat[i].sex = account->sex; - auth_dat[i].logincount = 0; - auth_dat[i].state = 0; - safestrncpy(auth_dat[i].email, e_mail_check(account->email) ? account->email : "a@a.com", sizeof(auth_dat[i].email)); - safestrncpy(auth_dat[i].error_message, "-", sizeof(auth_dat[i].error_message)); - auth_dat[i].unban_time = 0; - if( login_config.start_limited_time != -1 ) - expiration_time = time(NULL) + login_config.start_limited_time; - auth_dat[i].expiration_time = expiration_time; - strncpy(auth_dat[i].last_ip, "-", 16); - strncpy(auth_dat[i].memo, "-", 255); - auth_dat[i].account_reg2_num = 0; - - ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", account->userid, auth_num, account->pass, account->sex); - auth_num++; - - 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 0; -} - -//----------------------------------------------------- -// Check/authentication of a connection -//----------------------------------------------------- -int mmo_auth(struct login_session_data* sd) -{ - unsigned int i; - time_t raw_time; - char tmpstr[256]; - int len; - char user_password[32+1]; // reserve for md5-ed pw - - 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; - bool matched = false; - 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,","); !matched && dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) - { - sprintf(ip_dnsbl, "%s.%s", r_ip, dnsbl_serv); - if( host2ip(ip_dnsbl) ) - matched = true; - } - - if( matched ) - { - 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 - account_id_count <= END_ACCOUNT_NUM ) - { - struct mmo_account acc; - int result; - - len -= 2; - sd->userid[len] = '\0'; - - memset(&acc, '\0', sizeof(acc)); - safestrncpy(acc.userid, sd->userid, NAME_LENGTH); - safestrncpy(acc.pass, sd->passwd, NAME_LENGTH); - safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); - acc.sex = TOUPPER(sd->userid[len+1]); - - result = mmo_auth_new(&acc); - if( result ) - return result;// Failed to make account. [Skotlex]. - - auth_before_save_file = 0; // Creation of an account -> save accounts file immediatly - } - } - - // Strict account search - ARR_FIND( 0, auth_num, i, strcmp(sd->userid, auth_dat[i].userid) == 0 ); - - // if strict account search fails, we do a no sensitive case research for index - if( i < auth_num ) - { - i = search_account_index(sd->userid); - if( i == -1 ) - i = auth_num; - else - memcpy(sd->userid, auth_dat[i].userid, NAME_LENGTH); // for the possible tests/checks afterwards (copy correcte sensitive case). - } - - if( i == auth_num ) - { - ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); - return 0; // 0 = Unregistered ID - } - - if( login_config.use_md5_passwds ) - MD5_String(sd->passwd, user_password); - else - safestrncpy(user_password, sd->passwd, NAME_LENGTH); - - if( !check_password(sd, sd->passwdenc, user_password, auth_dat[i].pass) ) - { - ShowNotice("Invalid password (account: %s, pass: %s, received pass: %s, ip: %s)\n", sd->userid, auth_dat[i].pass, (sd->passwdenc) ? "[MD5]" : sd->passwd, ip); - return 1; // 1 = Incorrect Password - } - - if( auth_dat[i].expiration_time != 0 && auth_dat[i].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( auth_dat[i].unban_time != 0 && auth_dat[i].unban_time > time(NULL) ) - { - strftime(tmpstr, 20, login_config.date_format, localtime(&auth_dat[i].unban_time)); - tmpstr[19] = '\0'; - 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( auth_dat[i].state ) - { - ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, auth_dat[i].state, ip); - return auth_dat[i].state - 1; - } - - ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, auth_dat[i].account_id, ip); - - // auth start : time seed - time(&raw_time); - strftime(tmpstr, 24, "%Y-%m-%d %H:%M:%S",localtime(&raw_time)); - - sd->account_id = auth_dat[i].account_id; - sd->login_id1 = rand(); - sd->login_id2 = rand(); - safestrncpy(sd->lastlogin, auth_dat[i].lastlogin, 24); - sd->sex = auth_dat[i].sex; - - 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); - - safestrncpy(auth_dat[i].lastlogin, tmpstr, sizeof(auth_dat[i].lastlogin)); - safestrncpy(auth_dat[i].last_ip, ip, sizeof(auth_dat[i].last_ip)); - auth_dat[i].unban_time = 0; - auth_dat[i].logincount++; - - // Save until for change ip/time of auth is not very useful => limited save for that - // Save there informations isnot necessary, because they are saved in log file. - if (--auth_before_save_file <= 0) // Reduce counter. 0 or less, we save - mmo_auth_sync(); - - return -1; // account OK -} - -static int online_db_setoffline(DBKey key, void* data, va_list ap) -{ - struct online_login_data* p = (struct online_login_data*)data; - int server = va_arg(ap, int); - if( server == -1 ) - { - p->char_server = -1; - if( p->waiting_disconnect != -1 ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = -1; - } - } - else if( p->char_server == server ) - p->char_server = -2; //Char server disconnected. - return 0; -} - -//-------------------------------- -// Packet parsing for char-servers -//-------------------------------- -int parse_fromchar(int fd) -{ - unsigned int i; - int j, id; - uint32 ipl; - char ip[16]; - - ARR_FIND( 0, MAX_SERVERS, id, server[id].fd == fd ); - if( id == MAX_SERVERS ) - {// not a char server - set_eof(fd); - do_close(fd); - return 0; - } - - if( session[fd]->flag.eof ) - { - ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. - memset(&server[id], 0, sizeof(struct mmo_char_server)); - server[id].fd = -1; - do_close(fd); - return 0; - } - - ipl = server[id].ip; - ip2str(ipl, ip); - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x2709: // request from map-server via char-server to reload GM accounts - RFIFOSKIP(fd,2); - ShowStatus("Char-server '%s': Request to re-load GM configuration file (ip: %s).\n", server[id].name, ip); - read_gm_account(); - // send GM accounts to all char-servers - send_GM_accounts(-1); - break; - - case 0x2712: // request from char-server to authenticate an account - if( RFIFOREST(fd) < 19 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - int login_id1 = RFIFOL(fd,6); - int login_id2 = RFIFOL(fd,10); - char sex = sex_num2str(RFIFOB(fd,14)); - uint32 ip_ = ntohl(RFIFOL(fd,15)); - RFIFOSKIP(fd,19); - - 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->sex == sex && - node->ip == ip_ ) - {// found - uint32 expiration_time; - char email[40]; - unsigned int k; - - //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); - - // each auth entry can only be used once - idb_remove(auth_db, account_id); - - // retrieve email and account expiration time - ARR_FIND( 0, auth_num, k, auth_dat[k].account_id == account_id ); - if( k < auth_num ) - { - strcpy(email, auth_dat[k].email); - expiration_time = (uint32)auth_dat[k].expiration_time; - } - else - { - memset(email, 0, sizeof(email)); - expiration_time = 0; - } - - // send ack - WFIFOHEAD(fd,59); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = 0; - memcpy(WFIFOP(fd,15), email, 40); - WFIFOL(fd,55) = expiration_time; - WFIFOSET(fd,59); - } - 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,59); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = 1; - // It is unnecessary to send email - // It is unnecessary to send validity date of the account - WFIFOSET(fd,59); - } - } - 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; - { - char email[40]; - int acc = 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, acc, ip); - else - { - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == acc && (strcmp(auth_dat[i].email, "a@a.com") == 0 || auth_dat[i].email[0] == '\0') ); - if( i == auth_num ) - 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, acc, ip); - else - { - memcpy(auth_dat[i].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, acc, email, ip); - // Save - mmo_auth_sync(); - } - } - } - break; - - case 0x2716: // received an e-mail/limited time request, because a player comes back from a map-server to the char-server - if( RFIFOREST(fd) < 6 ) - return 0; - { - uint32 expiration_time = 0; - char email[40] = ""; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - ShowNotice("Char-server '%s': e-mail of the account %d NOT found (ip: %s).\n", server[id].name, RFIFOL(fd,2), ip); - else - { - safestrncpy(email, auth_dat[i].email, sizeof(email)); - expiration_time = (uint32)auth_dat[i].expiration_time; - } - - WFIFOHEAD(fd,50); - WFIFOW(fd,0) = 0x2717; - WFIFOL(fd,2) = account_id; - safestrncpy((char*)WFIFOP(fd,6), email, 40); - WFIFOL(fd,46) = expiration_time; - WFIFOSET(fd,50); - } - break; - - case 0x2719: // ping request from charserver - if( RFIFOREST(fd) < 2 ) - return 0; - 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; - { - char actual_email[40]; - char new_email[40]; - int account_id = RFIFOL(fd,2); - safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40); remove_control_chars(actual_email); - safestrncpy(new_email, (char*)RFIFOP(fd,46), 40); remove_control_chars(new_email); - 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 { - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - 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(auth_dat[i].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, auth_dat[i].userid, auth_dat[i].email, actual_email, ip); - else { - safestrncpy(auth_dat[i].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, auth_dat[i].userid, new_email, ip); - // Save - mmo_auth_sync(); - } - } - } - break; - - case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) - if (RFIFOREST(fd) < 10) - return 0; - { - int account_id = RFIFOL(fd,2); - uint32 state = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - 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( auth_dat[i].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); - 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); - } - auth_dat[i].state = state; - // Save - mmo_auth_sync(); - } - } - break; - - case 0x2725: // Receiving of map-server via char-server a ban request - if (RFIFOREST(fd) < 18) - return 0; - { - 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); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - 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 (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) - timestamp = time(NULL); - else - timestamp = auth_dat[i].unban_time; - 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 - { - unsigned char buf[16]; - char tmpstr[2048]; - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - 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); - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 1; // 0: change of status, 1: ban - WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - auth_dat[i].unban_time = timestamp; - // Save - mmo_auth_sync(); - } - } - } - break; - - case 0x2727: // Change of sex (sex is reversed) - if( RFIFOREST(fd) < 6 ) - return 0; - { - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - if( auth_dat[i].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 = ( auth_dat[i].sex == 'M' ) ? 'F' : 'M'; //Change gender - - auth_dat[i].sex = sex; - - ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); - WBUFW(buf,0) = 0x2723; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = sex_str2num(sex); - charif_sendallwos(-1, buf, 7); - // Save - mmo_auth_sync(); - } - } - 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; - { - int acc = RFIFOL(fd,4); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == acc ); - if( i == auth_num ) - ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, acc, 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, acc, ip); - for(j=0,p=13;jforeach(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 = (struct online_login_data*)idb_ensure(online_db, aid, create_online_user); - p->char_server = id; - if (p->waiting_disconnect != -1) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = -1; - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x272e: //Request account_reg2 for a character. - if (RFIFOREST(fd) < 10) - return 0; - { - size_t off; - - int account_id = RFIFOL(fd,2); - int char_id = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - WFIFOHEAD(fd,10000); - WFIFOW(fd,0) = 0x2729; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 1; //Type 1 for Account2 registry - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - { - //Account not found? Send at least empty data, map servers need a reply! - WFIFOW(fd,2) = 13; - WFIFOSET(fd,WFIFOW(fd,2)); - break; - } - - for( off = 13, j = 0; j < auth_dat[i].account_reg2_num && off < 9000; j++ ) - { - if( auth_dat[i].account_reg2[j].str[0] != '\0' ) - { - off += sprintf((char*)WFIFOP(fd,off), "%s", auth_dat[i].account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. - off += sprintf((char*)WFIFOP(fd,off), "%s", auth_dat[i].account_reg2[j].value)+1; - } - } - - if( off >= 9000 ) - ShowWarning("Too many account2 registries for AID %d. Some registries were not sent.\n", account_id); - - 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 - - RFIFOSKIP(fd,RFIFOREST(fd)); - return 0; -} - -//-------------------------------------------- -// Test to know if an IP come from LAN or WAN. -//-------------------------------------------- -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; -} - -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; - - sd->level = isGM(sd->account_id); - - if( sd->level < login_config.min_level_to_connect ) - { - ShowStatus("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d).\n", login_config.min_level_to_connect, sd->userid, sd->level); - 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 < MAX_SERVERS; ++i ) - if( session_isValid(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; - } - - if( login_config.online_check ) - { - 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 == -1 ) - 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; - } - } - } - - if( sd->level > 0 ) - ShowStatus("Connection of the GM (level:%d) account '%s' accepted.\n", sd->level, sd->userid); - else - 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) - WFIFOW(fd,44) = 0; // unknown - WFIFOB(fd,46) = sex_str2num(sd->sex); - for( i = 0, n = 0; i < MAX_SERVERS; ++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].maintenance; - 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; - idb_put(auth_db, sd->account_id, node); - - if( login_config.online_check ) - { - 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) -{ - int fd = sd->fd; - - 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 - char tmpstr[20]; - int i = search_account_index(sd->userid); - time_t unban_time = ( i >= 0 ) ? auth_dat[i].unban_time : 0; - strftime(tmpstr, 20, login_config.date_format, localtime(&unban_time)); - safestrncpy((char*)WFIFOP(fd,3), tmpstr, 20); // ban timestamp goes here - } - WFIFOSET(fd,23); -} - -//---------------------------------------------------------------------------------------- -// Default packet parsing (normal players or administation/char-server connection requests) -//---------------------------------------------------------------------------------------- -int parse_login(int fd) -{ - struct login_session_data* sd = session[fd]->session_data; - int result; - uint32 ipl; - char ip[16]; - - if( session[fd]->flag.eof ) - { - do_close(fd); - return 0; - } - - if( sd == NULL ) { - sd = CREATE(session[fd]->session_data, struct login_session_data, 1); - sd->fd = fd; - } - - ipl = session[fd]->client_addr; - ip2str(ipl, ip); - - 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; - - case 0x0204: // New alive packet: structure: 0x204 .16B. (new ragexe from 22 june 2004) - if (RFIFOREST(fd) < 18) - return 0; - RFIFOSKIP(fd,18); - break; - - case 0x0064: // request client login - case 0x01dd: // request client login (encryption mode) - case 0x0277: // New login packet (kRO 2006-04-24aSakexe langtype 0) - case 0x02b0: // New login packet (kRO 2007-05-14aSakexe langtype 0) - { - size_t packet_len = RFIFOREST(fd); // assume no other packet was sent - - if( (command == 0x0064 && packet_len < 55) - || (command == 0x01dd && packet_len < 47) - || (command == 0x0277 && packet_len < 84) - || (command == 0x02b0 && packet_len < 85) ) - return 0; - - // S 0064 .l .24B .24B .B - // S 01dd .l .24B .16B .B - // S 0277 .l .24B .24B .29B .B - // S 02b0 .l .24B .24B .30B .B - - sd->version = RFIFOL(fd,2); - safestrncpy(sd->userid, (char*)RFIFOP(fd,6), NAME_LENGTH); remove_control_chars(sd->userid); - if (command != 0x01dd) { - ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); - safestrncpy(sd->passwd, (char*)RFIFOP(fd,30), NAME_LENGTH); remove_control_chars(sd->passwd); - sd->passwdenc = 0; - } else { - ShowStatus("Request for connection (encryption mode) of %s (ip: %s).\n", sd->userid, ip); - memcpy(sd->passwd, RFIFOP(fd,30), 16); sd->passwd[16] = '\0'; // raw binary data here! - sd->passwdenc = PASSWORDENC; - } - RFIFOSKIP(fd,packet_len); - - result = mmo_auth(sd); - - if( result == -1 ) - login_auth_ok(sd); - else - login_auth_failed(sd, result); - } - break; - - case 0x01db: // Sending request of the coding key - case 0x791a: // Sending request of the coding key (administration packet) - RFIFOSKIP(fd,2); - { - unsigned int i; - - memset(sd->md5key, '\0', sizeof(sd->md5key)); - sd->md5keylen = (uint16)(12 + rand() % 4); - for( i = 0; i < sd->md5keylen; ++i ) - sd->md5key[i] = (char)(1 + rand() % 255); - - 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]; - uint32 server_ip; - uint16 server_port; - uint16 maintenance; - uint16 new_; - - safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH); //remove_control_chars(account.userid); - safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH); //remove_control_chars(account.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); remove_control_chars(server_name); - maintenance = RFIFOW(fd,82); - new_ = RFIFOW(fd,84); - RFIFOSKIP(fd,86); - - ShowInfo("Connection request of the char-server '%s' @ %d.%d.%d.%d:%d (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); - - result = mmo_auth(sd); - if( result == -1 && sd->sex == 'S' && sd->account_id < MAX_SERVERS && server[sd->account_id].fd == -1 ) - { - 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].maintenance = maintenance; - 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); - - // send GM account to char-server - send_GM_accounts(fd); - } - 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 - - case 0x7530: // Server version information request - ShowStatus("Sending server version information to ip: %s\n", ip); - RFIFOSKIP(fd,2); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x7531; - WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; - WFIFOB(fd,3) = ATHENA_MINOR_VERSION; - WFIFOB(fd,4) = ATHENA_REVISION; - WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; - WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; - WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; - WFIFOW(fd,8) = ATHENA_MOD_VERSION; - WFIFOSET(fd,10); - break; - - case 0x7918: // Request for administation login - if ((int)RFIFOREST(fd) < 4 || (int)RFIFOREST(fd) < ((RFIFOW(fd,2) == 0) ? 28 : 20)) - return 0; - WFIFOW(fd,0) = 0x7919; - WFIFOB(fd,2) = 1; - if( session[fd]->client_addr != admin_allowed_ip ) { - ShowNotice("'ladmin'-login: Connection in administration mode refused: IP isn't authorised (ladmin_allow, ip: %s).\n", ip); - } else { - struct login_session_data *ld = (struct login_session_data*)session[fd]->session_data; - if (RFIFOW(fd,2) == 0) { // non encrypted password - char password[25]; - memcpy(password, RFIFOP(fd,4), 24); - password[24] = '\0'; - remove_control_chars(password); - if( !admin_state ) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (non encrypted password: %s, ip: %s)\n", password, ip); - else - if( strcmp(password, admin_pass) != 0) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - invalid password (non encrypted password: %s, ip: %s)\n", password, ip); - else { - // If remote administration is enabled and password sent by client matches password read from login server configuration file - ShowNotice("'ladmin'-login: Connection in administration mode accepted (non encrypted password: %s, ip: %s)\n", password, ip); - WFIFOB(fd,2) = 0; - session[fd]->func_parse = parse_admin; - } - } else { // encrypted password - if (!ld) - ShowError("'ladmin'-login: error! MD5 key not created/requested for an administration login.\n"); - else { - char md5str[64] = "", md5bin[32]; - if (RFIFOW(fd,2) == 1) { - sprintf(md5str, "%s%s", ld->md5key, admin_pass); // 20 24 - } else if (RFIFOW(fd,2) == 2) { - sprintf(md5str, "%s%s", admin_pass, ld->md5key); // 24 20 - } - MD5_String2binary(md5str, md5bin); - if( !admin_state ) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (encrypted password, ip: %s)\n", ip); - else - if( memcmp(md5bin, RFIFOP(fd,4), 16) != 0 ) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - invalid password (encrypted password, ip: %s)\n", ip); - else { - // If remote administration is enabled and password hash sent by client matches hash of password read from login server configuration file - ShowNotice("'ladmin'-login: Connection in administration mode accepted (encrypted password, ip: %s)\n", ip); - ShowNotice("Connection of a remote administration accepted (encrypted password).\n"); - WFIFOB(fd,2) = 0; - session[fd]->func_parse = parse_admin; - } - } - } - } - WFIFOSET(fd,3); - - RFIFOSKIP(fd, (RFIFOW(fd,2) == 0) ? 28 : 20); - break; - - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); - set_eof(fd); - return 0; - } - } - - RFIFOSKIP(fd,RFIFOREST(fd)); - return 0; -} - -//----------------------- -// Console Command Parser [Wizputer] -//----------------------- -int parse_console(char* buf) -{ - char command[256]; - - memset(command, 0, sizeof(command)); - - sscanf(buf, "%[^\n]", command); - - ShowInfo("Console command :%s", 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(CL_BOLD"Help of commands:"CL_RESET"\n"); - 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; -} - -static int online_data_cleanup_sub(DBKey key, void *data, va_list ap) -{ - struct online_login_data *character= (struct online_login_data*)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, int data) -{ - online_db->foreach(online_db, online_data_cleanup_sub); - return 0; -} - -//---------------------------------- -// Reading Lan Support configuration -//---------------------------------- -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; - } - - ShowInfo("Reading the configuration file %s...\n", lancfgName); - - 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++; - } - } - - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; -} - -//----------------------------------- -// Reading main configuration file -//----------------------------------- -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; - } - ShowInfo("Reading configuration file %s...\n", cfgName); - 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")) { - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - msg_silent = 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); - ShowStatus("set login_port : %s\n",w2); - } - else if(!strcmpi(w1, "log_login")) - login_config.log_login = (bool)config_switch(w2); - - else if (strcmpi(w1, "admin_state") == 0) { - admin_state = (bool)config_switch(w2); - } else if (strcmpi(w1, "admin_pass") == 0) { - memset(admin_pass, 0, sizeof(admin_pass)); - strncpy(admin_pass, w2, sizeof(admin_pass)); - admin_pass[sizeof(admin_pass)-1] = '\0'; - } else if (strcmpi(w1, "admin_allowed_ip") == 0) - admin_allowed_ip = host2ip(w2); - else if (strcmpi(w1, "account_filename") == 0) { - memset(account_filename, 0, sizeof(account_filename)); - strncpy(account_filename, w2, sizeof(account_filename)); - account_filename[sizeof(account_filename)-1] = '\0'; - } else if (strcmpi(w1, "gm_account_filename") == 0) { - memset(GM_account_filename, 0, sizeof(GM_account_filename)); - strncpy(GM_account_filename, w2, sizeof(GM_account_filename)); - GM_account_filename[sizeof(GM_account_filename)-1] = '\0'; - } - else if (strcmpi(w1, "gm_account_filename_check_timer") == 0) - gm_account_filename_check_timer = atoi(w2); - - else if(!strcmpi(w1, "new_account")) - login_config.new_account_flag = (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 = atoi(w2); - else if(!strcmpi(w1, "use_MD5_passwords")) - login_config.use_md5_passwds = (bool)config_switch(w2); - else if(!strcmpi(w1, "min_level_to_connect")) - login_config.min_level_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, "case_sensitive")) -// login_config.case_sensitive = 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, "online_check")) - login_config.online_check = (bool)config_switch(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, "ip_sync_interval")) - login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. - else if(!strcmpi(w1, "import")) - login_config_read(w2); - } - fclose(fp); - ShowInfo("Finished reading %s.\n", cfgName); - return 0; -} - -//------------------------------------- -// Displaying of configuration warnings -//------------------------------------- -void display_conf_warnings(void) -{ - if( admin_state ) { - if (admin_pass[0] == '\0') { - ShowWarning("Administrator password is void (admin_pass).\n"); - } else if (strcmp(admin_pass, "admin") == 0) { - ShowWarning("You are using the default administrator password (admin_pass).\n"); - ShowWarning(" We highly recommend that you change it.\n"); - } - } - - if (gm_account_filename_check_timer < 0) { - ShowWarning("Invalid value for gm_account_filename_check_timer parameter. Setting to 15 sec (default).\n"); - gm_account_filename_check_timer = 15; - } else if (gm_account_filename_check_timer == 1) { - ShowWarning("Invalid value for gm_account_filename_check_timer parameter. Setting to 2 sec (minimum value).\n"); - gm_account_filename_check_timer = 2; - } - - if (login_config.min_level_to_connect < 0) { // 0: all players, 1-99 at least gm level x - ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting 0 (any player).\n", login_config.min_level_to_connect); - login_config.min_level_to_connect = 0; - } else if (login_config.min_level_to_connect > 99) { // 0: all players, 1-99 at least gm level x - ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting to 99 (only GM level 99)\n", login_config.min_level_to_connect); - login_config.min_level_to_connect = 99; - } - - if (login_config.start_limited_time < -1) { // -1: create unlimited account, 0 or more: additionnal sec from now to create limited time - ShowWarning("Invalid value for start_limited_time parameter\n"); - ShowWarning(" -> setting to -1 (new accounts are created with unlimited time).\n"); - login_config.start_limited_time = -1; - } - - return; -} - -void login_set_defaults() -{ - login_config.login_ip = INADDR_ANY; - login_config.login_port = 6900; - 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.case_sensitive = true; - login_config.use_md5_passwds = false; -// login_config.login_gm_read = true; - login_config.min_level_to_connect = 0; - login_config.online_check = true; - 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)); -} - -//-------------------------------------- -// Function called at exit of the server -//-------------------------------------- -void do_final(void) -{ - int i, fd; - ShowStatus("Terminating...\n"); - - mmo_auth_sync(); - online_db->destroy(online_db, NULL); - auth_db->destroy(auth_db, NULL); - - if(auth_dat) aFree(auth_dat); - if(gm_account_db) aFree(gm_account_db); - - for (i = 0; i < MAX_SERVERS; i++) { - if ((fd = server[i].fd) >= 0) { - memset(&server[i], 0, sizeof(struct mmo_char_server)); - server[i].fd = -1; - do_close(fd); - } - } - do_close(login_fd); - - ShowStatus("Finished.\n"); -} - -//------------------------------ -// Function called when the server -// has received a crash signal. -//------------------------------ -void do_abort(void) -{ -} - -void set_server_type(void) -{ - SERVER_TYPE = ATHENA_SERVER_LOGIN; -} - -//------------------------------ -// Login server initialization -//------------------------------ -int do_init(int argc, char** argv) -{ - int i; - - login_set_defaults(); - - // read login-server configuration - login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); - display_conf_warnings(); // not in login_config_read, because we can use 'import' option, and display same message twice or more - login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); - - srand((unsigned int)time(NULL)); - - for( i = 0; i < MAX_SERVERS; i++ ) - server[i].fd = -1; - - // Accounts database init - mmo_auth_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); - - // Read account information. - read_gm_account(); - - // set default parser as parse_login function - set_defaultparse(parse_login); - - add_timer_func_list(check_auth_sync, "check_auth_sync"); - add_timer_interval(gettick() + 60000, check_auth_sync, 0, 0, 60000); // every 60 sec we check if we must save accounts file (only if necessary to save) - - // every x sec we check if gm file has been changed - if( gm_account_filename_check_timer ) { - add_timer_func_list(check_GM_file, "check_GM_file"); - add_timer_interval(gettick() + gm_account_filename_check_timer * 1000, check_GM_file, 0, 0, gm_account_filename_check_timer * 1000); - } - - // 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); - } - - if( login_config.console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - new_reg_tick = gettick(); - - // server port open & binding - login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); - - ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); - - return 0; -} diff --git a/src/login/login.h b/src/login/login.h deleted file mode 100644 index 1147d6bb6..000000000 --- a/src/login/login.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _LOGIN_H_ -#define _LOGIN_H_ - -#include "../common/mmo.h" // NAME_LENGTH - -#define LOGIN_CONF_NAME "conf/login_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" - -// supported encryption types: 1- passwordencrypt, 2- passwordencrypt2, 3- both -#define PASSWORDENC 3 - -struct login_session_data { - - int account_id; - long login_id1; - long login_id2; - char sex; - - char userid[NAME_LENGTH]; - char passwd[NAME_LENGTH]; - int passwdenc; - char md5key[20]; - uint16 md5keylen; - - char lastlogin[24]; - uint8 level; - int version; - - int fd; -}; - -struct mmo_char_server { - - char name[20]; - int fd; - uint32 ip; - uint16 port; - uint16 users; // user count on this server - uint16 maintenance; // in maintenance mode? - uint16 new_; // allows creating new chars? -}; - -struct Login_Config { - - uint32 login_ip; // the address to bind to - uint16 login_port; // the port to bind to - 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; // autoregistration via _M/_F ? - int start_limited_time; // new account expiration time (-1: unlimited) -// bool case_sensitive; // are logins case sensitive ? - bool use_md5_passwds; // work with password hashes instead of plaintext passwords? -// bool login_gm_read; // should the login server handle info about gm accounts? - int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect - bool online_check; // reject incoming players that are already registered as online ? - bool check_client_version; // check the clientversion set in the clientinfo ? - int 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 - -}; - -struct mmo_account { - - int account_id; - char sex; - char userid[24]; - char pass[32+1]; // 23+1 for normal, 32+1 for md5-ed passwords - char lastlogin[24]; - int logincount; - uint32 state; // packet 0x006a value + 1 (0: compte OK) - char email[40]; // e-mail (by default: a@a.com) - char error_message[20]; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a) - time_t unban_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - char last_ip[16]; // save of last IP of connection - char memo[255]; // a memo field - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) -}; - - -#endif /* _LOGIN_H_ */ -- cgit v1.2.3-70-g09d2