diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/char/char.c | 302 | ||||
-rw-r--r-- | src/char/char.h | 1 | ||||
-rw-r--r-- | src/common/mmo.h | 8 | ||||
-rw-r--r-- | src/common/showmsg.h | 1 | ||||
-rw-r--r-- | src/common/utils.c | 11 | ||||
-rw-r--r-- | src/common/utils.h | 2 | ||||
-rw-r--r-- | src/login/login.c | 25 | ||||
-rw-r--r-- | src/map/atcommand.c | 54 | ||||
-rw-r--r-- | src/map/chrif.c | 24 | ||||
-rw-r--r-- | src/map/clif.c | 32 | ||||
-rw-r--r-- | src/map/clif.h | 2 |
11 files changed, 328 insertions, 134 deletions
diff --git a/src/char/char.c b/src/char/char.c index ce4fcbe53..ce05f32f4 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -105,7 +105,8 @@ uint32 char_ip = 0; char bind_ip_str[128]; uint32 bind_ip = INADDR_ANY; uint16 char_port = 6121; -int char_maintenance = 0; +int char_server_type = 0; +int char_maintenance_min_group_id = 0; bool char_new = true; int char_new_display = 0; @@ -1003,6 +1004,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) struct mmo_charstatus p; int j = 0, i; char last_map[MAP_NAME_LENGTH_EXT]; + size_t unban_time; stmt = SQL->StmtMalloc(sql_handle); if( stmt == NULL ) { @@ -1011,8 +1013,10 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) } memset(&p, 0, sizeof(p)); - for(i = 0 ; i < MAX_CHARS; i++ ) + for(i = 0 ; i < MAX_CHARS; i++ ) { sd->found_char[i] = -1; + sd->unban_time[i] = 0; + } // read char data if( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT " @@ -1020,7 +1024,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," - "`robe`,`slotchange`" + "`robe`,`slotchange`,`unban_time`" " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) || SQL_ERROR == SQL->StmtExecute(stmt) || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) @@ -1060,6 +1064,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) || SQL_ERROR == SQL->StmtBindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 36, SQLDT_USHORT, &p.slotchange, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 37, SQLDT_LONG, &unban_time, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); @@ -1070,6 +1075,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SQL->StmtNextRow(stmt); i++ ) { p.last_point.map = mapindex_name2id(last_map); sd->found_char[p.slot] = p.char_id; + sd->unban_time[p.slot] = unban_time; j += mmo_char_tobuf(WBUFP(buf, j), &p); } @@ -1930,6 +1936,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) { return 106+offset; } + /* Made Possible by Yommy~! <3 */ void mmo_char_send099d(int fd, struct char_session_data *sd) { WFIFOHEAD(fd,4 + (MAX_CHARS*MAX_CHAR_BUF)); @@ -1937,6 +1944,34 @@ void mmo_char_send099d(int fd, struct char_session_data *sd) { WFIFOW(fd,2) = mmo_chars_fromsql(sd, WFIFOP(fd,4)) + 4; WFIFOSET(fd,WFIFOW(fd,2)); } +/* Sends character ban list */ +/* Made Possible by Yommy~! <3 */ +void mmo_char_send020d(int fd, struct char_session_data *sd) { + int i; + time_t now = time(NULL); + + ARR_FIND(0, MAX_CHARS, i, sd->unban_time[i] > now); + + if( i != MAX_CHARS ) { + int c; + + WFIFOHEAD(fd, 4 + (MAX_CHARS*24)); + + WFIFOW(fd, 0) = 0x20d; + + for(i = 0, c = 0; i < MAX_CHARS; i++) { + if( sd->unban_time[i] > now ) { + WFIFOL(fd, 4 + (24*c)) = sd->found_char[i]; + timestamp2string((char*)WFIFOP(fd,8 + (28*c)), 20, sd->unban_time[i], "%Y-%m-%d %H:%M:%S"); + c++; + } + } + + WFIFOW(fd, 2) = 4 + (24*c); + + WFIFOSET(fd, WFIFOW(fd, 2)); + } +} int mmo_char_send006b(int fd, struct char_session_data* sd); //---------------------------------------- // [Ind/Hercules] notify client about charselect window data @@ -2226,7 +2261,7 @@ int parse_fromlogin(int fd) { // acknowledgement of account authentication request case 0x2713: - if (RFIFOREST(fd) < 25) + if (RFIFOREST(fd) < 29) return 0; { int account_id = RFIFOL(fd,2); @@ -2237,7 +2272,8 @@ int parse_fromlogin(int fd) { int request_id = RFIFOL(fd,16); uint32 version = RFIFOL(fd,20); uint8 clienttype = RFIFOB(fd,24); - RFIFOSKIP(fd,25); + int group_id = RFIFOL(fd,25); + RFIFOSKIP(fd,29); if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) && !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex ) @@ -2245,17 +2281,24 @@ int parse_fromlogin(int fd) { int client_fd = request_id; sd->version = version; sd->clienttype = clienttype; - switch( result ) - { - case 0:// ok - char_auth_ok(client_fd, sd); - break; - case 1:// auth failed - WFIFOHEAD(client_fd,3); - WFIFOW(client_fd,0) = 0x6c; - WFIFOB(client_fd,2) = 0;// rejected from server - WFIFOSET(client_fd,3); - break; + switch( result ) { + case 0:// ok + /* restrictions apply */ + if( char_server_type == CST_MAINTENANCE && group_id < char_maintenance_min_group_id ) { + WFIFOHEAD(client_fd,3); + WFIFOW(client_fd,0) = 0x6c; + WFIFOB(client_fd,2) = 0;// rejected from server + WFIFOSET(client_fd,3); + break; + } + char_auth_ok(client_fd, sd); + break; + case 1:// auth failed + WFIFOHEAD(client_fd,3); + WFIFOW(client_fd,0) = 0x6c; + WFIFOB(client_fd,2) = 0;// rejected from server + WFIFOSET(client_fd,3); + break; } } } @@ -2268,7 +2311,6 @@ int parse_fromlogin(int fd) { // find the authenticated session with this account id ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) ); if( i < fd_max ) { - int server_id; memcpy(sd->email, RFIFOP(fd,6), 40); sd->expiration_time = (time_t)RFIFOL(fd,46); sd->group_id = RFIFOB(fd,50); @@ -2281,10 +2323,8 @@ int parse_fromlogin(int fd) { safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate)); safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode)); sd->pincode_change = RFIFOL(fd,68); - ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); // continued from char_auth_ok... - if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 - (max_connect_user == 0 && sd->group_id != gm_allow_group) || + if( (max_connect_user == 0 && sd->group_id != gm_allow_group) || ( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) { // refuse connection (over populated) WFIFOHEAD(i,3); @@ -2298,6 +2338,9 @@ int parse_fromlogin(int fd) { #else mmo_char_send006b(i, sd); #endif + #if PACKETVER >= 20080000 + mmo_char_send020d(i, sd); + #endif #if PACKETVER >= 20110309 pincode->handle(i, sd); #endif @@ -3135,7 +3178,7 @@ int parse_frommap(int fd) RFIFOSKIP(fd, 86); break; - case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) + case 0x2b0e: // Request from map-server to change an account's or character's status (accounts will just be forwarded to login server) if (RFIFOREST(fd) < 44) return 0; { @@ -3144,7 +3187,7 @@ int parse_frommap(int fd) 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 + int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5 changesex, 6 charban, 7 charunban short year = RFIFOW(fd,32); short month = RFIFOW(fd,34); short day = RFIFOW(fd,36); @@ -3154,25 +3197,24 @@ int parse_frommap(int fd) RFIFOSKIP(fd,44); SQL->EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + + if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`,`name`,`char_id`,`unban_time` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) Sql_ShowDebug(sql_handle); - else - if( SQL->NumRows(sql_handle) == 0 ) - { + else if( SQL->NumRows(sql_handle) == 0 ) { result = 1; // 1-player not found - } - else - if( SQL_SUCCESS != SQL->NextRow(sql_handle) ) + } else if( SQL_SUCCESS != SQL->NextRow(sql_handle) ) { Sql_ShowDebug(sql_handle); - //FIXME: set proper result value? - else - { + result = 1; // 1-player not found + } else { char name[NAME_LENGTH]; - int account_id; + int account_id, char_id; char* data; + time_t unban_time; SQL->GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); + SQL->GetData(sql_handle, 2, &data, NULL); char_id = atoi(data); + SQL->GetData(sql_handle, 3, &data, NULL); unban_time = atol(data); if( login_fd <= 0 ) result = 3; // 3-login-server offline @@ -3180,53 +3222,111 @@ int parse_frommap(int fd) // 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; + 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; + case 6: //char ban + /* handled by char server, so no redirection */ + { + time_t timestamp; + struct tm *tmtime; + SqlStmt* stmt = SQL->StmtMalloc(sql_handle); + + if (unban_time == 0 || unban_time < time(NULL)) + timestamp = time(NULL); // new ban + else + timestamp = unban_time; // add to existing ban + + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + year; + tmtime->tm_mon = tmtime->tm_mon + month; + tmtime->tm_mday = tmtime->tm_mday + day; + tmtime->tm_hour = tmtime->tm_hour + hour; + tmtime->tm_min = tmtime->tm_min + minute; + tmtime->tm_sec = tmtime->tm_sec + second; + timestamp = mktime(tmtime); + + if( SQL_SUCCESS != SQL->StmtPrepare(stmt, + "UPDATE `%s` SET `unban_time` = ? WHERE `char_id` = ? LIMIT 1", + char_db) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_LONG, (void*)×tamp, sizeof(timestamp)) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_INT, (void*)&char_id, sizeof(char_id)) + || SQL_SUCCESS != SQL->StmtExecute(stmt) + + ) { + SqlStmt_ShowDebug(stmt); + } + + SQL->StmtFree(stmt); + + // condition applies; send to all map-servers to disconnect the player + if( timestamp > time(NULL) ) { + unsigned char buf[11]; + + WBUFW(buf,0) = 0x2b14; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 2; + WBUFL(buf,7) = (unsigned int)timestamp; + mapif_sendall(buf, 11); + + // disconnect player if online on char-server + disconnect_player(account_id); + } + } + break; + case 7: //char unban + /* handled by char server, so no redirection */ + if( SQL_ERROR == SQL->Query(sql_handle, "UPDATE `%s` SET `unban_time` = '0' WHERE `char_id` = '%d' LIMIT 1", char_db, char_id) ) { + Sql_ShowDebug(sql_handle); + result = 1; + } + break; + + } } } SQL->FreeResult(sql_handle); // send answer if a player ask, not if the server ask - if( acc != -1 && type != 5) { // Don't send answer for changesex + if( acc != -1 && type != 5 ) { // Don't send answer for changesex WFIFOHEAD(fd,34); WFIFOW(fd, 0) = 0x2b0f; WFIFOL(fd, 2) = acc; @@ -3794,7 +3894,7 @@ static void char_delete2_cancel(int fd, struct char_session_data* sd) int parse_char(int fd) { - int i, ch; + int i; char email[40]; unsigned short cmd; int map_fd; @@ -3872,8 +3972,7 @@ int parse_char(int fd) WFIFOL(fd,0) = account_id; WFIFOSET(fd,4); - if( runflag != CHARSERVER_ST_RUNNING ) - { + if( runflag != CHARSERVER_ST_RUNNING ) { WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x6c; WFIFOB(fd,2) = 0;// rejected from server @@ -3889,6 +3988,14 @@ int parse_char(int fd) node->login_id2 == login_id2 /*&& node->ip == ipl*/ ) {// authentication found (coming from map server) + /* restrictions apply */ + if( char_server_type == CST_MAINTENANCE && node->group_id < char_maintenance_min_group_id ) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0;// rejected from server + WFIFOSET(fd,3); + break; + } idb_remove(auth_db, account_id); char_auth_ok(fd, sd); } @@ -3924,9 +4031,11 @@ int parse_char(int fd) int char_id; uint32 subnet_map_ip; struct auth_node* node; + int server_id = 0; int slot = RFIFOB(fd,2); RFIFOSKIP(fd,3); + #if PACKETVER >= 20110309 if( *pincode->enabled ){ // hack check struct online_char_data* character; @@ -3940,6 +4049,19 @@ int parse_char(int fd) } } #endif + + ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); + /* not available, tell it to wait (client wont close; char select will respawn). + * magic response found by Ind thanks to Yommy <3 */ + if( server_id == ARRAYLENGTH(server) ) { + WFIFOHEAD(fd, 24); + WFIFOW(fd, 0) = 0x840; + WFIFOW(fd, 2) = 24; + safestrncpy((char*)WFIFOP(fd,4), "0", 20);/* we can't send empty (otherwise the list will pop up) */ + WFIFOSET(fd, 24); + break; + } + if ( SQL_SUCCESS != SQL->Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) || SQL_SUCCESS != SQL->NextRow(sql_handle) || SQL_SUCCESS != SQL->GetData(sql_handle, 0, &data, NULL) ) @@ -3956,6 +4078,15 @@ int parse_char(int fd) char_id = atoi(data); SQL->FreeResult(sql_handle); + /* client doesn't let it get to this point if you're banned, so its a forged packet */ + if( sd->found_char[slot] == char_id && sd->unban_time[slot] > time(NULL) ) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; // rejected from server + WFIFOSET(fd,3); + break; + } + /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */ set_char_online(-2,char_id,sd->account_id); if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */ @@ -4095,6 +4226,7 @@ int parse_char(int fd) /* Others I found [Ind] */ /* 0x02 = Symbols in Character Names are forbidden */ /* 0x03 = You are not elegible to open the Character Slot. */ + /* 0x0B = This service is only available for premium users. */ switch (i) { case -1: WFIFOB(fd,2) = 0x00; break; case -2: WFIFOB(fd,2) = 0xFF; break; @@ -4115,9 +4247,7 @@ int parse_char(int fd) WFIFOSET(fd,len); // add new entry to the chars list - ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); - if( ch < MAX_CHARS ) - sd->found_char[ch] = i; // the char_id of the new char + sd->found_char[char_dat.slot] = i; // the char_id of the new char } #if PACKETVER >= 20120307 RFIFOSKIP(fd,31); @@ -4176,9 +4306,7 @@ int parse_char(int fd) } // 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; + sd->found_char[i] = -1; /* Delete character */ if(delete_char_sql(cid)<0){ @@ -4592,7 +4720,7 @@ int check_connect_login_server(int tid, int64 tick, int id, intptr_t data) { WFIFOW(login_fd,58) = htons(char_port); memcpy(WFIFOP(login_fd,60), server_name, 20); WFIFOW(login_fd,80) = 0; - WFIFOW(login_fd,82) = char_maintenance; + WFIFOW(login_fd,82) = char_server_type; WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] WFIFOSET(login_fd,86); @@ -4852,8 +4980,8 @@ int char_config_read(const char* cfgName) } } 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_server_type") == 0) { + char_server_type = atoi(w2); } else if (strcmpi(w1, "char_new") == 0) { char_new = (bool)atoi(w2); } else if (strcmpi(w1, "char_new_display") == 0) { @@ -4940,6 +5068,8 @@ int char_config_read(const char* cfgName) } } else if (strcmpi(w1, "guild_exp_rate") == 0) { guild_exp_rate = atoi(w2); + } else if (strcmpi(w1, "char_maintenance_min_group_id") == 0) { + char_maintenance_min_group_id = atoi(w2); } else if (strcmpi(w1, "import") == 0) { char_config_read(w2); } else diff --git a/src/char/char.h b/src/char/char.h index a3bbdd904..c7a387645 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -20,6 +20,7 @@ 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 + time_t unban_time[MAX_CHARS]; // char unban time array char email[40]; // e-mail (default: a@a.com) by [Yor] time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) int group_id; // permission diff --git a/src/common/mmo.h b/src/common/mmo.h index 369f5c894..309203aa8 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -853,6 +853,14 @@ enum ammo_type { A_THROWWEAPON //9 }; +enum e_char_server_type { + CST_NORMAL = 0, + CST_MAINTENANCE = 1, + CST_OVER18 = 2, + CST_PAYING = 3, + CST_P2P = 4, +}; + /* packet size constant for itemlist */ #if MAX_INVENTORY > MAX_STORAGE && MAX_INVENTORY > MAX_CART #define MAX_ITEMLIST MAX_INVENTORY diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 59a0d9538..43d38973f 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -99,5 +99,6 @@ extern void ClearScreen(void); extern void ShowFatalError(const char *, ...); extern void ShowConfigWarning(config_setting_t *config, const char *string, ...); #endif +extern int _vShowMessage(enum msg_type flag, const char *string, va_list ap); #endif /* _SHOWMSG_H_ */ diff --git a/src/common/utils.c b/src/common/utils.c index 9e3dbac47..9a7d4971b 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -287,6 +287,17 @@ unsigned int get_percentage(const unsigned int A, const unsigned int B) return (unsigned int)floor(result); } +//----------------------------------------------------- +// custom timestamp formatting (from eApp) +//----------------------------------------------------- +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) +{ + size_t len = strftime(str, size, format, localtime(×tamp)); + memset(str + len, '\0', size - len); + return str; +} + + /* [Ind/Hercules] Caching */ bool HCache_check(const char *file) { struct stat bufa, bufb; diff --git a/src/common/utils.h b/src/common/utils.h index 32087d78f..3e1463d6b 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -25,6 +25,8 @@ bool exists(const char* filename); /// calculates the value of A / B, in percent (rounded down) unsigned int get_percentage(const unsigned int A, const unsigned int B); +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format); + ////////////////////////////////////////////////////////////////////////// // byte word dword access [Shinomori] ////////////////////////////////////////////////////////////////////////// diff --git a/src/login/login.c b/src/login/login.c index 73e89d4ff..75247845d 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -11,6 +11,7 @@ #include "../common/socket.h" #include "../common/strlib.h" #include "../common/timer.h" +#include "../common/utils.h" #include "../common/HPM.h" #include "account.h" #include "ipban.h" @@ -65,6 +66,7 @@ struct auth_node { char sex; uint32 version; uint8 clienttype; + int group_id; }; static DBMap* auth_db; // int account_id -> struct auth_node* @@ -270,18 +272,6 @@ bool check_password(const char* md5key, int passwdenc, const char* passwd, const } } - -//----------------------------------------------------- -// custom timestamp formatting (from eApp) -//----------------------------------------------------- -const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) -{ - size_t len = strftime(str, size, format, localtime(×tamp)); - memset(str + len, '\0', size - len); - return str; -} - - //-------------------------------------------- // Test to know if an IP come from LAN or WAN. //-------------------------------------------- @@ -408,7 +398,7 @@ int parse_fromchar(int fd) //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); // send ack - WFIFOHEAD(fd,25); + WFIFOHEAD(fd,29); WFIFOW(fd,0) = 0x2713; WFIFOL(fd,2) = account_id; WFIFOL(fd,6) = login_id1; @@ -418,7 +408,8 @@ int parse_fromchar(int fd) WFIFOL(fd,16) = request_id; WFIFOL(fd,20) = node->version; WFIFOB(fd,24) = node->clienttype; - WFIFOSET(fd,25); + WFIFOL(fd,25) = node->group_id; + WFIFOSET(fd,29); // each auth entry can only be used once idb_remove(auth_db, account_id); @@ -426,7 +417,7 @@ int parse_fromchar(int fd) else {// authentication not found ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); - WFIFOHEAD(fd,25); + WFIFOHEAD(fd,29); WFIFOW(fd,0) = 0x2713; WFIFOL(fd,2) = account_id; WFIFOL(fd,6) = login_id1; @@ -436,7 +427,8 @@ int parse_fromchar(int fd) WFIFOL(fd,16) = request_id; WFIFOL(fd,20) = 0; WFIFOB(fd,24) = 0; - WFIFOSET(fd,25); + WFIFOL(fd,25) = 0; + WFIFOSET(fd,29); } } break; @@ -1206,6 +1198,7 @@ void login_auth_ok(struct login_session_data* sd) node->ip = ip; node->version = sd->version; node->clienttype = sd->clienttype; + node->group_id = sd->group_id; idb_put(auth_db, sd->account_id, node); { diff --git a/src/map/atcommand.c b/src/map/atcommand.c index cdd257195..a2bea32a8 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -549,16 +549,16 @@ ACMD(who) { int display_type = 1; int map_id = -1; - if (strstr(command, "map") != NULL) { + if (stristr(info->command, "map") != NULL) { if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map->mapname2mapid(map_name)) < 0) map_id = sd->bl.m; } else { sscanf(message, "%23s", player_name); } - if (strstr(command, "2") != NULL) + if (stristr(info->command, "2") != NULL) display_type = 2; - else if (strstr(command, "3") != NULL) + else if (stristr(info->command, "3") != NULL) display_type = 3; level = pc->get_group_level(sd); @@ -1002,17 +1002,17 @@ ACMD(kami) memset(atcmd_output, '\0', sizeof(atcmd_output)); - if(*(command + 5) != 'c' && *(command + 5) != 'C') { + if(*(info->command + 4) != 'c' && *(info->command + 4) != 'C') { if (!message || !*message) { clif->message(fd, msg_txt(980)); // Please enter a message (usage: @kami <message>). return false; } sscanf(message, "%199[^\n]", atcmd_output); - if (strstr(command, "l") != NULL) + if (stristr(info->command, "l") != NULL) clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP); else - intif->broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? BC_BLUE : BC_YELLOW); + intif->broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(info->command + 4) == 'b' || *(info->command + 4) == 'B') ? BC_BLUE : BC_YELLOW); } else { if(!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { clif->message(fd, msg_txt(981)); // Please enter color and message (usage: @kamic <color> <message>). @@ -1099,7 +1099,7 @@ ACMD(item) memset(item_name, '\0', sizeof(item_name)); - if (!strcmpi(command+1,"itembound") && (!message || !*message || ( + if (!strcmpi(info->command,"itembound") && (!message || !*message || ( sscanf(message, "\"%99[^\"]\" %d %d", item_name, &number, &bound) < 2 && sscanf(message, "%99s %d %d", item_name, &number, &bound) < 2 ))) { @@ -1123,7 +1123,7 @@ ACMD(item) return false; } - if(!strcmpi(command+1,"itembound") && !(bound >= IBT_MIN && bound <= IBT_MAX) ) { + if(!strcmpi(info->command,"itembound") && !(bound >= IBT_MIN && bound <= IBT_MAX) ) { clif->message(fd, msg_txt(298)); // Invalid bound type return false; } @@ -1171,7 +1171,7 @@ ACMD(item2) memset(item_name, '\0', sizeof(item_name)); - if (!strcmpi(command+1,"itembound2") && (!message || !*message || ( + if (!strcmpi(info->command,"itembound2") && (!message || !*message || ( sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 && sscanf(message, "%99s %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) { clif->message(fd, msg_txt(296)); // Please enter all parameters (usage: @itembound2 <item name/ID> <quantity> @@ -1189,7 +1189,7 @@ ACMD(item2) if (number <= 0) number = 1; - if( !strcmpi(command+1,"itembound2") && !(bound >= IBT_MIN && bound <= IBT_MAX) ) { + if( !strcmpi(info->command,"itembound2") && !(bound >= IBT_MIN && bound <= IBT_MAX) ) { clif->message(fd, msg_txt(298)); // Invalid bound type return false; } @@ -1204,7 +1204,7 @@ ACMD(item2) int loop, get_count, i; loop = 1; get_count = number; - if( !strcmpi(command+1,"itembound2") ) + if( !strcmpi(info->command,"itembound2") ) bound = 1; if( !itemdb->isstackable2(item_data) ) { if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) { @@ -1930,9 +1930,9 @@ ACMD(monster) if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) number = battle_config.atc_spawn_quantity_limit; - if (strcmp(command+1, "monstersmall") == 0) + if (strcmpi(info->command, "monstersmall") == 0) size = SZ_MEDIUM; // This is just gorgeous [mkbu95] - else if (strcmp(command+1, "monsterbig") == 0) + else if (strcmpi(info->command, "monsterbig") == 0) size = SZ_BIG; else size = SZ_SMALL; @@ -1997,7 +1997,7 @@ ACMD(killmonster) { map_id = sd->bl.m; } - drop_flag = strcmp(command+1, "killmonster2"); + drop_flag = strcmpi(info->command, "killmonster2"); map->foreachinmap(atcommand->atkillmonster_sub, map_id, BL_MOB, -drop_flag); @@ -2358,7 +2358,7 @@ ACMD(param) { return false; } - ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0 ); + ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(info->command, param[i]) == 0 ); if( i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... clif->message(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). @@ -2798,7 +2798,7 @@ ACMD(char_ban) return false; } - chrif->char_ask_name(sd->status.account_id, atcmd_player_name, 2, year, month, day, hour, minute, second); // type: 2 - ban + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, !strcmpi(info->command,"charban") ? 6 : 2, year, month, day, hour, minute, second); // type: 2 - ban; 6 - charban clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -2838,7 +2838,7 @@ ACMD(char_unban) } // send answer to login server via char-server - chrif->char_ask_name(sd->status.account_id, atcmd_player_name, 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, !strcmpi(info->command,"charunban") ? 7 : 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban account; type 7 - unban character clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -3138,7 +3138,7 @@ ACMD(spiritball) if( !message || !*message || (number = atoi(message)) < 0 || number > max_spiritballs ) { char msg[CHAT_SIZE_MAX]; - safesnprintf(msg, sizeof(msg), msg_txt(1028), max_spiritballs); // Please enter a party name (usage: @party <party_name>). + safesnprintf(msg, sizeof(msg), msg_txt(1028), max_spiritballs); // Please enter an amount (usage: @spiritball <number: 0-%d>). clif->message(fd, msg); return false; } @@ -6070,7 +6070,7 @@ ACMD(npctalk) { char name[NAME_LENGTH],mes[100],temp[100]; struct npc_data *nd; - bool ifcolor=(*(command + 8) != 'c' && *(command + 8) != 'C')?0:1; + bool ifcolor=(*(info->command + 7) != 'c' && *(info->command + 7) != 'C')?0:1; unsigned long color=0; if (sd->sc.count && //no "chatting" while muted. @@ -7754,7 +7754,7 @@ ACMD(cash) return false; } - if( !strcmpi(command+1,"cash") ) { + if( !strcmpi(info->command,"cash") ) { if( value > 0 ) { if( (ret=pc->getcash(sd, value, 0)) >= 0){ // If this option is set, the message is already sent by pc function @@ -7813,9 +7813,9 @@ ACMD(clone) { return true; } - if (strcmpi(command+1, "clone") == 0) + if (strcmpi(info->command, "clone") == 0) flag = 1; - else if (strcmpi(command+1, "slaveclone") == 0) { + else if (strcmpi(info->command, "slaveclone") == 0) { flag = 2; if(pc_isdead(sd)){ clif->message(fd, msg_txt(129+flag*2)); @@ -7983,15 +7983,15 @@ ACMD(itemlist) int size; StringBuf buf; - if( strcmp(command+1, "storagelist") == 0 ) { + if( strcmpi(info->command, "storagelist") == 0 ) { location = "storage"; items = sd->status.storage.items; size = MAX_STORAGE; - } else if( strcmp(command+1, "cartlist") == 0 ) { + } else if( strcmpi(info->command, "cartlist") == 0 ) { location = "cart"; items = sd->status.cart; size = MAX_CART; - } else if( strcmp(command+1, "itemlist") == 0 ) { + } else if( strcmpi(info->command, "itemlist") == 0 ) { location = "inventory"; items = sd->status.inventory; size = MAX_INVENTORY; @@ -8512,7 +8512,7 @@ ACMD(reloadquestdb) { } ACMD(addperm) { int perm_size = pcg->permission_count; - bool add = (strcmpi(command+1, "addperm") == 0) ? true : false; + bool add = (strcmpi(info->command, "addperm") == 0) ? true : false; int i; if( !message || !*message ) { @@ -9448,7 +9448,9 @@ void atcommand_basecommands(void) { ACMD_DEF2("allstats", stat_all), ACMD_DEF2("block", char_block), ACMD_DEF2("ban", char_ban), + ACMD_DEF2("charban", char_ban),/* char-specific ban time */ ACMD_DEF2("unblock", char_unblock), + ACMD_DEF2("charunban", char_unban),/* char-specific ban time */ ACMD_DEF2("unban", char_unban), ACMD_DEF2("mount", mount_peco), ACMD_DEF(guildspy), diff --git a/src/map/chrif.c b/src/map/chrif.c index 87ec71ec5..56572d492 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -752,7 +752,7 @@ int chrif_changeemail(int id, const char *actual_email, const char *new_email) { * 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) + * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex (use next function for 5), 6: charban *------------------------------------------*/ 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) { @@ -764,7 +764,7 @@ int chrif_char_ask_name(int acc, const char* character_name, unsigned short oper safestrncpy((char*)WFIFOP(chrif->fd,6), character_name, NAME_LENGTH); WFIFOW(chrif->fd,30) = operation_type; - if ( operation_type == 2 ) { + if ( operation_type == 2 || operation_type == 6 ) { WFIFOW(chrif->fd,32) = year; WFIFOW(chrif->fd,34) = month; WFIFOW(chrif->fd,36) = day; @@ -800,7 +800,7 @@ int chrif_changesex(struct map_session_data *sd) { * R 2b0f <accid>.l <name>.24B <type>.w <answer>.w * Processing a reply to chrif->char_ask_name() (request to modify an account). * type of operation: - * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex + * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex, 6: charban, 7: charunban * type of answer: * 0: login-server request done * 1: player not found @@ -811,6 +811,7 @@ void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 type, u struct map_session_data* sd; char action[25]; char output[256]; + bool charsrv = ( type == 6 || type == 7 ) ? true : false; sd = map->id2sd(acc); @@ -819,13 +820,17 @@ void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 type, u return; } + /* re-use previous msg_txt */ + if( type == 6 ) type = 2; + if( type == 7 ) type = 4; + if( type > 0 && type <= 5 ) snprintf(action,25,"%s",msg_txt(427+type)); //block|ban|unblock|unban|change the sex of else snprintf(action,25,"???"); switch( answer ) { - case 0 : sprintf(output, msg_txt(424), action, NAME_LENGTH, player_name); break; + case 0 : sprintf(output, msg_txt(charsrv?434:424), action, NAME_LENGTH, player_name); break; case 1 : sprintf(output, msg_txt(425), NAME_LENGTH, player_name); break; case 2 : sprintf(output, msg_txt(426), action, NAME_LENGTH, player_name); break; case 3 : sprintf(output, msg_txt(427), action, NAME_LENGTH, player_name); break; @@ -980,7 +985,7 @@ int chrif_accountban(int fd) { } sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters - if (RFIFOB(fd,6) == 0) { // 0: change of statut, 1: ban + if (RFIFOB(fd,6) == 0) { // 0: change of statut int ret_status = RFIFOL(fd,7); // status or final date of a banishment if(0<ret_status && ret_status<=9) clif->message(sd->fd, msg_txt(411+ret_status)); @@ -988,13 +993,20 @@ int chrif_accountban(int fd) { clif->message(sd->fd, msg_txt(421)); else clif->message(sd->fd, msg_txt(420)); //"Your account has not more authorised." - } else if (RFIFOB(fd,6) == 1) { // 0: change of statut, 1: ban + } else if (RFIFOB(fd,6) == 1) { // 1: ban time_t timestamp; char tmpstr[2048]; timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment strcpy(tmpstr, msg_txt(423)); //"Your account has been banished until " strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); clif->message(sd->fd, tmpstr); + } else if (RFIFOB(fd,6) == 2) { // 2: change of status for character + time_t timestamp; + char tmpstr[2048]; + timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment + strcpy(tmpstr, msg_txt(433)); //"This character has been banned until " + strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); + clif->message(sd->fd, tmpstr); } set_eof(sd->fd); // forced to disconnect for the change diff --git a/src/map/clif.c b/src/map/clif.c index d84a0dea8..6740c7a74 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -5634,7 +5634,38 @@ void clif_displaymessage2(const int fd, const char* mes) { aFree(message); } } +/* oh noo! another version of 0x8e! */ +void clif_displaymessage_sprintf(const int fd, const char* mes, ...) { + va_list ap; + if( fd == -2 ) { + ShowInfo("HCP: "); + va_start(ap,mes); + _vShowMessage(MSG_NONE,mes,ap); + va_end(ap); + ShowMessage("\n"); + } else if ( fd > 0 ) { + int len = 1; + char *ptr; + + WFIFOHEAD(fd, 5 + 255);/* ensure the maximum */ + + /* process */ + va_start(ap,mes); + len += vsnprintf((char *)WFIFOP(fd,4), 255, mes, ap); + va_end(ap); + + /* adjusting */ + ptr = (char *)WFIFOP(fd,4); + ptr[len - 1] = '\0'; + + /* */ + WFIFOW(fd,0) = 0x8e; + WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate + + WFIFOSET(fd, 5 + len); + } +} /// Send broadcast message in yellow or blue without font formatting (ZC_BROADCAST). /// 009a <packet len>.W <message>.?B void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target) @@ -18407,6 +18438,7 @@ void clif_defaults(void) { clif->msgtable_num = clif_msgtable_num; clif->message = clif_displaymessage; clif->messageln = clif_displaymessage2; + clif->messages = clif_displaymessage_sprintf; clif->colormes = clif_colormes; clif->process_message = clif_process_message; clif->wisexin = clif_wisexin; diff --git a/src/map/clif.h b/src/map/clif.h index e50af7432..043f7dd3a 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -787,6 +787,8 @@ struct clif_interface { void (*msgtable_num) (int fd, int line, int num); void (*message) (const int fd, const char* mes); void (*messageln) (const int fd, const char* mes); + /* message+s(printf) */ + void (*messages) (const int fd, const char* mes, ...); int (*colormes) (int fd, enum clif_colors color, const char* msg); bool (*process_message) (struct map_session_data* sd, int format, char** name_, int* namelen_, char** message_, int* messagelen_); void (*wisexin) (struct map_session_data *sd,int type,int flag); |