/** * Sends questlog to the map server * * Note: Completed quests (state == Q_COMPLETE) are guaranteed to be sent last * and the map server relies on this behavior (once the first Q_COMPLETE quest, * all of them are considered to be Q_COMPLETE) * * @see inter_parse_frommap */ int mapif_parse_quest_load(int fd) { int char_id = RFIFOL(fd,2); struct quest *tmp_questlog = NULL; int num_quests; tmp_questlog = mapif_quests_fromsql(char_id, &num_quests); WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); WFIFOW(fd,0) = 0x3860; WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; WFIFOL(fd,4) = char_id; if (num_quests > 0) memcpy(WFIFOP(fd,8), tmp_questlog, sizeof(struct quest)*num_quests); WFIFOSET(fd,num_quests*sizeof(struct quest)+8); if (tmp_questlog) aFree(tmp_questlog); return 0; }
/*========================================== * Delete Mail *------------------------------------------*/ static void mapif_Mail_delete(int fd, uint32 char_id, int mail_id, bool deleted) { bool failed = false; if( !deleted ) { if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_attachment_db, mail_id) ) { Sql_ShowDebug(sql_handle); failed = true; } } if( fd <= 0 ) return; // Only if the request came from a map-server and was not timer triggered for an offline character WFIFOHEAD(fd,11); WFIFOW(fd,0) = 0x384b; WFIFOL(fd,2) = char_id; WFIFOL(fd,6) = mail_id; WFIFOB(fd,10) = failed; WFIFOSET(fd,11); }
/*========================================== * S 2b0e <accid>.l <name>.24B <type>.w { <year>.w <month>.w <day>.w <hour>.w <minute>.w <second>.w } * Send an account modification request to the login server (via char server). * type of operation: * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex (use next function for 5) *------------------------------------------*/ int chrif_char_ask_name(int acc, const char* character_name, unsigned short operation_type, int year, int month, int day, int hour, int minute, int second) { chrif_check(-1); WFIFOHEAD(char_fd,44); WFIFOW(char_fd,0) = 0x2b0e; WFIFOL(char_fd,2) = acc; safestrncpy((char*)WFIFOP(char_fd,6), character_name, NAME_LENGTH); WFIFOW(char_fd,30) = operation_type; if ( operation_type == 2 ) { WFIFOW(char_fd,32) = year; WFIFOW(char_fd,34) = month; WFIFOW(char_fd,36) = day; WFIFOW(char_fd,38) = hour; WFIFOW(char_fd,40) = minute; WFIFOW(char_fd,42) = second; } WFIFOSET(char_fd,44); return 0; }
/*========================================== * Request/Receive top 10 Fame character list *------------------------------------------*/ int chrif_updatefamelist(struct map_session_data* sd) { char type; chrif_check(-1); switch(sd->class_ & MAPID_UPPERMASK) { case MAPID_BLACKSMITH: type = 1; break; case MAPID_ALCHEMIST: type = 2; break; case MAPID_TAEKWON: type = 3; break; default: return 0; } WFIFOHEAD(char_fd, 11); WFIFOW(char_fd,0) = 0x2b10; WFIFOL(char_fd,2) = sd->status.char_id; WFIFOL(char_fd,6) = sd->status.fame; WFIFOB(char_fd,10) = type; WFIFOSET(char_fd,11); return 0; }
/*========================================== * Send message to char-server with a character name to do some operations (by Yor) * Used to ask Char-server about a character name to have the account number to modify account file in login-server. * type of operation: * 1: block * 2: ban * 3: unblock * 4: unban * 5: changesex *------------------------------------------*/ int chrif_char_ask_name(int id, char * character_name, short operation_type, int year, int month, int day, int hour, int minute, int second) { chrif_check(-1); WFIFOHEAD(char_fd, 44); WFIFOW(char_fd, 0) = 0x2b0e; WFIFOL(char_fd, 2) = id; // account_id of who ask (for answer) -1 if nobody memcpy(WFIFOP(char_fd,6), character_name, NAME_LENGTH); WFIFOW(char_fd, 30) = operation_type; // type of operation if (operation_type == 2) { WFIFOW(char_fd, 32) = year; WFIFOW(char_fd, 34) = month; WFIFOW(char_fd, 36) = day; WFIFOW(char_fd, 38) = hour; WFIFOW(char_fd, 40) = minute; WFIFOW(char_fd, 42) = second; } // ShowInfo("chrif : sent 0x2b0e\n"); WFIFOSET(char_fd,44); return 0; }
/*========================================== * Request auth confirmation *------------------------------------------*/ void chrif_authreq(struct map_session_data *sd) { struct auth_node *node= chrif_search(sd->bl.id); if( node != NULL || !chrif_isconnected() ) { set_eof(sd->fd); return; } if( !chrif_isconnected() ) return; WFIFOHEAD(char_fd,19); WFIFOW(char_fd,0) = 0x2b26; WFIFOL(char_fd,2) = sd->status.account_id; WFIFOL(char_fd,6) = sd->status.char_id; WFIFOL(char_fd,10) = sd->login_id1; WFIFOB(char_fd,14) = sd->status.sex; WFIFOL(char_fd,15) = htonl(session[sd->fd]->client_addr); WFIFOSET(char_fd,19); chrif_sd_to_auth(sd, ST_LOGIN); }
// Send the requested account_reg int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) { struct accreg *reg=accreg_pt; inter_accreg_fromsql(account_id,char_id,reg,type); WFIFOW(fd,0)=0x3804; WFIFOL(fd,4)=account_id; WFIFOL(fd,8)=char_id; WFIFOB(fd,12)=type; if(reg->reg_num==0) { WFIFOW(fd,2)=13; } else { int i,p; for (p=13,i = 0; i < reg->reg_num; i++) { p+= sprintf(WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. p+= sprintf(WFIFOP(fd,p), "%s", reg->reg[i].value)+1; } WFIFOW(fd,2)=p; } WFIFOSET(fd,WFIFOW(fd,2)); return 0; }
int mapif_load_guild_storage(int fd,int account_id,int guild_id) { int guild_exist=1; WFIFOHEAD(fd, sizeof(struct guild_storage)+12); WFIFOW(fd,0)=0x3818; #if 0 // innodb guilds should render this check unnecessary [Aru] // Check if guild exists, I may write a function for this later, coz I use it several times. //printf("- Check if guild %d exists\n",g->guild_id); sprintf(tmp_sql, "SELECT count(*) FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id); if(mysql_query(&mysql_handle, tmp_sql) ) { ShowSQL("DB error - %s\n",mysql_error(&mysql_handle)); ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql); } sql_res = mysql_store_result(&mysql_handle) ; if (sql_res!=NULL && mysql_num_rows(sql_res)>0) { sql_row = mysql_fetch_row(sql_res); guild_exist = atoi (sql_row[0]); //printf("- Check if guild %d exists : %s\n",g->guild_id,((guild_exist==0)?"No":"Yes")); } mysql_free_result(sql_res) ; //resource free #endif if(guild_exist==1) { guild_storage_fromsql(guild_id,guild_storage_pt); WFIFOW(fd,2)=sizeof(struct guild_storage)+12; WFIFOL(fd,4)=account_id; WFIFOL(fd,8)=guild_id; memcpy(WFIFOP(fd,12),guild_storage_pt,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; }
/*========================================== * Return Mail *------------------------------------------*/ static void mapif_Mail_return(int fd, int char_id, int mail_id) { struct mail_message msg; int new_mail = 0; if(mail_loadmessage(mail_id, &msg)) { if(msg.dest_id != char_id) return; else if(SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id)) Sql_ShowDebug(sql_handle); else { char temp_[MAIL_TITLE_LENGTH]; // swap sender and receiver swap(msg.send_id, msg.dest_id); safestrncpy(temp_, msg.send_name, NAME_LENGTH); safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); safestrncpy(msg.dest_name, temp_, NAME_LENGTH); // set reply message title snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); msg.status = MAIL_NEW; msg.timestamp = time(NULL); new_mail = mail_savemessage(&msg); mapif_Mail_new(&msg); } } WFIFOHEAD(fd,11); WFIFOW(fd,0) = 0x384c; WFIFOL(fd,2) = char_id; WFIFOL(fd,6) = mail_id; WFIFOB(fd,10) = (new_mail == 0); WFIFOSET(fd,11); }
// アカウント変数要求返信 static void mapif_account_reg_reply(int fd, int account_id) { struct accreg *reg = accreg_db.search(account_id); WFIFOW(fd, 0) = 0x3804; WFIFOL(fd, 4) = account_id; if (reg == NULL) { WFIFOW(fd, 2) = 8; } else { int j, p; for (j = 0, p = 8; j < reg->reg_num; j++, p += 36) { WFIFO_STRING(fd, p, reg->reg[j].str, 32); WFIFOL(fd, p + 32) = reg->reg[j].value; } WFIFOW(fd, 2) = p; } WFIFOSET(fd, WFIFOW(fd, 2)); }
//---------------------------------------- // Function to send characters to a player //---------------------------------------- int chclif_mmo_send006b(int fd, struct char_session_data* sd){ int j, offset = 0; bool newvers = (sd->version >= date2version(20100413) ); if(newvers) //20100413 offset += 3; if (charserv_config.save_log) ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); j = 24 + offset; // offset WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); WFIFOW(fd,0) = 0x6b; if(newvers){ //20100413 WFIFOB(fd,4) = MAX_CHARS; // Max slots. WFIFOB(fd,5) = MIN_CHARS; // Available slots. (PremiumStartSlot) WFIFOB(fd,6) = MIN_CHARS+sd->chars_vip; // Premium slots. (Any existent chars past sd->char_slots but within MAX_CHARS will show a 'Premium Service' in red) } memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes j+=char_mmo_chars_fromsql(sd, WFIFOP(fd,j)); WFIFOW(fd,2) = j; // packet len WFIFOSET(fd,j); return 0; }
/** * Sends maps to all map-server * HZ 0x2b04 <size>.W <ip>.L <port>.W { <map>.?B }.?B * @param fd * @param map_id * @param count Number of map from new map-server has **/ static void chmapif_send_maps(int fd, int map_id, int count, unsigned char *mapbuf) { uint16 x; if (count == 0) { ShowWarning("Map-server %d has NO maps.\n", map_id); } else { unsigned char buf[16384]; // Transmitting maps information to the other map-servers WBUFW(buf,0) = 0x2b04; WBUFW(buf,2) = count * 4 + 10; WBUFL(buf,4) = htonl(map_server[map_id].ip); WBUFW(buf,8) = htons(map_server[map_id].port); memcpy(WBUFP(buf,10), mapbuf, count * 4); chmapif_sendallwos(fd, buf, WBUFW(buf,2)); } // Transmitting the maps of the other map-servers to the new map-server for (x = 0; x < ARRAYLENGTH(map_server); x++) { if (map_server[x].fd > 0 && x != map_id) { uint16 i, j; WFIFOHEAD(fd,10 +4*ARRAYLENGTH(map_server[x].map)); WFIFOW(fd,0) = 0x2b04; WFIFOL(fd,4) = htonl(map_server[x].ip); WFIFOW(fd,8) = htons(map_server[x].port); j = 0; for(i = 0; i < ARRAYLENGTH(map_server[x].map); i++) if (map_server[x].map[i]) WFIFOW(fd,10+(j++)*4) = map_server[x].map[i]; if (j > 0) { WFIFOW(fd,2) = j * 4 + 10; WFIFOSET(fd,WFIFOW(fd,2)); } } } }
//Send questlog to map server int mapif_parse_quest_load(int fd) { int char_id = RFIFOL(fd,2); struct quest tmp_questlog[MAX_QUEST_DB]; int num_quests, i, num_complete = 0; int complete[MAX_QUEST_DB]; memset(tmp_questlog, 0, sizeof(tmp_questlog)); memset(complete, 0, sizeof(complete)); num_quests = mapif_quests_fromsql(char_id, tmp_questlog); WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); WFIFOW(fd,0) = 0x3860; WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; WFIFOL(fd,4) = char_id; //Active and inactive quests for( i = 0; i < num_quests; i++ ) { if( tmp_questlog[i].state == Q_COMPLETE ) { complete[num_complete++] = i; continue; } memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); } // Completed quests for( i = num_quests - num_complete; i < num_quests; i++ ) memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); WFIFOSET(fd,num_quests*sizeof(struct quest)+8); return 0; }
// パーティ作成可否 int mapif_party_created (int fd, int account_id, int char_id, struct party *p) { WFIFOHEAD (fd, 39); WFIFOW (fd, 0) = 0x3820; WFIFOL (fd, 2) = account_id; WFIFOL (fd, 6) = char_id; if (p != NULL) { WFIFOB (fd, 10) = 0; WFIFOL (fd, 11) = p->party_id; memcpy (WFIFOP (fd, 15), p->name, NAME_LENGTH); ShowInfo ("int_party: Party created (%d - %s)\n", p->party_id, p->name); } else { WFIFOB (fd, 10) = 1; WFIFOL (fd, 11) = 0; memset (WFIFOP (fd, 15), 0, NAME_LENGTH); } WFIFOSET (fd, 39); return 0; }
void chlogif_prepsend_global_accreg(void) { if ( chlogif_isconnected() ){ WFIFOSET(login_fd, WFIFOW(login_fd,2)); } }
/** * Auth successful, inform client and create a temp auth_node. * @param sd: player session */ static void logclif_auth_ok(struct login_session_data* sd) { int fd = sd->fd; uint32 ip = session[fd]->client_addr; uint8 server_num, n; uint32 subnet_char_ip; struct auth_node* node; int i; #if PACKETVER < 20170315 int cmd = 0x69; // AC_ACCEPT_LOGIN int header = 47; int size = 32; #else int cmd = 0xac4; // AC_ACCEPT_LOGIN3 int header = 64; int size = 160; #endif if( runflag != LOGINSERVER_ST_RUNNING ){ // players can only login while running logclif_sent_auth_result(fd,1); // server closed return; } if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect ) { ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); logclif_sent_auth_result(fd,1); // server closed return; } else if( login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect ) { ShowStatus("Connection refused: the minimum group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); logclif_sent_auth_result(fd,1); // server closed return; } server_num = 0; for( i = 0; i < ARRAYLENGTH(ch_server); ++i ) if( session_isActive(ch_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); logclif_sent_auth_result(fd,1); // server closed return; } { struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); if( data ) {// account is already marked as online! if( data->char_server > -1 ) {// Request char servers to kick this account out. [Skotlex] uint8 buf[6]; ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); WBUFW(buf,0) = 0x2734; WBUFL(buf,2) = sd->account_id; logchrif_sendallwos(-1, buf, 6); if( data->waiting_disconnect == INVALID_TIMER ) data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0); logclif_sent_auth_result(fd,8); // 08 = Server still recognizes your last login 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); login_remove_online_user(sd->account_id); data = NULL; } } } login_log(ip, sd->userid, 100, "login ok"); ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); WFIFOHEAD(fd,header+size*server_num); WFIFOW(fd,0) = cmd; WFIFOW(fd,2) = header+size*server_num; WFIFOL(fd,4) = sd->login_id1; WFIFOL(fd,8) = sd->account_id; WFIFOL(fd,12) = sd->login_id2; WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) memset(WFIFOP(fd,20), 0, 24); WFIFOW(fd,44) = 0; // unknown WFIFOB(fd,46) = sex_str2num(sd->sex); #if PACKETVER >= 20170315 memset(WFIFOP(fd,47),0,17); // Unknown #endif for( i = 0, n = 0; i < ARRAYLENGTH(ch_server); ++i ) { if( !session_isValid(ch_server[i].fd) ) continue; subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] WFIFOL(fd,header+n*size) = htonl((subnet_char_ip) ? subnet_char_ip : ch_server[i].ip); WFIFOW(fd,header+n*size+4) = ntows(htons(ch_server[i].port)); // [!] LE byte order here [!] memcpy(WFIFOP(fd,header+n*size+6), ch_server[i].name, 20); WFIFOW(fd,header+n*size+26) = ch_server[i].users; WFIFOW(fd,header+n*size+28) = ch_server[i].type; WFIFOW(fd,header+n*size+30) = ch_server[i].new_; #if PACKETVER >= 20170315 memset(WFIFOP(fd, header+n*size+32), 0, 128); // Unknown #endif n++; } WFIFOSET(fd,header+size*server_num); // create temporary auth entry CREATE(node, struct auth_node, 1); node->account_id = sd->account_id; node->login_id1 = sd->login_id1; node->login_id2 = sd->login_id2; node->sex = sd->sex; node->ip = ip; node->clienttype = sd->clienttype; idb_put(auth_db, sd->account_id, node); { struct online_login_data* data; // mark client as 'online' data = login_add_online_user(-1, sd->account_id); // schedule deletion of this node data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0); } }
/** * Entry point from client to log-server. * Function that checks incoming command, then splits it to the correct handler. * @param fd: file descriptor to parse, (link to client) * @return 0=invalid session,marked for disconnection,unknow packet, banned..; 1=success */ int logclif_parse(int fd) { struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data; char ip[16]; uint32 ipl = session[fd]->client_addr; ip2str(ipl, ip); if( session[fd]->flag.eof ) { ShowInfo("Closed connection from '" CL_WHITE "%s" CL_RESET "'.\n", ip); do_close(fd); return 0; } if( sd == NULL ) { // Perform ip-ban check if( login_config.ipban && ipban_check(ipl) ) { ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip); login_log(ipl, "unknown", -3, "ip banned"); WFIFOHEAD(fd,23); WFIFOW(fd,0) = 0x6a; WFIFOB(fd,2) = 3; // 3 = Rejected from Server WFIFOSET(fd,23); set_eof(fd); return 0; } // create a session for this new connection CREATE(session[fd]->session_data, struct login_session_data, 1); sd = (struct login_session_data*)session[fd]->session_data; sd->fd = fd; } while( RFIFOREST(fd) >= 2 ) { uint16 command = RFIFOW(fd,0); int next=1; switch( command ) { // New alive packet: used to verify if client is always alive. case 0x0200: next = logclif_parse_keepalive(fd); break; // client md5 hash (binary) case 0x0204: next = logclif_parse_updclhash(fd,sd); break; // request client login (raw password) case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B // request client login (md5-hashed password) case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B case 0x01fa: // S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk) case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B next = logclif_parse_reqauth(fd, sd, command, ip); break; // Sending request of the coding key case 0x01db: next = logclif_parse_reqkey(fd, sd); break; // Connection request of a char-server case 0x2710: logclif_parse_reqcharconnec(fd,sd, ip); return 0; // processing will continue elsewhere default: ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); set_eof(fd); return 0; } if(next==0) return 0; // avoid processing of followup packets (prev was probably incomplete) } return 0; }
// Load account_reg from sql (type=2) int inter_accreg_fromsql(int account_id,int char_id, int fd, int type) { char* data; size_t len; unsigned int plen = 0; switch( type ) { case 3: //char reg if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `char_id`='%d'", char_reg_str_db, char_id) ) Sql_ShowDebug(sql_handle); break; case 2: //account reg if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", acc_reg_str_db, account_id) ) Sql_ShowDebug(sql_handle); break; case 1: //account2 reg ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); return 0; default: ShowError("inter_accreg_fromsql: Invalid type %d\n", type); return 0; } WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 1;/* is string type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; /** * Vessel! * * str type * { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) } **/ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { SQL->GetData(sql_handle, 0, &data, NULL); len = strlen(data)+1; WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */ plen += 1; safestrncpy((char*)WFIFOP(fd,plen), data, len); plen += len; SQL->GetData(sql_handle, 1, &data, NULL); WFIFOL(fd, plen) = (unsigned int)atol(data); plen += 4; SQL->GetData(sql_handle, 2, &data, NULL); len = strlen(data)+1; WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */ plen += 1; safestrncpy((char*)WFIFOP(fd,plen), data, len); plen += len; WFIFOW(fd, 14) += 1; if( plen > 60000 ) { WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); /* prepare follow up */ WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 1;/* is string type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; } } /* mark & go. */ WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); SQL->FreeResult(sql_handle); switch( type ) { case 3: //char reg if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `char_id`='%d'", char_reg_num_db, char_id) ) Sql_ShowDebug(sql_handle); break; case 2: //account reg if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", acc_reg_num_db, account_id) ) Sql_ShowDebug(sql_handle); break; case 1: //account2 reg ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); return 0; } WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 0;/* is int type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; /** * Vessel! * * int type * { keyLength(B), key(<keyLength>), index(L), value(L) } **/ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { SQL->GetData(sql_handle, 0, &data, NULL); len = strlen(data)+1; WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */ plen += 1; safestrncpy((char*)WFIFOP(fd,plen), data, len); plen += len; SQL->GetData(sql_handle, 1, &data, NULL); WFIFOL(fd, plen) = (unsigned int)atol(data); plen += 4; SQL->GetData(sql_handle, 2, &data, NULL); WFIFOL(fd, plen) = atoi(data); plen += 4; WFIFOW(fd, 14) += 1; if( plen > 60000 ) { WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); /* prepare follow up */ WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 0;/* is int type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; } } /* mark as complete & go. */ WFIFOB(fd, 12) = type; WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); SQL->FreeResult(sql_handle); return 1; }
// パーティ情報要求 void intif_request_partyinfo(int party_id) { WFIFOW(char_fd, 0) = 0x3021; WFIFOL(char_fd, 2) = party_id; WFIFOSET(char_fd, 6); }
// 0x7944 - request account id lookup by name (response: 0x7945) // 0x7946 - request account name lookup by id (response: 0x7947) // 0x7952 - request account information lookup by name (response: 0x7953) // 0x7954 - request account information lookup by id (response: 0x7953) //--------------------------------------- int parse_admin(int fd) { unsigned int i, j; char* account_name; struct mmo_account acc; 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), sizeof(ma.userid)); safestrncpy(ma.pass, (char*)RFIFOP(fd,26), sizeof(ma.pass)); ma.sex = RFIFOB(fd,50); safestrncpy(ma.email, (char*)RFIFOP(fd,51), sizeof(ma.email)); safestrncpy(ma.lastlogin, "-", sizeof(ma.lastlogin)); ShowNotice("'ladmin': Account creation request (account: %s pass: %s, sex: %c, email: %s, ip: %s)\n", ma.userid, ma.pass, ma.sex, ma.email, ip); WFIFOW(fd,0) = 0x7931; WFIFOL(fd,2) = mmo_auth_new(ma.userid, ma.pass, ma.sex, ip); safestrncpy((char*)WFIFOP(fd,6), ma.userid, 24); WFIFOSET(fd,30); } RFIFOSKIP(fd,91); break; /* case 0x7932: // Request for an account deletion if (RFIFOREST(fd) < 26) return 0; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7933; if( accounts->load_str(accounts, &acc, account_name) ) { // Char-server is notified of deletion (for characters deletion). unsigned char buf[65535]; WBUFW(buf,0) = 0x2730; WBUFL(buf,2) = acc.account_id; charif_sendallwos(-1, buf, 6); // send answer memcpy(WFIFOP(fd,6), acc.userid, 24); WFIFOL(fd,2) = acc.account_id; // delete account memset(acc.userid, '\0', sizeof(acc.userid)); auth_dat[i].account_id = -1; mmo_auth_sync(); } else { WFIFOL(fd,2) = -1; 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; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7935; if( accounts->load_str(accounts, &acc, account_name) ) { WFIFOL(fd,2) = acc.account_id; safestrncpy((char*)WFIFOP(fd,6), acc.userid, 24); safestrncpy(acc.pass, (char*)RFIFOP(fd,26), 24); ShowNotice("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", acc.userid, acc.pass, ip); accounts->save(accounts, &acc); } else { WFIFOL(fd,2) = -1; safestrncpy((char*)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; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); uint32 state = RFIFOL(fd,26); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7937; if( accounts->load_str(accounts, &acc, account_name) ) { memcpy(WFIFOP(fd,6), acc.userid, 24); WFIFOL(fd,2) = acc.account_id; if (acc.state == state) ShowNotice("'ladmin': Modification of a state, but the state of the account already has this value (account: %s, received state: %d, ip: %s)\n", account_name, state, ip); else { ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", acc.userid, state, ip); if (acc.state == 0) { unsigned char buf[16]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = acc.account_id; WBUFB(buf,6) = 0; // 0: change of statut, 1: ban WBUFL(buf,7) = state; // status or final date of a banishment charif_sendallwos(-1, buf, 11); } acc.state = state; accounts->save(accounts, &acc); } } else { ShowNotice("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", account_name, state, ip); WFIFOL(fd,2) = -1; memcpy(WFIFOP(fd,6), account_name, 24); } WFIFOL(fd,30) = state; 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); if( accounts->load_str(accounts, &acc, account_name) ) { 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(acc.pass, pass) == 0) { WFIFOL(fd,2) = acc.account_id; ShowNotice("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", acc.userid, acc.pass, ip); } else { ShowNotice("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", acc.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; // -1 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 { if( accounts->load_str(accounts, &acc, account_name) ) { memcpy(WFIFOP(fd,6), acc.userid, 24); if (acc.sex != sex) { unsigned char buf[16]; ShowNotice("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", acc.userid, sex, ip); WFIFOL(fd,2) = acc.account_id; acc.sex = sex; accounts->save(accounts, &acc); // send to all char-server the change WBUFW(buf,0) = 0x2723; WBUFL(buf,2) = acc.account_id; WBUFB(buf,6) = acc.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", acc.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; // -1 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 if( !accounts->load_str(accounts, &acc, account_name) ) 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); else { memcpy(WFIFOP(fd,6), acc.userid, 24); if (isGM(acc.account_id) == new_gm_level) 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", acc.userid, acc.account_id, (int)new_gm_level, ip); else { //TODO: change level } } } 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; { struct mmo_account acc; WFIFOW(fd,0) = 0x7953; account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; if( accounts->load_str(accounts, &acc, account_name) ) { ShowNotice("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", acc.userid, acc.account_id, ip); WFIFOL(fd,2) = acc.account_id; WFIFOB(fd,6) = acc.level; safestrncpy((char*)WFIFOP(fd,7), acc.userid, 24); WFIFOB(fd,31) = acc.sex; WFIFOL(fd,32) = acc.logincount; WFIFOL(fd,36) = acc.state; safestrncpy((char*)WFIFOP(fd,40), "-", 20); // error message (removed) safestrncpy((char*)WFIFOP(fd,60), acc.lastlogin, 24); safestrncpy((char*)WFIFOP(fd,84), acc.last_ip, 16); safestrncpy((char*)WFIFOP(fd,100), acc.email, 40); WFIFOL(fd,140) = (unsigned long)acc.expiration_time; WFIFOL(fd,144) = (unsigned long)acc.unban_time; WFIFOW(fd,148) = 0; // previously, this was strlen(memo), and memo went afterwards } else { ShowNotice("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); WFIFOL(fd,2) = -1; safestrncpy((char*)WFIFOP(fd,7), account_name, 24); // not found } WFIFOSET(fd,150); } RFIFOSKIP(fd,26); break; case 0x7954: // Request about information of an account (by account id) if (RFIFOREST(fd) < 6) return 0; { struct mmo_account acc; int account_id = RFIFOL(fd,2); WFIFOHEAD(fd,150); WFIFOW(fd,0) = 0x7953; WFIFOL(fd,2) = account_id; if( accounts->load_num(accounts, &acc, account_id) ) { ShowNotice("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", acc.userid, account_id, ip); WFIFOB(fd,6) = acc.level; safestrncpy((char*)WFIFOP(fd,7), acc.userid, 24); WFIFOB(fd,31) = acc.sex; WFIFOL(fd,32) = acc.logincount; WFIFOL(fd,36) = acc.state; safestrncpy((char*)WFIFOP(fd,40), "-", 20); // error message (removed) safestrncpy((char*)WFIFOP(fd,60), acc.lastlogin, 24); safestrncpy((char*)WFIFOP(fd,84), acc.last_ip, 16); safestrncpy((char*)WFIFOP(fd,100), acc.email, 40); WFIFOL(fd,140) = (unsigned long)acc.expiration_time; WFIFOL(fd,144) = (unsigned long)acc.unban_time; WFIFOW(fd,148) = 0; // previously, this was strlen(memo), and memo went afterwards } else { ShowNotice("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", account_id, ip); safestrncpy((char*)WFIFOP(fd,7), "", 24); // not found } WFIFOSET(fd,150); } RFIFOSKIP(fd,6); break; default: ShowStatus("'ladmin': End of connection, unknown packet (ip: %s)\n", ip); set_eof(fd); return 0; } } RFIFOSKIP(fd,RFIFOREST(fd)); return 0; }
void mapif_elemental_saved(int fd, unsigned char flag) { WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x387e; WFIFOB(fd,2) = flag; WFIFOSET(fd,3); }
void _FASTCALL harmony_action_request(int fd, int task, int id, intptr data) { TBL_PC *sd; if (fd == 0) { harmony_action_request_global(task, id, data); return; } switch (task) { case HARMTASK_PACKET: memcpy(WFIFOP(fd, 0), (const void*)data, id); //ShowInfo("Sending %d bytes to session #%d (%x)\n", id, fd, WFIFOW(fd, 0)); WFIFOSET(fd, id); return; } sd = (TBL_PC *)session[fd]->session_data; if (!sd) return; switch (task) { case HARMTASK_DC: ShowInfo("-- Harmony requested disconnect.\n"); set_eof(fd); break; case HARMTASK_KICK: ShowInfo("-- Harmony requested kick.\n"); if (id == 99) set_eof(fd); else clif_authfail_fd(fd, id); break; case HARMTASK_JAIL: { char msg[64]; snprintf(msg, sizeof(msg)-1, "@jail %s", sd->status.name); is_atcommand(0, sd, msg, 0); } break; case HARMTASK_BAN: harmony_ban(sd->status.account_id, id); break; case HARMTASK_ATCMD: is_atcommand(fd, sd, (const char*)data, 0); break; case HARMTASK_MSG: clif_displaymessage(fd, (const char*)data); break; case HARMTASK_IS_ACTIVE: *(int32*)data = (sd->bl.prev == NULL || sd->invincible_timer != INVALID_TIMER) ? 0 : 1; break; case HARMTASK_GET_ID: switch (id) { case HARMID_AID: *(int*)data = sd->status.account_id; break; case HARMID_GID: *(int*)data = sd->status.char_id; break; case HARMID_GDID: *(int*)data = sd->status.guild_id; break; case HARMID_PID: *(int*)data = sd->status.party_id; break; case HARMID_CLASS: *(short*)data = sd->status.class_; break; case HARMID_GM: #if HARMSW == HARMSW_RATHENA_GROUP *(int*)data = pc_group_id2level(sd->group_id); #else *(int*)data = pc_isGM(sd); #endif break; default: ShowError("Harmony requested unknown ID! (ID=%d)\n", id); ShowError("This indicates that you are running an incompatible version.\n"); break; } break; case HARMTASK_SCRIPT: { struct npc_data* nd = npc_name2id((const char*)data); if (nd) { run_script(nd->u.scr.script, 0, sd->bl.id, fake_nd->bl.id); } else { ShowError("A Harmony action chain tried to execute non-existing script '%s'\n", data); } } break; default: ShowError("Harmony requested unknown action! (ID=%d)\n", task); ShowError("This indicates that you are running an incompatible version.\n"); break; } }
// 倉庫データ要求 void intif_request_storage(int account_id) { WFIFOW(char_fd, 0) = 0x3010; WFIFOL(char_fd, 2) = account_id; WFIFOSET(char_fd, 6); }
void chlogif_send_setallaccoffline(int fd){ WFIFOHEAD(fd,2); WFIFOW(fd,0) = 0x2737; WFIFOSET(fd,2); }
// pings the charserver void chrif_keepalive(int fd) { WFIFOHEAD(fd,2); WFIFOW(fd,0) = 0x2b23; WFIFOSET(fd,2); }
int chlogif_parse(int fd) { struct char_session_data* sd = NULL; // only process data from the login-server if( fd != login_fd ) { ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); do_close(fd); return 0; } if( session[fd]->flag.eof ) { do_close(fd); login_fd = -1; chlogif_on_disconnect(); return 0; } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ set_eof(fd); return 0; } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) WFIFOW(fd,0) = 0x2719; WFIFOSET(fd,2); session[fd]->flag.ping = 2; } } sd = (struct char_session_data*)session[fd]->session_data; while(RFIFOREST(fd) >= 2) { int next=1; uint16 command = RFIFOW(fd,0); switch( command ) { case 0x2741: next = chlogif_parse_BankingAck(fd); break; case 0x2743: next = chlogif_parse_vipack(fd); break; // acknowledgement of connect-to-loginserver request case 0x2711: next = chlogif_parse_ackconnect(fd,sd); break; // acknowledgement of account authentication request case 0x2713: next = chlogif_parse_ackaccreq(fd, sd); break; // account data case 0x2717: next = chlogif_parse_reqaccdata(fd, sd); break; // login-server alive packet case 0x2718: next = chlogif_parse_keepalive(fd, sd); break; // changesex reply case 0x2723: next = chlogif_parse_ackchangesex(fd, sd); break; // reply to an account_reg2 registry request case 0x2729: next = chlogif_parse_ackacc2req(fd, sd); break; // State change of account/ban notification (from login-server) case 0x2731: next = chlogif_parse_accbannotification(fd, sd); break; // Login server request to kick a character out. [Skotlex] case 0x2734: next = chlogif_parse_askkick(fd,sd); break; // ip address update signal from login server case 0x2735: next = chlogif_parse_updip(fd,sd); break; // @accinfo result case 0x2721: next = chlogif_parse_AccInfoAck(fd); break; default: ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); set_eof(fd); return 0; } if(next==0) return 0; //do not parse next data } RFIFOFLUSH(fd); return 0; }
void pincode_notifyLoginPinError(int account_id) { WFIFOHEAD(chr->login_fd,6); WFIFOW(chr->login_fd,0) = 0x2739; WFIFOL(chr->login_fd,2) = account_id; WFIFOSET(chr->login_fd,6); }
/** * Transmit auth result to client. * @param fd: client file desciptor link * @param result: result to transmit to client, see below * 1 : Server closed * 2 : Someone has already logged in with this id * 8 : already online * <result>.B (SC_NOTIFY_BAN) */ static void logclif_sent_auth_result(int fd,char result){ WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x81; WFIFOB(fd,2) = result; WFIFOSET(fd,3); }
void mmo_send_accreg2(AccountDB* self, int fd, int account_id, int char_id) { Sql* sql_handle = ((AccountDB_SQL*)self)->accounts; AccountDB_SQL* db = (AccountDB_SQL*)self; char* data; int plen = 0; size_t len; if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", db->global_acc_reg_str_db, account_id) ) Sql_ShowDebug(sql_handle); WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 1;/* is string type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; /** * Vessel! * * str type * { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) } **/ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { SQL->GetData(sql_handle, 0, &data, NULL); len = strlen(data)+1; WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */ plen += 1; safestrncpy((char*)WFIFOP(fd,plen), data, len); plen += len; SQL->GetData(sql_handle, 1, &data, NULL); WFIFOL(fd, plen) = (unsigned int)atol(data); plen += 4; SQL->GetData(sql_handle, 2, &data, NULL); len = strlen(data)+1; WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */ plen += 1; safestrncpy((char*)WFIFOP(fd,plen), data, len); plen += len; WFIFOW(fd, 14) += 1; if( plen > 60000 ) { WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); /* prepare follow up */ WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 1;/* is string type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; } } /* mark & go. */ WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); SQL->FreeResult(sql_handle); if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `key`, `index`, `value` FROM `%s` WHERE `account_id`='%d'", db->global_acc_reg_num_db, account_id) ) Sql_ShowDebug(sql_handle); WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 0;/* is int type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; /** * Vessel! * * int type * { keyLength(B), key(<keyLength>), index(L), value(L) } **/ while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { SQL->GetData(sql_handle, 0, &data, NULL); len = strlen(data)+1; WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */ plen += 1; safestrncpy((char*)WFIFOP(fd,plen), data, len); plen += len; SQL->GetData(sql_handle, 1, &data, NULL); WFIFOL(fd, plen) = (unsigned int)atol(data); plen += 4; SQL->GetData(sql_handle, 2, &data, NULL); WFIFOL(fd, plen) = atoi(data); plen += 4; WFIFOW(fd, 14) += 1; if( plen > 60000 ) { WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); /* prepare follow up */ WFIFOHEAD(fd, 60000 + 300); WFIFOW(fd, 0) = 0x3804; /* 0x2 = length, set prior to being sent */ WFIFOL(fd, 4) = account_id; WFIFOL(fd, 8) = char_id; WFIFOB(fd, 12) = 0;/* var type (only set when all vars have been sent, regardless of type) */ WFIFOB(fd, 13) = 0;/* is int type */ WFIFOW(fd, 14) = 0;/* count */ plen = 16; } } /* mark as complete & go. */ WFIFOB(fd, 12) = 1; WFIFOW(fd, 2) = plen; WFIFOSET(fd, plen); SQL->FreeResult(sql_handle); }
/** * Char-server request to connect to the login-server. * This is needed to exchange packets. * @param fd: file descriptor to parse from (client) * @param sd: client session * @param ip: ipv4 address (client) * @return 0 packet received too shirt, 1 success */ static int logclif_parse_reqcharconnec(int fd, struct login_session_data *sd, char* ip){ if (RFIFOREST(fd) < 86) return 0; else { int result; char server_name[20]; char message[256]; uint32 server_ip; uint16 server_port; uint16 type; uint16 new_; safestrncpy(sd->userid, RFIFOCP(fd,2), NAME_LENGTH); safestrncpy(sd->passwd, RFIFOCP(fd,26), NAME_LENGTH); if( login_config.use_md5_passwds ) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = 0; server_ip = ntohl(RFIFOL(fd,54)); server_port = ntohs(RFIFOW(fd,58)); safestrncpy(server_name, RFIFOCP(fd,60), 20); type = RFIFOW(fd,82); new_ = RFIFOW(fd,84); RFIFOSKIP(fd,86); ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, ip); sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); login_log(session[fd]->client_addr, sd->userid, 100, message); result = login_mmo_auth(sd, true); if( runflag == LOGINSERVER_ST_RUNNING && result == -1 && sd->sex == 'S' && sd->account_id < ARRAYLENGTH(ch_server) && !session_isValid(ch_server[sd->account_id].fd) ) { ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); safestrncpy(ch_server[sd->account_id].name, server_name, sizeof(ch_server[sd->account_id].name)); ch_server[sd->account_id].fd = fd; ch_server[sd->account_id].ip = server_ip; ch_server[sd->account_id].port = server_port; ch_server[sd->account_id].users = 0; ch_server[sd->account_id].type = type; ch_server[sd->account_id].new_ = new_; session[fd]->func_parse = logchrif_parse; session[fd]->flag.server = 1; realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); // send connection success WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x2711; WFIFOB(fd,2) = 0; WFIFOSET(fd,3); } else { ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x2711; WFIFOB(fd,2) = 3; WFIFOSET(fd,3); } } return 1; }