Explorar o código

Adding charblock

Update HC 0x20d to send the blocklist value, based on Herc:aee2f631
Revamp ZH 0x2b0e and HA 0x2725 to send difftime instead
year,month,day,minutes,secondes values..
Remove duplicate code for char_ban
Add missing sql_upgrade for vip
lighta %!s(int64=11) %!d(string=hai) anos
pai
achega
3428ae297a

+ 9 - 5
conf/msg_conf/map_msg.conf

@@ -103,10 +103,10 @@
 82: Please provide a name or number from the list provided:
 83: Monster 'Emperium' cannot be spawned.
 84: All stats changed!
-85: Invalid time for ban command.
+85: Invalid time for %s command (time=%d).
 86: Sorry, player names have to be at least 4 characters.
 87: Sorry, player names can be no longer than 23 characters.
-88: Sending request to login server...
+88: Sending request to %s server...
 89: Night mode is already enabled.
 90: Day mode is already enabled.
 91: Character's base level can't go any higher.
@@ -439,8 +439,8 @@
 419: Server is jammed due to over populated.
 420: Your account has not more authorised.
 421: Your account has been totally erased.
-423: Your account has been banished until
-424: Login-server has been asked to %s the player '%.*s'.
+423: Your %s has been banished until %s 
+424: %s has been asked to %s the player '%.*s'.
 425: The player '%.*s' doesn't exist.
 426: Your GM level don't authorise you to %s the player '%.*s'.
 427: Login-server is offline. Impossible to %s the player '%.*s'.
@@ -450,6 +450,10 @@
 431: unban
 432: change the sex of
 
+433: This character has been banned until 
+434: Char-server has been asked to %s the character '%.*s'.
+435: Please enter a player name (usage: @charunblock <char name>).
+
 // Homunculus messages
 450: You already have a homunculus
 
@@ -851,7 +855,7 @@
 
 // @charban
 1022: Please enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish <time> <char name>).
-1023: You are not allowed to reduce the length of a ban.
+1023: You are not allowed to alter the time of a ban.
 
 // @charunblock
 1024: Please enter a player name (usage: @charunblock <char name>).

+ 1 - 0
sql-files/main.sql

@@ -122,6 +122,7 @@ CREATE TABLE IF NOT EXISTS `char` (
   `rename` SMALLINT(3) unsigned NOT NULL default '0',
   `delete_date` INT(11) UNSIGNED NOT NULL DEFAULT '0',
   `moves` int(11) unsigned NOT NULL DEFAULT '0',
+  `unban_time` int(11) unsigned NOT NULL default '0',
   PRIMARY KEY  (`char_id`),
   UNIQUE KEY `name_key` (`name`),
   KEY `account_id` (`account_id`),

+ 3 - 3
sql-files/upgrades/upgrade_20131115.sql

@@ -1,4 +1,4 @@
-ALTER TABLE `inventory` MODIFY `equip` int(11) unsigned NOT NULL default '0';
-ALTER TABLE `storage` MODIFY `equip` int(11) unsigned NOT NULL default '0';
-ALTER TABLE `cart_inventory` MODIFY `equip` int(11) unsigned NOT NULL default '0';
+ALTER TABLE `inventory` MODIFY `equip` int(11) unsigned NOT NULL default '0';
+ALTER TABLE `storage` MODIFY `equip` int(11) unsigned NOT NULL default '0';
+ALTER TABLE `cart_inventory` MODIFY `equip` int(11) unsigned NOT NULL default '0';
 ALTER TABLE `guild_storage` MODIFY `equip` int(11) unsigned NOT NULL default '0';

+ 3 - 0
sql-files/upgrades/upgrade_20131118.sql

@@ -0,0 +1,3 @@
+ALTER TABLE  `login` ADD  `vip_time` int(11) UNSIGNED NULL DEFAULT '0';
+ALTER TABLE  `login` ADD  `old_group` tinyint(3) NOT NULL default '0';
+ALTER TABLE `char` ADD `unban_time` int(11) unsigned NOT NULL default '0';

+ 183 - 114
src/char/char.c

@@ -148,6 +148,7 @@ struct char_session_data {
 	int bank_vault;
 	unsigned int char_moves[MAX_CHARS]; // character moves left
 	uint8 isvip;
+	time_t unban_time[MAX_CHARS];
 };
 
 struct startitem {
@@ -543,7 +544,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 		(p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) ||
 		(p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) ||
 		(p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) ||
-		(p->rename != cp->rename) || (p->robe != cp->robe) || (p->character_moves != cp->character_moves)
+		(p->rename != cp->rename) || (p->robe != cp->robe) || (p->character_moves != cp->character_moves) || (p->unban_time != cp->unban_time)
 	)
 	{	//Save status
 		if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d',"
@@ -553,7 +554,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 			"`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d',"
 			"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
 			"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
-			"`delete_date`='%lu',`robe`='%d',`moves`='%d'"
+			"`delete_date`='%lu',`robe`='%d',`moves`='%d', `unban_time`='%d'"
 			" WHERE  `account_id`='%d' AND `char_id` = '%d'",
 			char_db, p->base_level, p->job_level,
 			p->base_exp, p->job_exp, p->zeny,
@@ -564,7 +565,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 			mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y,
 			mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename,
 			(unsigned long)p->delete_date,  // FIXME: platform-dependent size
-			p->robe,p->character_moves,
+			p->robe,p->character_moves,p->unban_time,
 			p->account_id, p->char_id) )
 		{
 			Sql_ShowDebug(sql_handle);
@@ -1095,7 +1096,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`,`moves`"
+		"`robe`,`moves`, `unban_time`"
 		" FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS)
 	||	SQL_ERROR == SqlStmt_Execute(stmt)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0,  SQLDT_INT,    &p.char_id, 0, NULL, NULL)
@@ -1135,6 +1136,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT,  &p.robe, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_UINT,   &p.character_moves, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_LONG,   &p.unban_time, 0, NULL, NULL)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);
@@ -1146,6 +1148,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
 	{
 		p.last_point.map = mapindex_name2id(last_map);
 		sd->found_char[p.slot] = p.char_id;
+		sd->unban_time[p.slot] = p.unban_time;
 		j += mmo_char_tobuf(WBUFP(buf, j), &p);
 
 		// Addon System
@@ -1196,7 +1199,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
 		"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
 		"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
 		"`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`,"
-		"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`"
+		"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`, `unban_time`"
 		" FROM `%s` WHERE `char_id`=? LIMIT 1", char_db)
 	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
 	||	SQL_ERROR == SqlStmt_Execute(stmt)
@@ -1229,7 +1232,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT,    &p->guild_id, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT,    &p->pet_id, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT,    &p->hom_id, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT,	&p->ele_id, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT,    &p->ele_id, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT,  &p->hair, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT,  &p->hair_color, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT,  &p->clothes_color, 0, NULL, NULL)
@@ -1249,10 +1252,11 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT,    &p->mother, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT,    &p->child, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT,    &p->fame, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT,	&p->rename, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT,  &p->rename, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT,  &p->robe, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 52, SQLDT_UINT32, &p->character_moves, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 53, SQLDT_LONG,   &p->unban_time, 0, NULL, NULL)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);
@@ -1958,11 +1962,32 @@ void char_charlist_notify( int fd, struct char_session_data* sd ){
 	WFIFOSET(fd,6);
 }
 
+/*
+ * 0x20d <PacketLength>.W <TAG_CHARACTER_BLOCK_INFO>24B (HC_BLOCK_CHARACTER)
+ * <GID>L <szExpireDate>20B (TAG_CHARACTER_BLOCK_INFO)
+ */
 void char_block_character( int fd, struct char_session_data* sd ){
-	WFIFOHEAD(fd, 4);
-	WFIFOW(fd, 0) = 0x20d;
-	WFIFOW(fd, 2) = 4; //packet len
-	WFIFOSET(fd,4);
+	int i=0, len=4;
+	char szExpireDate[20];
+	time_t now = time(NULL);
+	
+	ARR_FIND(0, MAX_CHARS, i, sd->unban_time[i] > now); //should we use MAX_CHARS or sd->charslot
+	if(i < MAX_CHARS){
+		memset(szExpireDate,'\0',20);
+		WFIFOHEAD(fd, 4+MAX_CHARS*24);
+		WFIFOW(fd, 0) = 0x20d;
+
+		for(i=0; i<MAX_CHARS; i++){
+			if( sd->unban_time[i] > now ) {
+				WFIFOL(fd, 4+i*24) = sd->found_char[i]; //gid
+				timestamp2string(szExpireDate, 20, sd->unban_time[i], "%Y-%m-%d %H:%M:%S");
+				memcpy(WFIFOP(fd,8+i*24),szExpireDate,20);
+				len+=24;
+			}
+		}
+		WFIFOW(fd, 2) = len; //packet len
+		WFIFOSET(fd,len);
+	}
 }
 
 void mmo_char_send099d(int fd, struct char_session_data *sd) {
@@ -2034,7 +2059,9 @@ void mmo_char_send(int fd, struct char_session_data* sd){
 		char_charlist_notify(fd,sd);
 		char_block_character(fd,sd);
 	}
-	else mmo_char_send006b(fd,sd);
+	//else 
+	//@FIXME dump from kro doesn't show 6b transmission
+	mmo_char_send006b(fd,sd);
 }
 
 int char_married(int pl1, int pl2)
@@ -2965,7 +2992,141 @@ void mapif_on_disconnect(int id)
 	ShowStatus("Map-server #%d has disconnected.\n", id);
 	mapif_server_reset(id);
 }
+/** 
+ * Request from map-server to change an account's status (will just be forwarded to login server)
+ * ZH 2b0e <aid>L <charname>24B <opetype>W <timediff>L
+ * @param fd: link to mapserv
+ */	
+int mapif_parse_req_alter_acc(int fd){
+	if (RFIFOREST(fd) < 36)
+		return 0;
+	else {
+		int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
+		char esc_name[NAME_LENGTH*2+1];
+
+		int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
+		const char* name = (char*)RFIFOP(fd,6); // name of the target character
+		int operation = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban,  5 changesex, 6 charban, 7 charunban
+		int timediff = RFIFOL(fd,32);
+		RFIFOSKIP(fd,36);
 
+		Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
+		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 ){
+			result = 1; // 1-player not found
+		}
+		else if( SQL_SUCCESS != Sql_NextRow(sql_handle) ){
+			Sql_ShowDebug(sql_handle);
+			result = 1;
+		} else {
+			char name[NAME_LENGTH];
+			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);;
+			Sql_FreeResult(sql_handle);
+
+			if(operation!=6 && operation!=7 && login_fd <= 0 ) //6-7 operation doesn't send to login
+				result = 3; // 3-login-server offline
+			//FIXME: need to move this check to login server [ultramage]
+			//	if( acc != -1 && isGM(acc) < isGM(account_id) )
+			//		result = 2; // 2-gm level too low
+			else
+			switch( operation ) {
+			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,10);
+				WFIFOW(login_fd, 0) = 0x2725;
+				WFIFOL(login_fd, 2) = account_id;
+				WFIFOL(login_fd, 6) = timediff;
+				WFIFOSET(login_fd,10);
+			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: //charban /* handled by char server, so no redirection */
+				if(timediff<0 && unban_time==0) break; //attemp to reduce time of a non banned account ?!? 
+				else if(unban_time==0) unban_time=time(NULL); //new entry
+				unban_time += timediff;
+				// condition applies; send to all map-servers to disconnect the player
+				if( unban_time > time(NULL) ) {
+					unsigned char buf[11];
+					SqlStmt* stmt = SqlStmt_Malloc(sql_handle);
+					if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
+							  "UPDATE `%s` SET `unban_time` = ? WHERE `char_id` = ? LIMIT 1",
+							  char_db)
+						|| SQL_SUCCESS != SqlStmt_BindParam(stmt,  0, SQLDT_LONG,   (void*)&unban_time,   sizeof(unban_time))
+						|| SQL_SUCCESS != SqlStmt_BindParam(stmt,  1, SQLDT_INT,    (void*)&char_id,     sizeof(char_id))
+						|| SQL_SUCCESS != SqlStmt_Execute(stmt)
+
+						) {
+						SqlStmt_ShowDebug(stmt);
+						result=1;
+					}
+					else {
+						WBUFW(buf,0) = 0x2b14;
+						WBUFL(buf,2) = account_id;
+						WBUFB(buf,6) = 2;
+						WBUFL(buf,7) = (unsigned int)unban_time;
+						mapif_sendall(buf, 11);
+
+						// disconnect player if online on char-server
+						disconnect_player(account_id);
+						result=4;
+					}
+					SqlStmt_Free(stmt);
+				}
+			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;
+				} else result=4;
+			break;
+			} //end switch operation
+		}
+
+		// send answer if a player ask, not if the server ask
+		if( acc != -1 && operation != 5) { // Don't send answer for changesex
+			WFIFOHEAD(fd,34);
+			WFIFOW(fd, 0) = 0x2b0f;
+			WFIFOL(fd, 2) = acc;
+			safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
+			WFIFOW(fd,30) = operation;
+			WFIFOW(fd,32) = result;
+			WFIFOSET(fd,34);
+		}
+	}
+	return 1;
+}
 
 int parse_frommap(int fd)
 {
@@ -3381,108 +3542,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)
-			if (RFIFOREST(fd) < 44)
-				return 0;
-		{
-			int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline
-			char esc_name[NAME_LENGTH*2+1];
-
-			int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
-			const char* name = (char*)RFIFOP(fd,6); // name of the target character
-			int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
-			short year = RFIFOW(fd,32);
-			short month = RFIFOW(fd,34);
-			short day = RFIFOW(fd,36);
-			short hour = RFIFOW(fd,38);
-			short minute = RFIFOW(fd,40);
-			short second = RFIFOW(fd,42);
-			RFIFOSKIP(fd,44);
-
-			Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
-			if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
-				Sql_ShowDebug(sql_handle);
-			else
-			if( Sql_NumRows(sql_handle) == 0 )
-			{
-				result = 1; // 1-player not found
-			}
-			else
-			if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
-				Sql_ShowDebug(sql_handle);
-				//FIXME: set proper result value?
-			else
-			{
-				char name[NAME_LENGTH];
-				int account_id;
-				char* data;
-
-				Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
-				Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
-
-				if( login_fd <= 0 )
-					result = 3; // 3-login-server offline
-				//FIXME: need to move this check to login server [ultramage]
-//				else
-//				if( acc != -1 && isGM(acc) < isGM(account_id) )
-//					result = 2; // 2-gm level too low
-				else
-				switch( type ) {
-				case 1: // block
-						WFIFOHEAD(login_fd,10);
-						WFIFOW(login_fd,0) = 0x2724;
-						WFIFOL(login_fd,2) = account_id;
-						WFIFOL(login_fd,6) = 5; // new account status
-						WFIFOSET(login_fd,10);
-				break;
-				case 2: // ban
-						WFIFOHEAD(login_fd,18);
-						WFIFOW(login_fd, 0) = 0x2725;
-						WFIFOL(login_fd, 2) = account_id;
-						WFIFOW(login_fd, 6) = year;
-						WFIFOW(login_fd, 8) = month;
-						WFIFOW(login_fd,10) = day;
-						WFIFOW(login_fd,12) = hour;
-						WFIFOW(login_fd,14) = minute;
-						WFIFOW(login_fd,16) = second;
-						WFIFOSET(login_fd,18);
-				break;
-				case 3: // unblock
-						WFIFOHEAD(login_fd,10);
-						WFIFOW(login_fd,0) = 0x2724;
-						WFIFOL(login_fd,2) = account_id;
-						WFIFOL(login_fd,6) = 0; // new account status
-						WFIFOSET(login_fd,10);
-				break;
-				case 4: // unban
-						WFIFOHEAD(login_fd,6);
-						WFIFOW(login_fd,0) = 0x272a;
-						WFIFOL(login_fd,2) = account_id;
-						WFIFOSET(login_fd,6);
-				break;
-				case 5: // changesex
-						WFIFOHEAD(login_fd,6);
-						WFIFOW(login_fd,0) = 0x2727;
-						WFIFOL(login_fd,2) = account_id;
-						WFIFOSET(login_fd,6);
-				break;
-				}
-			}
-
-			Sql_FreeResult(sql_handle);
-
-			// send answer if a player ask, not if the server ask
-			if( acc != -1 && type != 5) { // Don't send answer for changesex
-				WFIFOHEAD(fd,34);
-				WFIFOW(fd, 0) = 0x2b0f;
-				WFIFOL(fd, 2) = acc;
-				safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH);
-				WFIFOW(fd,30) = type;
-				WFIFOW(fd,32) = result;
-				WFIFOSET(fd,34);
-			}
-		}
-		break;
+		case 0x2b0e: mapif_parse_req_alter_acc(fd); break;
 
 		case 0x2b10: // Update and send fame ranking list
 			if (RFIFOREST(fd) < 11)
@@ -4221,6 +4281,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);

+ 1 - 0
src/common/mmo.h

@@ -403,6 +403,7 @@ struct mmo_charstatus {
 	short rename;
 
 	time_t delete_date;
+	time_t unban_time;
 
 	// Char server addon system
 	unsigned int character_moves;

+ 16 - 3
src/common/timer.c

@@ -6,6 +6,7 @@
 #include "../common/malloc.h"
 #include "../common/showmsg.h"
 #include "../common/utils.h"
+#include "../common/nullpo.h"
 #include "timer.h"
 
 #include <stdio.h>
@@ -406,9 +407,19 @@ unsigned long get_uptime(void)
 	return (unsigned long)difftime(time(NULL), start_time);
 }
 
-void time2str(char *timestr, char *format, int timein) {
-	time_t timeout = time(NULL) + timein;
-	strftime(timestr, 24, format, localtime(&timeout));
+/**
+ * Converting a timestamp is a srintf according to format
+ * safefr then strftime as it ensure \0 at end of string
+ * @param str, pointer to the destination string
+ * @param size, max length of the string
+ * @param timestamp, see unix epoch
+ * @param format, format to convert timestamp on, see strftime format
+ * @return the string of timestamp
+ */
+const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format){
+	size_t len = strftime(str, size, format, localtime(&timestamp));
+	memset(str + len, '\0', size - len);
+	return str;
 }
 
 /*
@@ -451,6 +462,8 @@ double solve_time(char* modif_p) {
 	time_t now = time(NULL);
 	time_t then = now;
 	then_tm = *localtime(&then);
+	
+	nullpo_retr(0,modif_p);
 
 	while (modif_p[0] != '\0') {
 		value = atoi(modif_p);

+ 2 - 1
src/common/timer.h

@@ -5,6 +5,7 @@
 #define	_TIMER_H_
 
 #include "../common/cbasetypes.h"
+#include <time.h>
 
 #define DIFF_TICK(a,b) ((int)((a)-(b)))
 
@@ -50,7 +51,7 @@ int add_timer_func_list(TimerFunc func, char* name);
 
 unsigned long get_uptime(void);
 
-void time2str(char* timestr, char* format, int timein);
+const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format);
 void split_time(int time, int* year, int* month, int* day, int* hour, int* minute, int* second);
 double solve_time(char* modif_p);
 

+ 4 - 33
src/login/login.c

@@ -297,22 +297,6 @@ bool check_password(const char* md5key, int passwdenc, const char* passwd, const
 }
 
 
-/**
- * Converting a timestamp is a srintf according to format
- * safefr then strftime as it ensure \0 at end of string
- * @param str, pointer to the destination string
- * @param size, max length of the string
- * @param timestamp, see unix epoch
- * @param format, format to convert timestamp on, see strftime format
- * @return the string of timestamp
- */
-const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format){
-	size_t len = strftime(str, size, format, localtime(&timestamp));
-	memset(str + len, '\0', size - len);
-	return str;
-}
-
-
 //--------------------------------------------
 // Test to know if an IP come from LAN or WAN.
 //--------------------------------------------
@@ -766,37 +750,24 @@ int parse_fromchar(int fd){
 		break;
 
 		case 0x2725: // Receiving of map-server via char-server a ban request
-			if (RFIFOREST(fd) < 18)
+			if (RFIFOREST(fd) < 10)
 				return 0;
 			else{
 				struct mmo_account acc;
 
 				int account_id = RFIFOL(fd,2);
-				int year = (short)RFIFOW(fd,6);
-				int month = (short)RFIFOW(fd,8);
-				int mday = (short)RFIFOW(fd,10);
-				int hour = (short)RFIFOW(fd,12);
-				int min = (short)RFIFOW(fd,14);
-				int sec = (short)RFIFOW(fd,16);
-				RFIFOSKIP(fd,18);
+				int timediff = RFIFOL(fd,6);
+				RFIFOSKIP(fd,10);
 
 				if( !accounts->load_num(accounts, &acc, account_id) )
 					ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip);
 				else{
 					time_t timestamp;
-					struct tm *tmtime;
 					if (acc.unban_time == 0 || acc.unban_time < time(NULL))
 						timestamp = time(NULL); // new ban
 					else
 						timestamp = acc.unban_time; // add to existing ban
-					tmtime = localtime(&timestamp);
-					tmtime->tm_year = tmtime->tm_year + year;
-					tmtime->tm_mon  = tmtime->tm_mon + month;
-					tmtime->tm_mday = tmtime->tm_mday + mday;
-					tmtime->tm_hour = tmtime->tm_hour + hour;
-					tmtime->tm_min  = tmtime->tm_min + min;
-					tmtime->tm_sec  = tmtime->tm_sec + sec;
-					timestamp = mktime(tmtime);
+					timestamp += timediff;
 					if (timestamp == -1)
 						ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip);
 					else if( timestamp <= time(NULL) || timestamp == 0 )

+ 58 - 92
src/map/atcommand.c

@@ -2773,105 +2773,59 @@ ACMD_FUNC(char_block)
 		return -1;
 	}
 
-	chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
+	chrif_ask_char_operation(sd->status.account_id, atcmd_player_name, 1, 0); // type: 1 - block
 	clif_displaymessage(fd, msg_txt(sd,88)); // Character name sent to char-server to ask it.
 
 	return 0;
 }
 
 /*==========================================
- * charban command (usage: charban <time> <player_name>)
- * This command do a limited ban on a player
- * Time is done as follows:
- *   Adjustment value (-1, 1, +1, etc...)
- *   Modified element:
- *     a or y: year
- *     m:  month
- *     j or d: day
- *     h:  hour
- *     mn: minute
- *     s:  second
- * <example> @ban +1m-2mn1s-6y test_player
- *           this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time.
+ * accountban command (usage: ban <%time> <player_name>)
+ * charban command (usage: charban <%time> <player_name>)
+ * %time see common/timer.c::solve_time()
  *------------------------------------------*/
 ACMD_FUNC(char_ban)
 {
 	char * modif_p;
-	int year, month, day, hour, minute, second, value;
-	time_t timestamp;
-	struct tm *tmtime;
 	nullpo_retr(-1, sd);
+	int timediff=0;
+	int bantype=2; //2=account block, 6=char specific
+	char output[256];
 
 	memset(atcmd_output, '\0', sizeof(atcmd_output));
 	memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
 
+	bantype = strcmpi(command+1,"charban")?2:6; //! FIXME this breaking alias recognition
 	if (!message || !*message || sscanf(message, "%255s %23[^\n]", atcmd_output, atcmd_player_name) < 2) {
 		clif_displaymessage(fd, msg_txt(sd,1022)); // Please enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish <time> <char name>).
 		return -1;
 	}
 
 	atcmd_output[sizeof(atcmd_output)-1] = '\0';
+	
 
 	modif_p = atcmd_output;
-	year = month = day = hour = minute = second = 0;
-	while (modif_p[0] != '\0') {
-		value = atoi(modif_p);
-		if (value == 0)
-			modif_p++;
-		else {
-			if (modif_p[0] == '-' || modif_p[0] == '+')
-				modif_p++;
-			while (modif_p[0] >= '0' && modif_p[0] <= '9')
-				modif_p++;
-			if (modif_p[0] == 's') {
-				second = value;
-				modif_p++;
-			} else if (modif_p[0] == 'n') {
-				minute = value;
-				modif_p++;
-			} else if (modif_p[0] == 'm' && modif_p[1] == 'n') {
-				minute = value;
-				modif_p = modif_p + 2;
-			} else if (modif_p[0] == 'h') {
-				hour = value;
-				modif_p++;
-			} else if (modif_p[0] == 'd' || modif_p[0] == 'j') {
-				day = value;
-				modif_p++;
-			} else if (modif_p[0] == 'm') {
-				month = value;
-				modif_p++;
-			} else if (modif_p[0] == 'y' || modif_p[0] == 'a') {
-				year = value;
-				modif_p++;
-			} else if (modif_p[0] != '\0') {
-				modif_p++;
-			}
-		}
-	}
-	if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 && second == 0) {
-		clif_displaymessage(fd, msg_txt(sd,85)); // Invalid time for ban command.
+	timediff = (int)solve_time(modif_p); //discard seconds
+
+	if (timediff == 0) { //allow negative ?
+		char output[256];
+		safesnprintf(output,sizeof(output),msg_txt(sd,85),bantype==6?"charban":"ban",timediff); // Invalid time for %s command (time=%d)
+		clif_displaymessage(fd, output);
+		clif_displaymessage(fd, msg_txt(sd,702)); // Time parameter format is +/-<value> to alter. y/a = Year, m = Month, d/j = Day, h = Hour, n/mn = Minute, s = Second.
 		return -1;
 	}
-	/**
-	 * We now check if you can adjust the ban to negative (and if this is the case)
-	 **/
-	timestamp = time(NULL);
-	tmtime = localtime(&timestamp);
-	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( timestamp <= time(NULL) && !pc_can_use_command(sd, "unban", COMMAND_ATCOMMAND) ) {
-		clif_displaymessage(fd,msg_txt(sd,1023)); // You are not allowed to reduce the length of a ban.
+	
+	if( timediff<0 && (
+		( bantype==2 && !pc_can_use_command(sd, "unban", COMMAND_ATCOMMAND) ) 
+		|| ( bantype==6 && !pc_can_use_command(sd, "charunban", COMMAND_ATCOMMAND)) )
+		){
+		clif_displaymessage(fd,msg_txt(sd,1023)); // You are not allowed to alter the time of a ban.
 		return -1;
 	}
-
-	chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 2, year, month, day, hour, minute, second); // type: 2 - ban
-	clif_displaymessage(fd, msg_txt(sd,88)); // Character name sent to char-server to ask it.
+	
+	chrif_ask_char_operation(sd->status.account_id, atcmd_player_name, bantype, timediff); // type: 2 - ban
+	safesnprintf(output,sizeof(output),msg_txt(sd,88),bantype==6?"char":"login"); // Sending request to %s server...
+	clif_displaymessage(fd, output);
 
 	return 0;
 }
@@ -2891,28 +2845,33 @@ ACMD_FUNC(char_unblock)
 	}
 
 	// send answer to login server via char-server
-	chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 3, 0, 0, 0, 0, 0, 0); // type: 3 - unblock
+	chrif_ask_char_operation(sd->status.account_id, atcmd_player_name, 3, 0); // type: 3 - unblock
 	clif_displaymessage(fd, msg_txt(sd,88)); // Character name sent to char-server to ask it.
 
 	return 0;
 }
 
 /*==========================================
- * charunban command (usage: charunban <player_name>)
+ * acc unban command (usage: unban <player_name>)
+ * char unban command (usage: charunban <player_name>)
  *------------------------------------------*/
-ACMD_FUNC(char_unban)
-{
+ACMD_FUNC(char_unban){
+	int unbantype=4;
 	nullpo_retr(-1, sd);
 
 	memset(atcmd_player_name, '\0', sizeof(atcmd_player_name));
+	unbantype = strcmpi(command+1,"charunban")?4:7; //! FIXME this breaking alias recognition
 
-	if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {
-		clif_displaymessage(fd, msg_txt(sd,1025)); // Please enter a player name (usage: @charunban <char name>).
+	if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) {	
+		if(unbantype==4) clif_displaymessage(fd, msg_txt(sd,1025)); // Please enter a player name (usage: @unblock <char name>).
+		else clif_displaymessage(fd, msg_txt(sd,435)); //Please enter a player name (usage: @charunban <char name>).
 		return -1;
-	}
+	} 
+	
 
+	ShowInfo("char_unban unbantype=%d\n",unbantype);
 	// 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_ask_char_operation(sd->status.account_id, atcmd_player_name, unbantype, 0); // type: 4 - unban
 	clif_displaymessage(fd, msg_txt(sd,88)); // Character name sent to char-server to ask it.
 
 	return 0;
@@ -4615,14 +4574,15 @@ ACMD_FUNC(unjail)
 	return 0;
 }
 
-ACMD_FUNC(jailfor)
-{
+ACMD_FUNC(jailfor) {
 	struct map_session_data *pl_sd = NULL;
 	char * modif_p;
 	int jailtime = 0,x,y;
 	short m_index = 0;
 	nullpo_retr(-1, sd);
 
+	memset(atcmd_output, '\0', sizeof(atcmd_output));
+	
 	if (!message || !*message || sscanf(message, "%255s %23[^\n]",atcmd_output,atcmd_player_name) < 2) {
 		clif_displaymessage(fd, msg_txt(sd,400));	//Usage: @jailfor <time> <character name>
 		return -1;
@@ -4658,13 +4618,14 @@ ACMD_FUNC(jailfor)
 			clif_displaymessage(fd, msg_txt(sd,121)); // Player unjailed
 		} else {
 			int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
-			char timestr[CHAT_SIZE_MAX];
+			char timestr[21];
+			time_t now=time(NULL);
 			split_time(jailtime*60,&year,&month,&day,&hour,&minute,&second);
 			sprintf(atcmd_output,msg_txt(sd,402),msg_txt(sd,1137),year,month,day,hour,minute); // %s in jail for %d years, %d months, %d days, %d hours and %d minutes
-	 		clif_displaymessage(pl_sd->fd, atcmd_output);
+			clif_displaymessage(pl_sd->fd, atcmd_output);
 			sprintf(atcmd_output,msg_txt(sd,402),msg_txt(sd,1138),year,month,day,hour,minute); // This player is now in jail for %d years, %d months, %d days, %d hours and %d minutes
-	 		clif_displaymessage(fd, atcmd_output);
-			time2str(timestr,"%Y-%m-%d %H:%M",jailtime*60);
+			clif_displaymessage(fd, atcmd_output);
+			timestamp2string(timestr,20,now+jailtime*60,"%Y-%m-%d %H:%M");
 			sprintf(atcmd_output,"Release date is: %s",timestr);
 			clif_displaymessage(pl_sd->fd, atcmd_output);
 			clif_displaymessage(fd, atcmd_output);
@@ -4693,7 +4654,8 @@ ACMD_FUNC(jailfor)
 //By Coltaro
 ACMD_FUNC(jailtime){
 	int year, month, day, hour, minute, second;
-	char timestr[CHAT_SIZE_MAX];
+	char timestr[21];
+	time_t now = time(NULL);
 
 	nullpo_retr(-1, sd);
 
@@ -4716,7 +4678,7 @@ ACMD_FUNC(jailtime){
 	split_time(sd->sc.data[SC_JAILED]->val1*60,&year,&month,&day,&hour,&minute,&second);
 	sprintf(atcmd_output,msg_txt(sd,402),msg_txt(sd,1142),year,month,day,hour,minute); // You will remain in jail for %d years, %d months, %d days, %d hours and %d minutes
 	clif_displaymessage(fd, atcmd_output);
-	time2str(timestr,"%Y-%m-%d %H:%M",sd->sc.data[SC_JAILED]->val1*60);
+	timestamp2string(timestr,20,now+sd->sc.data[SC_JAILED]->val1*60,"%Y-%m-%d %H:%M");
 	sprintf(atcmd_output,"Release date is: %s",timestr);
 	clif_displaymessage(fd, atcmd_output);
 
@@ -9189,13 +9151,14 @@ ACMD_FUNC(langtype)
 }
 
 #ifdef VIP_ENABLE
-ACMD_FUNC(vip)
-{
+ACMD_FUNC(vip) {
 	struct map_session_data *pl_sd = NULL;
 	char * modif_p;
 	int viptime = 0;
 	nullpo_retr(-1, sd);
 
+	memset(atcmd_output, '\0', sizeof(atcmd_output));
+	
 	if (!message || !*message || sscanf(message, "%255s %23[^\n]",atcmd_output,atcmd_player_name) < 2) {
 		clif_displaymessage(fd, msg_txt(sd,700));	//Usage: @vip <time> <character name>
 		return -1;
@@ -9230,13 +9193,14 @@ ACMD_FUNC(vip)
 		clif_displaymessage(fd, msg_txt(sd,704)); // Player is no longer VIP.
 	} else {
 		int year,month,day,hour,minute,second;
-		char timestr[128];
+		char timestr[21];
+		time_t now=time(NULL);
 		split_time(pl_sd->vip.time*60,&year,&month,&day,&hour,&minute,&second);
 		sprintf(atcmd_output,msg_txt(sd,705),pl_sd->status.name,year,month,day,hour,minute); //%s is VIP for %d years, %d months, %d days, %d hours and %d minutes.
 		clif_displaymessage(pl_sd->fd, atcmd_output);
 		sprintf(atcmd_output,msg_txt(sd,706),year,month,day,hour,minute); //This player is now VIP for %d years, %d months, %d days, %d hours and %d minutes.
 		clif_displaymessage(fd, atcmd_output);
-		time2str(timestr,"%Y-%m-%d %H:%M",pl_sd->vip.time*60);
+		timestamp2string(timestr,20,now+pl_sd->vip.time*60,"%Y-%m-%d %H:%M");
 		sprintf(atcmd_output,"%s : %s",msg_txt(sd,707),timestr); //You are VIP until :
 		clif_displaymessage(pl_sd->fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
@@ -9379,6 +9343,8 @@ void atcommand_basecommands(void) {
 		ACMD_DEF2("ban", char_ban),
 		ACMD_DEF2("unblock", char_unblock),
 		ACMD_DEF2("unban", char_unban),
+		ACMD_DEF2("charban", char_ban),
+		ACMD_DEF2("charunban", char_unban),
 		ACMD_DEF2("mount", mount_peco),
 		ACMD_DEF(guildspy),
 		ACMD_DEF(partyspy),

+ 24 - 25
src/map/chrif.c

@@ -42,7 +42,7 @@ static DBMap* auth_db; // int id -> struct auth_node*
 static const int packet_len_table[0x3d] = { // U - used, F - free
 	60, 3,-1,27,10,-1, 6,-1,	// 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff
 	 6,-1,19, 7,-1,39,30, 10,	// 2b00-2b07: U->2b00, U->2b01, U->2b02, U->2b03, U->2b04, U->2b05, U->2b06, U->2b07
-	 6,30, 10, -1,86, 7,44,34,	// 2b08-2b0f: U->2b08, U->2b09, U->2b0a, U->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f
+	 6,30, 10, -1,86, 7,36,34,	// 2b08-2b0f: U->2b08, U->2b09, U->2b0a, U->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f
 	11,10,10, 0,11, -1,266,10,	// 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, U->2b15, U->2b16, U->2b17
 	 2,10, 2,-1,-1,-1, 2, 7,	// 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f
 	-1,10, 8, 2, 2,14,19,19,	// 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27
@@ -814,43 +814,36 @@ 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 }
+ * S 2b0e <accid>.l <name>.24B <operation_type>.w <timediff>L
  * 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, 7: charunban 
  *------------------------------------------*/
-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) {
-
+int chrif_ask_char_operation(int acc, const char* character_name, unsigned short operation_type, int timediff) {
 	chrif_check(-1);
 
-	WFIFOHEAD(char_fd,44);
+	WFIFOHEAD(char_fd,36);
 	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;
-	}
+	if ( operation_type == 2 || operation_type == 6)
+		WFIFOL(char_fd,32) = timediff;
 
-	WFIFOSET(char_fd,44);
+	WFIFOSET(char_fd,36);
 	return 0;
 }
 
 int chrif_changesex(struct map_session_data *sd) {
 	chrif_check(-1);
 
-	WFIFOHEAD(char_fd,44);
+	WFIFOHEAD(char_fd,36);
 	WFIFOW(char_fd,0) = 0x2b0e;
 	WFIFOL(char_fd,2) = sd->status.account_id;
 	safestrncpy((char*)WFIFOP(char_fd,6), sd->status.name, NAME_LENGTH);
 	WFIFOW(char_fd,30) = 5;
-	WFIFOSET(char_fd,44);
+	WFIFOSET(char_fd,36);
 
 	clif_displaymessage(sd->fd, msg_txt(sd,408)); //"Need disconnection to perform change-sex request..."
 
@@ -865,12 +858,13 @@ 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
  *   2: gm level too low
  *   3: login-server offline
+ *   4: char-server request done
  *------------------------------------------*/
 static void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 type, uint16 answer) {
 	struct map_session_data* sd;
@@ -886,14 +880,17 @@ static void chrif_char_ask_name_answer(int acc, const char* player_name, uint16
 
 	if( type > 0 && type <= 5 )
 		snprintf(action,25,"%s",msg_txt(sd,427+type)); //block|ban|unblock|unban|change the sex of
+	else if( type==6) snprintf(action,25,"%s","charban"); //TODO make some place for those type in msg_conf
+	else if( type==7) snprintf(action,25,"%s","charunban");
 	else
 		snprintf(action,25,"???");
 
 	switch( answer ) {
-		case 0 : sprintf(output, msg_txt(sd,424), action, NAME_LENGTH, player_name); break;
+		case 0 : sprintf(output, msg_txt(sd,424), "login-serv", action, NAME_LENGTH, player_name); break; //%s has been asked to %s the player '%.*s'.
 		case 1 : sprintf(output, msg_txt(sd,425), NAME_LENGTH, player_name); break;
 		case 2 : sprintf(output, msg_txt(sd,426), action, NAME_LENGTH, player_name); break;
 		case 3 : sprintf(output, msg_txt(sd,427), action, NAME_LENGTH, player_name); break;
+		case 4 : sprintf(output, msg_txt(sd,424), "char-serv", action, NAME_LENGTH, player_name); break;
 		default: output[0] = '\0'; break;
 	}
 
@@ -1026,10 +1023,11 @@ int chrif_deadopt(int father_id, int mother_id, int child_id) {
  * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor]
  *------------------------------------------*/
 int chrif_accountban(int fd) {
-	int acc;
+	int acc, res=0;
 	struct map_session_data *sd;
 
 	acc = RFIFOL(fd,2);
+	res = RFIFOB(fd,6); // 0: change of statut, 1: ban, 2 charban
 
 	if ( battle_config.etc_log )
 		ShowNotice("chrif_accountban %d.\n", acc);
@@ -1042,7 +1040,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 (res == 0) { 
 		int ret_status = RFIFOL(fd,7); // status or final date of a banishment
 		if(0<ret_status && ret_status<=9)
 			clif_displaymessage(sd->fd, msg_txt(sd,411+ret_status));
@@ -1050,12 +1048,13 @@ int chrif_accountban(int fd) {
 			clif_displaymessage(sd->fd, msg_txt(sd,421));
 		 else
 			clif_displaymessage(sd->fd, msg_txt(sd,420)); //"Your account has not more authorised."
-	} else if (RFIFOB(fd,6) == 1) { // 0: change of statut, 1: ban
+	} else if (res == 1 || res == 2) {
 		time_t timestamp;
-		char tmpstr[2048];
+		char tmpstr[256];
+		char strtime[25];
 		timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment
-		strcpy(tmpstr, msg_txt(sd,423)); //"Your account has been banished until "
-		strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(&timestamp));
+		strftime(strtime, 24, "%d-%m-%Y %H:%M:%S", localtime(&timestamp));
+		safesnprintf(tmpstr,sizeof(tmpstr),msg_txt(sd,423),res==2?"char":"account",strtime); //"Your %s has been banished until %s "
 		clif_displaymessage(sd->fd, tmpstr);
 	}
 

+ 1 - 1
src/map/chrif.h

@@ -50,7 +50,7 @@ int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port);
 
 int chrif_searchcharid(int char_id);
 int chrif_changeemail(int id, const char *actual_email, const char *new_email);
-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);
+int chrif_ask_char_operation(int acc, const char* character_name, unsigned short operation_type, int timediff);
 int chrif_updatefamelist(struct map_session_data *sd);
 int chrif_buildfamelist(void);
 int chrif_save_scdata(struct map_session_data *sd);

+ 2 - 2
src/map/trade.c

@@ -207,13 +207,13 @@ int impossible_trade_check(struct map_session_data *sd)
 			intif_wis_message_to_gm(wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
 			// if we block people
 			if (battle_config.ban_hack_trade < 0) {
-				chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
+				chrif_ask_char_operation(-1, sd->status.name, 1, 0); // type: 1 - block
 				set_eof(sd->fd); // forced to disconnect because of the hack
 				// message about the ban
 				strcpy(message_to_gm, msg_txt(sd,540)); //  This player has been definitively blocked.
 			// if we ban people
 			} else if (battle_config.ban_hack_trade > 0) {
-				chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_hack_trade, 0); // type: 2 - ban (year, month, day, hour, minute, second)
+				chrif_ask_char_operation(-1, sd->status.name, 2, battle_config.ban_hack_trade*60); // type: 2 - ban (year, month, day, hour, minute, second)
 				set_eof(sd->fd); // forced to disconnect because of the hack
 				// message about the ban
 				sprintf(message_to_gm, msg_txt(sd,507), battle_config.ban_hack_trade); //  This player has been banned for %d minute(s).